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