1 /*
2  * objects.h
3  * Copyright 2014 John Lindgren
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions, and the following disclaimer in the documentation
13  *    provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #ifndef LIBAUDCORE_OBJECTS_H
21 #define LIBAUDCORE_OBJECTS_H
22 
23 #ifdef AUD_GLIB_INTEGRATION
24 #include <glib.h>
25 #endif
26 
27 #include <libaudcore/templates.h>
28 
29 // Stores array pointer together with deduced array length.
30 
31 template<class T>
32 struct ArrayRef
33 {
34     const T * data;
35     int len;
36 
decltypeArrayRef37     constexpr ArrayRef(decltype(nullptr) = nullptr) : data(nullptr), len(0) {}
38 
39     template<int N>
ArrayRefArrayRef40     constexpr ArrayRef(const T (&array)[N]) : data(array), len(N)
41     {
42     }
43 
ArrayRefArrayRef44     constexpr ArrayRef(const T * data, int len) : data(data), len(len) {}
45 
beginArrayRef46     const T * begin() const { return data; }
endArrayRef47     const T * end() const { return data + len; }
48 };
49 
50 // Smart pointer.  Deletes object pointed to when the pointer goes out of scope.
51 
52 template<class T, void (*deleter)(T *) = aud::delete_typed>
53 class SmartPtr
54 {
55 public:
SmartPtr()56     constexpr SmartPtr() : ptr(nullptr) {}
SmartPtr(T * ptr)57     explicit constexpr SmartPtr(T * ptr) : ptr(ptr) {}
58 
~SmartPtr()59     ~SmartPtr()
60     {
61         if (ptr)
62             deleter(ptr);
63     }
64 
capture(T * ptr2)65     bool capture(T * ptr2)
66     {
67         if (ptr)
68             deleter(ptr);
69         ptr = ptr2;
70         return (bool)ptr;
71     }
72 
release()73     T * release()
74     {
75         T * ptr2 = ptr;
76         ptr = nullptr;
77         return ptr2;
78     }
79 
clear()80     void clear() { capture(nullptr); }
81 
SmartPtr(SmartPtr && b)82     SmartPtr(SmartPtr && b) : ptr(b.ptr) { b.ptr = nullptr; }
83 
84     SmartPtr & operator=(SmartPtr && b)
85     {
86         return aud::move_assign(*this, std::move(b));
87     }
88 
89     explicit operator bool() const { return (bool)ptr; }
90 
get()91     T * get() { return ptr; }
get()92     const T * get() const { return ptr; }
93     T & operator*() { return (*ptr); }
94     const T & operator*() const { return (*ptr); }
95     T * operator->() { return ptr; }
96     const T * operator->() const { return ptr; }
97 
98 private:
99     T * ptr;
100 };
101 
102 template<class T, class... Args>
SmartNew(Args &&...args)103 SmartPtr<T> SmartNew(Args &&... args)
104 {
105     return SmartPtr<T>(aud::construct<T>::make(operator new(sizeof(T)),
106                                                std::forward<Args>(args)...));
107 }
108 
109 // Convenience wrapper for a GLib-style string (char *).
110 
111 #ifdef AUD_GLIB_INTEGRATION
112 class CharPtr : public SmartPtr<char, aud::typed_func<char, g_free>>
113 {
114 public:
CharPtr()115     CharPtr() : SmartPtr() {}
CharPtr(char * ptr)116     explicit CharPtr(char * ptr) : SmartPtr(ptr) {}
117 
118     // non-const operator omitted to prevent "CharPtr s; g_free(s);"
119     operator const char *() const { return get(); }
120 };
121 #endif
122 
123 // Wrapper class for a string stored in the string pool.
124 
125 class String
126 {
127 public:
String()128     constexpr String() : raw(nullptr) {}
129 
~String()130     ~String()
131     {
132         if (raw)
133             raw_unref(raw);
134     }
135 
String(const String & b)136     String(const String & b) : raw(raw_ref(b.raw)) {}
137 
138     String & operator=(const String & b)
139     {
140         if (this != &b)
141         {
142             raw_unref(raw);
143             raw = raw_ref(b.raw);
144         }
145         return *this;
146     }
147 
String(String && b)148     String(String && b) : raw(b.raw) { b.raw = nullptr; }
149 
150     String & operator=(String && b)
151     {
152         return aud::move_assign(*this, std::move(b));
153     }
154 
155     bool operator==(const String & b) const { return raw_equal(raw, b.raw); }
156 
String(const char * str)157     explicit String(const char * str) : raw(raw_get(str)) {}
158 
159     String(decltype(nullptr)) = delete;
160 
161     operator const char *() const { return raw; }
162 
hash()163     unsigned hash() const { return raw_hash(raw); }
164 
165 private:
166     static char * raw_get(const char * str);
167     static char * raw_ref(const char * str);
168     static void raw_unref(char * str);
169     static unsigned raw_hash(const char * str);
170     static bool raw_equal(const char * str1, const char * str2);
171 
172     char * raw;
173 };
174 
175 struct StringStack;
176 
177 // Mutable string buffer, allocated on a stack-like structure.  The intent is
178 // to provide fast allocation/deallocation for strings with a short lifespan.
179 // Note that some usage patterns (for example, repeatedly appending to multiple
180 // strings) can rapidly cause memory fragmentation and eventually lead to an
181 // out-of-memory exception.
182 //
183 // Some usage guidelines:
184 //
185 //   1. Always declare StringBufs within function or block scope, never at file
186 //      or class scope.  Do not attempt to create a StringBuf with new or
187 //      malloc().
188 //   2. If you need to return a StringBuf from a function that uses several
189 //      different strings internally, make sure all the other strings go out of
190 //      scope first and then call settle() on the string to be returned.
191 //   3. Never transfer StringBuf objects across thread boundaries.
192 
193 class StringBuf
194 {
195 public:
StringBuf()196     constexpr StringBuf() : stack(nullptr), m_data(nullptr), m_len(0) {}
197 
StringBuf(int len)198     explicit StringBuf(int len) : stack(nullptr), m_data(nullptr), m_len(0)
199     {
200         resize(len);
201     }
202 
StringBuf(StringBuf && other)203     StringBuf(StringBuf && other)
204         : stack(other.stack), m_data(other.m_data), m_len(other.m_len)
205     {
206         other.stack = nullptr;
207         other.m_data = nullptr;
208         other.m_len = 0;
209     }
210 
211     StringBuf & operator=(StringBuf && other)
212     {
213         return aud::move_assign(*this, std::move(other));
214     }
215 
216     ~StringBuf();
217 
218     // Resizes to <len> bytes (not counting the terminating null byte) by
219     // appended uninitialized bytes or truncating.  The resized string will be
220     // null-terminated unless <len> is -1.  A length of -1 means to make the
221     // string as large as possible.  This can be useful when the required length
222     // is not known in advance.  However, it will be impossible to create any
223     // further StringBufs until resize() is called again.
224     void resize(int len);
225 
226     // Inserts the substring <s> at the given position, or appends it if <pos>
227     // is -1.  If <len> is -1, <s> is assumed to be null-terminated; otherwise,
228     // <len> indicates the number of bytes to insert.  If <s> is a null pointer,
229     // uninitialized bytes are inserted and <len> must not be -1.  A pointer to
230     // the inserted substring is returned for convenience.
231     char * insert(int pos, const char * s, int len = -1);
232 
233     // Removes <len> bytes at the given position.
234     void remove(int pos, int len);
235 
236     // Collapses any unused space preceding this string.
237     // Judicious use can combat memory fragmentation.
238     // Returns a move reference to allow e.g. "return str.settle();"
239     StringBuf && settle();
240 
len()241     int len() const { return m_len; }
242 
243     operator char *() { return m_data; }
244 
245     // deprecated, use assignment
246     void steal(StringBuf && other) __attribute__((deprecated));
247     // deprecated, use insert()
248     void combine(StringBuf && other) __attribute__((deprecated));
249 
250 private:
251     StringStack * stack;
252     char * m_data;
253     int m_len;
254 };
255 
256 #endif // LIBAUDCORE_OBJECTS_H
257