-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVariableVector.h
176 lines (155 loc) · 4.4 KB
/
VariableVector.h
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#pragma once
#include <ConfigurableFirmata.h>
#include <FirmataFeature.h>
#include "MemoryManagement.h"
#include "ObjectVector.h"
#include "Exceptions.h"
/// <summary>
/// A vector that can contain values of different sizes. The number of items in the vector is fixed, though
/// </summary>
class VariableVector
{
private:
int _size;
// True if all elements within the vector are sizeof(Variable)
bool _defaultSizesOnly;
Variable* _data;
public:
typedef Variable* iterator;
VariableVector()
{
_data = nullptr;
_defaultSizesOnly = true;
_size = 0;
}
bool InitDefault(int numDescriptions, VariableDescription* variableDescriptions)
{
_defaultSizesOnly = true;
if (_data != nullptr)
{
freeEx(_data);
_data = nullptr;
}
if (numDescriptions > 0)
{
_data = (Variable*)mallocEx(numDescriptions * sizeof(Variable));
if (_data == nullptr)
{
stdSimple::OutOfMemoryException::Throw("Out of memory initializing default variable description list");
return false;
}
memset(_data, 0, numDescriptions * sizeof(Variable));
for (int i = 0; i < numDescriptions; i++)
{
VariableDescription* start = variableDescriptions + i;
size_t fieldSize = start->fieldSize();
_data[i].setSize((uint16_t)fieldSize);
_data[i].Type = start->Type;
_data[i].Marker = start->Marker;
}
}
else
{
_data = nullptr;
}
_size = numDescriptions;
return true;
}
bool InitFrom(int numDescriptions, VariableDescription* variableDescriptions)
{
bool canUseDefaultSizes = true;
int totalSize = 0;
// Check whether the list contains any large value type objects. If not, we will be using constant field sizes of sizeof(Variable)
// In the same run, sum up all sizes
// Firmata.sendStringf(F("Initfrom: %d descriptions, address 0x%x"), numDescriptions, variableDescriptions);
for (int i = 0; i < numDescriptions; i++)
{
size_t size = variableDescriptions[i].fieldSize();
if (size > sizeof(double))
{
canUseDefaultSizes = false;
}
totalSize += MAX(size, sizeof(double)) + Variable::headersize(); // Each variable carries a header and holds at least 8 bytes
}
if (canUseDefaultSizes)
{
return InitDefault(numDescriptions, variableDescriptions);
}
// This variable contains the number of elements in the vector, even if the vector has variable-lenght entries
_size = numDescriptions;
_defaultSizesOnly = false;
totalSize += sizeof(VariableDescription);
_data = (Variable*)mallocEx(totalSize);
if (_data == nullptr)
{
stdSimple::OutOfMemoryException::Throw("Out of memory initalizing dynamic variable vector");
return false;
}
memset(_data, 0, totalSize);
Variable* currentField = _data;
byte* currentFieldPtr = (byte*)_data;
// Now init the data structure: It's a ordered list with "next" pointers in the form of the size fields
for (int i = 0; i < numDescriptions; i++)
{
VariableDescription* start = variableDescriptions + i;
size_t size = MAX(start->fieldSize(), 8);
currentField->Type = start->Type;
currentField->Marker = start->Marker;
currentField->setSize((uint16_t)size);
currentFieldPtr += Variable::headersize() + size;
currentField = (Variable*)currentFieldPtr;
}
// There's room for one last VariableDescription after the now filled data. Leave it empty, so we have a guard when traversing the list.
return true;
}
~VariableVector()
{
if (_data != nullptr)
{
freeEx(_data);
}
_data = nullptr;
}
Variable& at(int index) const
{
if (_defaultSizesOnly)
{
if (index >= _size)
{
throw stdSimple::ExecutionEngineException("Variable index out of range");
}
return _data[index];
}
else
{
Variable* variablePtr = _data;
byte* bytePtr = (byte*)_data;
int currentIndex = 0;
while(currentIndex < index && variablePtr->Marker != 0)
{
bytePtr += MAX(variablePtr->fieldSize(), 8) + Variable::headersize();
variablePtr = (Variable*)bytePtr;
currentIndex++;
}
if (variablePtr->Marker == 0)
{
// This will blow, stopping the program. We should never get here (means the index was out of bounds)
throw stdSimple::ExecutionEngineException("Variable vector subscript out of range");
}
// Return a reference to the variable we've found
return *variablePtr;
}
}
int size() const
{
return _size;
}
Variable& operator[] (int index)
{
return at(index);
}
Variable& operator[] (const int index) const
{
return at(index);
}
};