summaryrefslogtreecommitdiffstats
path: root/source/core/slang-offset-container.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-10-24 17:58:24 -0400
committerTim Foley <tfoleyNV@users.noreply.github.com>2019-10-24 14:58:24 -0700
commit89ddb50eaccc1b7b590dbde55032721762711fb2 (patch)
treee61da2c1604e0d52d3a9915363769ccf950b62f3 /source/core/slang-offset-container.cpp
parent58ad4b1a9ca43098a071c42bd752a4a48405bf0e (diff)
OffsetContainer serialization (#1093)
* OffsetContainer with unit tests. * State serialization working with OffsetContainer. * Fixes to make work with OffsetContainer. * Added OffsetContainer documentation. * Remove RelativeContainer. * Fix problem with + on Offset32Ptr on windows x86 target. * * Made OffsetBase a base class of OffsetContainer. * Added MemoryOffsetBase to just handle being a chunk of memory. * * Use operator[] to access contents of OffsetContainer * Fix the type hash to work across different size_t sizes. * Fixed some Offset type related comments. * Fix bug around using asBase, because it returns a reference just using 'auto' will means it becomes a value type. Remove assignment and copy ctor from OffsetBase. * Evaluation order of assignment can lead to wrong behavior with Offset32Ptr/raw pointers. Document the fact, and fix in StateSerializeUtil.
Diffstat (limited to 'source/core/slang-offset-container.cpp')
-rw-r--r--source/core/slang-offset-container.cpp196
1 files changed, 196 insertions, 0 deletions
diff --git a/source/core/slang-offset-container.cpp b/source/core/slang-offset-container.cpp
new file mode 100644
index 000000000..5fed2a452
--- /dev/null
+++ b/source/core/slang-offset-container.cpp
@@ -0,0 +1,196 @@
+// slang-offset-container.cpp
+#include "slang-offset-container.h"
+
+namespace Slang {
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! OffsetString !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+size_t OffsetString::calcEncodedSize(size_t size, uint8_t encode[kMaxSizeEncodeSize])
+{
+ SLANG_ASSERT(size <= 0xffffffff);
+ if (size <= kSizeBase)
+ {
+ encode[0] = uint8_t(size);
+ return 1;
+ }
+ // Encode
+ int num = 0;
+ while (size)
+ {
+ encode[num + 1] = uint8_t(size);
+ size >>= 8;
+ num++;
+ }
+
+ // It might be one byte past the front, if its < 0x100 but greater than kSizeBase
+ SLANG_ASSERT(num >= 1);
+
+ encode[0] = uint8_t(kSizeBase + num);
+ return num + 1;
+}
+
+/* static */const char* OffsetString::decodeSize(const char* in, size_t& outSize)
+{
+ const uint8_t* cur = (const uint8_t*)in;
+ if (*cur <= kSizeBase)
+ {
+ outSize = *cur;
+ return in + 1;
+ }
+
+ int numBytes = *cur - kSizeBase;
+ switch (numBytes)
+ {
+ case 1:
+ {
+ outSize = cur[1];
+ return in + 2;
+ }
+ case 2:
+ {
+ outSize = cur[1] | (uint32_t(cur[2]) << 8);
+ return in + 3;
+ }
+ case 3:
+ {
+ outSize = cur[1] | (uint32_t(cur[2]) << 8) | (uint32_t(cur[3]) << 16);
+ return in + 4;
+ }
+ case 4:
+ {
+ outSize = cur[1] | (uint32_t(cur[2]) << 8) | (uint32_t(cur[3]) << 16) | (uint32_t(cur[4]) << 24);
+ return in + 5;
+ }
+ default:
+ {
+ outSize = 0;
+ return nullptr;
+ }
+ }
+}
+
+/* static */size_t OffsetString::calcAllocationSize(size_t stringSize)
+{
+ uint8_t encode[kMaxSizeEncodeSize];
+ size_t encodeSize = calcEncodedSize(stringSize, encode);
+ // Add 1 for terminating 0
+ return encodeSize + stringSize + 1;
+}
+
+/* static */size_t OffsetString::calcAllocationSize(const UnownedStringSlice& slice)
+{
+ return calcAllocationSize(slice.size());
+}
+
+UnownedStringSlice OffsetString::getSlice() const
+{
+ size_t size;
+ const char* chars = decodeSize(m_sizeThenContents, size);
+
+ return UnownedStringSlice(chars, size);
+}
+
+const char* OffsetString::getCstr() const
+{
+ return getSlice().begin();
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! OffsetContainer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+OffsetContainer::OffsetContainer()
+{
+ m_capacity = 0;
+ m_data = nullptr;
+
+ // We need to allocate some of the first bytes 0 can be used for nullptr.
+ allocateAndZero(kStartOffset, 1);
+}
+
+OffsetContainer::~OffsetContainer()
+{
+ if (m_data)
+ {
+ ::free(m_data);
+ }
+}
+
+void* OffsetContainer::allocate(size_t size)
+{
+ return allocate(size, 1);
+}
+
+void OffsetContainer::fixAlignment(size_t alignment)
+{
+ allocate(0, alignment);
+}
+
+void* OffsetContainer::allocate(size_t size, size_t alignment)
+{
+ size_t offset = (m_dataSize + alignment - 1) & ~(alignment - 1);
+
+ if (offset + size > m_capacity)
+ {
+ const size_t minSize = offset + size;
+
+ size_t calcSize = m_capacity;
+ if (calcSize < 2048)
+ {
+ calcSize = 2048;
+ }
+ else
+ {
+ // Expand geometrically, but lets not double in size...
+ calcSize = calcSize + (calcSize / 2);
+ }
+
+ // We must be at least minSize
+ size_t newSize = (calcSize < minSize) ? minSize : calcSize;
+
+ // Reallocate space
+ m_data = (uint8_t*)::realloc(m_data, newSize);
+ m_capacity = newSize;
+ }
+
+ SLANG_ASSERT(offset + size <= m_capacity);
+
+ m_dataSize = offset + size;
+ return m_data + offset;
+}
+
+void* OffsetContainer::allocateAndZero(size_t size, size_t alignment)
+{
+ void* data = allocate(size, alignment);
+ memset(data, 0, size);
+ return data;
+}
+
+Offset32Ptr<OffsetString> OffsetContainer::newString(const UnownedStringSlice& slice)
+{
+ size_t stringSize = slice.size();
+
+ uint8_t head[OffsetString::kMaxSizeEncodeSize];
+ size_t headSize = OffsetString::calcEncodedSize(stringSize, head);
+
+ size_t allocSize = headSize + stringSize + 1;
+ uint8_t* bytes = (uint8_t*)allocate(allocSize);
+
+ ::memcpy(bytes, head, headSize);
+ ::memcpy(bytes + headSize, slice.begin(), stringSize);
+
+ // 0 terminate
+ bytes[headSize + stringSize] = 0;
+
+ return Offset32Ptr<OffsetString>(getOffset(bytes));
+}
+
+Offset32Ptr<OffsetString> OffsetContainer::newString(const char* contents)
+{
+ Offset32Ptr<OffsetString> relString;
+ if (contents)
+ {
+ relString = newString(UnownedStringSlice(contents));
+ }
+ return relString;
+}
+
+} // namespace Slang