1 /*
2 * Copyright 2013-2015, Rene Gollent, rene@gollent.com.
3 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8 #include "ArrayValueNode.h"
9
10 #include <new>
11
12 #include "Architecture.h"
13 #include "ArrayIndexPath.h"
14 #include "IntegerValue.h"
15 #include "Tracing.h"
16 #include "Type.h"
17 #include "ValueLoader.h"
18 #include "ValueLocation.h"
19 #include "ValueNodeContainer.h"
20
21
22 // maximum number of array elements to show by default
23 static const uint64 kMaxArrayElementCount = 10;
24
25
26 // #pragma mark - AbstractArrayValueNode
27
28
AbstractArrayValueNode(ValueNodeChild * nodeChild,ArrayType * type,int32 dimension)29 AbstractArrayValueNode::AbstractArrayValueNode(ValueNodeChild* nodeChild,
30 ArrayType* type, int32 dimension)
31 :
32 ValueNode(nodeChild),
33 fType(type),
34 fDimension(dimension),
35 fLowerBound(0),
36 fUpperBound(0),
37 fBoundsInitialized(false)
38 {
39 fType->AcquireReference();
40 }
41
42
~AbstractArrayValueNode()43 AbstractArrayValueNode::~AbstractArrayValueNode()
44 {
45 fType->ReleaseReference();
46
47 for (int32 i = 0; AbstractArrayValueNodeChild* child = fChildren.ItemAt(i);
48 i++) {
49 child->ReleaseReference();
50 }
51 }
52
53
54 Type*
GetType() const55 AbstractArrayValueNode::GetType() const
56 {
57 return fType;
58 }
59
60
61 status_t
ResolvedLocationAndValue(ValueLoader * valueLoader,ValueLocation * & _location,Value * & _value)62 AbstractArrayValueNode::ResolvedLocationAndValue(ValueLoader* valueLoader,
63 ValueLocation*& _location, Value*& _value)
64 {
65 // get the location
66 ValueLocation* location = NodeChild()->Location();
67 if (location == NULL)
68 return B_BAD_VALUE;
69
70 location->AcquireReference();
71 _location = location;
72 _value = NULL;
73 return B_OK;
74 }
75
76
77 status_t
CreateChildren(TeamTypeInformation * info)78 AbstractArrayValueNode::CreateChildren(TeamTypeInformation* info)
79 {
80 if (!fChildren.IsEmpty())
81 return B_OK;
82
83 return CreateChildrenInRange(info, 0, kMaxArrayElementCount - 1);
84 }
85
86
87 int32
CountChildren() const88 AbstractArrayValueNode::CountChildren() const
89 {
90 return fChildren.CountItems();
91 }
92
93
94 ValueNodeChild*
ChildAt(int32 index) const95 AbstractArrayValueNode::ChildAt(int32 index) const
96 {
97 return fChildren.ItemAt(index);
98 }
99
100
101 bool
IsRangedContainer() const102 AbstractArrayValueNode::IsRangedContainer() const
103 {
104 return true;
105 }
106
107
108 void
ClearChildren()109 AbstractArrayValueNode::ClearChildren()
110 {
111 fChildren.MakeEmpty();
112 fLowerBound = 0;
113 fUpperBound = 0;
114 if (fContainer != NULL)
115 fContainer->NotifyValueNodeChildrenDeleted(this);
116 }
117
118
119 status_t
CreateChildrenInRange(TeamTypeInformation * info,int32 lowIndex,int32 highIndex)120 AbstractArrayValueNode::CreateChildrenInRange(TeamTypeInformation* info,
121 int32 lowIndex, int32 highIndex)
122 {
123 // TODO: ensure that we don't already have children in the specified
124 // index range. These need to be skipped if so.
125 TRACE_LOCALS("TYPE_ARRAY\n");
126
127 int32 dimensionCount = fType->CountDimensions();
128 bool isFinalDimension = fDimension + 1 == dimensionCount;
129 status_t error = B_OK;
130
131 if (!fBoundsInitialized) {
132 int32 lowerBound, upperBound;
133 error = SupportedChildRange(lowerBound, upperBound);
134 if (error != B_OK)
135 return error;
136
137 fLowerBound = lowerBound;
138 fUpperBound = upperBound;
139 fBoundsInitialized = true;
140 }
141
142 if (lowIndex < fLowerBound)
143 lowIndex = fLowerBound;
144 if (highIndex > fUpperBound)
145 highIndex = fUpperBound;
146
147 // create children for the array elements
148 for (int32 i = lowIndex; i <= highIndex; i++) {
149 BString name(Name());
150 name << '[' << i << ']';
151 if (name.Length() <= Name().Length())
152 return B_NO_MEMORY;
153
154 AbstractArrayValueNodeChild* child;
155 if (isFinalDimension) {
156 child = new(std::nothrow) ArrayValueNodeChild(this, name, i,
157 fType->BaseType());
158 } else {
159 child = new(std::nothrow) InternalArrayValueNodeChild(this, name, i,
160 fType);
161 }
162
163 if (child == NULL || !fChildren.AddItem(child)) {
164 delete child;
165 return B_NO_MEMORY;
166 }
167
168 child->SetContainer(fContainer);
169 }
170
171 if (fContainer != NULL)
172 fContainer->NotifyValueNodeChildrenCreated(this);
173
174 return B_OK;
175 }
176
177
178 status_t
SupportedChildRange(int32 & lowIndex,int32 & highIndex) const179 AbstractArrayValueNode::SupportedChildRange(int32& lowIndex,
180 int32& highIndex) const
181 {
182 if (!fBoundsInitialized) {
183 ArrayDimension* dimension = fType->DimensionAt(fDimension);
184
185 SubrangeType* dimensionType = dynamic_cast<SubrangeType*>(
186 dimension->GetType());
187
188 if (dimensionType != NULL) {
189 lowIndex = dimensionType->LowerBound().ToInt32();
190 highIndex = dimensionType->UpperBound().ToInt32();
191 } else
192 return B_UNSUPPORTED;
193 } else {
194 lowIndex = fLowerBound;
195 highIndex = fUpperBound;
196 }
197
198 return B_OK;
199 }
200
201
202 // #pragma mark - ArrayValueNode
203
204
ArrayValueNode(ValueNodeChild * nodeChild,ArrayType * type)205 ArrayValueNode::ArrayValueNode(ValueNodeChild* nodeChild, ArrayType* type)
206 :
207 AbstractArrayValueNode(nodeChild, type, 0)
208 {
209 }
210
211
~ArrayValueNode()212 ArrayValueNode::~ArrayValueNode()
213 {
214 }
215
216
217 // #pragma mark - InternalArrayValueNode
218
219
InternalArrayValueNode(ValueNodeChild * nodeChild,ArrayType * type,int32 dimension)220 InternalArrayValueNode::InternalArrayValueNode(ValueNodeChild* nodeChild,
221 ArrayType* type, int32 dimension)
222 :
223 AbstractArrayValueNode(nodeChild, type, dimension)
224 {
225 }
226
227
~InternalArrayValueNode()228 InternalArrayValueNode::~InternalArrayValueNode()
229 {
230 }
231
232
233 // #pragma mark - AbstractArrayValueNodeChild
234
235
AbstractArrayValueNodeChild(AbstractArrayValueNode * parent,const BString & name,int64 elementIndex)236 AbstractArrayValueNodeChild::AbstractArrayValueNodeChild(
237 AbstractArrayValueNode* parent, const BString& name, int64 elementIndex)
238 :
239 fParent(parent),
240 fName(name),
241 fElementIndex(elementIndex)
242 {
243 }
244
245
~AbstractArrayValueNodeChild()246 AbstractArrayValueNodeChild::~AbstractArrayValueNodeChild()
247 {
248 }
249
250
251 const BString&
Name() const252 AbstractArrayValueNodeChild::Name() const
253 {
254 return fName;
255 }
256
257
258 ValueNode*
Parent() const259 AbstractArrayValueNodeChild::Parent() const
260 {
261 return fParent;
262 }
263
264
265 // #pragma mark - ArrayValueNodeChild
266
267
ArrayValueNodeChild(AbstractArrayValueNode * parent,const BString & name,int64 elementIndex,Type * type)268 ArrayValueNodeChild::ArrayValueNodeChild(AbstractArrayValueNode* parent,
269 const BString& name, int64 elementIndex, Type* type)
270 :
271 AbstractArrayValueNodeChild(parent, name, elementIndex),
272 fType(type)
273 {
274 fType->AcquireReference();
275 }
276
277
~ArrayValueNodeChild()278 ArrayValueNodeChild::~ArrayValueNodeChild()
279 {
280 fType->ReleaseReference();
281 }
282
283
284 Type*
GetType() const285 ArrayValueNodeChild::GetType() const
286 {
287 return fType;
288 }
289
290
291 status_t
ResolveLocation(ValueLoader * valueLoader,ValueLocation * & _location)292 ArrayValueNodeChild::ResolveLocation(ValueLoader* valueLoader,
293 ValueLocation*& _location)
294 {
295 // get the parent (== array) location
296 ValueLocation* parentLocation = fParent->Location();
297 if (parentLocation == NULL)
298 return B_BAD_VALUE;
299
300 // create an array index path
301 ArrayType* arrayType = fParent->GetArrayType();
302 int32 dimensionCount = arrayType->CountDimensions();
303
304 // add dummy indices first -- we'll replace them on our way back through
305 // our ancestors
306 ArrayIndexPath indexPath;
307 for (int32 i = 0; i < dimensionCount; i++) {
308 if (!indexPath.AddIndex(0))
309 return B_NO_MEMORY;
310 }
311
312 AbstractArrayValueNodeChild* child = this;
313 for (int32 i = dimensionCount - 1; i >= 0; i--) {
314 indexPath.SetIndexAt(i, child->ElementIndex());
315
316 child = dynamic_cast<AbstractArrayValueNodeChild*>(
317 child->ArrayParent()->NodeChild());
318 }
319
320 // resolve the element location
321 ValueLocation* location;
322 status_t error = arrayType->ResolveElementLocation(indexPath,
323 *parentLocation, location);
324 if (error != B_OK) {
325 TRACE_LOCALS("ArrayValueNodeChild::ResolveLocation(): "
326 "ResolveElementLocation() failed: %s\n", strerror(error));
327 return error;
328 }
329
330 _location = location;
331 return B_OK;
332 }
333
334
335 // #pragma mark - InternalArrayValueNodeChild
336
337
InternalArrayValueNodeChild(AbstractArrayValueNode * parent,const BString & name,int64 elementIndex,ArrayType * type)338 InternalArrayValueNodeChild::InternalArrayValueNodeChild(
339 AbstractArrayValueNode* parent, const BString& name, int64 elementIndex,
340 ArrayType* type)
341 :
342 AbstractArrayValueNodeChild(parent, name, elementIndex),
343 fType(type)
344 {
345 fType->AcquireReference();
346 }
347
348
~InternalArrayValueNodeChild()349 InternalArrayValueNodeChild::~InternalArrayValueNodeChild()
350 {
351 fType->ReleaseReference();
352 }
353
354
355 Type*
GetType() const356 InternalArrayValueNodeChild::GetType() const
357 {
358 return fType;
359 }
360
361
362 bool
IsInternal() const363 InternalArrayValueNodeChild::IsInternal() const
364 {
365 return true;
366 }
367
368
369 status_t
CreateInternalNode(ValueNode * & _node)370 InternalArrayValueNodeChild::CreateInternalNode(ValueNode*& _node)
371 {
372 ValueNode* node = new(std::nothrow) InternalArrayValueNode(this, fType,
373 fParent->Dimension() + 1);
374 if (node == NULL)
375 return B_NO_MEMORY;
376
377 _node = node;
378 return B_OK;
379 }
380
381
382 status_t
ResolveLocation(ValueLoader * valueLoader,ValueLocation * & _location)383 InternalArrayValueNodeChild::ResolveLocation(ValueLoader* valueLoader,
384 ValueLocation*& _location)
385 {
386 // This is an internal child node for a non-final dimension -- just clone
387 // the parent's location.
388 ValueLocation* parentLocation = fParent->Location();
389 if (parentLocation == NULL)
390 return B_BAD_VALUE;
391
392 parentLocation->AcquireReference();
393 _location = parentLocation;
394
395 return B_OK;
396 }
397