319 строки
8.8 KiB
C
319 строки
8.8 KiB
C
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#include "plvector.h"
|
|
#include "prmem.h"
|
|
#include <string.h>
|
|
|
|
#ifdef XP_WIN16
|
|
#define SIZE_T_MAX 0xFF80 /* a little less than 64K, the max alloc size on win16. */
|
|
#define MAX_ARR_ELEMS SIZE_T_MAX/sizeof(void*)
|
|
#endif
|
|
|
|
PR_IMPLEMENT(PLVector*)
|
|
PL_NewVector(PRUint32 initialSize, PRInt32 initialGrowBy)
|
|
{
|
|
PLVector* v = (PLVector*)PR_Malloc(sizeof(PLVector*));
|
|
if (v == NULL)
|
|
return NULL;
|
|
PL_VectorInitialize(v, initialSize, initialGrowBy);
|
|
return v;
|
|
}
|
|
|
|
PR_IMPLEMENT(void)
|
|
PL_VectorDestroy(PLVector* v)
|
|
{
|
|
PL_VectorFinalize(v);
|
|
PR_Free(v);
|
|
}
|
|
|
|
/* Initializes an existing vector */
|
|
PR_IMPLEMENT(void)
|
|
PL_VectorInitialize(PLVector* v, PRUint32 initialSize, PRInt32 initialGrowBy)
|
|
{
|
|
v->data = NULL;
|
|
v->size = v->maxSize = v->growBy = 0;
|
|
if (initialSize > 0 || initialGrowBy > 0)
|
|
PL_VectorSetSize(v, initialSize, initialGrowBy);
|
|
}
|
|
|
|
/* Destroys the elements, but doesn't free the vector */
|
|
PR_IMPLEMENT(void)
|
|
PL_VectorFinalize(PLVector* v)
|
|
{
|
|
/* This implementation doesn't do anything to delete the elements
|
|
in the vector -- that's up to the caller. (Don't shoot me,
|
|
I just copied the code from libmsg.) */
|
|
PR_Free(v->data);
|
|
}
|
|
|
|
PR_IMPLEMENT(PRBool)
|
|
PL_VectorSetSize(PLVector* v, PRUint32 newSize, PRInt32 growBy)
|
|
{
|
|
if (growBy != -1)
|
|
v->growBy = growBy; /* set new size */
|
|
|
|
if (newSize == 0) {
|
|
/* shrink to nothing */
|
|
PR_Free(v->data);
|
|
v->data = NULL;
|
|
v->size = v->maxSize = 0;
|
|
}
|
|
else if (v->data == NULL) {
|
|
/* create one with exact size */
|
|
#ifdef SIZE_T_MAX
|
|
PR_ASSERT(newSize <= SIZE_T_MAX/sizeof(void*)); /* no overflow */
|
|
#endif
|
|
v->data = (void**)PR_Malloc(newSize * sizeof(void *));
|
|
if (v->data == NULL) {
|
|
v->size = 0;
|
|
return PR_FALSE;
|
|
}
|
|
|
|
memset(v->data, 0, newSize * sizeof(void *)); /* zero fill */
|
|
|
|
v->size = v->maxSize = newSize;
|
|
}
|
|
else if (newSize <= v->maxSize) {
|
|
/* it fits */
|
|
if (newSize > v->size) {
|
|
/* initialize the new elements */
|
|
|
|
memset(&v->data[v->size], 0, (newSize-v->size) * sizeof(void *));
|
|
}
|
|
v->size = newSize;
|
|
}
|
|
else {
|
|
/* otherwise, grow array */
|
|
PRUint32 newMax;
|
|
void** newData;
|
|
PRInt32 growBy = v->growBy;
|
|
if (growBy == 0) {
|
|
/* heuristically determine growth when growBy == 0
|
|
(this avoids heap fragmentation in many situations) */
|
|
growBy = PR_MIN(1024, PR_MAX(4, v->size / 8));
|
|
}
|
|
#ifdef MAX_ARR_ELEMS
|
|
if (v->size + growBy > MAX_ARR_ELEMS)
|
|
growBy = MAX_ARR_ELEMS - v->size;
|
|
#endif
|
|
if (newSize < v->maxSize + growBy)
|
|
newMax = v->maxSize + growBy; /* granularity */
|
|
else
|
|
newMax = newSize; /* no slush */
|
|
|
|
#ifdef SIZE_T_MAX
|
|
if (newMax >= SIZE_T_MAX/sizeof(void*))
|
|
return PR_FALSE;
|
|
PR_ASSERT(newMax <= SIZE_T_MAX/sizeof(void*)); /* no overflow */
|
|
#endif
|
|
PR_ASSERT(newMax >= v->maxSize); /* no wrap around */
|
|
newData = (void**)PR_Malloc(newMax * sizeof(void*));
|
|
|
|
if (newData != NULL) {
|
|
/* copy new data from old */
|
|
memcpy(newData, v->data, v->size * sizeof(void*));
|
|
|
|
/* construct remaining elements */
|
|
PR_ASSERT(newSize > v->size);
|
|
|
|
memset(&newData[v->size], 0, (newSize-v->size) * sizeof(void*));
|
|
|
|
/* get rid of old stuff (note: no destructors called) */
|
|
PR_Free(v->data);
|
|
v->data = newData;
|
|
v->size = newSize;
|
|
v->maxSize = newMax;
|
|
}
|
|
else {
|
|
return PR_FALSE;
|
|
}
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
PR_IMPLEMENT(PRBool)
|
|
PL_VectorIsValidIndex(PLVector* v, PRUint32 index)
|
|
{
|
|
return (index < v->size) ? PR_TRUE : PR_FALSE;
|
|
}
|
|
|
|
|
|
PR_IMPLEMENT(void)
|
|
PL_VectorCompact(PLVector* v)
|
|
{
|
|
if (v->size != v->maxSize) {
|
|
/* shrink to desired size */
|
|
#ifdef SIZE_T_MAX
|
|
PR_ASSERT(v->size <= SIZE_T_MAX/sizeof(void *)); /* no overflow */
|
|
#endif
|
|
void ** newData = NULL;
|
|
if (v->size != 0) {
|
|
newData = (void **)PR_Malloc(v->size * sizeof(void *));
|
|
/* copy new data from old */
|
|
memcpy(newData, v->data, v->size * sizeof(void *));
|
|
}
|
|
|
|
/* get rid of old stuff (note: no destructors called) */
|
|
PR_Free(v->data);
|
|
v->data = newData;
|
|
v->maxSize = v->size;
|
|
}
|
|
}
|
|
|
|
#if 0 /* becomes Copy */
|
|
PR_IMPLEMENT(void)
|
|
PL_VectorSplice(PLVector* v, PRUint32 startIndex, PLVector* newVector)
|
|
{
|
|
PRUint32 i;
|
|
PR_ASSERT(newVector != NULL);
|
|
|
|
if (PL_VectorGetSize(newVector) > 0) {
|
|
PL_VectorInsert(v, startIndex, PL_VectorGet(newVector, 0),
|
|
PL_VectorGetSize(newVector));
|
|
for (i = 0; i < PL_VectorGetSize(newVector); i++)
|
|
PL_VectorSet(v, startIndex + i, PL_VectorGet(newVector, i));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
PR_IMPLEMENT(void)
|
|
PL_VectorCopy(PLVector* dstVector, PRUint32 dstPosition,
|
|
PLVector* srcVector, PRUint32 srcPosition, PRUint32 length)
|
|
{
|
|
PR_ASSERT(0); /* XXX not implemented yet */
|
|
#if 0
|
|
PL_VectorSetSize(dstVector, PR_MAX(PL_VectorGetSize(dstVector),
|
|
PL_VectorGetSize(srcVector)),
|
|
PL_VECTOR_GROW_DEFAULT);
|
|
|
|
if (v->data)
|
|
PR_Free(v->data);
|
|
v->size = oldA->v->size;
|
|
v->maxSize = oldA->v->maxSize;
|
|
v->growBy = oldA->v->growBy;
|
|
v->data = (void**)PR_Malloc(v->size * sizeof(void *));
|
|
if (v->data == NULL) {
|
|
v->size = 0;
|
|
}
|
|
else {
|
|
memcpy(v->data, oldA->v->data, v->size * sizeof(void *));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
PR_IMPLEMENT(PLVector*)
|
|
PL_VectorClone(PLVector* v)
|
|
{
|
|
PLVector* newVec = PL_NewVector(v->size, v->growBy);
|
|
PL_VectorCopy(newVec, 0, v, 0, v->size);
|
|
return newVec;
|
|
}
|
|
|
|
/* Accessing elements */
|
|
|
|
PR_IMPLEMENT(void)
|
|
PL_VectorSet(PLVector* v, PRUint32 index, void* newElement)
|
|
{
|
|
if (index >= v->size) {
|
|
if (!PL_VectorSetSize(v, index+1, PL_VECTOR_GROW_DEFAULT))
|
|
return;
|
|
}
|
|
v->data[index] = newElement;
|
|
}
|
|
|
|
/* Adds at the end */
|
|
PR_IMPLEMENT(PRUint32)
|
|
PL_VectorAdd(PLVector* v, void* newElement)
|
|
{
|
|
PRUint32 index = v->size;
|
|
#ifdef XP_WIN16
|
|
if (index >= SIZE_T_MAX / 4L) {
|
|
return -1;
|
|
}
|
|
#endif
|
|
PL_VectorSet(v, index, newElement);
|
|
return index;
|
|
}
|
|
|
|
/* Inserts new element count times at index */
|
|
PR_IMPLEMENT(void)
|
|
PL_VectorInsert(PLVector* v, PRUint32 index, void* newElement, PRUint32 count)
|
|
{
|
|
PR_ASSERT(count > 0); /* zero or negative size not allowed */
|
|
|
|
if (index >= v->size) {
|
|
/* adding after the end of the array */
|
|
if (!PL_VectorSetSize(v, index + count, PL_VECTOR_GROW_DEFAULT))
|
|
return; /* grow so index is valid */
|
|
}
|
|
else {
|
|
/* inserting in the middle of the array */
|
|
PRUint32 nOldSize = v->size;
|
|
if (!PL_VectorSetSize(v, v->size + count, PL_VECTOR_GROW_DEFAULT))
|
|
return; /* grow it to new size */
|
|
/* shift old data up to fill gap */
|
|
memmove(&v->data[index+count], &v->data[index],
|
|
(nOldSize-index) * sizeof(void *));
|
|
|
|
/* re-init slots we copied from */
|
|
memset(&v->data[index], 0, count * sizeof(void *));
|
|
}
|
|
|
|
/* insert new value in the gap */
|
|
PR_ASSERT(index + count <= v->size);
|
|
while (count--)
|
|
v->data[index++] = newElement;
|
|
}
|
|
|
|
/* Removes count elements at index */
|
|
PR_IMPLEMENT(void)
|
|
PL_VectorRemove(PLVector* v, PRUint32 index, PRUint32 count)
|
|
{
|
|
PRUint32 moveCount;
|
|
PR_ASSERT(count >= 0);
|
|
PR_ASSERT(index + count <= v->size);
|
|
|
|
/* just remove a range */
|
|
moveCount = v->size - (index + count);
|
|
|
|
if (moveCount)
|
|
memmove(&v->data[index], &v->data[index + count],
|
|
moveCount * sizeof(void *));
|
|
v->size -= count;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
PR_IMPLEMENT(void)
|
|
PL_VectorAssertValid(PLVector* v)
|
|
{
|
|
if (v->data == NULL) {
|
|
PR_ASSERT(v->size == 0);
|
|
PR_ASSERT(v->maxSize == 0);
|
|
}
|
|
else {
|
|
PR_ASSERT(v->size >= 0);
|
|
PR_ASSERT(v->maxSize >= 0);
|
|
PR_ASSERT(v->size <= v->maxSize);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|