diff options
Diffstat (limited to 'Runtime/Containers/ConstantString.cpp')
-rw-r--r-- | Runtime/Containers/ConstantString.cpp | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/Runtime/Containers/ConstantString.cpp b/Runtime/Containers/ConstantString.cpp new file mode 100644 index 0000000..9cda5af --- /dev/null +++ b/Runtime/Containers/ConstantString.cpp @@ -0,0 +1,123 @@ +#include "UnityPrefix.h" +#include "ConstantString.h" +#include "ConstantStringManager.h" +#include "Runtime/Threads/AtomicOps.h" + +///@TODO: Use 24 bits for refcount +///@TODO: Handle ref count overflow + +void ConstantString::create_empty () +{ + cleanup(); + m_Buffer = GetConstantStringManager().GetEmptyString(); + Assert(!owns_string()); +} + +// The header compressed the label and refcount into a 32 bits. +// Refcount lives on the 0xFFFF, label lives on the higher bits. +// We use atomic ops for thread safety on refcounting when deleting ConstantStrings. +struct AllocatedStringHeader +{ + volatile int refCountAndLabel; +}; + +MemLabelId GetLabel (const AllocatedStringHeader& header) +{ + int intLabel = (header.refCountAndLabel & (0x0000FFFF)) << 16; + ProfilerAllocationHeader* root = GET_ALLOC_HEADER(&GetConstantStringManager(), kMemString); + MemLabelId label( (MemLabelIdentifier)intLabel, root); + return label; +} + +void SetLabel (AllocatedStringHeader& header, MemLabelId label) +{ + int labelInt = label.label; + Assert(labelInt < 0xFFFF); + labelInt <<= 16; + + header.refCountAndLabel &= 0x0000FFFF; + header.refCountAndLabel |= labelInt; +} + +int GetRefCount (int refCountAndLabel) +{ + return refCountAndLabel & 0xFFFF; +} + + +inline static AllocatedStringHeader* GetHeader (const char* ptr) +{ + return reinterpret_cast<AllocatedStringHeader*> (const_cast<char*> (ptr) - sizeof(AllocatedStringHeader)); +} + +void ConstantString::operator = (const ConstantString& input) +{ + assign(input); +} + +void ConstantString::assign (const ConstantString& input) +{ + cleanup(); + m_Buffer = input.m_Buffer; + if (owns_string()) + { + AtomicIncrement(&GetHeader (get_char_ptr_fast())->refCountAndLabel); + } +} + + +void ConstantString::assign (const char* str, MemLabelId label) +{ + cleanup(); + const char* constantString = GetConstantStringManager().GetConstantString(str); + // Own Strings + if (constantString == NULL) + { + label.SetRootHeader(GET_ALLOC_HEADER(&GetConstantStringManager(), kMemString)); + size_t length = strlen(str); + + char* allocated = (char*)UNITY_MALLOC (label, length + 1 + sizeof(AllocatedStringHeader)); + char* allocatedString = allocated + sizeof(AllocatedStringHeader); + + AllocatedStringHeader& header = *GetHeader (allocatedString); + header.refCountAndLabel = 1; + SetLabel(header, label); + + Assert(GetRefCount(header.refCountAndLabel) == 1); + memcpy(allocatedString, str, length); + allocatedString[length] = 0; + + + m_Buffer = reinterpret_cast<char*> (reinterpret_cast<size_t> (allocatedString) | 1); + Assert(owns_string()); + } + else + { + m_Buffer = constantString; + Assert(!owns_string()); + } +} + +void ConstantString::cleanup () +{ + if (owns_string()) + { + AllocatedStringHeader* header = GetHeader(get_char_ptr_fast ()); + + int newRefCount = AtomicDecrement (&header->refCountAndLabel); + newRefCount = GetRefCount(newRefCount); + + if (newRefCount == 0) + { + MemLabelId label = GetLabel(*header); + UNITY_FREE(label, header); + } + } + + m_Buffer = NULL; +} + +ConstantString::~ConstantString () +{ + cleanup (); +} |