externals: Add zycore

Merge commit '80d62f224900ab486a5bc5a6e80ce1e25a0e38e8' as 'externals/zycore'
This commit is contained in:
MerryMage
2021-05-25 21:28:55 +01:00
44 changed files with 12994 additions and 0 deletions

128
externals/zycore/src/API/Memory.c vendored Normal file
View File

@@ -0,0 +1,128 @@
/***************************************************************************************************
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/API/Memory.h>
#if defined(ZYAN_WINDOWS)
#elif defined(ZYAN_POSIX)
# include <unistd.h>
#else
# error "Unsupported platform detected"
#endif
/* ============================================================================================== */
/* Exported functions */
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* General */
/* ---------------------------------------------------------------------------------------------- */
ZyanU32 ZyanMemoryGetSystemPageSize()
{
#if defined(ZYAN_WINDOWS)
SYSTEM_INFO system_info;
GetSystemInfo(&system_info);
return system_info.dwPageSize;
#elif defined(ZYAN_POSIX)
return sysconf(_SC_PAGE_SIZE);
#endif
}
ZyanU32 ZyanMemoryGetSystemAllocationGranularity()
{
#if defined(ZYAN_WINDOWS)
SYSTEM_INFO system_info;
GetSystemInfo(&system_info);
return system_info.dwAllocationGranularity;
#elif defined(ZYAN_POSIX)
return sysconf(_SC_PAGE_SIZE);
#endif
}
/* ---------------------------------------------------------------------------------------------- */
/* Memory management */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanMemoryVirtualProtect(void* address, ZyanUSize size,
ZyanMemoryPageProtection protection)
{
#if defined(ZYAN_WINDOWS)
DWORD old;
if (!VirtualProtect(address, size, protection, &old))
{
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
#elif defined(ZYAN_POSIX)
if (mprotect(address, size, protection))
{
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
#endif
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanMemoryVirtualFree(void* address, ZyanUSize size)
{
#if defined(ZYAN_WINDOWS)
ZYAN_UNUSED(size);
if (!VirtualFree(address, 0, MEM_RELEASE))
{
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
#elif defined(ZYAN_POSIX)
if (munmap(address, size))
{
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
#endif
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */

68
externals/zycore/src/API/Process.c vendored Normal file
View File

@@ -0,0 +1,68 @@
/***************************************************************************************************
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/Defines.h>
#if defined(ZYAN_WINDOWS)
# include <windows.h>
#elif defined(ZYAN_POSIX)
# include <sys/mman.h>
#else
# error "Unsupported platform detected"
#endif
#include <Zycore/API/Process.h>
/* ============================================================================================== */
/* Exported functions */
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* General */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanProcessFlushInstructionCache(void* address, ZyanUSize size)
{
#if defined(ZYAN_WINDOWS)
if (!FlushInstructionCache(GetCurrentProcess(), address, size))
{
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
#elif defined(ZYAN_POSIX)
if (msync(address, size, MS_SYNC | MS_INVALIDATE))
{
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
#endif
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */

View File

@@ -0,0 +1,200 @@
/***************************************************************************************************
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/API/Synchronization.h>
/* ============================================================================================== */
/* Internal functions */
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* */
/* ---------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */
/* Exported functions */
/* ============================================================================================== */
#if defined(ZYAN_POSIX)
#include <errno.h>
/* ---------------------------------------------------------------------------------------------- */
/* Critical Section */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanCriticalSectionInitialize(ZyanCriticalSection* critical_section)
{
pthread_mutexattr_t attribute;
int error = pthread_mutexattr_init(&attribute);
if (error != 0)
{
if (error == ENOMEM)
{
return ZYAN_STATUS_NOT_ENOUGH_MEMORY;
}
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
pthread_mutexattr_settype(&attribute, PTHREAD_MUTEX_RECURSIVE);
error = pthread_mutex_init(critical_section, &attribute);
pthread_mutexattr_destroy(&attribute);
if (error != 0)
{
if (error == EAGAIN)
{
return ZYAN_STATUS_OUT_OF_RESOURCES;
}
if (error == ENOMEM)
{
return ZYAN_STATUS_NOT_ENOUGH_MEMORY;
}
if (error == EPERM)
{
return ZYAN_STATUS_ACCESS_DENIED;
}
if ((error == EBUSY) || (error == EINVAL))
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanCriticalSectionEnter(ZyanCriticalSection* critical_section)
{
const int error = pthread_mutex_lock(critical_section);
if (error != 0)
{
if (error == EINVAL)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
if (error == EAGAIN)
{
return ZYAN_STATUS_INVALID_OPERATION;
}
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
return ZYAN_STATUS_SUCCESS;
}
ZyanBool ZyanCriticalSectionTryEnter(ZyanCriticalSection* critical_section)
{
// No fine grained error handling for this one
return pthread_mutex_trylock(critical_section) ? ZYAN_FALSE : ZYAN_TRUE;
}
ZyanStatus ZyanCriticalSectionLeave(ZyanCriticalSection* critical_section)
{
const int error = pthread_mutex_unlock(critical_section);
if (error != 0)
{
if (error == EINVAL)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
if (error == EPERM)
{
return ZYAN_STATUS_INVALID_OPERATION;
}
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanCriticalSectionDelete(ZyanCriticalSection* critical_section)
{
const int error = pthread_mutex_destroy(critical_section);
if (error != 0)
{
if ((error == EBUSY) || (error == EINVAL))
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
#elif defined(ZYAN_WINDOWS)
/* ---------------------------------------------------------------------------------------------- */
/* General */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanCriticalSectionInitialize(ZyanCriticalSection* critical_section)
{
InitializeCriticalSection(critical_section);
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanCriticalSectionEnter(ZyanCriticalSection* critical_section)
{
EnterCriticalSection(critical_section);
return ZYAN_STATUS_SUCCESS;
}
ZyanBool ZyanCriticalSectionTryEnter(ZyanCriticalSection* critical_section)
{
return TryEnterCriticalSection(critical_section) ? ZYAN_TRUE : ZYAN_FALSE;
}
ZyanStatus ZyanCriticalSectionLeave(ZyanCriticalSection* critical_section)
{
LeaveCriticalSection(critical_section);
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanCriticalSectionDelete(ZyanCriticalSection* critical_section)
{
DeleteCriticalSection(critical_section);
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
#else
# error "Unsupported platform detected"
#endif
/* ============================================================================================== */

156
externals/zycore/src/API/Terminal.c vendored Normal file
View File

@@ -0,0 +1,156 @@
/***************************************************************************************************
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/API/Terminal.h>
#if defined(ZYAN_POSIX)
# include <unistd.h>
#elif defined(ZYAN_WINDOWS)
# include <windows.h>
# include <io.h>
#else
# error "Unsupported platform detected"
#endif
// Provide fallback for old SDK versions
#ifdef ZYAN_WINDOWS
# ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
# define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
# endif
#endif
/* ============================================================================================== */
/* Exported functions */
/* ============================================================================================== */
ZyanStatus ZyanTerminalEnableVT100(ZyanStandardStream stream)
{
if ((stream != ZYAN_STDSTREAM_OUT) && (stream != ZYAN_STDSTREAM_ERR))
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
#ifdef ZYAN_WINDOWS
// Get file descriptor
int file;
switch (stream)
{
case ZYAN_STDSTREAM_OUT:
file = _fileno(ZYAN_STDOUT);
break;
case ZYAN_STDSTREAM_ERR:
file = _fileno(ZYAN_STDERR);
break;
default:
ZYAN_UNREACHABLE;
}
if (file < 0)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
HANDLE const handle = (HANDLE)_get_osfhandle(file);
if (handle == INVALID_HANDLE_VALUE)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
DWORD mode;
if (!GetConsoleMode(handle, &mode))
{
// The given standard stream is not bound to a terminal
return ZYAN_STATUS_INVALID_ARGUMENT;
}
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(handle, mode))
{
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
#endif
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanTerminalIsTTY(ZyanStandardStream stream)
{
// Get file descriptor
int file;
#ifdef ZYAN_WINDOWS
switch (stream)
{
case ZYAN_STDSTREAM_IN:
file = _fileno(ZYAN_STDIN);
break;
case ZYAN_STDSTREAM_OUT:
file = _fileno(ZYAN_STDOUT);
break;
case ZYAN_STDSTREAM_ERR:
file = _fileno(ZYAN_STDERR);
break;
default:
ZYAN_UNREACHABLE;
}
if (file < 0)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
#else
switch (stream)
{
case ZYAN_STDSTREAM_IN:
file = STDIN_FILENO;
break;
case ZYAN_STDSTREAM_OUT:
file = STDOUT_FILENO;
break;
case ZYAN_STDSTREAM_ERR:
file = STDERR_FILENO;
break;
default:
ZYAN_UNREACHABLE;
}
#endif
#ifdef ZYAN_WINDOWS
if (_isatty(file))
#else
if ( isatty(file))
#endif
{
return ZYAN_STATUS_TRUE;
}
if (ZYAN_ERRNO == EBADF)
{
// Invalid file descriptor
return ZYAN_STATUS_INVALID_ARGUMENT;
}
//ZYAN_ASSERT((errno == EINVAL) || (errno == ENOTTY));
return ZYAN_STATUS_FALSE;
}
/* ============================================================================================== */

194
externals/zycore/src/API/Thread.c vendored Normal file
View File

@@ -0,0 +1,194 @@
/***************************************************************************************************
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/API/Thread.h>
/* ============================================================================================== */
/* Internal functions */
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* */
/* ---------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */
/* Exported functions */
/* ============================================================================================== */
#if defined(ZYAN_POSIX)
#include <errno.h>
/* ---------------------------------------------------------------------------------------------- */
/* General */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanThreadGetCurrentThread(ZyanThread* thread)
{
*thread = pthread_self();
return ZYAN_STATUS_SUCCESS;
}
ZYAN_STATIC_ASSERT(sizeof(ZyanThreadId) <= sizeof(ZyanU64));
ZyanStatus ZyanThreadGetCurrentThreadId(ZyanThreadId* thread_id)
{
// TODO: Use `pthread_getthreadid_np` on platforms where it is available
pthread_t ptid = pthread_self();
*thread_id = *(ZyanThreadId*)ptid;
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* Thread Local Storage */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanThreadTlsAlloc(ZyanThreadTlsIndex* index, ZyanThreadTlsCallback destructor)
{
ZyanThreadTlsIndex value;
const int error = pthread_key_create(&value, destructor);
if (error != 0)
{
if (error == EAGAIN)
{
return ZYAN_STATUS_OUT_OF_RESOURCES;
}
if (error == ENOMEM)
{
return ZYAN_STATUS_NOT_ENOUGH_MEMORY;
}
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
*index = value;
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanThreadTlsFree(ZyanThreadTlsIndex index)
{
return !pthread_key_delete(index) ? ZYAN_STATUS_SUCCESS : ZYAN_STATUS_BAD_SYSTEMCALL;
}
ZyanStatus ZyanThreadTlsGetValue(ZyanThreadTlsIndex index, void** data)
{
*data = pthread_getspecific(index);
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanThreadTlsSetValue(ZyanThreadTlsIndex index, void* data)
{
const int error = pthread_setspecific(index, data);
if (error != 0)
{
if (error == EINVAL)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
#elif defined(ZYAN_WINDOWS)
/* ---------------------------------------------------------------------------------------------- */
/* General */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanThreadGetCurrentThread(ZyanThread* thread)
{
*thread = GetCurrentThread();
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanThreadGetCurrentThreadId(ZyanThreadId* thread_id)
{
*thread_id = GetCurrentThreadId();
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* Thread Local Storage (TLS) */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanThreadTlsAlloc(ZyanThreadTlsIndex* index, ZyanThreadTlsCallback destructor)
{
const ZyanThreadTlsIndex value = FlsAlloc(destructor);
if (value == FLS_OUT_OF_INDEXES)
{
return ZYAN_STATUS_OUT_OF_RESOURCES;
}
*index = value;
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanThreadTlsFree(ZyanThreadTlsIndex index)
{
return FlsFree(index) ? ZYAN_STATUS_SUCCESS : ZYAN_STATUS_BAD_SYSTEMCALL;
}
ZyanStatus ZyanThreadTlsGetValue(ZyanThreadTlsIndex index, void** data)
{
*data = FlsGetValue(index);
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanThreadTlsSetValue(ZyanThreadTlsIndex index, void* data)
{
if (!FlsSetValue(index, data))
{
const DWORD error = GetLastError();
if (error == ERROR_INVALID_PARAMETER)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
return ZYAN_STATUS_BAD_SYSTEMCALL;
}
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
#else
# error "Unsupported platform detected"
#endif
/* ============================================================================================== */

134
externals/zycore/src/Allocator.c vendored Normal file
View File

@@ -0,0 +1,134 @@
/***************************************************************************************************
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/Allocator.h>
#include <Zycore/LibC.h>
/* ============================================================================================== */
/* Internal functions */
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* Default allocator */
/* ---------------------------------------------------------------------------------------------- */
#ifndef ZYAN_NO_LIBC
static ZyanStatus ZyanAllocatorDefaultAllocate(ZyanAllocator* allocator, void** p,
ZyanUSize element_size, ZyanUSize n)
{
ZYAN_ASSERT(allocator);
ZYAN_ASSERT(p);
ZYAN_ASSERT(element_size);
ZYAN_ASSERT(n);
ZYAN_UNUSED(allocator);
*p = ZYAN_MALLOC(element_size * n);
if (!*p)
{
return ZYAN_STATUS_NOT_ENOUGH_MEMORY;
}
return ZYAN_STATUS_SUCCESS;
}
static ZyanStatus ZyanAllocatorDefaultReallocate(ZyanAllocator* allocator, void** p,
ZyanUSize element_size, ZyanUSize n)
{
ZYAN_ASSERT(allocator);
ZYAN_ASSERT(p);
ZYAN_ASSERT(element_size);
ZYAN_ASSERT(n);
ZYAN_UNUSED(allocator);
void* const x = ZYAN_REALLOC(*p, element_size * n);
if (!x)
{
return ZYAN_STATUS_NOT_ENOUGH_MEMORY;
}
*p = x;
return ZYAN_STATUS_SUCCESS;
}
static ZyanStatus ZyanAllocatorDefaultDeallocate(ZyanAllocator* allocator, void* p,
ZyanUSize element_size, ZyanUSize n)
{
ZYAN_ASSERT(allocator);
ZYAN_ASSERT(p);
ZYAN_ASSERT(element_size);
ZYAN_ASSERT(n);
ZYAN_UNUSED(allocator);
ZYAN_UNUSED(element_size);
ZYAN_UNUSED(n);
ZYAN_FREE(p);
return ZYAN_STATUS_SUCCESS;
}
#endif // ZYAN_NO_LIBC
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */
/* Exported functions */
/* ============================================================================================== */
ZyanStatus ZyanAllocatorInit(ZyanAllocator* allocator, ZyanAllocatorAllocate allocate,
ZyanAllocatorAllocate reallocate, ZyanAllocatorDeallocate deallocate)
{
if (!allocator || !allocate || !reallocate || !deallocate)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
allocator->allocate = allocate;
allocator->reallocate = reallocate;
allocator->deallocate = deallocate;
return ZYAN_STATUS_SUCCESS;
}
#ifndef ZYAN_NO_LIBC
ZyanAllocator* ZyanAllocatorDefault(void)
{
static ZyanAllocator allocator =
{
&ZyanAllocatorDefaultAllocate,
&ZyanAllocatorDefaultReallocate,
&ZyanAllocatorDefaultDeallocate
};
return &allocator;
}
#endif
/* ============================================================================================== */

279
externals/zycore/src/ArgParse.c vendored Normal file
View File

@@ -0,0 +1,279 @@
/***************************************************************************************************
Zyan Core Library (Zycore-C)
Original Author : Joel Hoener
* 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/ArgParse.h>
#include <Zycore/LibC.h>
/* ============================================================================================== */
/* Exported functions */
/* ============================================================================================== */
#ifndef ZYAN_NO_LIBC
ZyanStatus ZyanArgParse(const ZyanArgParseConfig *cfg, ZyanVector* parsed,
const char** error_token)
{
return ZyanArgParseEx(cfg, parsed, error_token, ZyanAllocatorDefault());
}
#endif
ZyanStatus ZyanArgParseEx(const ZyanArgParseConfig *cfg, ZyanVector* parsed,
const char** error_token, ZyanAllocator* allocator)
{
# define ZYAN_ERR_TOK(tok) if (error_token) { *error_token = tok; }
ZYAN_ASSERT(cfg);
ZYAN_ASSERT(parsed);
// TODO: Once we have a decent hash map impl, refactor this to use it. The majority of for
// loops through the argument list could be avoided.
if (cfg->min_unnamed_args > cfg->max_unnamed_args)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
// Check argument syntax.
for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def)
{
// TODO: Duplicate check
if (!def->name)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZyanUSize arg_len = ZYAN_STRLEN(def->name);
if (arg_len < 2 || def->name[0] != '-')
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
// Single dash arguments only accept a single char name.
if (def->name[1] != '-' && arg_len != 2)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
}
// Initialize output vector.
ZYAN_CHECK(ZyanVectorInitEx(parsed, sizeof(ZyanArgParseArg), cfg->argc, ZYAN_NULL, allocator,
ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD));
ZyanStatus err;
ZyanBool accept_dash_args = ZYAN_TRUE;
ZyanUSize num_unnamed_args = 0;
for (ZyanUSize i = 1; i < cfg->argc; ++i)
{
const char* cur_arg = cfg->argv[i];
ZyanUSize arg_len = ZYAN_STRLEN(cfg->argv[i]);
// Double-dash argument?
if (accept_dash_args && arg_len >= 2 && ZYAN_MEMCMP(cur_arg, "--", 2) == 0)
{
// GNU style end of argument parsing.
if (arg_len == 2)
{
accept_dash_args = ZYAN_FALSE;
}
// Regular double-dash argument.
else
{
// Allocate parsed argument struct.
ZyanArgParseArg* parsed_arg;
ZYAN_CHECK(ZyanVectorEmplace(parsed, (void**)&parsed_arg, ZYAN_NULL));
ZYAN_MEMSET(parsed_arg, 0, sizeof(*parsed_arg));
// Find corresponding argument definition.
for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def)
{
if (ZYAN_STRCMP(def->name, cur_arg) == 0)
{
parsed_arg->def = def;
break;
}
}
// Search exhausted & argument not found. RIP.
if (!parsed_arg->def)
{
err = ZYAN_STATUS_ARG_NOT_UNDERSTOOD;
ZYAN_ERR_TOK(cur_arg);
goto failure;
}
// Does the argument expect a value? If yes, consume next token.
if (!parsed_arg->def->boolean)
{
if (i == cfg->argc - 1)
{
err = ZYAN_STATUS_ARG_MISSES_VALUE;
ZYAN_ERR_TOK(cur_arg);
goto failure;
}
parsed_arg->has_value = ZYAN_TRUE;
ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, cfg->argv[++i]));
}
}
// Continue parsing at next token.
continue;
}
// Single-dash argument?
// TODO: How to deal with just dashes? Current code treats it as unnamed arg.
if (accept_dash_args && arg_len > 1 && cur_arg[0] == '-')
{
// Iterate argument token chars until there are either no more chars left
// or we encounter a non-boolean argument, in which case we consume the
// remaining chars as its value.
for (const char* read_ptr = cur_arg + 1; *read_ptr; ++read_ptr)
{
// Allocate parsed argument struct.
ZyanArgParseArg* parsed_arg;
ZYAN_CHECK(ZyanVectorEmplace(parsed, (void**)&parsed_arg, ZYAN_NULL));
ZYAN_MEMSET(parsed_arg, 0, sizeof(*parsed_arg));
// Find corresponding argument definition.
for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def)
{
if (ZYAN_STRLEN(def->name) == 2 &&
def->name[0] == '-' &&
def->name[1] == *read_ptr)
{
parsed_arg->def = def;
break;
}
}
// Search exhausted, no match found?
if (!parsed_arg->def)
{
err = ZYAN_STATUS_ARG_NOT_UNDERSTOOD;
ZYAN_ERR_TOK(cur_arg);
goto failure;
}
// Requires value?
if (!parsed_arg->def->boolean)
{
// If there are chars left, consume them (e.g. `-n1000`).
if (read_ptr[1])
{
parsed_arg->has_value = ZYAN_TRUE;
ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, read_ptr + 1));
}
// If not, consume next token (e.g. `-n 1000`).
else
{
if (i == cfg->argc - 1)
{
err = ZYAN_STATUS_ARG_MISSES_VALUE;
ZYAN_ERR_TOK(cur_arg)
goto failure;
}
parsed_arg->has_value = ZYAN_TRUE;
ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, cfg->argv[++i]));
}
// Either way, continue with next argument.
goto continue_main_loop;
}
}
}
// Still here? We're looking at an unnamed argument.
++num_unnamed_args;
if (num_unnamed_args > cfg->max_unnamed_args)
{
err = ZYAN_STATUS_TOO_MANY_ARGS;
ZYAN_ERR_TOK(cur_arg);
goto failure;
}
// Allocate parsed argument struct.
ZyanArgParseArg* parsed_arg;
ZYAN_CHECK(ZyanVectorEmplace(parsed, (void**)&parsed_arg, ZYAN_NULL));
ZYAN_MEMSET(parsed_arg, 0, sizeof(*parsed_arg));
parsed_arg->has_value = ZYAN_TRUE;
ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, cur_arg));
continue_main_loop:;
}
// All tokens processed. Do we have enough unnamed arguments?
if (num_unnamed_args < cfg->min_unnamed_args)
{
err = ZYAN_STATUS_TOO_FEW_ARGS;
// No sensible error token for this error type.
goto failure;
}
// Check whether all required arguments are present.
ZyanUSize num_parsed_args;
ZYAN_CHECK(ZyanVectorGetSize(parsed, &num_parsed_args));
for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def)
{
if (!def->required) continue;
ZyanBool arg_found = ZYAN_FALSE;
for (ZyanUSize i = 0; i < num_parsed_args; ++i)
{
const ZyanArgParseArg* arg = ZYAN_NULL;
ZYAN_CHECK(ZyanVectorGetPointer(parsed, i, (const void**)&arg));
// Skip unnamed args.
if (!arg->def) continue;
if (arg->def == def)
{
arg_found = ZYAN_TRUE;
break;
}
}
if (!arg_found)
{
err = ZYAN_STATUS_REQUIRED_ARG_MISSING;
ZYAN_ERR_TOK(def->name);
goto failure;
}
}
// Yay!
ZYAN_ERR_TOK(ZYAN_NULL);
return ZYAN_STATUS_SUCCESS;
failure:
ZYAN_CHECK(ZyanVectorDestroy(parsed));
return err;
# undef ZYAN_ERR_TOK
}
/* ============================================================================================== */

670
externals/zycore/src/Bitset.c vendored Normal file
View File

@@ -0,0 +1,670 @@
/***************************************************************************************************
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/Bitset.h>
#include <Zycore/LibC.h>
/* ============================================================================================== */
/* Internal constants */
/* ============================================================================================== */
#define ZYAN_BITSET_GROWTH_FACTOR 2.00f
#define ZYAN_BITSET_SHRINK_THRESHOLD 0.50f
/* ============================================================================================== */
/* Internal macros */
/* ============================================================================================== */
/**
* Computes the smallest integer value not less than `x`.
*
* @param x The value.
*
* @return The smallest integer value not less than `x`.
*/
#define ZYAN_BITSET_CEIL(x) \
(((x) == ((ZyanU32)(x))) ? (ZyanU32)(x) : ((ZyanU32)(x)) + 1)
/**
* Converts bits to bytes.
*
* @param x The value in bits.
*
* @return The amount of bytes needed to fit `x` bits.
*/
#define ZYAN_BITSET_BITS_TO_BYTES(x) \
ZYAN_BITSET_CEIL((x) / 8.0f)
/**
* Returns the offset of the given bit.
*
* @param index The bit index.
*
* @return The offset of the given bit.
*/
#define ZYAN_BITSET_BIT_OFFSET(index) \
(7 - ((index) % 8))
/* ============================================================================================== */
/* Internal functions */
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* Helper functions */
/* ---------------------------------------------------------------------------------------------- */
/**
* Initializes the given `vector` with `count` "zero"-bytes.
*
* @param vector A pointer to the `ZyanVector` instance.
* @param count The number of bytes.
*
* @return A zyan status code.
*/
static ZyanStatus ZyanBitsetInitVectorElements(ZyanVector* vector, ZyanUSize count)
{
ZYAN_ASSERT(vector);
static const ZyanU8 zero = 0;
for (ZyanUSize i = 0; i < count; ++i)
{
ZYAN_CHECK(ZyanVectorPushBack(vector, &zero));
}
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* Byte operations */
/* ---------------------------------------------------------------------------------------------- */
static ZyanStatus ZyanBitsetOperationAND(ZyanU8* b1, const ZyanU8* b2)
{
*b1 &= *b2;
return ZYAN_STATUS_SUCCESS;
}
static ZyanStatus ZyanBitsetOperationOR (ZyanU8* b1, const ZyanU8* b2)
{
*b1 |= *b2;
return ZYAN_STATUS_SUCCESS;
}
static ZyanStatus ZyanBitsetOperationXOR(ZyanU8* b1, const ZyanU8* b2)
{
*b1 ^= *b2;
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */
/* Exported functions */
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* Constructor and destructor */
/* ---------------------------------------------------------------------------------------------- */
#ifndef ZYAN_NO_LIBC
ZyanStatus ZyanBitsetInit(ZyanBitset* bitset, ZyanUSize count)
{
return ZyanBitsetInitEx(bitset, count, ZyanAllocatorDefault(), ZYAN_BITSET_GROWTH_FACTOR,
ZYAN_BITSET_SHRINK_THRESHOLD);
}
#endif // ZYAN_NO_LIBC
ZyanStatus ZyanBitsetInitEx(ZyanBitset* bitset, ZyanUSize count, ZyanAllocator* allocator,
float growth_factor, float shrink_threshold)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
const ZyanU32 bytes = ZYAN_BITSET_BITS_TO_BYTES(count);
bitset->size = count;
ZYAN_CHECK(ZyanVectorInitEx(&bitset->bits, sizeof(ZyanU8), bytes, ZYAN_NULL, allocator,
growth_factor, shrink_threshold));
ZYAN_CHECK(ZyanBitsetInitVectorElements(&bitset->bits, bytes));
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanBitsetInitBuffer(ZyanBitset* bitset, ZyanUSize count, void* buffer,
ZyanUSize capacity)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
const ZyanU32 bytes = ZYAN_BITSET_BITS_TO_BYTES(count);
if (capacity < bytes)
{
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
}
bitset->size = count;
ZYAN_CHECK(ZyanVectorInitCustomBuffer(&bitset->bits, sizeof(ZyanU8), buffer, capacity,
ZYAN_NULL));
ZYAN_CHECK(ZyanBitsetInitVectorElements(&bitset->bits, bytes));
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanBitsetDestroy(ZyanBitset* bitset)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
return ZyanVectorDestroy(&bitset->bits);
}
/* ---------------------------------------------------------------------------------------------- */
/* Logical operations */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanBitsetPerformByteOperation(ZyanBitset* destination, const ZyanBitset* source,
ZyanBitsetByteOperation operation)
{
if (!destination || !source || !operation)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZyanUSize s1;
ZyanUSize s2;
ZYAN_CHECK(ZyanVectorGetSize(&destination->bits, &s1));
ZYAN_CHECK(ZyanVectorGetSize(&source->bits, &s2));
const ZyanUSize min = ZYAN_MIN(s1, s2);
for (ZyanUSize i = 0; i < min; ++i)
{
ZyanU8* v1;
const ZyanU8* v2;
ZYAN_CHECK(ZyanVectorGetPointerMutable(&destination->bits, i, (void**)&v1));
ZYAN_CHECK(ZyanVectorGetPointer(&source->bits, i, (const void**)&v2));
ZYAN_ASSERT(v1);
ZYAN_ASSERT(v2);
ZYAN_CHECK(operation(v1, v2));
}
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanBitsetAND(ZyanBitset* destination, const ZyanBitset* source)
{
return ZyanBitsetPerformByteOperation(destination, source, ZyanBitsetOperationAND);
}
ZyanStatus ZyanBitsetOR (ZyanBitset* destination, const ZyanBitset* source)
{
return ZyanBitsetPerformByteOperation(destination, source, ZyanBitsetOperationOR );
}
ZyanStatus ZyanBitsetXOR(ZyanBitset* destination, const ZyanBitset* source)
{
return ZyanBitsetPerformByteOperation(destination, source, ZyanBitsetOperationXOR);
}
ZyanStatus ZyanBitsetFlip(ZyanBitset* bitset)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZyanUSize size;
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
for (ZyanUSize i = 0; i < size; ++i)
{
ZyanU8* value;
ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, i, (void**)&value));
*value = ~(*value);
}
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* Bit access */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanBitsetSet(ZyanBitset* bitset, ZyanUSize index)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
if (index >= bitset->size)
{
return ZYAN_STATUS_OUT_OF_RANGE;
}
ZyanU8* value;
ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, index / 8, (void**)&value));
*value |= (1 << ZYAN_BITSET_BIT_OFFSET(index));
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanBitsetReset(ZyanBitset* bitset, ZyanUSize index)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
if (index >= bitset->size)
{
return ZYAN_STATUS_OUT_OF_RANGE;
}
ZyanU8* value;
ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, index / 8, (void**)&value));
*value &= ~(1 << ZYAN_BITSET_BIT_OFFSET(index));
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanBitsetAssign(ZyanBitset* bitset, ZyanUSize index, ZyanBool value)
{
if (value)
{
return ZyanBitsetSet(bitset, index);
}
return ZyanBitsetReset(bitset, index);
}
ZyanStatus ZyanBitsetToggle(ZyanBitset* bitset, ZyanUSize index)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
if (index >= bitset->size)
{
return ZYAN_STATUS_OUT_OF_RANGE;
}
ZyanU8* value;
ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, index / 8, (void**)&value));
*value ^= (1 << ZYAN_BITSET_BIT_OFFSET(index));
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanBitsetTest(ZyanBitset* bitset, ZyanUSize index)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
if (index >= bitset->size)
{
return ZYAN_STATUS_OUT_OF_RANGE;
}
const ZyanU8* value;
ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, index / 8, (const void**)&value));
if ((*value & (1 << ZYAN_BITSET_BIT_OFFSET(index))) == 0)
{
return ZYAN_STATUS_FALSE;
}
return ZYAN_STATUS_TRUE;
}
ZyanStatus ZyanBitsetTestMSB(ZyanBitset* bitset)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
return ZyanBitsetTest(bitset, bitset->size - 1);
}
ZyanStatus ZyanBitsetTestLSB(ZyanBitset* bitset)
{
return ZyanBitsetTest(bitset, 0);
}
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanBitsetSetAll(ZyanBitset* bitset)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZyanUSize size;
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
for (ZyanUSize i = 0; i < size; ++i)
{
ZyanU8* value;
ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, i, (void**)&value));
*value = 0xFF;
}
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanBitsetResetAll(ZyanBitset* bitset)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZyanUSize size;
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
for (ZyanUSize i = 0; i < size; ++i)
{
ZyanU8* value;
ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, i, (void**)&value));
*value = 0x00;
}
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* Size management */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanBitsetPush(ZyanBitset* bitset, ZyanBool value)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
if ((bitset->size++ % 8) == 0)
{
static const ZyanU8 zero = 0;
ZYAN_CHECK(ZyanVectorPushBack(&bitset->bits, &zero));
}
return ZyanBitsetAssign(bitset, bitset->size - 1, value);
}
ZyanStatus ZyanBitsetPop(ZyanBitset* bitset)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
if ((--bitset->size % 8) == 0)
{
return ZyanVectorPopBack(&bitset->bits);
}
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanBitsetClear(ZyanBitset* bitset)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
bitset->size = 0;
return ZyanVectorClear(&bitset->bits);
}
/* ---------------------------------------------------------------------------------------------- */
/* Memory management */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanBitsetReserve(ZyanBitset* bitset, ZyanUSize count)
{
return ZyanVectorReserve(&bitset->bits, ZYAN_BITSET_BITS_TO_BYTES(count));
}
ZyanStatus ZyanBitsetShrinkToFit(ZyanBitset* bitset)
{
return ZyanVectorShrinkToFit(&bitset->bits);
}
/* ---------------------------------------------------------------------------------------------- */
/* Information */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanBitsetGetSize(const ZyanBitset* bitset, ZyanUSize* size)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
*size = bitset->size;
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanBitsetGetCapacity(const ZyanBitset* bitset, ZyanUSize* capacity)
{
ZYAN_CHECK(ZyanBitsetGetCapacityBytes(bitset, capacity));
*capacity *= 8;
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanBitsetGetSizeBytes(const ZyanBitset* bitset, ZyanUSize* size)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
return ZyanVectorGetSize(&bitset->bits, size);
}
ZyanStatus ZyanBitsetGetCapacityBytes(const ZyanBitset* bitset, ZyanUSize* capacity)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
return ZyanVectorGetCapacity(&bitset->bits, capacity);
}
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanBitsetCount(const ZyanBitset* bitset, ZyanUSize* count)
{
if (!bitset || !count)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
*count = 0;
ZyanUSize size;
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
for (ZyanUSize i = 0; i < size; ++i)
{
ZyanU8* value;
ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, i, (const void**)&value));
ZyanU8 popcnt = *value;
popcnt = (popcnt & 0x55) + ((popcnt >> 1) & 0x55);
popcnt = (popcnt & 0x33) + ((popcnt >> 2) & 0x33);
popcnt = (popcnt & 0x0F) + ((popcnt >> 4) & 0x0F);
*count += popcnt;
}
*count = ZYAN_MIN(*count, bitset->size);
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanBitsetAll(const ZyanBitset* bitset)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZyanUSize size;
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
for (ZyanUSize i = 0; i < size; ++i)
{
ZyanU8* value;
ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, i, (const void**)&value));
if (i < (size - 1))
{
if (*value != 0xFF)
{
return ZYAN_STATUS_FALSE;
}
} else
{
const ZyanU8 mask = ~(8 - (bitset->size % 8));
if ((*value & mask) != mask)
{
return ZYAN_STATUS_FALSE;
}
}
}
return ZYAN_STATUS_TRUE;
}
ZyanStatus ZyanBitsetAny(const ZyanBitset* bitset)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZyanUSize size;
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
for (ZyanUSize i = 0; i < size; ++i)
{
ZyanU8* value;
ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, i, (const void**)&value));
if (i < (size - 1))
{
if (*value != 0x00)
{
return ZYAN_STATUS_TRUE;
}
} else
{
const ZyanU8 mask = ~(8 - (bitset->size % 8));
if ((*value & mask) != 0x00)
{
return ZYAN_STATUS_TRUE;
}
}
}
return ZYAN_STATUS_FALSE;
}
ZyanStatus ZyanBitsetNone(const ZyanBitset* bitset)
{
if (!bitset)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZyanUSize size;
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
for (ZyanUSize i = 0; i < size; ++i)
{
ZyanU8* value;
ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, i, (const void**)&value));
if (i < (size - 1))
{
if (*value != 0x00)
{
return ZYAN_STATUS_FALSE;
}
} else
{
const ZyanU8 mask = ~(8 - (bitset->size % 8));
if ((*value & mask) != 0x00)
{
return ZYAN_STATUS_FALSE;
}
}
}
return ZYAN_STATUS_TRUE;
}
/* ---------------------------------------------------------------------------------------------- */
//ZyanStatus ZyanBitsetToU32(const ZyanBitset* bitset, ZyanU32* value)
//{
// if (!bitset)
// {
// return ZYAN_STATUS_INVALID_ARGUMENT;
// }
// if (bitset->size > 32)
// {
// return ZYAN_STATUS_INVALID_OPERATION;
// }
//
// // TODO:
//
// return ZYAN_STATUS_SUCCESS;
//}
//
//ZyanStatus ZyanBitsetToU64(const ZyanBitset* bitset, ZyanU64* value)
//{
// if (!bitset)
// {
// return ZYAN_STATUS_INVALID_ARGUMENT;
// }
// if (bitset->size > 64)
// {
// return ZYAN_STATUS_INVALID_OPERATION;
// }
//
// // TODO:
//
// return ZYAN_STATUS_SUCCESS;
//}
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */

