⛏️ index : haiku.git

/*
 * Copyright 2012-2015, Rene Gollent, rene@gollent.com
 * Distributed under the terms of the MIT License.
 */


#include "BListValueNode.h"

#include <new>

#include <AutoDeleter.h>

#include "AddressValueNode.h"
#include "Architecture.h"
#include "StringValue.h"
#include "TeamTypeInformation.h"
#include "Tracing.h"
#include "Type.h"
#include "TypeLookupConstraints.h"
#include "ValueLoader.h"
#include "ValueLocation.h"
#include "ValueNodeContainer.h"


// maximum number of array elements to show by default
static const int64 kMaxArrayElementCount = 20;


//#pragma mark - BListValueNode::BListElementNodeChild


class BListValueNode::BListElementNodeChild : public ValueNodeChild {
public:
								BListElementNodeChild(BListValueNode* parent,
									int64 elementIndex, Type* type);
	virtual						~BListElementNodeChild();

	virtual	const BString&		Name() const { return fName; };
	virtual	Type*				GetType() const { return fType; };
	virtual	ValueNode*			Parent() const { return fParent; };

	virtual status_t			ResolveLocation(ValueLoader* valueLoader,
									ValueLocation*& _location);

private:
	Type*						fType;
	BListValueNode*				fParent;
	int64						fElementIndex;
	BString						fName;
};


BListValueNode::BListElementNodeChild::BListElementNodeChild(
	BListValueNode* parent, int64 elementIndex, Type* type)
	:
	ValueNodeChild(),
	fType(type),
	fParent(parent),
	fElementIndex(elementIndex),
	fName()
{
	fType->AcquireReference();
	fParent->AcquireReference();
	fName.SetToFormat("[%" B_PRId64 "]", fElementIndex);
}


BListValueNode::BListElementNodeChild::~BListElementNodeChild()
{
	fType->ReleaseReference();
	fParent->ReleaseReference();
}


status_t
BListValueNode::BListElementNodeChild::ResolveLocation(
	ValueLoader* valueLoader, ValueLocation*& _location)
{
	uint8 addressSize = valueLoader->GetArchitecture()->AddressSize();
	ValueLocation* location = new(std::nothrow) ValueLocation();
	if (location == NULL)
		return B_NO_MEMORY;


	uint64 listAddress = fParent->fDataLocation.ToUInt64();
	listAddress += fElementIndex * addressSize;

	ValuePieceLocation piece;
	piece.SetToMemory(listAddress);
	piece.SetSize(addressSize);
	location->AddPiece(piece);

	_location = location;
	return B_OK;
}


//#pragma mark - BListItemCountNodeChild

class BListValueNode::BListItemCountNodeChild : public ValueNodeChild {
public:
								BListItemCountNodeChild(BVariant location,
									BListValueNode* parent, Type* type);
	virtual						~BListItemCountNodeChild();

	virtual	const BString&		Name() const { return fName; };
	virtual	Type*				GetType() const { return fType; };
	virtual	ValueNode*			Parent() const { return fParent; };

	virtual status_t			ResolveLocation(ValueLoader* valueLoader,
									ValueLocation*& _location);

private:
	Type*						fType;
	BListValueNode*				fParent;
	BVariant					fLocation;
	BString						fName;
};


BListValueNode::BListItemCountNodeChild::BListItemCountNodeChild(
	BVariant location, BListValueNode* parent, Type* type)
	:
	ValueNodeChild(),
	fType(type),
	fParent(parent),
	fLocation(location),
	fName("Capacity")
{
	fType->AcquireReference();
	fParent->AcquireReference();
}


BListValueNode::BListItemCountNodeChild::~BListItemCountNodeChild()
{
	fType->ReleaseReference();
	fParent->ReleaseReference();
}


status_t
BListValueNode::BListItemCountNodeChild::ResolveLocation(
	ValueLoader* valueLoader, ValueLocation*& _location)
{
	ValueLocation* location = new(std::nothrow) ValueLocation();
	if (location == NULL)
		return B_NO_MEMORY;

	ValuePieceLocation piece;
	piece.SetToMemory(fLocation.ToUInt64());
	piece.SetSize(sizeof(int32));
	location->AddPiece(piece);

	_location = location;
	return B_OK;
}


//#pragma mark - BListValueNode

BListValueNode::BListValueNode(ValueNodeChild* nodeChild,
	Type* type)
	:
	ValueNode(nodeChild),
	fType(type),
	fItemCountType(NULL),
	fItemCount(0),
	fCountChildCreated(false)
{
	fType->AcquireReference();
}


BListValueNode::~BListValueNode()
{
	fType->ReleaseReference();
	for (int32 i = 0; i < fChildren.CountItems(); i++)
		fChildren.ItemAt(i)->ReleaseReference();

	if (fItemCountType != NULL)
		fItemCountType->ReleaseReference();
}


Type*
BListValueNode::GetType() const
{
	return fType;
}


