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