507
externals/zycore/src/Format.c vendored Normal file
View File

@@ -0,0 +1,507 @@
/***************************************************************************************************
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/Format.h>
#include <Zycore/LibC.h>
/* ============================================================================================== */
/* Constants */
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* Defines */
/* ---------------------------------------------------------------------------------------------- */
#define ZYCORE_MAXCHARS_DEC_32 10
#define ZYCORE_MAXCHARS_DEC_64 20
#define ZYCORE_MAXCHARS_HEX_32 8
#define ZYCORE_MAXCHARS_HEX_64 16
/* ---------------------------------------------------------------------------------------------- */
/* Lookup Tables */
/* ---------------------------------------------------------------------------------------------- */
static const char* const DECIMAL_LOOKUP =
"00010203040506070809"
"10111213141516171819"
"20212223242526272829"
"30313233343536373839"
"40414243444546474849"
"50515253545556575859"
"60616263646566676869"
"70717273747576777879"
"80818283848586878889"
"90919293949596979899";
/* ---------------------------------------------------------------------------------------------- */
/* Static strings */
/* ---------------------------------------------------------------------------------------------- */
static const ZyanStringView STR_ADD = ZYAN_DEFINE_STRING_VIEW("+");
static const ZyanStringView STR_SUB = ZYAN_DEFINE_STRING_VIEW("-");
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */
/* Internal macros */
/* ============================================================================================== */
/**
* Writes a terminating '\0' character at the end of the string data.
*/
#define ZYCORE_STRING_NULLTERMINATE(string) \
*(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) = '\0';
/* ============================================================================================== */
/* Internal functions */
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* Decimal */
/* ---------------------------------------------------------------------------------------------- */
#if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN)
ZyanStatus ZyanStringAppendDecU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length)
{
if (!string)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
char buffer[ZYCORE_MAXCHARS_DEC_32];
char *buffer_end = &buffer[ZYCORE_MAXCHARS_DEC_32];
char *buffer_write_pointer = buffer_end;
while (value >= 100)
{
const ZyanU32 value_old = value;
buffer_write_pointer -= 2;
value /= 100;
ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2);
}
buffer_write_pointer -= 2;
ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2);
const ZyanUSize offset_odd = (ZyanUSize)(value < 10);
const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd;
const ZyanUSize length_total = ZYAN_MAX(length_number, padding_length);
const ZyanUSize length_target = string->vector.size;
if (string->vector.size + length_total > string->vector.capacity)
{
ZYAN_CHECK(ZyanStringResize(string, string->vector.size + length_total - 1));
}
ZyanUSize offset_write = 0;
if (padding_length > length_number)
{
offset_write = padding_length - length_number;
ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write);
}
ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1,
buffer_write_pointer + offset_odd, length_number);
string->vector.size = length_target + length_total;
ZYCORE_STRING_NULLTERMINATE(string);
return ZYAN_STATUS_SUCCESS;
}
#endif
ZyanStatus ZyanStringAppendDecU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length)
{
if (!string)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
char buffer[ZYCORE_MAXCHARS_DEC_64];
char *buffer_end = &buffer[ZYCORE_MAXCHARS_DEC_64];
char *buffer_write_pointer = buffer_end;
while (value >= 100)
{
const ZyanU64 value_old = value;
buffer_write_pointer -= 2;
value /= 100;
ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2);
}
buffer_write_pointer -= 2;
ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2);
const ZyanUSize offset_odd = (ZyanUSize)(value < 10);
const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd;
const ZyanUSize length_total = ZYAN_MAX(length_number, padding_length);
const ZyanUSize length_target = string->vector.size;
if (string->vector.size + length_total > string->vector.capacity)
{
ZYAN_CHECK(ZyanStringResize(string, string->vector.size + length_total - 1));
}
ZyanUSize offset_write = 0;
if (padding_length > length_number)
{
offset_write = padding_length - length_number;
ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write);
}
ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1,
buffer_write_pointer + offset_odd, length_number);
string->vector.size = length_target + length_total;
ZYCORE_STRING_NULLTERMINATE(string);
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* Hexadecimal */
/* ---------------------------------------------------------------------------------------------- */
#if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN)
ZyanStatus ZyanStringAppendHexU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length,
ZyanBool uppercase)
{
if (!string)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
const ZyanUSize len = string->vector.size;
ZyanUSize remaining = string->vector.capacity - string->vector.size;
if (remaining < (ZyanUSize)padding_length)
{
ZYAN_CHECK(ZyanStringResize(string, len + padding_length - 1));
remaining = padding_length;
}
if (!value)
{
const ZyanU8 n = (padding_length ? padding_length : 1);
if (remaining < (ZyanUSize)n)
{
ZYAN_CHECK(ZyanStringResize(string, string->vector.size + n - 1));
}
ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n);
string->vector.size = len + n;
ZYCORE_STRING_NULLTERMINATE(string);
return ZYAN_STATUS_SUCCESS;
}
ZyanU8 n = 0;
char* buffer = ZYAN_NULL;
for (ZyanI8 i = ZYCORE_MAXCHARS_HEX_32 - 1; i >= 0; --i)
{
const ZyanU8 v = (value >> i * 4) & 0x0F;
if (!n)
{
if (!v)
{
continue;
}
if (remaining <= (ZyanU8)i)
{
ZYAN_CHECK(ZyanStringResize(string, string->vector.size + i));
}
buffer = (char*)string->vector.data + len - 1;
if (padding_length > i)
{
n = padding_length - i - 1;
ZYAN_MEMSET(buffer, '0', n);
}
}
ZYAN_ASSERT(buffer);
if (uppercase)
{
buffer[n++] = "0123456789ABCDEF"[v];
} else
{
buffer[n++] = "0123456789abcdef"[v];
}
}
string->vector.size = len + n;
ZYCORE_STRING_NULLTERMINATE(string);
return ZYAN_STATUS_SUCCESS;
}
#endif
ZyanStatus ZyanStringAppendHexU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
ZyanBool uppercase)
{
if (!string)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
const ZyanUSize len = string->vector.size;
ZyanUSize remaining = string->vector.capacity - string->vector.size;
if (remaining < (ZyanUSize)padding_length)
{
ZYAN_CHECK(ZyanStringResize(string, len + padding_length - 1));
remaining = padding_length;
}
if (!value)
{
const ZyanU8 n = (padding_length ? padding_length : 1);
if (remaining < (ZyanUSize)n)
{
ZYAN_CHECK(ZyanStringResize(string, string->vector.size + n - 1));
}
ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n);
string->vector.size = len + n;
ZYCORE_STRING_NULLTERMINATE(string);
return ZYAN_STATUS_SUCCESS;
}
ZyanU8 n = 0;
char* buffer = ZYAN_NULL;
for (ZyanI8 i = ((value & 0xFFFFFFFF00000000) ?
ZYCORE_MAXCHARS_HEX_64 : ZYCORE_MAXCHARS_HEX_32) - 1; i >= 0; --i)
{
const ZyanU8 v = (value >> i * 4) & 0x0F;
if (!n)
{
if (!v)
{
continue;
}
if (remaining <= (ZyanU8)i)
{
ZYAN_CHECK(ZyanStringResize(string, string->vector.size + i));
}
buffer = (char*)string->vector.data + len - 1;
if (padding_length > i)
{
n = padding_length - i - 1;
ZYAN_MEMSET(buffer, '0', n);
}
}
ZYAN_ASSERT(buffer);
if (uppercase)
{
buffer[n++] = "0123456789ABCDEF"[v];
} else
{
buffer[n++] = "0123456789abcdef"[v];
}
}
string->vector.size = len + n;
ZYCORE_STRING_NULLTERMINATE(string);
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */
/* Exported functions */
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* Insertion */
/* ---------------------------------------------------------------------------------------------- */
//ZyanStatus ZyanStringInsertFormat(ZyanString* string, ZyanUSize index, const char* format, ...)
//{
//
//}
//
///* ---------------------------------------------------------------------------------------------- */
//
//ZyanStatus ZyanStringInsertDecU(ZyanString* string, ZyanUSize index, ZyanU64 value,
// ZyanUSize padding_length)
//{
//
//}
//
//ZyanStatus ZyanStringInsertDecS(ZyanString* string, ZyanUSize index, ZyanI64 value,
// ZyanUSize padding_length, ZyanBool force_sign, const ZyanString* prefix)
//{
//
//}
//
//ZyanStatus ZyanStringInsertHexU(ZyanString* string, ZyanUSize index, ZyanU64 value,
// ZyanUSize padding_length, ZyanBool uppercase)
//{
//
//}
//
//ZyanStatus ZyanStringInsertHexS(ZyanString* string, ZyanUSize index, ZyanI64 value,
// ZyanUSize padding_length, ZyanBool uppercase, ZyanBool force_sign, const ZyanString* prefix)
//{
//
//}
/* ---------------------------------------------------------------------------------------------- */
/* Appending */
/* ---------------------------------------------------------------------------------------------- */
#ifndef ZYAN_NO_LIBC
ZyanStatus ZyanStringAppendFormat(ZyanString* string, const char* format, ...)
{
if (!string || !format)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZyanVAList arglist;
ZYAN_VA_START(arglist, format);
const ZyanUSize len = string->vector.size;
ZyanI32 w = ZYAN_VSNPRINTF((char*)string->vector.data + len - 1,
string->vector.capacity - len + 1, format, arglist);
if (w < 0)
{
ZYAN_VA_END(arglist);
return ZYAN_STATUS_FAILED;
}
if (w <= (ZyanI32)(string->vector.capacity - len))
{
string->vector.size = len + w;
ZYAN_VA_END(arglist);
return ZYAN_STATUS_SUCCESS;
}
// The remaining capacity was not sufficent to fit the formatted string. Trying to resize ..
const ZyanStatus status = ZyanStringResize(string, string->vector.size + w - 1);
if (!ZYAN_SUCCESS(status))
{
ZYAN_VA_END(arglist);
return status;
}
w = ZYAN_VSNPRINTF((char*)string->vector.data + len - 1,
string->vector.capacity - string->vector.size + 1, format, arglist);
if (w < 0)
{
ZYAN_VA_END(arglist);
return ZYAN_STATUS_FAILED;
}
ZYAN_ASSERT(w <= (ZyanI32)(string->vector.capacity - string->vector.size));
ZYAN_VA_END(arglist);
return ZYAN_STATUS_SUCCESS;
}
#endif // ZYAN_NO_LIBC
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length)
{
#if defined(ZYAN_X64) || defined(ZYAN_AARCH64)
return ZyanStringAppendDecU64(string, value, padding_length);
#else
// Working with 64-bit values is slow on non 64-bit systems
if (value & 0xFFFFFFFF00000000)
{
return ZyanStringAppendDecU64(string, value, padding_length);
}
return ZyanStringAppendDecU32(string, (ZyanU32)value, padding_length);
#endif
}
ZyanStatus ZyanStringAppendDecS(ZyanString* string, ZyanI64 value, ZyanU8 padding_length,
ZyanBool force_sign, const ZyanStringView* prefix)
{
if (value < 0)
{
ZYAN_CHECK(ZyanStringAppend(string, &STR_SUB));
if (prefix)
{
ZYAN_CHECK(ZyanStringAppend(string, prefix));
}
return ZyanStringAppendDecU(string, ZyanAbsI64(value), padding_length);
}
if (force_sign)
{
ZYAN_ASSERT(value >= 0);
ZYAN_CHECK(ZyanStringAppend(string, &STR_ADD));
}
if (prefix)
{
ZYAN_CHECK(ZyanStringAppend(string, prefix));
}
return ZyanStringAppendDecU(string, value, padding_length);
}
ZyanStatus ZyanStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
ZyanBool uppercase)
{
#if defined(ZYAN_X64) || defined(ZYAN_AARCH64)
return ZyanStringAppendHexU64(string, value, padding_length, uppercase);
#else
// Working with 64-bit values is slow on non 64-bit systems
if (value & 0xFFFFFFFF00000000)
{
return ZyanStringAppendHexU64(string, value, padding_length, uppercase);
}
return ZyanStringAppendHexU32(string, (ZyanU32)value, padding_length, uppercase);
#endif
}
ZyanStatus ZyanStringAppendHexS(ZyanString* string, ZyanI64 value, ZyanU8 padding_length,
ZyanBool uppercase, ZyanBool force_sign, const ZyanStringView* prefix)
{
if (value < 0)
{
ZYAN_CHECK(ZyanStringAppend(string, &STR_SUB));
if (prefix)
{
ZYAN_CHECK(ZyanStringAppend(string, prefix));
}
return ZyanStringAppendHexU(string, ZyanAbsI64(value), padding_length, uppercase);
}
if (force_sign)
{
ZYAN_ASSERT(value >= 0);
ZYAN_CHECK(ZyanStringAppend(string, &STR_ADD));
}
if (prefix)
{
ZYAN_CHECK(ZyanStringAppend(string, prefix));
}
return ZyanStringAppendHexU(string, value, padding_length, uppercase);
}
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */

