SparseArray.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. template<class T>
  7. class SAChunk
  8. {
  9. public:
  10. SAChunk<T> * next;
  11. uint32 startIndex;
  12. T * data[];
  13. };
  14. template<class T>
  15. class SparseArray
  16. {
  17. private:
  18. ArenaAllocator * alloc;
  19. uint32 chunkSize;
  20. SAChunk<T> * firstChunk;
  21. public:
  22. static SparseArray<T> * New(ArenaAllocator *allocator, uint32 chunkSize)
  23. {
  24. SparseArray<T> * array;
  25. if (!Math::IsPow2(chunkSize))
  26. {
  27. chunkSize = Math::NextPowerOf2(chunkSize);
  28. }
  29. // Throw early if this overflows, since chunkSize never changes, subsequent operations will be safe
  30. UInt32Math::MulAdd<sizeof(T*), sizeof(SAChunk<T>)>(chunkSize);
  31. array = Anew(allocator, SparseArray<T>);
  32. array->alloc = allocator;
  33. array->chunkSize = chunkSize;
  34. array->firstChunk = NULL;
  35. return array;
  36. }
  37. void Set(uint32 index, T *element)
  38. {
  39. SAChunk<T> * chunk, **pPrev = &(this->firstChunk);
  40. uint32 indexInChunk = (index % this->chunkSize);
  41. for (chunk = this->firstChunk; chunk; chunk = chunk->next)
  42. {
  43. if (index < chunk->startIndex)
  44. {
  45. // Need a new chunk...
  46. chunk = NULL;
  47. break;
  48. }
  49. if (index < chunk->startIndex + this->chunkSize)
  50. {
  51. break;
  52. }
  53. pPrev = &(chunk->next);
  54. }
  55. if (chunk == NULL)
  56. {
  57. chunk = (SAChunk<T> *)this->alloc->AllocZero(sizeof(SAChunk<T>) + (chunkSize * sizeof(T *)));
  58. chunk->startIndex = index - indexInChunk;
  59. // Since startIndex and chunkSize don't change, check now if this overflows.
  60. // Cache the result or save memory ?
  61. UInt32Math::Add(chunk->startIndex, chunkSize);
  62. chunk->next = *pPrev;
  63. *pPrev = chunk;
  64. }
  65. chunk->data[indexInChunk] = element;
  66. }
  67. T * Get(uint32 index)
  68. {
  69. SAChunk<T> * chunk;
  70. uint32 indexInChunk = (index % this->chunkSize);
  71. for (chunk = this->firstChunk; chunk; chunk = chunk->next)
  72. {
  73. if (index < chunk->startIndex)
  74. {
  75. return NULL;
  76. }
  77. if (index < chunk->startIndex + this->chunkSize)
  78. {
  79. return chunk->data[indexInChunk];
  80. }
  81. }
  82. return NULL;
  83. }
  84. SparseArray<T> * Copy()
  85. {
  86. SparseArray<T> * newSA = SparseArray<T>::New(this->alloc, this->chunkSize);
  87. SAChunk<T> * chunk, *pred = NULL;
  88. for (chunk = this->firstChunk; chunk; chunk = chunk->next)
  89. {
  90. SAChunk<T> *newChunk = (SAChunk<T> *)this->alloc->Alloc(sizeof(SAChunk<T>) + (sizeof(T *) * this->chunkSize));
  91. newChunk->startIndex = chunk->startIndex;
  92. js_memcpy_s(newChunk->data, sizeof(T *) * this->chunkSize, chunk->data, sizeof(T *) * this->chunkSize);
  93. if (pred)
  94. {
  95. pred->next = newChunk;
  96. }
  97. else
  98. {
  99. newSA->firstChunk = newChunk;
  100. }
  101. pred = newChunk;
  102. }
  103. if (pred)
  104. {
  105. pred->next = NULL;
  106. }
  107. else
  108. {
  109. newSA->firstChunk = NULL;
  110. }
  111. return newSA;
  112. }
  113. void And(SparseArray<T> *this2)
  114. {
  115. SAChunk<T> * chunk, *pred = NULL;
  116. SAChunk<T> * chunk2;
  117. AssertMsg(this->chunkSize == this2->chunkSize, "Anding incompatible arrays");
  118. chunk2 = this2->firstChunk;
  119. for (chunk = this->firstChunk; chunk; chunk = chunk->next)
  120. {
  121. while (chunk2 && chunk->startIndex > chunk2->startIndex)
  122. {
  123. chunk2 = chunk2->next;
  124. }
  125. if (chunk2 == NULL || chunk->startIndex < chunk2->startIndex)
  126. {
  127. if (pred)
  128. {
  129. pred->next = chunk->next;
  130. }
  131. else
  132. {
  133. this->firstChunk = chunk->next;
  134. }
  135. continue;
  136. }
  137. AssertMsg(chunk->startIndex == chunk2->startIndex, "Huh??");
  138. for (int i = 0; i < this->chunkSize; i++)
  139. {
  140. if (chunk->data[i])
  141. {
  142. if (chunk2->data[i])
  143. {
  144. if (*(chunk->data[i]) == *(chunk2->data[i]))
  145. {
  146. continue;
  147. }
  148. }
  149. chunk->data[i] = NULL;
  150. }
  151. }
  152. chunk2 = chunk2->next;
  153. pred = chunk;
  154. }
  155. }
  156. void Clear()
  157. {
  158. this->firstChunk = NULL;
  159. }
  160. #if DBG_DUMP
  161. void Dump()
  162. {
  163. for (SAChunk<T> *chunk = this->firstChunk; chunk; chunk = chunk->next)
  164. {
  165. for (int index = chunk->startIndex; index < this->chunkSize; index++)
  166. {
  167. if (chunk->data[index])
  168. {
  169. Output::Print(_u("Index %4d => "), index);
  170. chunk->data[index]->Dump();
  171. Output::Print(_u("\n"));
  172. }
  173. }
  174. }
  175. }
  176. #endif
  177. };