summaryrefslogtreecommitdiff
path: root/Runtime/Containers/ConstantString.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Containers/ConstantString.cpp')
-rw-r--r--Runtime/Containers/ConstantString.cpp123
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 ();
+}