mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-02-24 16:09:38 +00:00
externals: Add zycore
Merge commit '80d62f224900ab486a5bc5a6e80ce1e25a0e38e8' as 'externals/zycore'
This commit is contained in:
848
externals/zycore/src/Vector.c
vendored
Normal file
848
externals/zycore/src/Vector.c
vendored
Normal file
@@ -0,0 +1,848 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <Zycore/LibC.h>
|
||||
#include <Zycore/Vector.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Checks, if the passed vector should grow.
|
||||
*
|
||||
* @param size The desired size of the vector.
|
||||
* @param capacity The current capacity of the vector.
|
||||
*
|
||||
* @return `ZYAN_TRUE`, if the vector should grow or `ZYAN_FALSE`, if not.
|
||||
*/
|
||||
#define ZYCORE_VECTOR_SHOULD_GROW(size, capacity) \
|
||||
((size) > (capacity))
|
||||
|
||||
/**
|
||||
* Checks, if the passed vector should shrink.
|
||||
*
|
||||
* @param size The desired size of the vector.
|
||||
* @param capacity The current capacity of the vector.
|
||||
* @param threshold The shrink threshold.
|
||||
*
|
||||
* @return `ZYAN_TRUE`, if the vector should shrink or `ZYAN_FALSE`, if not.
|
||||
*/
|
||||
#define ZYCORE_VECTOR_SHOULD_SHRINK(size, capacity, threshold) \
|
||||
((size) < (capacity) * (threshold))
|
||||
|
||||
/**
|
||||
* Returns the offset of the element at the given `index`.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The element index.
|
||||
*
|
||||
* @return The offset of the element at the given `index`.
|
||||
*/
|
||||
#define ZYCORE_VECTOR_OFFSET(vector, index) \
|
||||
((void*)((ZyanU8*)(vector)->data + ((index) * (vector)->element_size)))
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Helper functions */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Reallocates the internal buffer of the vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param capacity The new capacity.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
static ZyanStatus ZyanVectorReallocate(ZyanVector* vector, ZyanUSize capacity)
|
||||
{
|
||||
ZYAN_ASSERT(vector);
|
||||
ZYAN_ASSERT(vector->capacity >= ZYAN_VECTOR_MIN_CAPACITY);
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
if (!vector->allocator)
|
||||
{
|
||||
if (vector->capacity < capacity)
|
||||
{
|
||||
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
|
||||
}
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->allocator);
|
||||
ZYAN_ASSERT(vector->allocator->reallocate);
|
||||
|
||||
if (capacity < ZYAN_VECTOR_MIN_CAPACITY)
|
||||
{
|
||||
if (vector->capacity > ZYAN_VECTOR_MIN_CAPACITY)
|
||||
{
|
||||
capacity = ZYAN_VECTOR_MIN_CAPACITY;
|
||||
} else
|
||||
{
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
vector->capacity = capacity;
|
||||
ZYAN_CHECK(vector->allocator->reallocate(vector->allocator, &vector->data,
|
||||
vector->element_size, vector->capacity));
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts all elements starting at the specified `index` by the amount of
|
||||
* `count` to the left.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The start index.
|
||||
* @param count The amount of shift operations.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
static ZyanStatus ZyanVectorShiftLeft(ZyanVector* vector, ZyanUSize index, ZyanUSize count)
|
||||
{
|
||||
ZYAN_ASSERT(vector);
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
ZYAN_ASSERT(count > 0);
|
||||
//ZYAN_ASSERT((ZyanISize)count - (ZyanISize)index + 1 >= 0);
|
||||
|
||||
void* const source = ZYCORE_VECTOR_OFFSET(vector, index + count);
|
||||
void* const dest = ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
const ZyanUSize size = (vector->size - index - count) * vector->element_size;
|
||||
ZYAN_MEMMOVE(dest, source, size);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts all elements starting at the specified `index` by the amount of
|
||||
* `count` to the right.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The start index.
|
||||
* @param count The amount of shift operations.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
static ZyanStatus ZyanVectorShiftRight(ZyanVector* vector, ZyanUSize index, ZyanUSize count)
|
||||
{
|
||||
ZYAN_ASSERT(vector);
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
ZYAN_ASSERT(count > 0);
|
||||
ZYAN_ASSERT(vector->size + count <= vector->capacity);
|
||||
|
||||
void* const source = ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
void* const dest = ZYCORE_VECTOR_OFFSET(vector, index + count);
|
||||
const ZyanUSize size = (vector->size - index) * vector->element_size;
|
||||
ZYAN_MEMMOVE(dest, source, size);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Constructor and destructor */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
ZyanStatus ZyanVectorInit(ZyanVector* vector, ZyanUSize element_size, ZyanUSize capacity,
|
||||
ZyanMemberProcedure destructor)
|
||||
{
|
||||
return ZyanVectorInitEx(vector, element_size, capacity, destructor, ZyanAllocatorDefault(),
|
||||
ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD);
|
||||
}
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
ZyanStatus ZyanVectorInitEx(ZyanVector* vector, ZyanUSize element_size, ZyanUSize capacity,
|
||||
ZyanMemberProcedure destructor, ZyanAllocator* allocator, float growth_factor,
|
||||
float shrink_threshold)
|
||||
{
|
||||
if (!vector || !element_size || !allocator || (growth_factor < 1.0f) ||
|
||||
(shrink_threshold < 0.0f) || (shrink_threshold > 1.0f))
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(allocator->allocate);
|
||||
|
||||
vector->allocator = allocator;
|
||||
vector->growth_factor = growth_factor;
|
||||
vector->shrink_threshold = shrink_threshold;
|
||||
vector->size = 0;
|
||||
vector->capacity = ZYAN_MAX(ZYAN_VECTOR_MIN_CAPACITY, capacity);
|
||||
vector->element_size = element_size;
|
||||
vector->destructor = destructor;
|
||||
vector->data = ZYAN_NULL;
|
||||
|
||||
return allocator->allocate(vector->allocator, &vector->data, vector->element_size,
|
||||
vector->capacity);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorInitCustomBuffer(ZyanVector* vector, ZyanUSize element_size,
|
||||
void* buffer, ZyanUSize capacity, ZyanMemberProcedure destructor)
|
||||
{
|
||||
if (!vector || !element_size || !buffer || !capacity)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
vector->allocator = ZYAN_NULL;
|
||||
vector->growth_factor = 1.0f;
|
||||
vector->shrink_threshold = 0.0f;
|
||||
vector->size = 0;
|
||||
vector->capacity = capacity;
|
||||
vector->element_size = element_size;
|
||||
vector->destructor = destructor;
|
||||
vector->data = buffer;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorDestroy(ZyanVector* vector)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
if (vector->destructor)
|
||||
{
|
||||
for (ZyanUSize i = 0; i < vector->size; ++i)
|
||||
{
|
||||
vector->destructor(ZYCORE_VECTOR_OFFSET(vector, i));
|
||||
}
|
||||
}
|
||||
|
||||
if (vector->allocator && vector->capacity)
|
||||
{
|
||||
ZYAN_ASSERT(vector->allocator->deallocate);
|
||||
ZYAN_CHECK(vector->allocator->deallocate(vector->allocator, vector->data,
|
||||
vector->element_size, vector->capacity));
|
||||
}
|
||||
|
||||
vector->data = ZYAN_NULL;
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Duplication */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
ZyanStatus ZyanVectorDuplicate(ZyanVector* destination, const ZyanVector* source,
|
||||
ZyanUSize capacity)
|
||||
{
|
||||
return ZyanVectorDuplicateEx(destination, source, capacity, ZyanAllocatorDefault(),
|
||||
ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD);
|
||||
}
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
ZyanStatus ZyanVectorDuplicateEx(ZyanVector* destination, const ZyanVector* source,
|
||||
ZyanUSize capacity, ZyanAllocator* allocator, float growth_factor, float shrink_threshold)
|
||||
{
|
||||
if (!source)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
const ZyanUSize len = source->size;
|
||||
|
||||
capacity = ZYAN_MAX(capacity, len);
|
||||
ZYAN_CHECK(ZyanVectorInitEx(destination, source->element_size, capacity, source->destructor,
|
||||
allocator, growth_factor, shrink_threshold));
|
||||
ZYAN_ASSERT(destination->capacity >= len);
|
||||
|
||||
ZYAN_MEMCPY(destination->data, source->data, len * source->element_size);
|
||||
destination->size = len;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorDuplicateCustomBuffer(ZyanVector* destination, const ZyanVector* source,
|
||||
void* buffer, ZyanUSize capacity)
|
||||
{
|
||||
if (!source)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
const ZyanUSize len = source->size;
|
||||
|
||||
if (capacity < len)
|
||||
{
|
||||
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
ZYAN_CHECK(ZyanVectorInitCustomBuffer(destination, source->element_size, buffer, capacity,
|
||||
source->destructor));
|
||||
ZYAN_ASSERT(destination->capacity >= len);
|
||||
|
||||
ZYAN_MEMCPY(destination->data, source->data, len * source->element_size);
|
||||
destination->size = len;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Element access */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
const void* ZyanVectorGet(const ZyanVector* vector, ZyanUSize index)
|
||||
{
|
||||
if (!vector || (index >= vector->size))
|
||||
{
|
||||
return ZYAN_NULL;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
return ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
}
|
||||
|
||||
void* ZyanVectorGetMutable(const ZyanVector* vector, ZyanUSize index)
|
||||
{
|
||||
if (!vector || (index >= vector->size))
|
||||
{
|
||||
return ZYAN_NULL;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
return ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorGetPointer(const ZyanVector* vector, ZyanUSize index, const void** value)
|
||||
{
|
||||
if (!vector || !value)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index >= vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
*value = (const void*)ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorGetPointerMutable(const ZyanVector* vector, ZyanUSize index, void** value)
|
||||
{
|
||||
if (!vector || !value)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index >= vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
*value = ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorSet(ZyanVector* vector, ZyanUSize index, const void* value)
|
||||
{
|
||||
if (!vector || !value)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index >= vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
void* const offset = ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
if (vector->destructor)
|
||||
{
|
||||
vector->destructor(offset);
|
||||
}
|
||||
ZYAN_MEMCPY(offset, value, vector->element_size);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Insertion */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanVectorPushBack(ZyanVector* vector, const void* element)
|
||||
{
|
||||
if (!vector || !element)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
if (ZYCORE_VECTOR_SHOULD_GROW(vector->size + 1, vector->capacity))
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorReallocate(vector,
|
||||
ZYAN_MAX(1, (ZyanUSize)((vector->size + 1) * vector->growth_factor))));
|
||||
}
|
||||
|
||||
void* const offset = ZYCORE_VECTOR_OFFSET(vector, vector->size);
|
||||
ZYAN_MEMCPY(offset, element, vector->element_size);
|
||||
|
||||
++vector->size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorInsert(ZyanVector* vector, ZyanUSize index, const void* element)
|
||||
{
|
||||
return ZyanVectorInsertRange(vector, index, element, 1);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorInsertRange(ZyanVector* vector, ZyanUSize index, const void* elements,
|
||||
ZyanUSize count)
|
||||
{
|
||||
if (!vector || !elements || !count)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index > vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
if (ZYCORE_VECTOR_SHOULD_GROW(vector->size + count, vector->capacity))
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorReallocate(vector,
|
||||
ZYAN_MAX(1, (ZyanUSize)((vector->size + count) * vector->growth_factor))));
|
||||
}
|
||||
|
||||
if (index < vector->size)
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorShiftRight(vector, index, count));
|
||||
}
|
||||
|
||||
void* const offset = ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
ZYAN_MEMCPY(offset, elements, count * vector->element_size);
|
||||
vector->size += count;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorEmplace(ZyanVector* vector, void** element, ZyanMemberFunction constructor)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return ZyanVectorEmplaceEx(vector, vector->size, element, constructor);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorEmplaceEx(ZyanVector* vector, ZyanUSize index, void** element,
|
||||
ZyanMemberFunction constructor)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index > vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
if (ZYCORE_VECTOR_SHOULD_GROW(vector->size + 1, vector->capacity))
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorReallocate(vector,
|
||||
ZYAN_MAX(1, (ZyanUSize)((vector->size + 1) * vector->growth_factor))));
|
||||
}
|
||||
|
||||
if (index < vector->size)
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorShiftRight(vector, index, 1));
|
||||
}
|
||||
|
||||
*element = ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
if (constructor)
|
||||
{
|
||||
ZYAN_CHECK(constructor(*element));
|
||||
}
|
||||
|
||||
++vector->size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Utils */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanVectorSwapElements(ZyanVector* vector, ZyanUSize index_first, ZyanUSize index_second)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if ((index_first >= vector->size) || (index_second >= vector->size))
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (vector->size == vector->capacity)
|
||||
{
|
||||
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
ZyanU64* const t = ZYCORE_VECTOR_OFFSET(vector, vector->size);
|
||||
ZyanU64* const a = ZYCORE_VECTOR_OFFSET(vector, index_first);
|
||||
ZyanU64* const b = ZYCORE_VECTOR_OFFSET(vector, index_second);
|
||||
ZYAN_MEMCPY(t, a, vector->element_size);
|
||||
ZYAN_MEMCPY(a, b, vector->element_size);
|
||||
ZYAN_MEMCPY(b, t, vector->element_size);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Deletion */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanVectorDelete(ZyanVector* vector, ZyanUSize index)
|
||||
{
|
||||
return ZyanVectorDeleteRange(vector, index, 1);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorDeleteRange(ZyanVector* vector, ZyanUSize index, ZyanUSize count)
|
||||
{
|
||||
if (!vector || !count)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index + count > vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (vector->destructor)
|
||||
{
|
||||
for (ZyanUSize i = index; i < index + count; ++i)
|
||||
{
|
||||
vector->destructor(ZYCORE_VECTOR_OFFSET(vector, i));
|
||||
}
|
||||
}
|
||||
|
||||
if (index + count < vector->size)
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorShiftLeft(vector, index, count));
|
||||
}
|
||||
|
||||
vector->size -= count;
|
||||
if (ZYCORE_VECTOR_SHOULD_SHRINK(vector->size, vector->capacity, vector->shrink_threshold))
|
||||
{
|
||||
return ZyanVectorReallocate(vector,
|
||||
ZYAN_MAX(1, (ZyanUSize)(vector->size * vector->growth_factor)));
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorPopBack(ZyanVector* vector)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (vector->size == 0)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (vector->destructor)
|
||||
{
|
||||
vector->destructor(ZYCORE_VECTOR_OFFSET(vector, vector->size - 1));
|
||||
}
|
||||
|
||||
--vector->size;
|
||||
if (ZYCORE_VECTOR_SHOULD_SHRINK(vector->size, vector->capacity, vector->shrink_threshold))
|
||||
{
|
||||
return ZyanVectorReallocate(vector,
|
||||
ZYAN_MAX(1, (ZyanUSize)(vector->size * vector->growth_factor)));
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorClear(ZyanVector* vector)
|
||||
{
|
||||
return ZyanVectorResizeEx(vector, 0, ZYAN_NULL);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Searching */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanVectorFind(const ZyanVector* vector, const void* element, ZyanISize* found_index,
|
||||
ZyanEqualityComparison comparison)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return ZyanVectorFindEx(vector, element, found_index, comparison, 0, vector->size);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorFindEx(const ZyanVector* vector, const void* element, ZyanISize* found_index,
|
||||
ZyanEqualityComparison comparison, ZyanUSize index, ZyanUSize count)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if ((index + count > vector->size) || (index == vector->size))
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
{
|
||||
*found_index = -1;
|
||||
return ZYAN_STATUS_FALSE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
for (ZyanUSize i = index; i < index + count; ++i)
|
||||
{
|
||||
if (comparison(ZYCORE_VECTOR_OFFSET(vector, i), element))
|
||||
{
|
||||
*found_index = i;
|
||||
return ZYAN_STATUS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*found_index = -1;
|
||||
return ZYAN_STATUS_FALSE;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorBinarySearch(const ZyanVector* vector, const void* element,
|
||||
ZyanUSize* found_index, ZyanComparison comparison)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return ZyanVectorBinarySearchEx(vector, element, found_index, comparison, 0, vector->size);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorBinarySearchEx(const ZyanVector* vector, const void* element,
|
||||
ZyanUSize* found_index, ZyanComparison comparison, ZyanUSize index, ZyanUSize count)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (((index >= vector->size) && (count > 0)) || (index + count > vector->size))
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
{
|
||||
*found_index = index;
|
||||
return ZYAN_STATUS_FALSE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
ZyanStatus status = ZYAN_STATUS_FALSE;
|
||||
ZyanISize l = index;
|
||||
ZyanISize h = index + count - 1;
|
||||
while (l <= h)
|
||||
{
|
||||
const ZyanUSize mid = l + ((h - l) >> 1);
|
||||
const ZyanI32 cmp = comparison(ZYCORE_VECTOR_OFFSET(vector, mid), element);
|
||||
if (cmp < 0)
|
||||
{
|
||||
l = mid + 1;
|
||||
} else
|
||||
{
|
||||
h = mid - 1;
|
||||
if (cmp == 0)
|
||||
{
|
||||
status = ZYAN_STATUS_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*found_index = l;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Memory management */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanVectorResize(ZyanVector* vector, ZyanUSize size)
|
||||
{
|
||||
return ZyanVectorResizeEx(vector, size, ZYAN_NULL);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorResizeEx(ZyanVector* vector, ZyanUSize size, const void* initializer)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (size == vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (vector->destructor && (size < vector->size))
|
||||
{
|
||||
for (ZyanUSize i = size; i < vector->size; ++i)
|
||||
{
|
||||
vector->destructor(ZYCORE_VECTOR_OFFSET(vector, i));
|
||||
}
|
||||
}
|
||||
|
||||
if (ZYCORE_VECTOR_SHOULD_GROW(size, vector->capacity) ||
|
||||
ZYCORE_VECTOR_SHOULD_SHRINK(size, vector->capacity, vector->shrink_threshold))
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorReallocate(vector, (ZyanUSize)(size * vector->growth_factor)));
|
||||
};
|
||||
|
||||
if (initializer && (size > vector->size))
|
||||
{
|
||||
for (ZyanUSize i = vector->size; i < size; ++i)
|
||||
{
|
||||
ZYAN_MEMCPY(ZYCORE_VECTOR_OFFSET(vector, i), initializer, vector->element_size);
|
||||
}
|
||||
}
|
||||
|
||||
vector->size = size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorReserve(ZyanVector* vector, ZyanUSize capacity)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (capacity > vector->capacity)
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorReallocate(vector, capacity));
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorShrinkToFit(ZyanVector* vector)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return ZyanVectorReallocate(vector, vector->size);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Information */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanVectorGetCapacity(const ZyanVector* vector, ZyanUSize* capacity)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*capacity = vector->capacity;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorGetSize(const ZyanVector* vector, ZyanUSize* size)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*size = vector->size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
Reference in New Issue
Block a user