xref: /haiku/src/kits/debugger/value/value_nodes/ArrayValueNode.cpp (revision 1deede7388b04dbeec5af85cae7164735ea9e70d)
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 
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 
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*
55 AbstractArrayValueNode::GetType() const
56 {
57 	return fType;
58 }
59 
60 
61 status_t
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
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
88 AbstractArrayValueNode::CountChildren() const
89 {
90 	return fChildren.CountItems();
91 }
92 
93 
94 ValueNodeChild*
95 AbstractArrayValueNode::ChildAt(int32 index) const
96 {
97 	return fChildren.ItemAt(index);
98 }
99 
100 
101 bool
102 AbstractArrayValueNode::IsRangedContainer() const
103 {
104 	return true;
105 }
106 
107 
108 void
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
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
179 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 
205 ArrayValueNode::ArrayValueNode(ValueNodeChild* nodeChild, ArrayType* type)
206 	:
207 	AbstractArrayValueNode(nodeChild, type, 0)
208 {
209 }
210 
211 
212 ArrayValueNode::~ArrayValueNode()
213 {
214 }
215 
216 
217 // #pragma mark - InternalArrayValueNode
218 
219 
220 InternalArrayValueNode::InternalArrayValueNode(ValueNodeChild* nodeChild,
221 	ArrayType* type, int32 dimension)
222 	:
223 	AbstractArrayValueNode(nodeChild, type, dimension)
224 {
225 }
226 
227 
228 InternalArrayValueNode::~InternalArrayValueNode()
229 {
230 }
231 
232 
233 // #pragma mark - AbstractArrayValueNodeChild
234 
235 
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 
246 AbstractArrayValueNodeChild::~AbstractArrayValueNodeChild()
247 {
248 }
249 
250 
251 const BString&
252 AbstractArrayValueNodeChild::Name() const
253 {
254 	return fName;
255 }
256 
257 
258 ValueNode*
259 AbstractArrayValueNodeChild::Parent() const
260 {
261 	return fParent;
262 }
263 
264 
265 // #pragma mark - ArrayValueNodeChild
266 
267 
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 
278 ArrayValueNodeChild::~ArrayValueNodeChild()
279 {
280 	fType->ReleaseReference();
281 }
282 
283 
284 Type*
285 ArrayValueNodeChild::GetType() const
286 {
287 	return fType;
288 }
289 
290 
291 status_t
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 
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 
349 InternalArrayValueNodeChild::~InternalArrayValueNodeChild()
350 {
351 	fType->ReleaseReference();
352 }
353 
354 
355 Type*
356 InternalArrayValueNodeChild::GetType() const
357 {
358 	return fType;
359 }
360 
361 
362 bool
363 InternalArrayValueNodeChild::IsInternal() const
364 {
365 	return true;
366 }
367 
368 
369 status_t
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
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