dynamic_array.h 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #ifndef dynamic_array_h
  2. #define dynamic_array_h
  3. //#include "Runtime/Allocator/MemoryMacros.h"
  4. //#include "Runtime/Utilities/StaticAssert.h"
  5. #include "rparticle/Macros/RParticleMacros.h"
  6. //#include "base/allocator/CCAllocatorBase.h"
  7. #include "base/allocator/CCAllocatorBase.h"
  8. #include <memory> // std::uninitialized_fill
  9. // dynamic_array - simplified version of std::vector<T>
  10. //
  11. // features:
  12. // . always uses memcpy for copying elements. Your data structures must be simple and can't have internal pointers / rely on copy constructor.
  13. // . EASTL like push_back(void) implementation
  14. // Existing std STL implementations implement insertion operations by copying from an element.
  15. // For example, resize(size() + 1) creates a throw-away temporary object.
  16. // There is no way in existing std STL implementations to add an element to a container without implicitly or
  17. // explicitly providing one to copy from (aside from some existing POD optimizations).
  18. // For expensive-to-construct objects this creates a potentially serious performance problem.
  19. // . grows X2 on reallocation
  20. // . small code footprint
  21. // . clear actually deallocates memory
  22. // . resize does NOT initialize members!
  23. //
  24. // Changelog:
  25. // Added pop_back()
  26. // Added assign()
  27. // Added clear() - frees the data, use resize(0) to clear w/o freeing
  28. // zero allocation for empty array
  29. //
  30. //
  31. typedef MemLabelId MemLabelRef;
  32. template<typename T>
  33. struct AlignOfType
  34. {
  35. enum { align = ALIGN_OF(T) };
  36. };
  37. template <typename T, size_t align = AlignOfType<T>::align>
  38. struct dynamic_array
  39. {
  40. public:
  41. typedef T* iterator;
  42. typedef const T* const_iterator;
  43. typedef T value_type;
  44. typedef size_t size_type;
  45. typedef size_t difference_type;
  46. typedef T& reference;
  47. typedef const T& const_reference;
  48. public:
  49. dynamic_array() : m_data(NULL), /* m_label(defaultLabel, NULL), */ m_size(0), m_capacity(0)
  50. {
  51. // m_label = MemLabelId(defaultLabel, GET_CURRENT_ALLOC_ROOT_HEADER());
  52. }
  53. dynamic_array(MemLabelRef label) : m_data(NULL), m_label(label), m_size(0), m_capacity(0)
  54. {
  55. }
  56. explicit dynamic_array (size_t size, MemLabelRef label)
  57. : m_label(label), m_size(size), m_capacity (size)
  58. {
  59. m_data = allocate (size);
  60. }
  61. dynamic_array (size_t size, T const& init_value, MemLabelRef label)
  62. : m_label(label), m_size (size), m_capacity (size)
  63. {
  64. m_data = allocate (size);
  65. std::uninitialized_fill (m_data, m_data + size, init_value);
  66. }
  67. ~dynamic_array()
  68. {
  69. if (owns_data())
  70. m_data = deallocate(m_data);
  71. }
  72. dynamic_array(const dynamic_array& other) : m_capacity(0), m_size(0), m_label(other.m_label)
  73. {
  74. //m_label.SetRootHeader(GET_CURRENT_ALLOC_ROOT_HEADER());
  75. m_data = NULL;
  76. assign(other.begin(), other.end());
  77. }
  78. dynamic_array& operator=(const dynamic_array& other)
  79. {
  80. // should not allocate memory unless we have to
  81. assign(other.begin(), other.end());
  82. return *this;
  83. }
  84. void clear()
  85. {
  86. if (owns_data())
  87. m_data = deallocate(m_data);
  88. m_size = 0;
  89. m_capacity = 0;
  90. }
  91. void assign(const_iterator begin, const_iterator end)
  92. {
  93. Assert(begin<=end);
  94. resize_uninitialized(end-begin);
  95. memcpy(m_data, begin, m_size * sizeof(T));
  96. }
  97. void erase(iterator input_begin, iterator input_end)
  98. {
  99. Assert(input_begin <= input_end);
  100. Assert(input_begin >= begin());
  101. Assert(input_end <= end());
  102. size_t leftOverSize = end() - input_end;
  103. memmove(input_begin, input_end, leftOverSize * sizeof(T));
  104. m_size -= input_end - input_begin;
  105. }
  106. iterator erase(iterator position)
  107. {
  108. Assert(position >= begin());
  109. Assert(position < end());
  110. size_t leftOverSize = end() - position - 1;
  111. memmove(position, position+1, leftOverSize * sizeof(T));
  112. m_size -= 1;
  113. return position;
  114. }
  115. iterator insert(iterator insert_before, const_iterator input_begin, const_iterator input_end)
  116. {
  117. Assert(input_begin <= input_end);
  118. Assert(insert_before >= begin());
  119. Assert(insert_before <= end());
  120. // resize (make sure that insertBefore does not get invalid in the meantime because of a reallocation)
  121. size_t insert_before_index = insert_before - begin();
  122. size_t elements_to_be_moved = size() - insert_before_index;
  123. resize_uninitialized((input_end - input_begin) + size());
  124. insert_before = begin() + insert_before_index;
  125. size_t insertsize = input_end - input_begin;
  126. // move to the end of where the inserted data will be
  127. memmove(insert_before + insertsize, insert_before, elements_to_be_moved * sizeof(T));
  128. // inject input data in the hole we just created
  129. memcpy(insert_before, input_begin, insertsize * sizeof(T));
  130. return insert_before;
  131. }
  132. iterator insert(iterator insertBefore, const T& t) { return insert(insertBefore, &t, &t + 1); }
  133. void swap(dynamic_array& other) throw()
  134. {
  135. // if (m_data) UNITY_TRANSFER_OWNERSHIP_TO_HEADER(m_data, m_label, other.m_label.GetRootHeader());
  136. // if (other.m_data) UNITY_TRANSFER_OWNERSHIP_TO_HEADER(other.m_data, other.m_label, m_label.GetRootHeader());
  137. std::swap(m_data, other.m_data);
  138. std::swap(m_size, other.m_size);
  139. std::swap(m_capacity, other.m_capacity);
  140. std::swap(m_label, other.m_label);
  141. }
  142. T& push_back()
  143. {
  144. if (++m_size > capacity())
  145. reserve(std::max<size_t>(capacity()*2, 1));
  146. return back();
  147. }
  148. void push_back(const T& t)
  149. {
  150. push_back() = t;
  151. }
  152. void pop_back()
  153. {
  154. Assert(m_size >= 1);
  155. m_size--;
  156. }
  157. void resize_uninitialized(size_t size, bool double_on_resize = false)
  158. {
  159. m_size = size;
  160. if (m_size <= capacity())
  161. return;
  162. if(double_on_resize && size < capacity()*2)
  163. size = capacity()*2;
  164. reserve(size);
  165. }
  166. void resize_initialized(size_t size, const T& t = T(), bool double_on_resize = false)
  167. {
  168. if (size > capacity())
  169. {
  170. size_t requested_size = size;
  171. if(double_on_resize && size < capacity()*2)
  172. requested_size = capacity()*2;
  173. reserve(requested_size);
  174. }
  175. if (size > m_size)
  176. std::uninitialized_fill (m_data + m_size, m_data + size, t);
  177. m_size = size;
  178. }
  179. void reserve(size_t inCapacity)
  180. {
  181. if (capacity() >= inCapacity)
  182. return;
  183. if (owns_data())
  184. {
  185. m_capacity = inCapacity;
  186. m_data = reallocate(m_data, inCapacity);
  187. }
  188. else
  189. {
  190. T* newData = allocate(inCapacity);
  191. memcpy(newData, m_data, m_size * sizeof(T));
  192. // Invalidate old non-owned data, since using the data from two places is most likely a really really bad idea.
  193. #if DEBUGMODE
  194. memset(m_data, 0xCD, capacity() * sizeof(T));
  195. #endif
  196. m_capacity = inCapacity; // and clear reference bit
  197. m_data = newData;
  198. }
  199. }
  200. void assign_external (T* begin, T* end)
  201. {
  202. if (owns_data())
  203. m_data = deallocate(m_data);
  204. m_size = m_capacity = reinterpret_cast<value_type*> (end) - reinterpret_cast<value_type*> (begin);
  205. Assert(m_size < k_reference_bit);
  206. m_capacity |= k_reference_bit;
  207. m_data = begin;
  208. }
  209. void set_owns_data (bool ownsData)
  210. {
  211. if (ownsData)
  212. m_capacity &= ~k_reference_bit;
  213. else
  214. m_capacity |= k_reference_bit;
  215. }
  216. void shrink_to_fit()
  217. {
  218. if (owns_data())
  219. {
  220. m_capacity = m_size;
  221. m_data = reallocate(m_data, m_size);
  222. }
  223. }
  224. const T& back() const { Assert (m_size != 0); return m_data[m_size - 1]; }
  225. const T& front() const { Assert (m_size != 0); return m_data[0]; }
  226. T& back() { Assert (m_size != 0); return m_data[m_size - 1]; }
  227. T& front() { Assert (m_size != 0); return m_data[0]; }
  228. T* data () { return m_data; }
  229. T const* data () const { return m_data; }
  230. bool empty () const { return m_size == 0; }
  231. size_t size() const { return m_size; }
  232. size_t capacity() const { return m_capacity & ~k_reference_bit; }
  233. T const& operator[] (size_t index) const { DebugAssert(index < m_size); return m_data[index]; }
  234. T& operator[] (size_t index) { DebugAssert(index < m_size); return m_data[index]; }
  235. T const* begin() const { return m_data; }
  236. T* begin() { return m_data; }
  237. T const* end() const { return m_data + m_size; }
  238. T* end() { return m_data + m_size; }
  239. bool owns_data() { return (m_capacity & k_reference_bit) == 0; }
  240. bool equals(const dynamic_array& other)
  241. {
  242. if(m_size != other.m_size)
  243. return false;
  244. for( int i = 0; i < m_size; i++)
  245. {
  246. if (m_data[i] != other.m_data[i])
  247. return false;
  248. }
  249. return true;
  250. }
  251. void set_memory_label (MemLabelRef label)
  252. {
  253. Assert(m_data == NULL);
  254. m_label = label;
  255. }
  256. private:
  257. static const size_t k_reference_bit = (size_t)1 << (sizeof (size_t) * 8 - 1);
  258. T* allocate (size_t size)
  259. {
  260. // If you are getting this error then you are trying to allocate memory for an incomplete type
  261. // CompileTimeAssert(sizeof(T) != 0, "incomplete type");
  262. // CompileTimeAssert(align != 0, "incomplete type");
  263. // return static_cast<T*> (UNITY_MALLOC_ALIGNED (m_label, size * sizeof(T), align));
  264. return static_cast<T*> (malloc(size * sizeof(T)));
  265. }
  266. T* deallocate (T* data)
  267. {
  268. Assert(owns_data());
  269. // UNITY_FREE (m_label, data);
  270. free(data);
  271. return NULL;
  272. }
  273. T* reallocate (T* data, size_t size)
  274. {
  275. // If you are getting this error then you are trying to allocate memory for an incomplete type
  276. // CompileTimeAssert(sizeof(T) != 0, "incomplete type");
  277. // CompileTimeAssert(align != 0, "incomplete type");
  278. Assert(owns_data());
  279. // int alignof = static_cast<int>(align);
  280. // return static_cast<T*> (UNITY_REALLOC_ALIGNED(m_label, data, size * sizeof(T), alignof));
  281. return static_cast<T*> (realloc(data, size * sizeof(T)));
  282. }
  283. T* m_data;
  284. MemLabelId m_label;
  285. size_t m_size;
  286. size_t m_capacity;
  287. };
  288. #endif /* dynamic_array_h */