Files
handleaiuinew/env/LMI/include/kApi/Data/kList.cpp
T
2024-05-18 23:53:26 +08:00

619 lines
14 KiB
C++

/**
* @file kList.cpp
*
* @internal
* Copyright (C) 2013-2021 by LMI Technologies Inc.
* Licensed under the MIT License.
* Redistributed files must retain the above copyright notice.
*/
#include <kApi/Data/kList.h>
#include <kApi/Data/kCollection.h>
#include <kApi/Io/kSerializer.h>
kBeginClassEx(k, kList)
//serialization versions
kAddPrivateVersionEx(kList, "kdat6", "6.0.0.0", "kList-0", WriteDat6V0, ReadDat6V0)
//special constructors
kAddPrivateFrameworkConstructor(kList, ConstructFramework)
//virtual methods
kAddPrivateVMethod(kList, kObject, VRelease)
kAddPrivateVMethod(kList, kObject, VDisposeItems)
kAddPrivateVMethod(kList, kObject, VClone)
kAddPrivateVMethod(kList, kObject, VHasShared)
kAddPrivateVMethod(kList, kObject, VSize)
kAddPrivateVMethod(kList, kObject, VAllocTraits)
//kCollection interface
kAddInterface(kList, kCollection);
kAddPrivateIVMethod(kList, kCollection, VGetIterator, CollectionGetIterator)
kAddPrivateIVMethod(kList, kCollection, VItemType, CollectionItemType)
kAddIVMethod(kList, kCollection, VCount, Count)
kAddPrivateIVMethod(kList, kCollection, VHasNext, CollectionHasNext)
kAddPrivateIVMethod(kList, kCollection, VNext, CollectionNext)
kEndClassEx()
kFx(kStatus) kList_Construct(kList* list, kType itemType, kSize initialCapacity, kAlloc allocator)
{
kAlloc alloc = kAlloc_Fallback(allocator);
kStatus status;
kCheck(kAlloc_GetObject(alloc, kTypeOf(kList), list));
if (!kSuccess(status = xkList_Init(*list, kTypeOf(kList), itemType, initialCapacity, alloc)))
{
kAlloc_FreeRef(alloc, list);
}
return status;
}
kFx(kStatus) xkList_ConstructFramework(kList* list, kAlloc allocator)
{
return kList_Construct(list, kNULL, 0, allocator);
}
kFx(kStatus) xkList_Init(kList list, kType classType, kType itemType, kSize initialCapacity, kAlloc alloc)
{
kObjR(kList, list);
kStatus status = kOK;
kCheck(kObject_Init(list, classType, alloc));
obj->blocks = kNULL;
obj->free = kNULL;
obj->first = kNULL;
obj->last = kNULL;
obj->count = 0;
obj->capacity = 0;
kZero(obj->contentField);
obj->itemSize = 0;
kTry
{
kTest(xkList_Layout(list, itemType));
kTest(kList_Reserve(list, initialCapacity));
}
kCatch(&status)
{
xkList_VRelease(list);
kEndCatch(status);
}
return kOK;
}
kFx(kStatus) xkList_VClone(kList list, kList source, kAlloc valueAlloc, kObject context)
{
kObj(kList, list);
kAlloc objectAlloc = kObject_Alloc(list);
kObject contentClone = kNULL;
kStatus status;
kCheck(kList_Allocate(list, kList_ItemType(source), kList_Count(source)));
kTry
{
kListItem item = kList_First(source);
while (!kIsNull(item))
{
const void* content = xkList_ItemContent(source, item);
if (xkList_ItemIsRef(source))
{
kTest(kObject_Clone(&contentClone, *(kObject*)content, objectAlloc, valueAlloc, context));
content = &contentClone;
}
kTest(kList_Add(list, content, kNULL));
contentClone = kNULL;
item = kList_Next(source, item);
}
}
kCatch(&status)
{
kObject_Dispose(contentClone);
kEndCatch(status);
}
return kOK;
}
kFx(kStatus) xkList_VRelease(kList list)
{
kCheck(xkList_Deallocate(list));
kCheck(kObject_VRelease(list));
return kOK;
}
kFx(kStatus) kList_Allocate(kList list, kType itemType, kSize initialCapacity)
{
kObj(kList, list);
kCheck(xkList_Deallocate(list));
obj->free = kNULL;
obj->first = kNULL;
obj->last = kNULL;
obj->count = 0;
obj->capacity = 0;
obj->contentField.type = kNULL;
kCheck(xkList_Layout(list, itemType));
kCheck(kList_Reserve(list, initialCapacity));
return kOK;
}
kFx(kStatus) kList_Assign(kList list, kList source)
{
kObjN(kList, sourceObj, source);
kListItem item = kNULL;
kCheck(kList_Allocate(list, sourceObj->contentField.type, sourceObj->count));
item = kList_First(source);
while (!kIsNull(item))
{
kCheck(kList_Add(list, xkList_ItemContent(source, item), kNULL));
item = kList_Next(source, item);
}
return kOK;
}
kFx(kStatus) xkList_Layout(kList list, kType itemType)
{
kObj(kList, list);
xkStructField nextField, previousField;
xkStructField* fields[3];
nextField.type = kTypeOf(kPointer);
nextField.offset = offsetof(kListItemStruct, next);
nextField.count = 1;
fields[0] = &nextField;
previousField.type = kTypeOf(kPointer);
previousField.offset = offsetof(kListItemStruct, previous);
previousField.count = 1;
fields[1] = &previousField;
obj->contentField.type = kIsNull(itemType) ? kTypeOf(kVoid) : itemType;
obj->contentField.offset = kSIZE_NULL;
obj->contentField.count = 1;
fields[2] = &obj->contentField;
kCheck(xkType_LayoutStruct(fields, kCountOf(fields), &obj->itemSize));
return kOK;
}
kFx(kStatus) xkList_Deallocate(kList list)
{
kObj(kList, list);
while (!kIsNull(obj->blocks))
{
kListItemBlock* next = obj->blocks->next;
kCheck(kAlloc_Free(kObject_Alloc(list), obj->blocks));
obj->blocks = next;
}
return kOK;
}
kFx(kBool) xkList_VHasShared(kList list)
{
kObj(kList, list);
if (kObject_IsShared(list))
{
return kTRUE;
}
else if (xkList_ItemIsRef(list))
{
kListItem item = kList_First(list);
while (!kIsNull(item))
{
kObject content = kList_AsT(list, item, kObject);
if (!kIsNull(content) && kObject_HasShared(content))
{
return kTRUE;
}
item = kList_Next(list, item);
}
}
return kFALSE;
}
kFx(kSize) xkList_VSize(kList list)
{
kObj(kList, list);
kSize size = sizeof(kListClass);
kListItemBlock* blockObj = obj->blocks;
while (!kIsNull(blockObj))
{
size += (kByte*)blockObj->items - (kByte*)blockObj;
size += obj->itemSize*blockObj->itemCount;
blockObj = blockObj->next;
}
if (xkList_ItemIsRef(list))
{
kListItem item = kList_First(list);
while (!kIsNull(item))
{
kObject content = kList_AsT(list, item, kObject);
if (!kIsNull(content))
{
size += kObject_Size(content);
}
item = kList_Next(list, item);
}
}
return size;
}
kFx(kAllocTrait) xkList_VAllocTraits(kList list)
{
kObj(kList, list);
kAllocTrait traits = kAlloc_Traits(kObject_Alloc(list));
if (xkList_ItemIsRef(list))
{
kListItem item = kList_First(list);
while (!kIsNull(item))
{
kObject content = kList_AsT(list, item, kObject);
if (!kIsNull(content))
{
traits |= kObject_AllocTraits(content);
}
item = kList_Next(list, item);
}
}
return traits;
}
kFx(kStatus) xkList_WriteDat6V0(kList list, kSerializer serializer)
{
kObj(kList, list);
kListItem item = kList_First(list);
kTypeVersion contentVersion;
kCheck(kSerializer_WriteType(serializer, obj->contentField.type, &contentVersion));
kCheck(kSerializer_WriteSize(serializer, obj->count));
while (!kIsNull(item))
{
kCheck(kSerializer_WriteItems(serializer, obj->contentField.type, contentVersion, xkList_ItemContent(list, item), 1));
item = kList_Next(list, item);
}
return kOK;
}
kFx(kStatus) xkList_ReadDat6V0(kList list, kSerializer serializer)
{
kObj(kList, list);
kListItemStruct* itemObj = kNULL;
kType contentType;
kTypeVersion contentVersion;
kSize count = 0;
kCheck(kSerializer_ReadType(serializer, &contentType, &contentVersion));
kCheck(kSerializer_ReadSize(serializer, &count));
kCheck(kList_Allocate(list, contentType, count));
for (kSize i = 0; i < count; ++i)
{
itemObj = obj->free;
obj->free = itemObj->next;
itemObj->next = kNULL;
itemObj->previous = obj->last;
if (!kIsNull(itemObj->previous))
{
itemObj->previous->next = itemObj;
}
obj->last = itemObj;
if (kIsNull(obj->first))
{
obj->first = itemObj;
}
kItemZero((void*)xkList_ItemContent(list, itemObj), obj->contentField.fieldSize);
kCheck(kSerializer_ReadItems(serializer, obj->contentField.type, contentVersion, (void*)xkList_ItemContent(list, itemObj), 1));
}
obj->count = count;
return kOK;
}
kFx(kStatus) kList_Reserve(kList list, kSize capacity)
{
kObj(kList, list);
if (capacity > obj->capacity)
{
kSize itemCount = kMax_(capacity - obj->capacity, xkLIST_MIN_ITEMS_PER_BLOCK);
kSize itemOffset = kSize_Align(sizeof(kListItemBlock), kALIGN_ANY);
kSize blockSize = kSize_Align(itemOffset + itemCount*obj->itemSize, kALIGN_ANY);
kListItemBlock* block = kNULL;
kSize i;
kCheck(kAlloc_Get(kObject_Alloc(list), blockSize, &block));
block->itemCount = itemCount;
block->items = (kListItemStruct*) kPointer_ByteOffset(block, (kSSize)itemOffset);
block->next = obj->blocks;
obj->blocks = block;
for (i = 0; i < itemCount; ++i)
{
kListItemStruct* item = (kListItemStruct*) kPointer_ItemOffset(&block->items[0], (kSSize)i, obj->itemSize);
item->next = obj->free;
obj->free = item;
}
obj->capacity += itemCount;
}
return kOK;
}
kFx(kStatus) kList_Add(kList list, const void* itemContent, kListItem* item)
{
kObj(kList, list);
kListItemStruct* itemObj = kNULL;
void* contentSlot = kNULL;
if (obj->count == obj->capacity)
{
kCheck(kList_Reserve(list, obj->capacity+1));
}
itemObj = obj->free;
obj->free = itemObj->next;
itemObj->next = kNULL;
itemObj->previous = obj->last;
if (!kIsNull(itemObj->previous))
{
itemObj->previous->next = itemObj;
}
obj->last = itemObj;
if (kIsNull(obj->first))
{
obj->first = itemObj;
}
obj->count++;
contentSlot = (void*)xkList_ItemContent(list, itemObj);
if (!kIsNull(itemContent))
{
kValue_Import(obj->contentField.type, contentSlot, itemContent);
}
if (!kIsNull(item))
{
*item = itemObj;
}
return kOK;
}
kFx(kStatus) kList_Insert(kList list, kListItem before, const void* itemContent, kListItem* item)
{
kObj(kList, list);
kListItemStruct* itemObj = kNULL;
kListItemStruct* beforeObj = (kListItemStruct*) before;
void* contentSlot = kNULL;
if (kIsNull(before))
{
return kList_Add(list, itemContent, item);
}
if (obj->count == obj->capacity)
{
kCheck(kList_Reserve(list, obj->capacity+1));
}
itemObj = obj->free;
obj->free = itemObj->next;
itemObj->next = beforeObj;
itemObj->previous = beforeObj->previous;
if (!kIsNull(itemObj->previous))
{
itemObj->previous->next = itemObj;
}
beforeObj->previous = itemObj;
if (obj->first == beforeObj)
{
obj->first = itemObj;
}
obj->count++;
contentSlot = (void*)xkList_ItemContent(list, itemObj);
if (!kIsNull(itemContent))
{
kValue_Import(obj->contentField.type, contentSlot, itemContent);
}
if (!kIsNull(item))
{
*item = itemObj;
}
return kOK;
}
kFx(kStatus) kList_Remove(kList list, kListItem item)
{
kObj(kList, list);
kListItemStruct* itemObj = (kListItemStruct*) item;
if (!kIsNull(itemObj->previous))
{
itemObj->previous->next = itemObj->next;
}
if (!kIsNull(itemObj->next))
{
itemObj->next->previous = itemObj->previous;
}
if (obj->first == itemObj)
{
obj->first = itemObj->next;
}
if (obj->last == itemObj)
{
obj->last = itemObj->previous;
}
itemObj->next = obj->free;
itemObj->previous = kNULL;
obj->free = itemObj;
obj->count--;
return kOK;
}
kFx(kStatus) kList_Clear(kList list)
{
kObj(kList, list);
if (obj->count > 0)
{
obj->last->next = obj->free;
obj->free = obj->first;
obj->first = kNULL;
obj->last = kNULL;
obj->count = 0;
}
return kOK;
}
kFx(kStatus) kList_Purge(kList list)
{
kObj(kList, list);
if (!kIsNull(obj->contentField.type) && xkList_ItemIsRef(list))
{
kListItem item = kList_First(list);
while (!kIsNull(item))
{
kCheck(kObject_Dispose(kList_AsT(list, item, kObject)));
item = kList_Next(list, item);
}
}
kCheck(kList_Clear(list));
return kOK;
}
kFx(kStatus) kList_SetItem(kList list, kListItem item, const void* content)
{
kObj(kList, list);
void* contentSlot = xkList_ItemContent(list, item);
kValue_Import(obj->contentField.type, contentSlot, content);
return kOK;
}
kFx(kStatus) kList_Item(kList list, kListItem item, void* content)
{
kObj(kList, list);
void* contentSlot = xkList_ItemContent(list, item);
kItemCopy(content, contentSlot, obj->contentField.fieldSize);
return kOK;
}
kFx(kListItem) kList_FindIndex(kList list, kSize index)
{
kObj(kList, list);
if (index > obj->count)
{
return kNULL;
}
else
{
kListItem it = kList_First(list);
kSize i;
for (i = 0; i < index; ++i)
{
it = kList_Next(list, it);
}
return it;
}
}
kFx(void*) kList_AtIndex(kList list, kSize index)
{
kListItem item = kList_FindIndex(list, index);
return kIsNull(item) ? kNULL : kList_At(list, item);
}