673
externals/zycore/src/List.c vendored Normal file
View File

@@ -0,0 +1,673 @@
/***************************************************************************************************
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/List.h>
/* ============================================================================================== */
/* Internal macros */
/* ============================================================================================== */
/**
* Returns a pointer to the data of the given `node`.
*
* @param node A pointer to the `ZyanNodeData` struct.
*
* @return A pointer to the data of the given `node`.
*/
#define ZYCORE_LIST_GET_NODE_DATA(node) \
((void*)(node + 1))
/* ============================================================================================== */
/* Internal functions */
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* Helper functions */
/* ---------------------------------------------------------------------------------------------- */
/**
* Allocates memory for a new list node.
*
* @param list A pointer to the `ZyanList` instance.
* @param node Receives a pointer to the new `ZyanListNode` struct.
*
* @return A zyan status code.
*/
static ZyanStatus ZyanListAllocateNode(ZyanList* list, ZyanListNode** node)
{
ZYAN_ASSERT(list);
ZYAN_ASSERT(node);
const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL);
if (is_dynamic)
{
ZYAN_ASSERT(list->allocator->allocate);
ZYAN_CHECK(list->allocator->allocate(list->allocator, (void**)node,
sizeof(ZyanListNode) + list->element_size, 1));
} else
{
if (list->first_unused)
{
*node = list->first_unused;
list->first_unused = (*node)->next;
} else
{
const ZyanUSize size = list->size * (sizeof(ZyanListNode) + list->element_size);
if (size + (sizeof(ZyanListNode) + list->element_size) > list->capacity)
{
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
}
*node = (ZyanListNode*)((ZyanU8*)list->buffer + size);
}
}
return ZYAN_STATUS_SUCCESS;
}
/**
* Frees memory of a node.
*
* @param list A pointer to the `ZyanList` instance.
* @param node A pointer to the `ZyanListNode` struct.
*
* @return A zyan status code.
*/
static ZyanStatus ZyanListDeallocateNode(ZyanList* list, ZyanListNode* node)
{
ZYAN_ASSERT(list);
ZYAN_ASSERT(node);
const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL);
if (is_dynamic)
{
ZYAN_ASSERT(list->allocator->deallocate);
ZYAN_CHECK(list->allocator->deallocate(list->allocator, (void*)node,
sizeof(ZyanListNode) + list->element_size, 1));
} else
{
node->next = list->first_unused;
list->first_unused = node;
}
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */
/* Exported functions */
/* ============================================================================================== */
/* ---------------------------------------------------------------------------------------------- */
/* Constructor and destructor */
/* ---------------------------------------------------------------------------------------------- */
#ifndef ZYAN_NO_LIBC
ZYAN_REQUIRES_LIBC ZyanStatus ZyanListInit(ZyanList* list, ZyanUSize element_size,
ZyanMemberProcedure destructor)
{
return ZyanListInitEx(list, element_size, destructor, ZyanAllocatorDefault());
}
#endif // ZYAN_NO_LIBC
ZyanStatus ZyanListInitEx(ZyanList* list, ZyanUSize element_size, ZyanMemberProcedure destructor,
ZyanAllocator* allocator)
{
if (!list || !element_size || !allocator)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
list->allocator = allocator;
list->size = 0;
list->element_size = element_size;
list->destructor = destructor;
list->head = ZYAN_NULL;
list->tail = ZYAN_NULL;
list->buffer = ZYAN_NULL;
list->capacity = 0;
list->first_unused = ZYAN_NULL;
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanListInitCustomBuffer(ZyanList* list, ZyanUSize element_size,
ZyanMemberProcedure destructor, void* buffer, ZyanUSize capacity)
{
if (!list || !element_size || !buffer || !capacity)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
list->allocator = ZYAN_NULL;
list->size = 0;
list->element_size = element_size;
list->destructor = destructor;
list->head = ZYAN_NULL;
list->tail = ZYAN_NULL;
list->buffer = buffer;
list->capacity = capacity;
list->first_unused = ZYAN_NULL;
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanListDestroy(ZyanList* list)
{
if (!list)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZYAN_ASSERT(list->element_size);
const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL);
ZyanListNode* node = (is_dynamic || list->destructor) ? list->head : ZYAN_NULL;
while (node)
{
if (list->destructor)
{
list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
}
ZyanListNode* const next = node->next;
if (is_dynamic)
{
ZYAN_CHECK(list->allocator->deallocate(list->allocator, node,
sizeof(ZyanListNode) + list->element_size, 1));
}
node = next;
}
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* Duplication */
/* ---------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* Item access */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanListGetHeadNode(const ZyanList* list, const ZyanListNode** node)
{
if (!list)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
*node = list->head;
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanListGetTailNode(const ZyanList* list, const ZyanListNode** node)
{
if (!list)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
*node = list->tail;
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanListGetPrevNode(const ZyanListNode** node)
{
if (!node || !*node)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
*node = (*node)->prev;
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanListGetNextNode(const ZyanListNode** node)
{
if (!node || !*node)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
*node = (*node)->next;
return ZYAN_STATUS_SUCCESS;
}
const void* ZyanListGetNodeData(const ZyanListNode* node)
{
if (!node)
{
return ZYAN_NULL;
}
return (const void*)ZYCORE_LIST_GET_NODE_DATA(node);
}
ZyanStatus ZyanListGetNodeDataEx(const ZyanListNode* node, const void** value)
{
if (!node)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
*value = (const void*)ZYCORE_LIST_GET_NODE_DATA(node);
return ZYAN_STATUS_SUCCESS;
}
void* ZyanListGetNodeDataMutable(const ZyanListNode* node)
{
if (!node)
{
return ZYAN_NULL;
}
return ZYCORE_LIST_GET_NODE_DATA(node);
}
ZyanStatus ZyanListGetNodeDataMutableEx(const ZyanListNode* node, void** value)
{
if (!node)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
*value = ZYCORE_LIST_GET_NODE_DATA(node);
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanListSetNodeData(const ZyanList* list, const ZyanListNode* node, const void* value)
{
if (!list || !node || !value)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
if (list->destructor)
{
list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
}
ZYAN_ASSERT(list->element_size);
ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), value, list->element_size);
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* Insertion */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanListPushBack(ZyanList* list, const void* item)
{
if (!list || !item)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZyanListNode* node;
ZYAN_CHECK(ZyanListAllocateNode(list, &node));
node->prev = list->tail;
node->next = ZYAN_NULL;
ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), item, list->element_size);
if (!list->head)
{
list->head = node;
list->tail = node;
} else
{
list->tail->next = node;
list->tail = node;
}
++list->size;
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanListPushFront(ZyanList* list, const void* item)
{
if (!list || !item)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZyanListNode* node;
ZYAN_CHECK(ZyanListAllocateNode(list, &node));
node->prev = ZYAN_NULL;
node->next = list->head;
ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), item, list->element_size);
if (!list->head)
{
list->head = node;
list->tail = node;
} else
{
list->head->prev= node;
list->head = node;
}
++list->size;
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanListEmplaceBack(ZyanList* list, void** item, ZyanMemberFunction constructor)
{
if (!list || !item)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZyanListNode* node;
ZYAN_CHECK(ZyanListAllocateNode(list, &node));
node->prev = list->tail;
node->next = ZYAN_NULL;
*item = ZYCORE_LIST_GET_NODE_DATA(node);
if (constructor)
{
constructor(*item);
}
if (!list->head)
{
list->head = node;
list->tail = node;
} else
{
list->tail->next = node;
list->tail = node;
}
++list->size;
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanListEmplaceFront(ZyanList* list, void** item, ZyanMemberFunction constructor)
{
if (!list || !item)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
ZyanListNode* node;
ZYAN_CHECK(ZyanListAllocateNode(list, &node));
node->prev = ZYAN_NULL;
node->next = list->head;
*item = ZYCORE_LIST_GET_NODE_DATA(node);
if (constructor)
{
constructor(*item);
}
if (!list->head)
{
list->head = node;
list->tail = node;
} else
{
list->head->prev= node;
list->head = node;
}
++list->size;
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* Deletion */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanListPopBack(ZyanList* list)
{
if (!list)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
if (!list->tail)
{
return ZYAN_STATUS_INVALID_OPERATION;
}
ZyanListNode* const node = list->tail;
if (list->destructor)
{
list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
}
list->tail = node->prev;
if (list->tail)
{
list->tail->next = ZYAN_NULL;
}
if (list->head == node)
{
list->head = list->tail;
}
--list->size;
return ZyanListDeallocateNode(list, node);
}
ZyanStatus ZyanListPopFront(ZyanList* list)
{
if (!list)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
if (!list->head)
{
return ZYAN_STATUS_INVALID_OPERATION;
}
ZyanListNode* const node = list->head;
if (list->destructor)
{
list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
}
list->head = node->next;
if (list->head)
{
list->head->prev = ZYAN_NULL;
}
if (list->tail == node)
{
list->tail = list->head;
}
--list->size;
return ZyanListDeallocateNode(list, node);
}
ZyanStatus ZyanListRemove(ZyanList* list, const ZyanListNode* node)
{
ZYAN_UNUSED(list);
ZYAN_UNUSED(node);
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanListRemoveRange(ZyanList* list, const ZyanListNode* first, const ZyanListNode* last)
{
ZYAN_UNUSED(list);
ZYAN_UNUSED(first);
ZYAN_UNUSED(last);
return ZYAN_STATUS_SUCCESS;
}
ZyanStatus ZyanListClear(ZyanList* list)
{
return ZyanListResizeEx(list, 0, ZYAN_NULL);
}
/* ---------------------------------------------------------------------------------------------- */
/* Searching */
/* ---------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------- */
/* Memory management */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanListResize(ZyanList* list, ZyanUSize size)
{
return ZyanListResizeEx(list, size, ZYAN_NULL);
}
ZyanStatus ZyanListResizeEx(ZyanList* list, ZyanUSize size, const void* initializer)
{
if (!list)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
if (size == list->size)
{
return ZYAN_STATUS_SUCCESS;
}
if (size == 0)
{
const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL);
ZyanListNode* node = (is_dynamic || list->destructor) ? list->head : ZYAN_NULL;
while (node)
{
if (list->destructor)
{
list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
}
ZyanListNode* const next = node->next;
if (is_dynamic)
{
ZYAN_CHECK(list->allocator->deallocate(list->allocator, node,
sizeof(ZyanListNode) + list->element_size, 1));
}
node = next;
}
list->size = 0;
list->head = 0;
list->tail = 0;
list->first_unused = ZYAN_NULL;
return ZYAN_STATUS_SUCCESS;
}
if (size > list->size)
{
ZyanListNode* node;
for (ZyanUSize i = list->size; i < size; ++i)
{
ZYAN_CHECK(ZyanListAllocateNode(list, &node));
node->prev = list->tail;
node->next = ZYAN_NULL;
if (initializer)
{
ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), initializer, list->element_size);
}
if (!list->head)
{
list->head = node;
list->tail = node;
} else
{
list->tail->next = node;
list->tail = node;
}
// `ZyanListAllocateNode` needs the list size
++list->size;
}
} else
{
for (ZyanUSize i = size; i < list->size; ++i)
{
ZyanListNode* const node = list->tail;
if (list->destructor)
{
list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
}
list->tail = node->prev;
if (list->tail)
{
list->tail->next = ZYAN_NULL;
}
ZYAN_CHECK(ZyanListDeallocateNode(list, node));
}
list->size = size;
}
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* Information */
/* ---------------------------------------------------------------------------------------------- */
ZyanStatus ZyanListGetSize(const ZyanList* list, ZyanUSize* size)
{
if (!list)
{
return ZYAN_STATUS_INVALID_ARGUMENT;
}
*size = list->size;
return ZYAN_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */

1098
externals/zycore/src/String.c vendored Normal file

File diff suppressed because it is too large Load Diff

848
externals/zycore/src/Vector.c vendored Normal file
View 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;
}
/* ---------------------------------------------------------------------------------------------- */
/* ============================================================================================== */

38
externals/zycore/src/Zycore.c vendored Normal file
View File

@@ -0,0 +1,38 @@
/***************************************************************************************************
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/Zycore.h>
/* ============================================================================================== */
/* Exported functions */
/* ============================================================================================== */
ZyanU64 ZycoreGetVersion(void)
{
return ZYCORE_VERSION;
}
/* ============================================================================================== */