blob: 9cda5af858cd4ba812de9476d15d0f9f12760d98 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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 ();
}
|