SkTArray.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. /*
  2. * Copyright 2011 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #ifndef SkTArray_DEFINED
  8. #define SkTArray_DEFINED
  9. #include "../private/SkSafe32.h"
  10. #include "../private/SkTLogic.h"
  11. #include "../private/SkTemplates.h"
  12. #include "SkTypes.h"
  13. #include <new>
  14. #include <utility>
  15. /** When MEM_MOVE is true T will be bit copied when moved.
  16. When MEM_MOVE is false, T will be copy constructed / destructed.
  17. In all cases T will be default-initialized on allocation,
  18. and its destructor will be called from this object's destructor.
  19. */
  20. template <typename T, bool MEM_MOVE = false> class SkTArray {
  21. public:
  22. /**
  23. * Creates an empty array with no initial storage
  24. */
  25. SkTArray() { this->init(); }
  26. /**
  27. * Creates an empty array that will preallocate space for reserveCount
  28. * elements.
  29. */
  30. explicit SkTArray(int reserveCount) { this->init(0, reserveCount); }
  31. /**
  32. * Copies one array to another. The new array will be heap allocated.
  33. */
  34. SkTArray(const SkTArray& that) {
  35. this->init(that.fCount);
  36. this->copy(that.fItemArray);
  37. }
  38. SkTArray(SkTArray&& that) {
  39. // TODO: If 'that' owns its memory why don't we just steal the pointer?
  40. this->init(that.fCount);
  41. that.move(fMemArray);
  42. that.fCount = 0;
  43. }
  44. /**
  45. * Creates a SkTArray by copying contents of a standard C array. The new
  46. * array will be heap allocated. Be careful not to use this constructor
  47. * when you really want the (void*, int) version.
  48. */
  49. SkTArray(const T* array, int count) {
  50. this->init(count);
  51. this->copy(array);
  52. }
  53. SkTArray& operator=(const SkTArray& that) {
  54. if (this == &that) {
  55. return *this;
  56. }
  57. for (int i = 0; i < fCount; ++i) {
  58. fItemArray[i].~T();
  59. }
  60. fCount = 0;
  61. this->checkRealloc(that.count());
  62. fCount = that.count();
  63. this->copy(that.fItemArray);
  64. return *this;
  65. }
  66. SkTArray& operator=(SkTArray&& that) {
  67. if (this == &that) {
  68. return *this;
  69. }
  70. for (int i = 0; i < fCount; ++i) {
  71. fItemArray[i].~T();
  72. }
  73. fCount = 0;
  74. this->checkRealloc(that.count());
  75. fCount = that.count();
  76. that.move(fMemArray);
  77. that.fCount = 0;
  78. return *this;
  79. }
  80. ~SkTArray() {
  81. for (int i = 0; i < fCount; ++i) {
  82. fItemArray[i].~T();
  83. }
  84. if (fOwnMemory) {
  85. sk_free(fMemArray);
  86. }
  87. }
  88. /**
  89. * Resets to count() == 0 and resets any reserve count.
  90. */
  91. void reset() {
  92. this->pop_back_n(fCount);
  93. fReserved = false;
  94. }
  95. /**
  96. * Resets to count() = n newly constructed T objects and resets any reserve count.
  97. */
  98. void reset(int n) {
  99. SkASSERT(n >= 0);
  100. for (int i = 0; i < fCount; ++i) {
  101. fItemArray[i].~T();
  102. }
  103. // Set fCount to 0 before calling checkRealloc so that no elements are moved.
  104. fCount = 0;
  105. this->checkRealloc(n);
  106. fCount = n;
  107. for (int i = 0; i < fCount; ++i) {
  108. new (fItemArray + i) T;
  109. }
  110. fReserved = false;
  111. }
  112. /**
  113. * Resets to a copy of a C array and resets any reserve count.
  114. */
  115. void reset(const T* array, int count) {
  116. for (int i = 0; i < fCount; ++i) {
  117. fItemArray[i].~T();
  118. }
  119. fCount = 0;
  120. this->checkRealloc(count);
  121. fCount = count;
  122. this->copy(array);
  123. fReserved = false;
  124. }
  125. /**
  126. * Ensures there is enough reserved space for n additional elements. The is guaranteed at least
  127. * until the array size grows above n and subsequently shrinks below n, any version of reset()
  128. * is called, or reserve() is called again.
  129. */
  130. void reserve(int n) {
  131. SkASSERT(n >= 0);
  132. if (n > 0) {
  133. this->checkRealloc(n);
  134. fReserved = fOwnMemory;
  135. } else {
  136. fReserved = false;
  137. }
  138. }
  139. void removeShuffle(int n) {
  140. SkASSERT(n < fCount);
  141. int newCount = fCount - 1;
  142. fCount = newCount;
  143. fItemArray[n].~T();
  144. if (n != newCount) {
  145. this->move(n, newCount);
  146. }
  147. }
  148. /**
  149. * Number of elements in the array.
  150. */
  151. int count() const { return fCount; }
  152. /**
  153. * Is the array empty.
  154. */
  155. bool empty() const { return !fCount; }
  156. /**
  157. * Adds 1 new default-initialized T value and returns it by reference. Note
  158. * the reference only remains valid until the next call that adds or removes
  159. * elements.
  160. */
  161. T& push_back() {
  162. void* newT = this->push_back_raw(1);
  163. return *new (newT) T;
  164. }
  165. /**
  166. * Version of above that uses a copy constructor to initialize the new item
  167. */
  168. T& push_back(const T& t) {
  169. void* newT = this->push_back_raw(1);
  170. return *new (newT) T(t);
  171. }
  172. /**
  173. * Version of above that uses a move constructor to initialize the new item
  174. */
  175. T& push_back(T&& t) {
  176. void* newT = this->push_back_raw(1);
  177. return *new (newT) T(std::move(t));
  178. }
  179. /**
  180. * Construct a new T at the back of this array.
  181. */
  182. template<class... Args> T& emplace_back(Args&&... args) {
  183. void* newT = this->push_back_raw(1);
  184. return *new (newT) T(std::forward<Args>(args)...);
  185. }
  186. /**
  187. * Allocates n more default-initialized T values, and returns the address of
  188. * the start of that new range. Note: this address is only valid until the
  189. * next API call made on the array that might add or remove elements.
  190. */
  191. T* push_back_n(int n) {
  192. SkASSERT(n >= 0);
  193. void* newTs = this->push_back_raw(n);
  194. for (int i = 0; i < n; ++i) {
  195. new (static_cast<char*>(newTs) + i * sizeof(T)) T;
  196. }
  197. return static_cast<T*>(newTs);
  198. }
  199. /**
  200. * Version of above that uses a copy constructor to initialize all n items
  201. * to the same T.
  202. */
  203. T* push_back_n(int n, const T& t) {
  204. SkASSERT(n >= 0);
  205. void* newTs = this->push_back_raw(n);
  206. for (int i = 0; i < n; ++i) {
  207. new (static_cast<char*>(newTs) + i * sizeof(T)) T(t);
  208. }
  209. return static_cast<T*>(newTs);
  210. }
  211. /**
  212. * Version of above that uses a copy constructor to initialize the n items
  213. * to separate T values.
  214. */
  215. T* push_back_n(int n, const T t[]) {
  216. SkASSERT(n >= 0);
  217. this->checkRealloc(n);
  218. for (int i = 0; i < n; ++i) {
  219. new (fItemArray + fCount + i) T(t[i]);
  220. }
  221. fCount += n;
  222. return fItemArray + fCount - n;
  223. }
  224. /**
  225. * Version of above that uses the move constructor to set n items.
  226. */
  227. T* move_back_n(int n, T* t) {
  228. SkASSERT(n >= 0);
  229. this->checkRealloc(n);
  230. for (int i = 0; i < n; ++i) {
  231. new (fItemArray + fCount + i) T(std::move(t[i]));
  232. }
  233. fCount += n;
  234. return fItemArray + fCount - n;
  235. }
  236. /**
  237. * Removes the last element. Not safe to call when count() == 0.
  238. */
  239. void pop_back() {
  240. SkASSERT(fCount > 0);
  241. --fCount;
  242. fItemArray[fCount].~T();
  243. this->checkRealloc(0);
  244. }
  245. /**
  246. * Removes the last n elements. Not safe to call when count() < n.
  247. */
  248. void pop_back_n(int n) {
  249. SkASSERT(n >= 0);
  250. SkASSERT(fCount >= n);
  251. fCount -= n;
  252. for (int i = 0; i < n; ++i) {
  253. fItemArray[fCount + i].~T();
  254. }
  255. this->checkRealloc(0);
  256. }
  257. /**
  258. * Pushes or pops from the back to resize. Pushes will be default
  259. * initialized.
  260. */
  261. void resize_back(int newCount) {
  262. SkASSERT(newCount >= 0);
  263. if (newCount > fCount) {
  264. this->push_back_n(newCount - fCount);
  265. } else if (newCount < fCount) {
  266. this->pop_back_n(fCount - newCount);
  267. }
  268. }
  269. /** Swaps the contents of this array with that array. Does a pointer swap if possible,
  270. otherwise copies the T values. */
  271. void swap(SkTArray& that) {
  272. using std::swap;
  273. if (this == &that) {
  274. return;
  275. }
  276. if (fOwnMemory && that.fOwnMemory) {
  277. swap(fItemArray, that.fItemArray);
  278. swap(fCount, that.fCount);
  279. swap(fAllocCount, that.fAllocCount);
  280. } else {
  281. // This could be more optimal...
  282. SkTArray copy(std::move(that));
  283. that = std::move(*this);
  284. *this = std::move(copy);
  285. }
  286. }
  287. T* begin() {
  288. return fItemArray;
  289. }
  290. const T* begin() const {
  291. return fItemArray;
  292. }
  293. T* end() {
  294. return fItemArray ? fItemArray + fCount : nullptr;
  295. }
  296. const T* end() const {
  297. return fItemArray ? fItemArray + fCount : nullptr;
  298. }
  299. T* data() { return fItemArray; }
  300. const T* data() const { return fItemArray; }
  301. size_t size() const { return (size_t)fCount; }
  302. void resize(size_t count) { this->resize_back((int)count); }
  303. /**
  304. * Get the i^th element.
  305. */
  306. T& operator[] (int i) {
  307. SkASSERT(i < fCount);
  308. SkASSERT(i >= 0);
  309. return fItemArray[i];
  310. }
  311. const T& operator[] (int i) const {
  312. SkASSERT(i < fCount);
  313. SkASSERT(i >= 0);
  314. return fItemArray[i];
  315. }
  316. /**
  317. * equivalent to operator[](0)
  318. */
  319. T& front() { SkASSERT(fCount > 0); return fItemArray[0];}
  320. const T& front() const { SkASSERT(fCount > 0); return fItemArray[0];}
  321. /**
  322. * equivalent to operator[](count() - 1)
  323. */
  324. T& back() { SkASSERT(fCount); return fItemArray[fCount - 1];}
  325. const T& back() const { SkASSERT(fCount > 0); return fItemArray[fCount - 1];}
  326. /**
  327. * equivalent to operator[](count()-1-i)
  328. */
  329. T& fromBack(int i) {
  330. SkASSERT(i >= 0);
  331. SkASSERT(i < fCount);
  332. return fItemArray[fCount - i - 1];
  333. }
  334. const T& fromBack(int i) const {
  335. SkASSERT(i >= 0);
  336. SkASSERT(i < fCount);
  337. return fItemArray[fCount - i - 1];
  338. }
  339. bool operator==(const SkTArray<T, MEM_MOVE>& right) const {
  340. int leftCount = this->count();
  341. if (leftCount != right.count()) {
  342. return false;
  343. }
  344. for (int index = 0; index < leftCount; ++index) {
  345. if (fItemArray[index] != right.fItemArray[index]) {
  346. return false;
  347. }
  348. }
  349. return true;
  350. }
  351. bool operator!=(const SkTArray<T, MEM_MOVE>& right) const {
  352. return !(*this == right);
  353. }
  354. inline int allocCntForTest() const;
  355. protected:
  356. /**
  357. * Creates an empty array that will use the passed storage block until it
  358. * is insufficiently large to hold the entire array.
  359. */
  360. template <int N>
  361. SkTArray(SkAlignedSTStorage<N,T>* storage) {
  362. this->initWithPreallocatedStorage(0, storage->get(), N);
  363. }
  364. /**
  365. * Copy another array, using preallocated storage if preAllocCount >=
  366. * array.count(). Otherwise storage will only be used when array shrinks
  367. * to fit.
  368. */
  369. template <int N>
  370. SkTArray(const SkTArray& array, SkAlignedSTStorage<N,T>* storage) {
  371. this->initWithPreallocatedStorage(array.fCount, storage->get(), N);
  372. this->copy(array.fItemArray);
  373. }
  374. /**
  375. * Move another array, using preallocated storage if preAllocCount >=
  376. * array.count(). Otherwise storage will only be used when array shrinks
  377. * to fit.
  378. */
  379. template <int N>
  380. SkTArray(SkTArray&& array, SkAlignedSTStorage<N,T>* storage) {
  381. this->initWithPreallocatedStorage(array.fCount, storage->get(), N);
  382. array.move(fMemArray);
  383. array.fCount = 0;
  384. }
  385. /**
  386. * Copy a C array, using preallocated storage if preAllocCount >=
  387. * count. Otherwise storage will only be used when array shrinks
  388. * to fit.
  389. */
  390. template <int N>
  391. SkTArray(const T* array, int count, SkAlignedSTStorage<N,T>* storage) {
  392. this->initWithPreallocatedStorage(count, storage->get(), N);
  393. this->copy(array);
  394. }
  395. private:
  396. void init(int count = 0, int reserveCount = 0) {
  397. SkASSERT(count >= 0);
  398. SkASSERT(reserveCount >= 0);
  399. fCount = count;
  400. if (!count && !reserveCount) {
  401. fAllocCount = 0;
  402. fMemArray = nullptr;
  403. fOwnMemory = true;
  404. fReserved = false;
  405. } else {
  406. fAllocCount = SkTMax(count, SkTMax(kMinHeapAllocCount, reserveCount));
  407. fMemArray = sk_malloc_throw(fAllocCount, sizeof(T));
  408. fOwnMemory = true;
  409. fReserved = reserveCount > 0;
  410. }
  411. }
  412. void initWithPreallocatedStorage(int count, void* preallocStorage, int preallocCount) {
  413. SkASSERT(count >= 0);
  414. SkASSERT(preallocCount > 0);
  415. SkASSERT(preallocStorage);
  416. fCount = count;
  417. fMemArray = nullptr;
  418. fReserved = false;
  419. if (count > preallocCount) {
  420. fAllocCount = SkTMax(count, kMinHeapAllocCount);
  421. fMemArray = sk_malloc_throw(fAllocCount, sizeof(T));
  422. fOwnMemory = true;
  423. } else {
  424. fAllocCount = preallocCount;
  425. fMemArray = preallocStorage;
  426. fOwnMemory = false;
  427. }
  428. }
  429. /** In the following move and copy methods, 'dst' is assumed to be uninitialized raw storage.
  430. * In the following move methods, 'src' is destroyed leaving behind uninitialized raw storage.
  431. */
  432. void copy(const T* src) {
  433. // Some types may be trivially copyable, in which case we *could* use memcopy; but
  434. // MEM_MOVE == true implies that the type is trivially movable, and not necessarily
  435. // trivially copyable (think sk_sp<>). So short of adding another template arg, we
  436. // must be conservative and use copy construction.
  437. for (int i = 0; i < fCount; ++i) {
  438. new (fItemArray + i) T(src[i]);
  439. }
  440. }
  441. template <bool E = MEM_MOVE> SK_WHEN(E, void) move(int dst, int src) {
  442. memcpy(&fItemArray[dst], &fItemArray[src], sizeof(T));
  443. }
  444. template <bool E = MEM_MOVE> SK_WHEN(E, void) move(void* dst) {
  445. sk_careful_memcpy(dst, fMemArray, fCount * sizeof(T));
  446. }
  447. template <bool E = MEM_MOVE> SK_WHEN(!E, void) move(int dst, int src) {
  448. new (&fItemArray[dst]) T(std::move(fItemArray[src]));
  449. fItemArray[src].~T();
  450. }
  451. template <bool E = MEM_MOVE> SK_WHEN(!E, void) move(void* dst) {
  452. for (int i = 0; i < fCount; ++i) {
  453. new (static_cast<char*>(dst) + sizeof(T) * i) T(std::move(fItemArray[i]));
  454. fItemArray[i].~T();
  455. }
  456. }
  457. static constexpr int kMinHeapAllocCount = 8;
  458. // Helper function that makes space for n objects, adjusts the count, but does not initialize
  459. // the new objects.
  460. void* push_back_raw(int n) {
  461. this->checkRealloc(n);
  462. void* ptr = fItemArray + fCount;
  463. fCount += n;
  464. return ptr;
  465. }
  466. void checkRealloc(int delta) {
  467. SkASSERT(fCount >= 0);
  468. SkASSERT(fAllocCount >= 0);
  469. SkASSERT(-delta <= fCount);
  470. // Move into 64bit math temporarily, to avoid local overflows
  471. int64_t newCount = fCount + delta;
  472. // We allow fAllocCount to be in the range [newCount, 3*newCount]. We also never shrink
  473. // when we're currently using preallocated memory, would allocate less than
  474. // kMinHeapAllocCount, or a reserve count was specified that has yet to be exceeded.
  475. bool mustGrow = newCount > fAllocCount;
  476. bool shouldShrink = fAllocCount > 3 * newCount && fOwnMemory && !fReserved;
  477. if (!mustGrow && !shouldShrink) {
  478. return;
  479. }
  480. // Whether we're growing or shrinking, we leave at least 50% extra space for future growth.
  481. int64_t newAllocCount = newCount + ((newCount + 1) >> 1);
  482. // Align the new allocation count to kMinHeapAllocCount.
  483. static_assert(SkIsPow2(kMinHeapAllocCount), "min alloc count not power of two.");
  484. newAllocCount = (newAllocCount + (kMinHeapAllocCount - 1)) & ~(kMinHeapAllocCount - 1);
  485. // At small sizes the old and new alloc count can both be kMinHeapAllocCount.
  486. if (newAllocCount == fAllocCount) {
  487. return;
  488. }
  489. fAllocCount = Sk64_pin_to_s32(newAllocCount);
  490. SkASSERT(fAllocCount >= newCount);
  491. void* newMemArray = sk_malloc_throw(fAllocCount, sizeof(T));
  492. this->move(newMemArray);
  493. if (fOwnMemory) {
  494. sk_free(fMemArray);
  495. }
  496. fMemArray = newMemArray;
  497. fOwnMemory = true;
  498. fReserved = false;
  499. }
  500. union {
  501. T* fItemArray;
  502. void* fMemArray;
  503. };
  504. int fCount;
  505. int fAllocCount;
  506. bool fOwnMemory : 1;
  507. bool fReserved : 1;
  508. };
  509. template <typename T, bool M> static inline void swap(SkTArray<T, M>& a, SkTArray<T, M>& b) {
  510. a.swap(b);
  511. }
  512. template<typename T, bool MEM_MOVE> constexpr int SkTArray<T, MEM_MOVE>::kMinHeapAllocCount;
  513. /**
  514. * Subclass of SkTArray that contains a preallocated memory block for the array.
  515. */
  516. template <int N, typename T, bool MEM_MOVE= false>
  517. class SkSTArray : public SkTArray<T, MEM_MOVE> {
  518. private:
  519. typedef SkTArray<T, MEM_MOVE> INHERITED;
  520. public:
  521. SkSTArray() : INHERITED(&fStorage) {
  522. }
  523. SkSTArray(const SkSTArray& array)
  524. : INHERITED(array, &fStorage) {
  525. }
  526. SkSTArray(SkSTArray&& array)
  527. : INHERITED(std::move(array), &fStorage) {
  528. }
  529. explicit SkSTArray(const INHERITED& array)
  530. : INHERITED(array, &fStorage) {
  531. }
  532. explicit SkSTArray(INHERITED&& array)
  533. : INHERITED(std::move(array), &fStorage) {
  534. }
  535. explicit SkSTArray(int reserveCount)
  536. : INHERITED(reserveCount) {
  537. }
  538. SkSTArray(const T* array, int count)
  539. : INHERITED(array, count, &fStorage) {
  540. }
  541. SkSTArray& operator=(const SkSTArray& array) {
  542. INHERITED::operator=(array);
  543. return *this;
  544. }
  545. SkSTArray& operator=(SkSTArray&& array) {
  546. INHERITED::operator=(std::move(array));
  547. return *this;
  548. }
  549. SkSTArray& operator=(const INHERITED& array) {
  550. INHERITED::operator=(array);
  551. return *this;
  552. }
  553. SkSTArray& operator=(INHERITED&& array) {
  554. INHERITED::operator=(std::move(array));
  555. return *this;
  556. }
  557. private:
  558. SkAlignedSTStorage<N,T> fStorage;
  559. };
  560. #endif