473 lines
12 KiB
C++
473 lines
12 KiB
C++
/**
|
|||
|
|
* @file kArrayList.cpp
|
||
|
|
*
|
||
|
|
* @internal
|
||
|
|
* Copyright (C) 2005-2021 by LMI Technologies Inc.
|
||
|
|
* Licensed under the MIT License.
|
||
|
|
* Redistributed files must retain the above copyright notice.
|
||
|
|
*/
|
||
|
|
#include <kApi/Data/kArrayList.h>
|
||
|
|
#include <kApi/Data/kCollection.h>
|
||
|
|
#include <kApi/Io/kSerializer.h>
|
||
|
|
|
||
|
|
kBeginClassEx(k, kArrayList)
|
||
|
|
|
||
|
|
//serialization versions
|
||
|
|
kAddPrivateVersionEx(kArrayList, "kdat5", "5.0.0.0", "27-1", WriteDat5V1, ReadDat5V1)
|
||
|
|
kAddPrivateVersionEx(kArrayList, "kdat6", "5.7.1.0", "kArrayList-0", WriteDat6V0, ReadDat6V0)
|
||
|
|
|
||
|
|
//special constructors
|
||
|
|
kAddPrivateFrameworkConstructor(kArrayList, ConstructFramework)
|
||
|
|
|
||
|
|
//virtual methods
|
||
|
|
kAddPrivateVMethod(kArrayList, kObject, VRelease)
|
||
|
|
kAddPrivateVMethod(kArrayList, kObject, VDisposeItems)
|
||
|
|
kAddPrivateVMethod(kArrayList, kObject, VClone)
|
||
|
|
kAddPrivateVMethod(kArrayList, kObject, VHasShared)
|
||
|
|
kAddPrivateVMethod(kArrayList, kObject, VSize)
|
||
|
|
kAddPrivateVMethod(kArrayList, kObject, VAllocTraits)
|
||
|
|
|
||
|
|
//collection interface
|
||
|
|
kAddInterface(kArrayList, kCollection)
|
||
|
|
kAddPrivateIVMethod(kArrayList, kCollection, VGetIterator, GetIterator)
|
||
|
|
kAddIVMethod(kArrayList, kCollection, VItemType, ItemType)
|
||
|
|
kAddIVMethod(kArrayList, kCollection, VCount, Count)
|
||
|
|
kAddPrivateIVMethod(kArrayList, kCollection, VHasNext, HasNext)
|
||
|
|
kAddPrivateIVMethod(kArrayList, kCollection, VNext, Next)
|
||
|
|
|
||
|
|
kEndClassEx()
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Construct(kArrayList* list, kType itemType, kSize initialCapacity, kAlloc allocator)
|
||
|
|
{
|
||
|
|
kAlloc alloc = kAlloc_Fallback(allocator);
|
||
|
|
kStatus status;
|
||
|
|
|
||
|
|
kCheck(kAlloc_GetObject(alloc, kTypeOf(kArrayList), list));
|
||
|
|
|
||
|
|
if (!kSuccess(status = xkArrayList_Init(*list, kTypeOf(kArrayList), itemType, initialCapacity, alloc)))
|
||
|
|
{
|
||
|
|
kAlloc_FreeRef(alloc, list);
|
||
|
|
}
|
||
|
|
|
||
|
|
return status;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) xkArrayList_ConstructFramework(kArrayList* list, kAlloc allocator)
|
||
|
|
{
|
||
|
|
return kArrayList_Construct(list, kNULL, 0, allocator);
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) xkArrayList_Init(kArrayList list, kType classType, kType itemType, kSize initialCapacity, kAlloc alloc)
|
||
|
|
{
|
||
|
|
kObjR(kArrayList, list);
|
||
|
|
kStatus status = kOK;
|
||
|
|
|
||
|
|
kCheck(kObject_Init(list, classType, alloc));
|
||
|
|
|
||
|
|
obj->itemType = kIsNull(itemType) ? kTypeOf(kVoid) : itemType;
|
||
|
|
obj->itemSize = kType_Size(obj->itemType);
|
||
|
|
obj->allocSize = 0;
|
||
|
|
obj->items = kNULL;
|
||
|
|
obj->count = 0;
|
||
|
|
obj->capacity = 0;
|
||
|
|
obj->isAttached = kFALSE;
|
||
|
|
|
||
|
|
kTry
|
||
|
|
{
|
||
|
|
kTest(kArrayList_Reserve(list, initialCapacity));
|
||
|
|
}
|
||
|
|
kCatch(&status)
|
||
|
|
{
|
||
|
|
xkArrayList_VRelease(list);
|
||
|
|
kEndCatch(status);
|
||
|
|
}
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) xkArrayList_VClone(kArrayList list, kArrayList source, kAlloc valueAlloc, kObject context)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
obj->itemType = kArrayList_ItemType(source);
|
||
|
|
obj->itemSize = kArrayList_ItemSize(source);
|
||
|
|
|
||
|
|
kCheck(kArrayList_Resize(list, kArrayList_Count(source)));
|
||
|
|
|
||
|
|
kCheck(kCloneItems(obj->itemType, kObject_Alloc(list), obj->items, kObject_Alloc(source), kArrayList_Data(source), obj->count, context, kObject_Alloc(list), valueAlloc));
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) xkArrayList_VRelease(kArrayList list)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
if (!obj->isAttached)
|
||
|
|
{
|
||
|
|
kCheck(kAlloc_Free(kObject_Alloc(list), obj->items));
|
||
|
|
}
|
||
|
|
|
||
|
|
kCheck(kObject_VRelease(list));
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kBool) xkArrayList_VHasShared(kArrayList list)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
return kObject_IsShared(list) || kHasSharedItems(obj->itemType, obj->items, obj->count);
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kSize) xkArrayList_VSize(kArrayList list)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
kSize dataSize = (!obj->isAttached) ? obj->allocSize : kArrayList_DataSize(list);
|
||
|
|
kSize size = sizeof(kArrayListClass) + dataSize;
|
||
|
|
|
||
|
|
size += kMeasureItems(obj->itemType, obj->items, obj->count);
|
||
|
|
|
||
|
|
return size;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kAllocTrait) xkArrayList_VAllocTraits(kArrayList list)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
return kAlloc_Traits(kObject_Alloc(list)) | kEnumerateAllocTraits(obj->itemType, obj->items, obj->count);
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) xkArrayList_WriteDat5V1(kArrayList list, kSerializer serializer)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
kTypeVersion itemVersion;
|
||
|
|
|
||
|
|
kCheck(kSerializer_WriteSize(serializer, obj->capacity));
|
||
|
|
kCheck(kSerializer_Write32s(serializer, kTRUE)); //isDynamic
|
||
|
|
|
||
|
|
kCheck(kSerializer_WriteSize(serializer, obj->count));
|
||
|
|
kCheck(kSerializer_WriteType(serializer, obj->itemType, &itemVersion));
|
||
|
|
kCheck(kSerializer_WriteItems(serializer, obj->itemType, itemVersion, obj->items, obj->count));
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) xkArrayList_ReadDat5V1(kArrayList list, kSerializer serializer)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
kSize capacity = 0;
|
||
|
|
kSize count = 0;
|
||
|
|
kTypeVersion itemVersion;
|
||
|
|
k32s isDynamic;
|
||
|
|
kType itemType = kNULL;
|
||
|
|
|
||
|
|
kCheck(kSerializer_ReadSize(serializer, &capacity));
|
||
|
|
kCheck(kSerializer_Read32s(serializer, &isDynamic));
|
||
|
|
|
||
|
|
kCheck(kSerializer_ReadSize(serializer, &count));
|
||
|
|
kCheck(kSerializer_ReadType(serializer, &itemType, &itemVersion));
|
||
|
|
|
||
|
|
kCheck(kArrayList_Allocate(list, itemType, count));
|
||
|
|
kCheck(kArrayList_Resize(list, count));
|
||
|
|
|
||
|
|
kCheck(kSerializer_ReadItems(serializer, itemType, itemVersion, obj->items, count));
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) xkArrayList_WriteDat6V0(kArrayList list, kSerializer serializer)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
kTypeVersion itemVersion;
|
||
|
|
|
||
|
|
kCheck(kSerializer_WriteType(serializer, obj->itemType, &itemVersion));
|
||
|
|
kCheck(kSerializer_WriteSize(serializer, obj->count));
|
||
|
|
kCheck(kSerializer_WriteItems(serializer, obj->itemType, itemVersion, obj->items, obj->count));
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) xkArrayList_ReadDat6V0(kArrayList list, kSerializer serializer)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
kType itemType = kNULL;
|
||
|
|
kTypeVersion itemVersion;
|
||
|
|
kSize count = 0;
|
||
|
|
|
||
|
|
kCheck(kSerializer_ReadType(serializer, &itemType, &itemVersion));
|
||
|
|
kCheck(kSerializer_ReadSize(serializer, &count));
|
||
|
|
|
||
|
|
kCheck(kArrayList_Allocate(list, itemType, count));
|
||
|
|
kCheck(kArrayList_Resize(list, count));
|
||
|
|
|
||
|
|
kCheck(kSerializer_ReadItems(serializer, itemType, itemVersion, obj->items, count));
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Allocate(kArrayList list, kType itemType, kSize initialCapacity)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
if (obj->isAttached)
|
||
|
|
{
|
||
|
|
obj->items = kNULL;
|
||
|
|
obj->isAttached = kFALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
obj->itemType = kIsNull(itemType) ? kTypeOf(kVoid) : itemType;
|
||
|
|
obj->itemSize = kType_Size(obj->itemType);
|
||
|
|
obj->count = 0;
|
||
|
|
obj->capacity = 0;
|
||
|
|
|
||
|
|
kCheck(kArrayList_Reserve(list, initialCapacity));
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Attach(kArrayList list, void* items, kType itemType, kSize capacity)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
if (!obj->isAttached)
|
||
|
|
{
|
||
|
|
kCheck(kAlloc_FreeRef(kObject_Alloc(list), &obj->items));
|
||
|
|
}
|
||
|
|
|
||
|
|
obj->itemType = kIsNull(itemType) ? kTypeOf(kVoid) : itemType;
|
||
|
|
obj->itemSize = kType_Size(obj->itemType);
|
||
|
|
obj->allocSize = 0;
|
||
|
|
obj->items = items;
|
||
|
|
obj->count = capacity;
|
||
|
|
obj->capacity = capacity;
|
||
|
|
obj->isAttached = kTRUE;
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Import(kArrayList list, const void* items, kType itemType, kSize count)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
kCheck(kArrayList_Allocate(list, itemType, count));
|
||
|
|
|
||
|
|
kCheck(kMemCopy(obj->items, items, count*obj->itemSize));
|
||
|
|
obj->count = count;
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Append(kArrayList list, const void* items, kSize count)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
kCheck(kArrayList_Reserve(list, obj->count + count));
|
||
|
|
|
||
|
|
kCheck(kMemCopy(kArrayList_DataAt(list, (kSSize)obj->count), items, count*obj->itemSize));
|
||
|
|
obj->count += count;
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Assign(kArrayList list, kArrayList source)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
kObjN(kArrayList, sourceObj, source);
|
||
|
|
|
||
|
|
kCheck(kArrayList_Allocate(list, sourceObj->itemType, sourceObj->count));
|
||
|
|
|
||
|
|
kCheck(kArrayList_Resize(list, sourceObj->count));
|
||
|
|
|
||
|
|
kCheck(kCopyItems(obj->itemType, obj->items, sourceObj->items, obj->count));
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Purge(kArrayList list)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
kCheck(kDisposeItems(obj->itemType, obj->items, obj->count));
|
||
|
|
|
||
|
|
kCheck(kArrayList_Clear(list));
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Zero(kArrayList list)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
kCheck(kZeroItems(obj->itemType, obj->items, obj->count));
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Reserve(kArrayList list, kSize minimumCapacity)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
if (obj->capacity < minimumCapacity)
|
||
|
|
{
|
||
|
|
kSize grownCapacity = kMax_(minimumCapacity, xkARRAY_LIST_GROWTH_FACTOR*obj->capacity);
|
||
|
|
kSize newCapacity = kMax_(grownCapacity, xkARRAY_LIST_MIN_CAPACITY);
|
||
|
|
kSize newSize = kMax_(obj->allocSize, newCapacity*obj->itemSize);
|
||
|
|
|
||
|
|
if (newSize > obj->allocSize)
|
||
|
|
{
|
||
|
|
void* oldItems = obj->items;
|
||
|
|
void* newItems = kNULL;
|
||
|
|
|
||
|
|
kCheck(kAlloc_Get(kObject_Alloc(list), newSize, &newItems));
|
||
|
|
|
||
|
|
if (obj->count > 0)
|
||
|
|
{
|
||
|
|
kMemCopy(newItems, oldItems, obj->count*obj->itemSize);
|
||
|
|
}
|
||
|
|
|
||
|
|
obj->items = newItems;
|
||
|
|
obj->allocSize = newSize;
|
||
|
|
|
||
|
|
kCheck(kAlloc_Free(kObject_Alloc(list), oldItems));
|
||
|
|
}
|
||
|
|
|
||
|
|
obj->capacity = newCapacity;
|
||
|
|
}
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Resize(kArrayList list, kSize count)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
if (count > obj->capacity)
|
||
|
|
{
|
||
|
|
kCheck(kArrayList_Reserve(list, count));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (kType_IsReference(obj->itemType) && (count > obj->count))
|
||
|
|
{
|
||
|
|
kMemSet(kArrayList_DataAt(list, (kSSize)obj->count), 0, obj->itemSize*(count - obj->count));
|
||
|
|
}
|
||
|
|
|
||
|
|
obj->count = count;
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Add(kArrayList list, const void* item)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
if (obj->count == obj->capacity)
|
||
|
|
{
|
||
|
|
kCheck(kArrayList_Reserve(list, obj->capacity + 1));
|
||
|
|
}
|
||
|
|
|
||
|
|
kValue_Import(obj->itemType, kArrayList_DataAt(list, (kSSize)obj->count), item);
|
||
|
|
|
||
|
|
obj->count++;
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_SetItem(kArrayList list, kSize index, const void* item)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
kCheckArgs(index < obj->count);
|
||
|
|
|
||
|
|
kValue_Import(obj->itemType, kArrayList_DataAt(list, (kSSize)index), item);
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Item(kArrayList list, kSize index, void* item)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
kCheckArgs(index < obj->count);
|
||
|
|
|
||
|
|
kItemCopy(item, kArrayList_DataAt(list, (kSSize)index), obj->itemSize);
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Insert(kArrayList list, kSize before, const void* item)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
kCheckArgs(before <= obj->count);
|
||
|
|
|
||
|
|
if (obj->count == obj->capacity)
|
||
|
|
{
|
||
|
|
kCheck(kArrayList_Reserve(list, obj->capacity + 1));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (before != obj->count)
|
||
|
|
{
|
||
|
|
kMemMove(kArrayList_DataAt(list, (kSSize)before + 1), kArrayList_DataAt(list, (kSSize)before), obj->itemSize*(obj->count - before));
|
||
|
|
}
|
||
|
|
|
||
|
|
kValue_Import(obj->itemType, kArrayList_DataAt(list, (kSSize)before), item);
|
||
|
|
|
||
|
|
obj->count++;
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kStatus) kArrayList_Remove(kArrayList list, kSize index, void* item)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
kCheckArgs(index < obj->count);
|
||
|
|
|
||
|
|
if (item)
|
||
|
|
{
|
||
|
|
kItemCopy(item, kArrayList_DataAt(list, (kSSize)index), obj->itemSize);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (index != (obj->count-1))
|
||
|
|
{
|
||
|
|
kMemMove(kArrayList_DataAt(list, (kSSize)index), kArrayList_DataAt(list, (kSSize)index + 1), obj->itemSize*(obj->count - index - 1));
|
||
|
|
}
|
||
|
|
|
||
|
|
obj->count--;
|
||
|
|
|
||
|
|
return kOK;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kIterator) xkArrayList_GetIterator(kArrayList list)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
|
||
|
|
return obj->items;
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(kBool) xkArrayList_HasNext(kArrayList list, kIterator iterator)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
void* end = (kByte*)obj->items + obj->count*obj->itemSize;
|
||
|
|
|
||
|
|
return (iterator != end);
|
||
|
|
}
|
||
|
|
|
||
|
|
kFx(void*) xkArrayList_Next(kArrayList list, kIterator* iterator)
|
||
|
|
{
|
||
|
|
kObj(kArrayList, list);
|
||
|
|
void* next = *iterator;
|
||
|
|
|
||
|
|
*iterator = (kByte*)*iterator + obj->itemSize;
|
||
|
|
|
||
|
|
return next;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|