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