/*
* Copyright (c) 2003 - 2004 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
#include <xml/cxml/nw_tinytree.h>
#include "cxml_internal.h"
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
static
CXML_Uint8*
CXML_Vector_AllocateSegment (CXML_Vector_t* thisObj, NW_TinyTree_TreeNode_t* sentinel)
{
CXML_Uint8* buffer = NULL;
if(sentinel)
{
buffer = (NW_Uint8*) NW_Mem_Malloc ((thisObj->segmentSize + 1) * thisObj->elementSize);
if(buffer)
{
NW_Mem_memcpy(buffer, sentinel, sizeof(NW_TinyTree_TreeNode_t));
buffer += thisObj->elementSize;
}
}
else
{
buffer = (NW_Uint8*) NW_Mem_Malloc (thisObj->segmentSize * thisObj->elementSize);
}
return buffer;
}
/* ------------------------------------------------------------------------- */
static
NW_Status_t
CXML_Vector_ResizeCapacity (CXML_Vector_t* thisObj,
CXML_Vector_Metric_t capacityNeeded,
NW_TinyTree_TreeNode_t* sentinel)
{
CXML_Vector_Metric_t newNumSegments;
CXML_Vector_Metric_t newSegmentListSize;
NW_Uint8** newSegmentList;
// CXML_Vector_Metric_t index;
/* calculate the new segmentList size */
newNumSegments =
(CXML_Vector_Metric_t) ((capacityNeeded - 1) / thisObj->segmentSize + 1);
newSegmentListSize = (CXML_Vector_Metric_t)
(((newNumSegments - 1) / CXML_SEGMENT_LIST_INCREMENT + 1) * CXML_SEGMENT_LIST_INCREMENT);
/* if we are shrinking the array, we must first deallocate all the segments
that will be obsolete */
while (thisObj->numSegments > newNumSegments) {
NW_Mem_Free (thisObj->segmentList[--thisObj->numSegments]);
}
thisObj->capacity =
(CXML_Vector_Metric_t) (thisObj->numSegments * thisObj->segmentSize);
/* allocate the new segmentList and copy the old segmentList entries into the
new */
newSegmentList =
(NW_Uint8**) NW_Mem_Malloc (newSegmentListSize * sizeof (*newSegmentList));
if (newSegmentList == NULL) {
return NW_STAT_OUT_OF_MEMORY;
}
(void) NW_Mem_memcpy (newSegmentList, thisObj->segmentList,
thisObj->numSegments * sizeof (*newSegmentList));
/* free the old segmentList and install the new */
NW_Mem_Free (thisObj->segmentList);
thisObj->segmentList = newSegmentList;
thisObj->segmentListSize = newSegmentListSize;
/* if we are growing the array we need to allocate the new segments */
while (thisObj->numSegments < newNumSegments) {
thisObj->segmentList[thisObj->numSegments] =
CXML_Vector_AllocateSegment(thisObj, sentinel);
if (thisObj->segmentList[thisObj->numSegments++] == NULL) {
thisObj->numSegments -= 1;
return NW_STAT_OUT_OF_MEMORY;
}
}
thisObj->capacity =
(CXML_Vector_Metric_t) (thisObj->numSegments * thisObj->segmentSize);
/* successful completion */
return NW_STAT_SUCCESS;
}
/* ------------------------------------------------------------------------- */
static
NW_Status_t
CXML_Vector_MoveElements (CXML_Vector_t* thisObj,
CXML_Vector_Metric_t srcIndex,
CXML_Vector_Metric_t dstIndex,
NW_TinyTree_TreeNode_t* sentinel)
{
NW_Int32 sizeDelta;
CXML_Vector_Metric_t numElements;
NW_Int32 index;
/* */
if (dstIndex > srcIndex) {
sizeDelta = dstIndex - srcIndex;
} else {
sizeDelta = - (NW_Int32) (srcIndex - dstIndex);
}
if (thisObj->size + sizeDelta > thisObj->capacity) {
NW_Status_t status;
status = CXML_Vector_ResizeCapacity (thisObj,
(CXML_Vector_Metric_t) (thisObj->size + sizeDelta), sentinel);
if (status != NW_STAT_SUCCESS) {
return status;
}
}
/* now do the actual move */
/* TODO: this is a very inefficient way of moving the data, we will probably
need to implement a block move capability */
numElements = (CXML_Vector_Metric_t) (thisObj->size - srcIndex);
if (srcIndex > dstIndex) {
for (index = 0; index < NW_INT32_CAST(numElements); index++) {
(void) NW_Mem_memcpy (CXML_Vector_AddressAt (thisObj,
(CXML_Vector_Metric_t) (dstIndex + index)), CXML_Vector_AddressAt (thisObj,
(CXML_Vector_Metric_t) (srcIndex + index)), thisObj->elementSize);
}
} else {
for (index = numElements - 1; index >= 0; index--) {
(void) NW_Mem_memcpy (CXML_Vector_AddressAt (thisObj,
(CXML_Vector_Metric_t) (dstIndex + index)), CXML_Vector_AddressAt (thisObj,
(CXML_Vector_Metric_t) (srcIndex + index)), thisObj->elementSize);
}
}
/* successful completion */
return NW_STAT_SUCCESS;
}
CXML_Vector_t*
CXML_Vector_Construct(CXML_Vector_Metric_t elementSize,
CXML_Vector_Metric_t segmentSize)
{
CXML_Vector_t* vector = (CXML_Vector_t*) NW_Mem_Malloc(sizeof(CXML_Vector_t));
if(vector)
{
vector->elementSize = elementSize;
vector->capacity = 0;
vector->size = 0;
vector->segmentSize = segmentSize;
vector->segmentListSize = CXML_SEGMENT_LIST_INCREMENT;
//Allocate memory for one segment here. For more memory the
//function CXML_Vector_ResizeCapacity() will do the job.
vector->segmentList = (NW_Uint8**)
NW_Mem_Malloc (vector->segmentListSize * sizeof (*vector->segmentList));
if (vector->segmentList == NULL) {
NW_Mem_Free(vector);
return NULL;
}
vector->numSegments = 0;
}
return vector;
}
void
CXML_Vector_Destruct(CXML_Vector_t* vector)
{
CXML_Vector_Metric_t index;
for (index = 0; index < vector->numSegments; index++) {
NW_Mem_Free (vector->segmentList[index]);
}
NW_Mem_Free (vector->segmentList);
NW_Mem_Free(vector);
}
void
CXML_Vector_AdjustSegment(CXML_Vector_t* vector)
{
CXML_Vector_Metric_t index;
/*
* Walk through segment list adjusting pointers to the
* sentinel element at the beginning of each segment
*/
for (index = 0; index < vector->numSegments; index++) {
vector->segmentList[index] -= vector->elementSize;
}
}
NW_Uint8*
CXML_Vector_AddressAt (const CXML_Vector_t* thisObj,
CXML_Vector_Metric_t index)
{
CXML_Vector_Metric_t segmentIndex;
/* determine the segment index and return the offset into that segment */
segmentIndex =
(CXML_Vector_Metric_t) (index / thisObj->segmentSize);
return
(NW_Uint8*) thisObj->segmentList[segmentIndex]
+ (index % thisObj->segmentSize) * thisObj->elementSize;
}
/* ------------------------------------------------------------------------- */
void**
CXML_Vector_InsertAt (CXML_Vector_t* thisObj,
void* element,
CXML_Vector_Metric_t where,
void* sentinel)
{
NW_Status_t status;
/* convert the where if CXML_Vector_AtEnd is specified */
if (where == CXML_Vector_AtEnd) {
where = thisObj->size;
}
/* make sure that the where element is not out of bounds */
NW_ASSERT (where <= thisObj->size);
/* move all the elements up by one, if this fails we simply return
the error code passed to us */
status =
CXML_Vector_MoveElements (thisObj, where,
(CXML_Vector_Metric_t) (where + 1),
(NW_TinyTree_TreeNode_t*) sentinel);
if (status != NW_STAT_SUCCESS) {
return NULL;
}
/* copy the element into vector */
if (element != NULL) {
(void) NW_Mem_memcpy (CXML_Vector_AddressAt (thisObj, where),
element, thisObj->elementSize);
} else {
/*
* if element is NULL, then we need to zero out the memory block. This is necessary
* because later code which fills in the values for this newly allocated vector
* element may leave some bytes in the memory block un-assigned due to padding.
*/
NW_Mem_memset ( CXML_Vector_AddressAt (thisObj, where),
0, thisObj->elementSize);
}
/* increment the size count */
thisObj->size += 1;
/* successful completion */
return (void**)
CXML_Vector_AddressAt (thisObj, where);
}
/* ------------------------------------------------------------------------- */
NW_Status_t
CXML_Vector_RemoveAt (CXML_Vector_t* thisObj,
CXML_Vector_Metric_t index)
{
NW_Status_t status;
/* convert the index if CXML_Vector_AtEnd is specified */
if (index == CXML_Vector_AtEnd) {
index = (CXML_Vector_Metric_t) (thisObj->size - 1);
}
/* make sure that the index element is not out of bounds */
if (index >= thisObj->size) {
return NW_STAT_FAILURE;
}
/* don't bother to move anything if the resultant size is zero */
if (thisObj->size > 1) {
/* move all the elements down by one, if this fails we simply return
the error code passed to us */
status =
CXML_Vector_MoveElements (thisObj, (CXML_Vector_Metric_t) (index + 1),
index, NULL);
if (status != NW_STAT_SUCCESS) {
return status;
}
}
/* increment the size count */
thisObj->size -= 1;
/* successful completion */
return NW_STAT_SUCCESS;
}
/* ------------------------------------------------------------------------- */
void**
CXML_Vector_ElementAt (const CXML_Vector_t* vector,
CXML_Vector_Metric_t index)
{
if (index >= vector->size) {
return NULL;
}
return (void**) CXML_Vector_AddressAt (vector, index);
}
/* ------------------------------------------------------------------------- */
CXML_Vector_Metric_t
CXML_Vector_GetElementIndex (const CXML_Vector_t* vector,
void* target)
{
CXML_Vector_Metric_t index;
for (index = 0; index < vector->size; index++) {
void* element;
/* get and compare the element */
element = CXML_Vector_ElementAt (vector, index);
if (NW_Mem_memcmp (target, element, vector->elementSize) == 0) {
return index;
}
}
/* no match found, return CXML_Vector_AtEnd */
return CXML_Vector_AtEnd;
}