vector.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. // Copyright 2009-2021 Intel Corporation
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #include "alloc.h"
  5. #include <algorithm>
  6. namespace embree
  7. {
  8. class Device;
  9. template<typename T, typename allocator>
  10. class vector_t
  11. {
  12. public:
  13. typedef T value_type;
  14. typedef T* iterator;
  15. typedef const T* const_iterator;
  16. __forceinline vector_t ()
  17. : size_active(0), size_alloced(0), items(nullptr) {}
  18. __forceinline explicit vector_t (size_t sz)
  19. : size_active(0), size_alloced(0), items(nullptr) { internal_resize_init(sz); }
  20. template<typename M>
  21. __forceinline explicit vector_t (M alloc, size_t sz)
  22. : alloc(alloc), size_active(0), size_alloced(0), items(nullptr) { internal_resize_init(sz); }
  23. __forceinline vector_t (Device* alloc)
  24. : vector_t(alloc,0) {}
  25. __forceinline vector_t(void* data, size_t bytes)
  26. : size_active(0), size_alloced(bytes/sizeof(T)), items((T*)data) {}
  27. __forceinline ~vector_t() {
  28. clear();
  29. }
  30. __forceinline vector_t (const vector_t& other)
  31. {
  32. size_active = other.size_active;
  33. size_alloced = other.size_alloced;
  34. items = alloc.allocate(size_alloced);
  35. for (size_t i=0; i<size_active; i++)
  36. ::new (&items[i]) value_type(other.items[i]);
  37. }
  38. __forceinline vector_t (vector_t&& other)
  39. : alloc(std::move(other.alloc))
  40. {
  41. size_active = other.size_active; other.size_active = 0;
  42. size_alloced = other.size_alloced; other.size_alloced = 0;
  43. items = other.items; other.items = nullptr;
  44. }
  45. __forceinline vector_t& operator=(const vector_t& other)
  46. {
  47. resize(other.size_active);
  48. for (size_t i=0; i<size_active; i++)
  49. items[i] = value_type(other.items[i]);
  50. return *this;
  51. }
  52. __forceinline vector_t& operator=(vector_t&& other)
  53. {
  54. clear();
  55. alloc = std::move(other.alloc);
  56. size_active = other.size_active; other.size_active = 0;
  57. size_alloced = other.size_alloced; other.size_alloced = 0;
  58. items = other.items; other.items = nullptr;
  59. return *this;
  60. }
  61. __forceinline allocator& getAlloc() {
  62. return alloc;
  63. }
  64. /********************** Iterators ****************************/
  65. __forceinline iterator begin() { return items; };
  66. __forceinline const_iterator begin() const { return items; };
  67. __forceinline iterator end () { return items+size_active; };
  68. __forceinline const_iterator end () const { return items+size_active; };
  69. /********************** Capacity ****************************/
  70. __forceinline bool empty () const { return size_active == 0; }
  71. __forceinline size_t size () const { return size_active; }
  72. __forceinline size_t capacity () const { return size_alloced; }
  73. __forceinline void resize(size_t new_size) {
  74. internal_resize(new_size,internal_grow_size(new_size));
  75. }
  76. __forceinline void reserve(size_t new_alloced)
  77. {
  78. /* do nothing if container already large enough */
  79. if (new_alloced <= size_alloced)
  80. return;
  81. /* resize exact otherwise */
  82. internal_resize(size_active,new_alloced);
  83. }
  84. __forceinline void shrink_to_fit() {
  85. internal_resize(size_active,size_active);
  86. }
  87. /******************** Element access **************************/
  88. __forceinline T& operator[](size_t i) { assert(i < size_active); return items[i]; }
  89. __forceinline const T& operator[](size_t i) const { assert(i < size_active); return items[i]; }
  90. __forceinline T& at(size_t i) { assert(i < size_active); return items[i]; }
  91. __forceinline const T& at(size_t i) const { assert(i < size_active); return items[i]; }
  92. __forceinline T& front() const { assert(size_active > 0); return items[0]; };
  93. __forceinline T& back () const { assert(size_active > 0); return items[size_active-1]; };
  94. __forceinline T* data() { return items; };
  95. __forceinline const T* data() const { return items; };
  96. /******************** Modifiers **************************/
  97. __forceinline void push_back(const T& nt)
  98. {
  99. const T v = nt; // need local copy as input reference could point to this vector
  100. internal_resize(size_active,internal_grow_size(size_active+1));
  101. ::new (&items[size_active++]) T(v);
  102. }
  103. __forceinline void pop_back()
  104. {
  105. assert(!empty());
  106. size_active--;
  107. items[size_active].~T();
  108. }
  109. __forceinline void clear()
  110. {
  111. /* destroy elements */
  112. for (size_t i=0; i<size_active; i++){
  113. items[i].~T();
  114. }
  115. /* free memory */
  116. alloc.deallocate(items,size_alloced);
  117. items = nullptr;
  118. size_active = size_alloced = 0;
  119. }
  120. /******************** Comparisons **************************/
  121. friend bool operator== (const vector_t& a, const vector_t& b)
  122. {
  123. if (a.size() != b.size()) return false;
  124. for (size_t i=0; i<a.size(); i++)
  125. if (a[i] != b[i])
  126. return false;
  127. return true;
  128. }
  129. friend bool operator!= (const vector_t& a, const vector_t& b) {
  130. return !(a==b);
  131. }
  132. private:
  133. __forceinline void internal_resize_init(size_t new_active)
  134. {
  135. assert(size_active == 0);
  136. assert(size_alloced == 0);
  137. assert(items == nullptr);
  138. if (new_active == 0) return;
  139. items = alloc.allocate(new_active);
  140. for (size_t i=0; i<new_active; i++) ::new (&items[i]) T();
  141. size_active = new_active;
  142. size_alloced = new_active;
  143. }
  144. __forceinline void internal_resize(size_t new_active, size_t new_alloced)
  145. {
  146. assert(new_active <= new_alloced);
  147. /* destroy elements */
  148. if (new_active < size_active)
  149. {
  150. for (size_t i=new_active; i<size_active; i++){
  151. items[i].~T();
  152. }
  153. size_active = new_active;
  154. }
  155. /* only reallocate if necessary */
  156. if (new_alloced == size_alloced) {
  157. for (size_t i=size_active; i<new_active; i++) ::new (&items[i]) T;
  158. size_active = new_active;
  159. return;
  160. }
  161. /* reallocate and copy items */
  162. T* old_items = items;
  163. items = alloc.allocate(new_alloced);
  164. for (size_t i=0; i<size_active; i++) {
  165. ::new (&items[i]) T(std::move(old_items[i]));
  166. old_items[i].~T();
  167. }
  168. for (size_t i=size_active; i<new_active; i++) {
  169. ::new (&items[i]) T;
  170. }
  171. alloc.deallocate(old_items,size_alloced);
  172. size_active = new_active;
  173. size_alloced = new_alloced;
  174. }
  175. __forceinline size_t internal_grow_size(size_t new_alloced)
  176. {
  177. /* do nothing if container already large enough */
  178. if (new_alloced <= size_alloced)
  179. return size_alloced;
  180. /* if current size is 0 allocate exact requested size */
  181. if (size_alloced == 0)
  182. return new_alloced;
  183. /* resize to next power of 2 otherwise */
  184. size_t new_size_alloced = size_alloced;
  185. while (new_size_alloced < new_alloced) {
  186. new_size_alloced = std::max(size_t(1),2*new_size_alloced);
  187. }
  188. return new_size_alloced;
  189. }
  190. private:
  191. allocator alloc;
  192. size_t size_active; // number of valid items
  193. size_t size_alloced; // number of items allocated
  194. T* items; // data array
  195. };
  196. /*! vector class that performs standard allocations */
  197. template<typename T>
  198. using vector = vector_t<T,std::allocator<T>>;
  199. /*! vector class that performs aligned allocations */
  200. template<typename T>
  201. using avector = vector_t<T,aligned_allocator<T,std::alignment_of<T>::value> >;
  202. /*! vector class that performs OS allocations */
  203. template<typename T>
  204. using ovector = vector_t<T,os_allocator<T> >;
  205. /*! vector class with externally managed data buffer */
  206. template<typename T>
  207. using evector = vector_t<T,no_allocator<T>>;
  208. }