* Copyright 2013-2015, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "ArrayValueNode.h"
#include <new>
#include "Architecture.h"
#include "ArrayIndexPath.h"
#include "IntegerValue.h"
#include "Tracing.h"
#include "Type.h"
#include "ValueLoader.h"
#include "ValueLocation.h"
#include "ValueNodeContainer.h"
static const uint64 kMaxArrayElementCount = 10;
AbstractArrayValueNode::AbstractArrayValueNode(ValueNodeChild* nodeChild,
ArrayType* type, int32 dimension)
:
ValueNode(nodeChild),
fType(type),
fDimension(dimension),
fLowerBound(0),
fUpperBound(0),
fBoundsInitialized(false)
{
fType->AcquireReference();
}
AbstractArrayValueNode::~AbstractArrayValueNode()
{
fType->ReleaseReference();
for (int32 i = 0; AbstractArrayValueNodeChild* child = fChildren.ItemAt(i);
i++) {
child->ReleaseReference();
}
}
Type*
AbstractArrayValueNode::GetType() const
{
return fType;
}
status_t
AbstractArrayValueNode::ResolvedLocationAndValue(ValueLoader* valueLoader,
ValueLocation*& _location, Value*& _value)
{
ValueLocation* location = NodeChild()->Location();
if (location == NULL)
return B_BAD_VALUE;
location->AcquireReference();
_location = location;
_value = NULL;
return B_OK;
}
status_t
AbstractArrayValueNode::CreateChildren(TeamTypeInformation* info)
{
if (!fChildren.IsEmpty())
return B_OK;
return CreateChildrenInRange(info, 0, kMaxArrayElementCount - 1);
}
int32
AbstractArrayValueNode::CountChildren() const
{
return fChildren.CountItems();
}
ValueNodeChild*
AbstractArrayValueNode::ChildAt(int32 index) const
{
return fChildren.ItemAt(index);
}
bool
AbstractArrayValueNode::IsRangedContainer() const
{
return true;
}
void
AbstractArrayValueNode::ClearChildren()
{
fChildren.MakeEmpty();
fLowerBound = 0;
fUpperBound = 0;
if (fContainer != NULL)
fContainer->NotifyValueNodeChildrenDeleted(this);
}
status_t
AbstractArrayValueNode::CreateChildrenInRange(TeamTypeInformation* info,
int32 lowIndex, int32 highIndex)
{
TRACE_LOCALS("TYPE_ARRAY\n");
int32 dimensionCount = fType->CountDimensions();
bool isFinalDimension = fDimension + 1 == dimensionCount;
status_t error = B_OK;
if (!fBoundsInitialized) {
int32 lowerBound, upperBound;
error = SupportedChildRange(lowerBound, upperBound);
if (error != B_OK)
return error;
fLowerBound = lowerBound;
fUpperBound = upperBound;
fBoundsInitialized = true;
}
if (lowIndex < fLowerBound)
lowIndex = fLowerBound;
if (highIndex > fUpperBound)
highIndex = fUpperBound;
for (int32 i = lowIndex; i <= highIndex; i++) {
BString name(Name());
name << '[' << i << ']';
if (name.Length() <= Name().Length())
return B_NO_MEMORY;
AbstractArrayValueNodeChild* child;
if (isFinalDimension) {
child = new(std::nothrow) ArrayValueNodeChild(this, name, i,
fType->BaseType());
} else {
child = new(std::nothrow) InternalArrayValueNodeChild(this, name, i,
fType);
}
if (child == NULL || !fChildren.AddItem(child)) {
delete child;
return B_NO_MEMORY;
}
child->SetContainer(fContainer);
}
if (fContainer != NULL)
fContainer->NotifyValueNodeChildrenCreated(this);
return B_OK;
}
status_t
AbstractArrayValueNode::SupportedChildRange(int32& lowIndex,
int32& highIndex) const
{
if (!fBoundsInitialized) {
ArrayDimension* dimension = fType->DimensionAt(fDimension);
SubrangeType* dimensionType = dynamic_cast<SubrangeType*>(
dimension->GetType());
if (dimensionType != NULL) {
lowIndex = dimensionType->LowerBound().ToInt32();
highIndex = dimensionType->UpperBound().ToInt32();
} else
return B_UNSUPPORTED;
} else {
lowIndex = fLowerBound;
highIndex = fUpperBound;
}
return B_OK;
}
ArrayValueNode::ArrayValueNode(ValueNodeChild* nodeChild, ArrayType* type)
:
AbstractArrayValueNode(nodeChild, type, 0)
{
}
ArrayValueNode::~ArrayValueNode()
{
}
InternalArrayValueNode::InternalArrayValueNode(ValueNodeChild* nodeChild,
ArrayType* type, int32 dimension)
:
AbstractArrayValueNode(nodeChild, type, dimension)
{
}
InternalArrayValueNode::~InternalArrayValueNode()
{
}
AbstractArrayValueNodeChild::AbstractArrayValueNodeChild(
AbstractArrayValueNode* parent, const BString& name, int64 elementIndex)
:
fParent(parent),
fName(name),
fElementIndex(elementIndex)
{
}
AbstractArrayValueNodeChild::~AbstractArrayValueNodeChild()
{
}
const BString&
AbstractArrayValueNodeChild::Name() const
{
return fName;
}
ValueNode*
AbstractArrayValueNodeChild::Parent() const
{
return fParent;
}
ArrayValueNodeChild::ArrayValueNodeChild(AbstractArrayValueNode* parent,
const BString& name, int64 elementIndex, Type* type)
:
AbstractArrayValueNodeChild(parent, name, elementIndex),
fType(type)
{
fType->AcquireReference();
}
ArrayValueNodeChild::~ArrayValueNodeChild()
{
fType->ReleaseReference();
}
Type*
ArrayValueNodeChild::GetType() const
{
return fType;
}
status_t
ArrayValueNodeChild::ResolveLocation(ValueLoader* valueLoader,
ValueLocation*& _location)
{
ValueLocation* parentLocation = fParent->Location();
if (parentLocation == NULL)
return B_BAD_VALUE;
ArrayType* arrayType = fParent->GetArrayType();
int32 dimensionCount = arrayType->CountDimensions();
ArrayIndexPath indexPath;
for (int32 i = 0; i < dimensionCount; i++) {
if (!indexPath.AddIndex(0))
return B_NO_MEMORY;
}
AbstractArrayValueNodeChild* child = this;
for (int32 i = dimensionCount - 1; i >= 0; i--) {
indexPath.SetIndexAt(i, child->ElementIndex());
child = dynamic_cast<AbstractArrayValueNodeChild*>(
child->ArrayParent()->NodeChild());
}
ValueLocation* location;
status_t error = arrayType->ResolveElementLocation(indexPath,
*parentLocation, location);
if (error != B_OK) {
TRACE_LOCALS("ArrayValueNodeChild::ResolveLocation(): "
"ResolveElementLocation() failed: %s\n", strerror(error));
return error;
}
_location = location;
return B_OK;
}
InternalArrayValueNodeChild::InternalArrayValueNodeChild(
AbstractArrayValueNode* parent, const BString& name, int64 elementIndex,
ArrayType* type)
:
AbstractArrayValueNodeChild(parent, name, elementIndex),
fType(type)
{
fType->AcquireReference();
}
InternalArrayValueNodeChild::~InternalArrayValueNodeChild()
{
fType->ReleaseReference();
}
Type*
InternalArrayValueNodeChild::GetType() const
{
return fType;
}
bool
InternalArrayValueNodeChild::IsInternal() const
{
return true;
}
status_t
InternalArrayValueNodeChild::CreateInternalNode(ValueNode*& _node)
{
ValueNode* node = new(std::nothrow) InternalArrayValueNode(this, fType,
fParent->Dimension() + 1);
if (node == NULL)
return B_NO_MEMORY;
_node = node;
return B_OK;
}
status_t
InternalArrayValueNodeChild::ResolveLocation(ValueLoader* valueLoader,
ValueLocation*& _location)
{
ValueLocation* parentLocation = fParent->Location();
if (parentLocation == NULL)
return B_BAD_VALUE;
parentLocation->AcquireReference();
_location = parentLocation;
return B_OK;
}