util_array.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. * Copyright 2011-2018 Blender Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #ifndef __UTIL_ARRAY_H__
  17. #define __UTIL_ARRAY_H__
  18. #include <cassert>
  19. #include <cstring>
  20. #include "util/util_aligned_malloc.h"
  21. #include "util/util_guarded_allocator.h"
  22. #include "util/util_types.h"
  23. #include "util/util_vector.h"
  24. CCL_NAMESPACE_BEGIN
  25. /* Simplified version of vector, serving multiple purposes:
  26. * - somewhat faster in that it does not clear memory on resize/alloc,
  27. * this was actually showing up in profiles quite significantly. it
  28. * also does not run any constructors/destructors
  29. * - if this is used, we are not tempted to use inefficient operations
  30. * - aligned allocation for CPU native data types */
  31. template<typename T, size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES> class array {
  32. public:
  33. array() : data_(NULL), datasize_(0), capacity_(0)
  34. {
  35. }
  36. explicit array(size_t newsize)
  37. {
  38. if (newsize == 0) {
  39. data_ = NULL;
  40. datasize_ = 0;
  41. capacity_ = 0;
  42. }
  43. else {
  44. data_ = mem_allocate(newsize);
  45. datasize_ = newsize;
  46. capacity_ = datasize_;
  47. }
  48. }
  49. array(const array &from)
  50. {
  51. if (from.datasize_ == 0) {
  52. data_ = NULL;
  53. datasize_ = 0;
  54. capacity_ = 0;
  55. }
  56. else {
  57. data_ = mem_allocate(from.datasize_);
  58. if (from.datasize_ > 0) {
  59. memcpy(data_, from.data_, from.datasize_ * sizeof(T));
  60. }
  61. datasize_ = from.datasize_;
  62. capacity_ = datasize_;
  63. }
  64. }
  65. array &operator=(const array &from)
  66. {
  67. if (this != &from) {
  68. resize(from.size());
  69. if (datasize_ > 0) {
  70. memcpy((void *)data_, from.data_, datasize_ * sizeof(T));
  71. }
  72. }
  73. return *this;
  74. }
  75. array &operator=(const vector<T> &from)
  76. {
  77. resize(from.size());
  78. if (from.size() > 0 && datasize_ > 0) {
  79. memcpy(data_, &from[0], datasize_ * sizeof(T));
  80. }
  81. return *this;
  82. }
  83. ~array()
  84. {
  85. mem_free(data_, capacity_);
  86. }
  87. bool operator==(const array<T> &other) const
  88. {
  89. if (datasize_ != other.datasize_) {
  90. return false;
  91. }
  92. if (datasize_ == 0) {
  93. return true;
  94. }
  95. return memcmp(data_, other.data_, datasize_ * sizeof(T)) == 0;
  96. }
  97. bool operator!=(const array<T> &other) const
  98. {
  99. return !(*this == other);
  100. }
  101. void steal_data(array &from)
  102. {
  103. if (this != &from) {
  104. clear();
  105. data_ = from.data_;
  106. datasize_ = from.datasize_;
  107. capacity_ = from.capacity_;
  108. from.data_ = NULL;
  109. from.datasize_ = 0;
  110. from.capacity_ = 0;
  111. }
  112. }
  113. T *steal_pointer()
  114. {
  115. T *ptr = data_;
  116. data_ = NULL;
  117. clear();
  118. return ptr;
  119. }
  120. T *resize(size_t newsize)
  121. {
  122. if (newsize == 0) {
  123. clear();
  124. }
  125. else if (newsize != datasize_) {
  126. if (newsize > capacity_) {
  127. T *newdata = mem_allocate(newsize);
  128. if (newdata == NULL) {
  129. /* Allocation failed, likely out of memory. */
  130. clear();
  131. return NULL;
  132. }
  133. else if (data_ != NULL) {
  134. memcpy(
  135. (void *)newdata, data_, ((datasize_ < newsize) ? datasize_ : newsize) * sizeof(T));
  136. mem_free(data_, capacity_);
  137. }
  138. data_ = newdata;
  139. capacity_ = newsize;
  140. }
  141. datasize_ = newsize;
  142. }
  143. return data_;
  144. }
  145. T *resize(size_t newsize, const T &value)
  146. {
  147. size_t oldsize = size();
  148. resize(newsize);
  149. for (size_t i = oldsize; i < size(); i++) {
  150. data_[i] = value;
  151. }
  152. return data_;
  153. }
  154. void clear()
  155. {
  156. if (data_ != NULL) {
  157. mem_free(data_, capacity_);
  158. data_ = NULL;
  159. }
  160. datasize_ = 0;
  161. capacity_ = 0;
  162. }
  163. size_t empty() const
  164. {
  165. return datasize_ == 0;
  166. }
  167. size_t size() const
  168. {
  169. return datasize_;
  170. }
  171. T *data()
  172. {
  173. return data_;
  174. }
  175. const T *data() const
  176. {
  177. return data_;
  178. }
  179. T &operator[](size_t i) const
  180. {
  181. assert(i < datasize_);
  182. return data_[i];
  183. }
  184. void reserve(size_t newcapacity)
  185. {
  186. if (newcapacity > capacity_) {
  187. T *newdata = mem_allocate(newcapacity);
  188. if (data_ != NULL) {
  189. memcpy(newdata, data_, ((datasize_ < newcapacity) ? datasize_ : newcapacity) * sizeof(T));
  190. mem_free(data_, capacity_);
  191. }
  192. data_ = newdata;
  193. capacity_ = newcapacity;
  194. }
  195. }
  196. size_t capacity() const
  197. {
  198. return capacity_;
  199. }
  200. // do not use this method unless you are sure the code is not performance critical
  201. void push_back_slow(const T &t)
  202. {
  203. if (capacity_ == datasize_) {
  204. reserve(datasize_ == 0 ? 1 : (size_t)((datasize_ + 1) * 1.2));
  205. }
  206. data_[datasize_++] = t;
  207. }
  208. void push_back_reserved(const T &t)
  209. {
  210. assert(datasize_ < capacity_);
  211. push_back_slow(t);
  212. }
  213. void append(const array<T> &from)
  214. {
  215. if (from.size()) {
  216. size_t old_size = size();
  217. resize(old_size + from.size());
  218. memcpy(data_ + old_size, from.data(), sizeof(T) * from.size());
  219. }
  220. }
  221. protected:
  222. inline T *mem_allocate(size_t N)
  223. {
  224. if (N == 0) {
  225. return NULL;
  226. }
  227. T *mem = (T *)util_aligned_malloc(sizeof(T) * N, alignment);
  228. if (mem != NULL) {
  229. util_guarded_mem_alloc(sizeof(T) * N);
  230. }
  231. else {
  232. throw std::bad_alloc();
  233. }
  234. return mem;
  235. }
  236. inline void mem_free(T *mem, size_t N)
  237. {
  238. if (mem != NULL) {
  239. util_guarded_mem_free(sizeof(T) * N);
  240. util_aligned_free(mem);
  241. }
  242. }
  243. T *data_;
  244. size_t datasize_;
  245. size_t capacity_;
  246. };
  247. CCL_NAMESPACE_END
  248. #endif /* __UTIL_ARRAY_H__ */