cubeb_utils.h (8094B)
1 /* 2 * Copyright © 2016 Mozilla Foundation 3 * 4 * This program is made available under an ISC-style license. See the 5 * accompanying file LICENSE for details. 6 */ 7 8 #if !defined(CUBEB_UTILS) 9 #define CUBEB_UTILS 10 11 #include "cubeb/cubeb.h" 12 13 #ifdef __cplusplus 14 15 #include <assert.h> 16 #include <mutex> 17 #include <stdint.h> 18 #include <string.h> 19 #include <type_traits> 20 #if defined(_WIN32) 21 #include "cubeb_utils_win.h" 22 #else 23 #include "cubeb_utils_unix.h" 24 #endif 25 26 /** Similar to memcpy, but accounts for the size of an element. */ 27 template <typename T> 28 void 29 PodCopy(T * destination, const T * source, size_t count) 30 { 31 static_assert(std::is_trivial<T>::value, "Requires trivial type"); 32 assert(destination && source); 33 memcpy(destination, source, count * sizeof(T)); 34 } 35 36 /** Similar to memmove, but accounts for the size of an element. */ 37 template <typename T> 38 void 39 PodMove(T * destination, const T * source, size_t count) 40 { 41 static_assert(std::is_trivial<T>::value, "Requires trivial type"); 42 assert(destination && source); 43 memmove(destination, source, count * sizeof(T)); 44 } 45 46 /** Similar to a memset to zero, but accounts for the size of an element. */ 47 template <typename T> 48 void 49 PodZero(T * destination, size_t count) 50 { 51 static_assert(std::is_trivial<T>::value, "Requires trivial type"); 52 assert(destination); 53 memset(destination, 0, count * sizeof(T)); 54 } 55 56 namespace { 57 template <typename T, typename Trait> 58 void 59 Copy(T * destination, const T * source, size_t count, Trait) 60 { 61 for (size_t i = 0; i < count; i++) { 62 destination[i] = source[i]; 63 } 64 } 65 66 template <typename T> 67 void 68 Copy(T * destination, const T * source, size_t count, std::true_type) 69 { 70 PodCopy(destination, source, count); 71 } 72 } // namespace 73 74 /** 75 * This allows copying a number of elements from a `source` pointer to a 76 * `destination` pointer, using `memcpy` if it is safe to do so, or a loop that 77 * calls the constructors and destructors otherwise. 78 */ 79 template <typename T> 80 void 81 Copy(T * destination, const T * source, size_t count) 82 { 83 assert(destination && source); 84 Copy(destination, source, count, typename std::is_trivial<T>::type()); 85 } 86 87 namespace { 88 template <typename T, typename Trait> 89 void 90 ConstructDefault(T * destination, size_t count, Trait) 91 { 92 for (size_t i = 0; i < count; i++) { 93 destination[i] = T(); 94 } 95 } 96 97 template <typename T> 98 void 99 ConstructDefault(T * destination, size_t count, std::true_type) 100 { 101 PodZero(destination, count); 102 } 103 } // namespace 104 105 /** 106 * This allows zeroing (using memset) or default-constructing a number of 107 * elements calling the constructors and destructors if necessary. 108 */ 109 template <typename T> 110 void 111 ConstructDefault(T * destination, size_t count) 112 { 113 assert(destination); 114 ConstructDefault(destination, count, typename std::is_arithmetic<T>::type()); 115 } 116 117 template <typename T> class auto_array { 118 public: 119 explicit auto_array(uint32_t capacity = 0) 120 : data_(capacity ? new T[capacity] : nullptr), capacity_(capacity), 121 length_(0) 122 { 123 } 124 125 ~auto_array() { delete[] data_; } 126 127 /** Get a constant pointer to the underlying data. */ 128 T * data() const { return data_; } 129 130 T * end() const { return data_ + length_; } 131 132 const T & at(size_t index) const 133 { 134 assert(index < length_ && "out of range"); 135 return data_[index]; 136 } 137 138 T & at(size_t index) 139 { 140 assert(index < length_ && "out of range"); 141 return data_[index]; 142 } 143 144 /** Get how much underlying storage this auto_array has. */ 145 size_t capacity() const { return capacity_; } 146 147 /** Get how much elements this auto_array contains. */ 148 size_t length() const { return length_; } 149 150 /** Keeps the storage, but removes all the elements from the array. */ 151 void clear() { length_ = 0; } 152 153 /** Change the storage of this auto array, copying the elements to the new 154 * storage. 155 * @returns true in case of success 156 * @returns false if the new capacity is not big enough to accomodate for the 157 * elements in the array. 158 */ 159 bool reserve(size_t new_capacity) 160 { 161 if (new_capacity < length_) { 162 return false; 163 } 164 T * new_data = new T[new_capacity]; 165 if (data_ && length_) { 166 PodCopy(new_data, data_, length_); 167 } 168 capacity_ = new_capacity; 169 delete[] data_; 170 data_ = new_data; 171 172 return true; 173 } 174 175 /** Append `length` elements to the end of the array, resizing the array if 176 * needed. 177 * @parameter elements the elements to append to the array. 178 * @parameter length the number of elements to append to the array. 179 */ 180 void push(const T * elements, size_t length) 181 { 182 if (length_ + length > capacity_) { 183 reserve(length_ + length); 184 } 185 if (data_) { 186 PodCopy(data_ + length_, elements, length); 187 } 188 length_ += length; 189 } 190 191 /** Append `length` zero-ed elements to the end of the array, resizing the 192 * array if needed. 193 * @parameter length the number of elements to append to the array. 194 */ 195 void push_silence(size_t length) 196 { 197 if (length_ + length > capacity_) { 198 reserve(length + length_); 199 } 200 if (data_) { 201 PodZero(data_ + length_, length); 202 } 203 length_ += length; 204 } 205 206 /** Prepend `length` zero-ed elements to the front of the array, resizing and 207 * shifting the array if needed. 208 * @parameter length the number of elements to prepend to the array. 209 */ 210 void push_front_silence(size_t length) 211 { 212 if (length_ + length > capacity_) { 213 reserve(length + length_); 214 } 215 if (data_) { 216 PodMove(data_ + length, data_, length_); 217 PodZero(data_, length); 218 } 219 length_ += length; 220 } 221 222 /** Return the number of free elements in the array. */ 223 size_t available() const { return capacity_ - length_; } 224 225 /** Copies `length` elements to `elements` if it is not null, and shift 226 * the remaining elements of the `auto_array` to the beginning. 227 * @parameter elements a buffer to copy the elements to, or nullptr. 228 * @parameter length the number of elements to copy. 229 * @returns true in case of success. 230 * @returns false if the auto_array contains less than `length` elements. */ 231 bool pop(T * elements, size_t length) 232 { 233 if (length > length_) { 234 return false; 235 } 236 if (!data_) { 237 return true; 238 } 239 if (elements) { 240 PodCopy(elements, data_, length); 241 } 242 PodMove(data_, data_ + length, length_ - length); 243 244 length_ -= length; 245 246 return true; 247 } 248 249 void set_length(size_t length) 250 { 251 assert(length <= capacity_); 252 length_ = length; 253 } 254 255 private: 256 /** The underlying storage */ 257 T * data_; 258 /** The size, in number of elements, of the storage. */ 259 size_t capacity_; 260 /** The number of elements the array contains. */ 261 size_t length_; 262 }; 263 264 struct auto_array_wrapper { 265 virtual void push(void * elements, size_t length) = 0; 266 virtual size_t length() = 0; 267 virtual void push_silence(size_t length) = 0; 268 virtual bool pop(size_t length) = 0; 269 virtual void * data() = 0; 270 virtual void * end() = 0; 271 virtual void clear() = 0; 272 virtual bool reserve(size_t capacity) = 0; 273 virtual void set_length(size_t length) = 0; 274 virtual ~auto_array_wrapper() {} 275 }; 276 277 template <typename T> 278 struct auto_array_wrapper_impl : public auto_array_wrapper { 279 auto_array_wrapper_impl() {} 280 281 explicit auto_array_wrapper_impl(uint32_t size) : ar(size) {} 282 283 void push(void * elements, size_t length) override 284 { 285 ar.push(static_cast<T *>(elements), length); 286 } 287 288 size_t length() override { return ar.length(); } 289 290 void push_silence(size_t length) override { ar.push_silence(length); } 291 292 bool pop(size_t length) override { return ar.pop(nullptr, length); } 293 294 void * data() override { return ar.data(); } 295 296 void * end() override { return ar.end(); } 297 298 void clear() override { ar.clear(); } 299 300 bool reserve(size_t capacity) override { return ar.reserve(capacity); } 301 302 void set_length(size_t length) override { ar.set_length(length); } 303 304 ~auto_array_wrapper_impl() { ar.clear(); } 305 306 private: 307 auto_array<T> ar; 308 }; 309 310 extern "C" { 311 size_t 312 cubeb_sample_size(cubeb_sample_format format); 313 } 314 315 using auto_lock = std::lock_guard<owned_critical_section>; 316 #endif // __cplusplus 317 318 #endif /* CUBEB_UTILS */