status_t
BListValueNode::ResolvedLocationAndValue(ValueLoader* valueLoader,
	ValueLocation*& _location, Value*& _value)
{
	// get the location
	ValueLocation* location = NodeChild()->Location();
	if (location == NULL)
		return B_BAD_VALUE;


	// get the value type
	type_code valueType;
	if (valueLoader->GetArchitecture()->AddressSize() == 4) {
		valueType = B_UINT32_TYPE;
		TRACE_LOCALS("    -> 32 bit\n");
	} else {
		valueType = B_UINT64_TYPE;
		TRACE_LOCALS("    -> 64 bit\n");
	}

	// load the value data

	status_t error = B_OK;

	ValueLocation* memberLocation = NULL;
	CompoundType* baseType = dynamic_cast<CompoundType*>(fType);

	if (baseType->CountTemplateParameters() != 0) {
		// for BObjectList we need to walk up
		// the hierarchy: BObjectList -> _PointerList_ -> BList
		if (baseType->CountBaseTypes() == 0)
			return B_BAD_DATA;

		baseType = dynamic_cast<CompoundType*>(baseType->BaseTypeAt(0)
			->GetType());
		if (baseType == NULL || baseType->Name() != "_PointerList_")
			return B_BAD_DATA;

		if (baseType->CountBaseTypes() == 0)
			return B_BAD_DATA;

		baseType = dynamic_cast<CompoundType*>(baseType->BaseTypeAt(0)
			->GetType());
		if (baseType == NULL || baseType->Name() != "BList")
			return B_BAD_DATA;

	}

	for (int32 i = 0; i < baseType->CountDataMembers(); i++) {
		DataMember* member = baseType->DataMemberAt(i);
		if (strcmp(member->Name(), "fObjectList") == 0) {
			error = baseType->ResolveDataMemberLocation(member,
				*location, memberLocation);
			BReference<ValueLocation> locationRef(memberLocation, true);
			if (error != B_OK) {
				TRACE_LOCALS(
					"BListValueNode::ResolvedLocationAndValue(): "
					"failed to resolve location of header member: %s\n",
					strerror(error));
				return error;
			}

			error = valueLoader->LoadValue(memberLocation, valueType,
				false, fDataLocation);
			if (error != B_OK)
				return error;
		} else if (strcmp(member->Name(), "fItemCount") == 0) {
			error = baseType->ResolveDataMemberLocation(member,
				*location, memberLocation);
			BReference<ValueLocation> locationRef(memberLocation, true);
			if (error != B_OK) {
				TRACE_LOCALS(
					"BListValueNode::ResolvedLocationAndValue(): "
					"failed to resolve location of header member: %s\n",
					strerror(error));
				return error;
			}

			fItemCountType = member->GetType();
			fItemCountType->AcquireReference();

			fItemCountLocation = memberLocation->PieceAt(0).address;

			BVariant listSize;
			error = valueLoader->LoadValue(memberLocation, B_INT32_TYPE,
				false, listSize);
			if (error != B_OK)
				return error;

			fItemCount = listSize.ToInt32();
			TRACE_LOCALS(
				"BListValueNode::ResolvedLocationAndValue(): "
				"detected list size %" B_PRId32 "\n",
				fItemCount);
		}
		memberLocation = NULL;
	}

	location->AcquireReference();
	_location = location;
	_value = NULL;

	return B_OK;
}


status_t
BListValueNode::CreateChildren(TeamTypeInformation* info)
{
	return CreateChildrenInRange(info, 0, kMaxArrayElementCount);
}


int32
BListValueNode::CountChildren() const
{
	return fChildren.CountItems();
}


ValueNodeChild*
BListValueNode::ChildAt(int32 index) const
{
	return fChildren.ItemAt(index);
}


bool
BListValueNode::IsRangedContainer() const
{
	return true;
}


bool
BListValueNode::IsContainerRangeFixed() const
{
	return true;
}


void
BListValueNode::ClearChildren()
{
	fChildren.MakeEmpty();
	fCountChildCreated = false;
	if (fContainer != NULL)
		fContainer->NotifyValueNodeChildrenDeleted(this);
}


status_t
BListValueNode::CreateChildrenInRange(TeamTypeInformation* info,
	int32 lowIndex, int32 highIndex)
{
	if (fLocationResolutionState != B_OK)
		return fLocationResolutionState;

	if (lowIndex < 0)
		lowIndex = 0;
	if (highIndex >= fItemCount)
		highIndex = fItemCount - 1;

	if (!fCountChildCreated && fItemCountType != NULL) {
		BListItemCountNodeChild* countChild = new(std::nothrow)
			BListItemCountNodeChild(fItemCountLocation, this, fItemCountType);

		if (countChild == NULL)
			return B_NO_MEMORY;

		fCountChildCreated = true;
		countChild->SetContainer(fContainer);
		fChildren.AddItem(countChild);
	}

	BReference<Type> addressTypeRef;
	Type* type = NULL;
	CompoundType* objectType = dynamic_cast<CompoundType*>(fType);
	if (objectType->CountTemplateParameters() != 0) {
		AddressType* addressType = NULL;
		status_t result = objectType->TemplateParameterAt(0)->GetType()
			->CreateDerivedAddressType(DERIVED_TYPE_POINTER, addressType);
		if (result != B_OK)
			return result;

		type = addressType;
		addressTypeRef.SetTo(type, true);
	} else {
		BString typeName;
		TypeLookupConstraints constraints;
		constraints.SetTypeKind(TYPE_ADDRESS);
		constraints.SetBaseTypeName("void");
		status_t result = info->LookupTypeByName(typeName, constraints,
			type);
		if (result != B_OK)
			return result;
	}

	for (int32 i = lowIndex; i <= highIndex; i++)
	{
		BListElementNodeChild* child =
			new(std::nothrow) BListElementNodeChild(this, i, type);
		if (child == NULL)
			return B_NO_MEMORY;
		child->SetContainer(fContainer);
		fChildren.AddItem(child);
	}

	fChildrenCreated = true;

	if (fContainer != NULL)
		fContainer->NotifyValueNodeChildrenCreated(this);

	return B_OK;
}


status_t
BListValueNode::SupportedChildRange(int32& lowIndex, int32& highIndex) const
{
	lowIndex = 0;
	highIndex = fItemCount - 1;

	return B_OK;
}