duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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 */