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
23static const uint64 kMaxArrayElementCount = 10;
24
25
26// #pragma mark - AbstractArrayValueNode
27
28
29AbstractArrayValueNode::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
43AbstractArrayValueNode::~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
54Type*
55AbstractArrayValueNode::GetType() const
56{
57	return fType;
58}
59
60
61status_t
62AbstractArrayValueNode::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
77status_t
78AbstractArrayValueNode::CreateChildren(TeamTypeInformation* info)
79{
80	if (!fChildren.IsEmpty())
81		return B_OK;
82
83	return CreateChildrenInRange(info, 0, kMaxArrayElementCount - 1);
84}
85
86
87int32
88AbstractArrayValueNode::CountChildren() const
89{
90	return fChildren.CountItems();
91}
92
93
94ValueNodeChild*
95AbstractArrayValueNode::ChildAt(int32 index) const
96{
97	return fChildren.ItemAt(index);
98}
99
100
101bool
102AbstractArrayValueNode::IsRangedContainer() const
103{
104	return true;
105}
106
107
108void
109AbstractArrayValueNode::ClearChildren()
110{
111	fChildren.MakeEmpty();
112	fLowerBound = 0;
113	fUpperBound = 0;
114	if (fContainer != NULL)
115		fContainer->NotifyValueNodeChildrenDeleted(this);
116}
117
118
119status_t
120AbstractArrayValueNode::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
178status_t
179AbstractArrayValueNode::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
205ArrayValueNode::ArrayValueNode(ValueNodeChild* nodeChild, ArrayType* type)
206	:
207	AbstractArrayValueNode(nodeChild, type, 0)
208{
209}
210
211
212ArrayValueNode::~ArrayValueNode()
213{
214}
215
216
217// #pragma mark - InternalArrayValueNode
218
219
220InternalArrayValueNode::InternalArrayValueNode(ValueNodeChild* nodeChild,
221	ArrayType* type, int32 dimension)
222	:
223	AbstractArrayValueNode(nodeChild, type, dimension)
224{
225}
226
227
228InternalArrayValueNode::~InternalArrayValueNode()
229{
230}
231
232
233// #pragma mark - AbstractArrayValueNodeChild
234
235
236AbstractArrayValueNodeChild::AbstractArrayValueNodeChild(
237	AbstractArrayValueNode* parent, const BString& name, int64 elementIndex)
238	:
239	fParent(parent),
240	fName(name),
241	fElementIndex(elementIndex)
242{
243}
244
245
246AbstractArrayValueNodeChild::~AbstractArrayValueNodeChild()
247{
248}
249
250
251const BString&
252AbstractArrayValueNodeChild::Name() const
253{
254	return fName;
255}
256
257
258ValueNode*
259AbstractArrayValueNodeChild::Parent() const
260{
261	return fParent;
262}
263
264
265// #pragma mark - ArrayValueNodeChild
266
267
268ArrayValueNodeChild::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
278ArrayValueNodeChild::~ArrayValueNodeChild()
279{
280	fType->ReleaseReference();
281}
282
283
284Type*
285ArrayValueNodeChild::GetType() const
286{
287	return fType;
288}
289
290
291status_t
292ArrayValueNodeChild::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
338InternalArrayValueNodeChild::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
349InternalArrayValueNodeChild::~InternalArrayValueNodeChild()
350{
351	fType->ReleaseReference();
352}
353
354
355Type*
356InternalArrayValueNodeChild::GetType() const
357{
358	return fType;
359}
360
361
362bool
363InternalArrayValueNodeChild::IsInternal() const
364{
365	return true;
366}
367
368
369status_t
370InternalArrayValueNodeChild::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
382status_t
383InternalArrayValueNodeChild::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