| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #pragma once
- template<class T>
- class SAChunk
- {
- public:
- SAChunk<T> * next;
- uint32 startIndex;
- T * data[];
- };
- template<class T>
- class SparseArray
- {
- private:
- ArenaAllocator * alloc;
- uint32 chunkSize;
- SAChunk<T> * firstChunk;
- public:
- static SparseArray<T> * New(ArenaAllocator *allocator, uint32 chunkSize)
- {
- SparseArray<T> * array;
- if (!Math::IsPow2(chunkSize))
- {
- chunkSize = Math::NextPowerOf2(chunkSize);
- }
- // Throw early if this overflows, since chunkSize never changes, subsequent operations will be safe
- UInt32Math::MulAdd<sizeof(T*), sizeof(SAChunk<T>)>(chunkSize);
- array = Anew(allocator, SparseArray<T>);
- array->alloc = allocator;
- array->chunkSize = chunkSize;
- array->firstChunk = NULL;
- return array;
- }
- void Set(uint32 index, T *element)
- {
- SAChunk<T> * chunk, **pPrev = &(this->firstChunk);
- uint32 indexInChunk = (index % this->chunkSize);
- for (chunk = this->firstChunk; chunk; chunk = chunk->next)
- {
- if (index < chunk->startIndex)
- {
- // Need a new chunk...
- chunk = NULL;
- break;
- }
- if (index < chunk->startIndex + this->chunkSize)
- {
- break;
- }
- pPrev = &(chunk->next);
- }
- if (chunk == NULL)
- {
- chunk = (SAChunk<T> *)this->alloc->AllocZero(sizeof(SAChunk<T>) + (chunkSize * sizeof(T *)));
- chunk->startIndex = index - indexInChunk;
- // Since startIndex and chunkSize don't change, check now if this overflows.
- // Cache the result or save memory ?
- UInt32Math::Add(chunk->startIndex, chunkSize);
- chunk->next = *pPrev;
- *pPrev = chunk;
- }
- chunk->data[indexInChunk] = element;
- }
- T * Get(uint32 index)
- {
- SAChunk<T> * chunk;
- uint32 indexInChunk = (index % this->chunkSize);
- for (chunk = this->firstChunk; chunk; chunk = chunk->next)
- {
- if (index < chunk->startIndex)
- {
- return NULL;
- }
- if (index < chunk->startIndex + this->chunkSize)
- {
- return chunk->data[indexInChunk];
- }
- }
- return NULL;
- }
- SparseArray<T> * Copy()
- {
- SparseArray<T> * newSA = SparseArray<T>::New(this->alloc, this->chunkSize);
- SAChunk<T> * chunk, *pred = NULL;
- for (chunk = this->firstChunk; chunk; chunk = chunk->next)
- {
- SAChunk<T> *newChunk = (SAChunk<T> *)this->alloc->Alloc(sizeof(SAChunk<T>) + (sizeof(T *) * this->chunkSize));
- newChunk->startIndex = chunk->startIndex;
- js_memcpy_s(newChunk->data, sizeof(T *) * this->chunkSize, chunk->data, sizeof(T *) * this->chunkSize);
- if (pred)
- {
- pred->next = newChunk;
- }
- else
- {
- newSA->firstChunk = newChunk;
- }
- pred = newChunk;
- }
- if (pred)
- {
- pred->next = NULL;
- }
- else
- {
- newSA->firstChunk = NULL;
- }
- return newSA;
- }
- void And(SparseArray<T> *this2)
- {
- SAChunk<T> * chunk, *pred = NULL;
- SAChunk<T> * chunk2;
- AssertMsg(this->chunkSize == this2->chunkSize, "Anding incompatible arrays");
- chunk2 = this2->firstChunk;
- for (chunk = this->firstChunk; chunk; chunk = chunk->next)
- {
- while (chunk2 && chunk->startIndex > chunk2->startIndex)
- {
- chunk2 = chunk2->next;
- }
- if (chunk2 == NULL || chunk->startIndex < chunk2->startIndex)
- {
- if (pred)
- {
- pred->next = chunk->next;
- }
- else
- {
- this->firstChunk = chunk->next;
- }
- continue;
- }
- AssertMsg(chunk->startIndex == chunk2->startIndex, "Huh??");
- for (int i = 0; i < this->chunkSize; i++)
- {
- if (chunk->data[i])
- {
- if (chunk2->data[i])
- {
- if (*(chunk->data[i]) == *(chunk2->data[i]))
- {
- continue;
- }
- }
- chunk->data[i] = NULL;
- }
- }
- chunk2 = chunk2->next;
- pred = chunk;
- }
- }
- void Clear()
- {
- this->firstChunk = NULL;
- }
- #if DBG_DUMP
- void Dump()
- {
- for (SAChunk<T> *chunk = this->firstChunk; chunk; chunk = chunk->next)
- {
- for (int index = chunk->startIndex; index < this->chunkSize; index++)
- {
- if (chunk->data[index])
- {
- Output::Print(_u("Index %4d => "), index);
- chunk->data[index]->Dump();
- Output::Print(_u("\n"));
- }
- }
- }
- }
- #endif
- };
|