diff options
Diffstat (limited to 'source/core')
| -rw-r--r-- | source/core/slang-memory-arena.h | 25 | ||||
| -rw-r--r-- | source/core/slang-random-generator.cpp | 78 | ||||
| -rw-r--r-- | source/core/slang-random-generator.h | 10 | ||||
| -rw-r--r-- | source/core/slang-riff.cpp | 96 | ||||
| -rw-r--r-- | source/core/slang-riff.h | 15 |
5 files changed, 223 insertions, 1 deletions
diff --git a/source/core/slang-memory-arena.h b/source/core/slang-memory-arena.h index d346197f0..f63a48413 100644 --- a/source/core/slang-memory-arena.h +++ b/source/core/slang-memory-arena.h @@ -84,6 +84,11 @@ public: @return The allocation (or nullptr if unable to allocate). */ void* allocateUnaligned(size_t sizeInBytes); + /** Allocate some aligned memory of at least size bytes, without alignment, and only from current block. + @param sizeInBytes Size of allocation wanted. + @return The allocation (or nullptr if unable to allocate in current block). */ + void* allocateCurrentUnaligned(size_t sizeInBytes); + /** Allocates a null terminated string. NOTE, it is not possible to rewind to a zero length string allocation (because such a strings memory is not held on the arena) @@ -127,6 +132,9 @@ public: /// Gets the block alignment that is passed at initialization otherwise 0 an invalid block alignment. size_t getBlockAlignment() const { return m_blockAlignment; } + /// Get the default block payload size + size_t getBlockPayloadSize() const { return m_blockPayloadSize; } + /// Estimate of total amount of memory used in bytes. The number can never be smaller than actual used memory but may be larger size_t calcTotalMemoryUsed() const; /// Total memory allocated in bytes @@ -241,6 +249,23 @@ SLANG_FORCE_INLINE void* MemoryArena::allocateUnaligned(size_t sizeInBytes) } // -------------------------------------------------------------------------- +SLANG_FORCE_INLINE void* MemoryArena::allocateCurrentUnaligned(size_t sizeInBytes) +{ + // Align with the minimum alignment + uint8_t* mem = m_current; + uint8_t* end = mem + sizeInBytes; + if (end <= m_end) + { + m_current = end; + return mem; + } + else + { + return nullptr; + } +} + +// -------------------------------------------------------------------------- SLANG_FORCE_INLINE void* MemoryArena::allocate(size_t sizeInBytes) { assert(sizeInBytes > 0); diff --git a/source/core/slang-random-generator.cpp b/source/core/slang-random-generator.cpp index ce43067aa..ec06336f1 100644 --- a/source/core/slang-random-generator.cpp +++ b/source/core/slang-random-generator.cpp @@ -71,6 +71,57 @@ int64_t RandomGenerator::nextInt64InRange(int64_t min, int64_t max) return (nextPositiveInt64() % diff) + min; } +static uint8_t* _nextData(RandomGenerator* rand, uint8_t* out, size_t size) +{ + if (size) + { + SLANG_ASSERT(size <= 4); + uint32_t v = uint32_t(rand->nextInt32()); + uint8_t* dst = (uint8_t*)out; + for (size_t i = 0; i < size; ++i) + { + dst[i] = uint8_t(v); + v >>= 8; + } + } + return out + size; +} + +void RandomGenerator::nextData(void* out, size_t size) +{ + uint8_t* dst = (uint8_t*)out; + uint8_t*const end = dst + size; + + // For short runs just output + if (size <= 4) + { + _nextData(this, dst, size); + return; + } + + { + const size_t preAlign = size_t(((size_t(dst) + 3) & ~size_t(3)) - size_t(dst)); + dst = _nextData(this, dst, preAlign); + } + + // Check invariants + SLANG_ASSERT((size_t(dst) & 3) == 0 && end >= dst); + + { + const size_t middleCount = size_t(end - dst) >> 2; + if (middleCount) + { + nextInt32s((int32_t*)dst, middleCount); + dst += middleCount * sizeof(int32_t); + } + } + + // Check invariants + SLANG_ASSERT((size_t(dst) & 3) == 0 && end >= dst); + + _nextData(this, dst, size_t(end - dst)); +} + /* static */RandomGenerator* RandomGenerator::create(int32_t seed) { return new DefaultRandomGenerator(seed); @@ -155,7 +206,34 @@ int32_t Mt19937RandomGenerator::nextInt32() return int32_t(y); } +void Mt19937RandomGenerator::nextInt32s(int32_t* dst, size_t count) +{ + while (count) + { + if (m_index >= kNumEntries) + { + _generate(); + } + + const size_t remaining = kNumEntries - m_index; + const size_t run = (count < remaining) ? count : remaining; + + const uint32_t* src = m_mt + m_index; + for (size_t i = 0; i < run; i++) + { + uint32_t y = src[i]; + y = y ^ (y >> 11); + y = y ^ ((y << 7) & uint32_t(0x9d2c5680u)); + y = y ^ ((y << 15) & uint32_t(0xefc6000u)); + y = y ^ (y >> 18); + dst[i] = int32_t(y); + } + m_index += int(run); + dst += run; + count -= run; + } +} } // namespace Slang diff --git a/source/core/slang-random-generator.h b/source/core/slang-random-generator.h index 57f0e8630..392b4cb4c 100644 --- a/source/core/slang-random-generator.h +++ b/source/core/slang-random-generator.h @@ -30,6 +30,9 @@ class RandomGenerator: public RefObject /// Get the next bool virtual bool nextBool(); + /// Get multiple int32s + virtual void nextInt32s(int32_t* dst, size_t count) = 0; + /// Next uint32_t uint32_t nextUInt32() { return uint32_t(nextInt32()); } @@ -53,6 +56,10 @@ class RandomGenerator: public RefObject /// Returns value from min up to BUT NOT INCLUDING max int64_t nextInt64InRange(int64_t min, int64_t max); + /// Fill with random data. + /// NOTE! Output is only identical bytes if generator in same state *and* size_t(dst) & 3 is the same on calls. + void nextData(void* dst, size_t size); + /// Create a RandomGenerator with specified seed using default generator type static RandomGenerator* create(int32_t seed); }; @@ -73,7 +80,8 @@ class Mt19937RandomGenerator: public RandomGenerator Mt19937RandomGenerator* clone() SLANG_OVERRIDE { return new ThisType(*this); } void reset(int32_t seed) SLANG_OVERRIDE; int32_t nextInt32() SLANG_OVERRIDE; - + void nextInt32s(int32_t* dst, size_t count) SLANG_OVERRIDE; + /// Ctor Mt19937RandomGenerator(); Mt19937RandomGenerator(const ThisType& rhs); diff --git a/source/core/slang-riff.cpp b/source/core/slang-riff.cpp index 1de51d840..da547319b 100644 --- a/source/core/slang-riff.cpp +++ b/source/core/slang-riff.cpp @@ -665,6 +665,47 @@ size_t RiffContainer::DataChunk::calcPayloadSize() const return size; } +void RiffContainer::DataChunk::getPayload(void* inDst) const +{ + uint8_t* dst = (uint8_t*)inDst; + + Data* data = m_dataList; + while (data) + { + const size_t size = data->getSize(); + ::memcpy(dst, data->getPayload(), size); + + dst += size; + data = data->m_next; + } +} + +bool RiffContainer::DataChunk::isEqual(const void* inData, size_t count) const +{ + const uint8_t* src = (const uint8_t*)inData; + + Data* data = m_dataList; + while (data) + { + const size_t size = data->getSize(); + // Can't have more content than remaining + // Contents must match + if (size > count || ::memcmp(src, data->getPayload(), size) != 0) + { + return false; + } + + src += size; + count -= size; + + // Next data block + data = data->m_next; + } + + // If match must be at the end + return count == 0; +} + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RiffContainer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RiffContainer::RiffContainer() : @@ -862,8 +903,63 @@ RiffContainer::Data* RiffContainer::addData() return data; } +RiffContainer::Data* RiffContainer::makeSingleData(DataChunk* dataChunk) +{ + // There is no data + if (dataChunk->m_dataList == nullptr) + { + return nullptr; + } + + if (dataChunk->m_dataList->m_next == nullptr) + { + return dataChunk->m_dataList; + } + + { + Data* data = dataChunk->m_dataList; + + // Okay lets combine all into one block + const size_t payloadSize = dataChunk->calcPayloadSize(); + + void* dst = m_arena.allocate(payloadSize); + dataChunk->getPayload(dst); + + // Remove other datas + data->m_next = nullptr; + // Make this the end + dataChunk->m_endData = data; + + // Point to the block with all of the data + data->m_ownership = Ownership::Arena; + data->m_payload = dst; + data->m_size = payloadSize; + + return data; + } +} + void RiffContainer::write(const void* inData, size_t size) { + // We must be in a chunk + SLANG_ASSERT(m_dataChunk); + // Get the last data chunk + Data* endData = m_dataChunk->m_endData; + if (endData) + { + uint8_t* end = ((uint8_t*)endData->m_payload) + endData->m_size; + // See if can just add to end of current data + if ( end == m_arena.getCursor() && m_arena.allocateCurrentUnaligned(size)) + { + ::memcpy(end, inData, size); + endData->m_size += size; + + // Add current chunks data + m_dataChunk->m_payloadSize += size; + return; + } + } + auto data = addData(); setPayload(data, inData, size); } diff --git a/source/core/slang-riff.h b/source/core/slang-riff.h index 61e6eed1e..1622f60f4 100644 --- a/source/core/slang-riff.h +++ b/source/core/slang-riff.h @@ -284,6 +284,12 @@ public: /// Calculate the payload size size_t calcPayloadSize() const; + /// Copy the payload to dst. Dst must be at least the payload size. + void getPayload(void* dst) const; + + /// True if payloads contents is equal to data + bool isEqual(const void* data, size_t count) const; + /// Get single data payload. Data* getSingleData() const; @@ -347,12 +353,21 @@ public: /// Get the root ListChunk* getRoot() const { return m_rootList; } + /// Get the current chunk + Chunk* getCurrentChunk() { return m_dataChunk ? static_cast<Chunk*>(m_dataChunk) : static_cast<Chunk*>(m_listChunk); } + /// Reset the container void reset(); /// true if has a root container, and nothing remains open bool isFullyConstructed() { return m_rootList && m_listChunk == nullptr && m_dataChunk == nullptr; } + /// Makes a data chunk contain a single contiguous data block + Data* makeSingleData(DataChunk* dataChunk); + + /// Get the memory arena that is backing the storage of data + MemoryArena& getMemoryArena() { return m_arena; } + /// The if the list and sublists appear correct static bool isChunkOk(Chunk* chunk); |
