Compare commits
51 Commits
types
...
abandoned_
| Author | SHA1 | Date | |
|---|---|---|---|
| d0ff4170be | |||
| 0d169433a4 | |||
| f78561ab59 | |||
| 1455b26558 | |||
| 66c00f6d6f | |||
| c49ab87286 | |||
| 40017d2ad0 | |||
| 0c35487ab3 | |||
| 9772bf6c43 | |||
| 7d8159d194 | |||
| 0f91f5373c | |||
| 94d6c4d8be | |||
| 757d9d5ae8 | |||
| 7ec5d242aa | |||
| 34450de16d | |||
| e0acb5b08a | |||
| 88e2393000 | |||
| c373f03490 | |||
| 32dc1e1a81 | |||
| 3fae966f63 | |||
| b0be90cbba | |||
| 9af63bac9c | |||
| b6e1fdc6fc | |||
| 82ad4b4bfb | |||
| 5b22053ff3 | |||
| 140a0b4d34 | |||
| 2d02e4cc66 | |||
| 57f0533f84 | |||
| af1ab56872 | |||
| b68f56840e | |||
| 025acf4c97 | |||
| 0557a45481 | |||
| 450ba063cf | |||
| 2cf3f76e70 | |||
| aecab5e5d7 | |||
| e0cb295f65 | |||
| bd2b3acec6 | |||
| e199c69315 | |||
| 811f644dec | |||
| 4080e7299b | |||
| 2ce705baee | |||
| 30e40047c5 | |||
| c5b6d7ba15 | |||
| 632cdd8765 | |||
| f25acf244d | |||
| d60b2ebdb3 | |||
| dbbea40bc3 | |||
| b2a1f3bc1c | |||
| 7f9c0691c0 | |||
| e85e4ee46e | |||
| 350c8ebcbe |
2
buildfiles/ev_str.c
Normal file
2
buildfiles/ev_str.c
Normal file
@@ -0,0 +1,2 @@
|
||||
#define EV_STR_IMPLEMENTATION
|
||||
#include "../ev_str.h"
|
||||
2
buildfiles/ev_vec.c
Normal file
2
buildfiles/ev_vec.c
Normal file
@@ -0,0 +1,2 @@
|
||||
#define EV_VEC_IMPLEMENTATION
|
||||
#include "../ev_vec.h"
|
||||
116
defines.h
116
defines.h
@@ -1,30 +1,100 @@
|
||||
#pragma once
|
||||
#ifndef EV_HEADERS_DEFINES_H
|
||||
#define EV_HEADERS_DEFINES_H
|
||||
|
||||
#ifndef EV_OS_WINDOWS
|
||||
# define EV_OS_WINDOWS 0
|
||||
#endif
|
||||
#ifndef EV_OS_LINUX
|
||||
# define EV_OS_LINUX 0
|
||||
#endif
|
||||
#ifndef EV_OS_IOS
|
||||
# define EV_OS_IOS 0
|
||||
#endif
|
||||
#ifndef EV_OS_MACOS
|
||||
# define EV_OS_MACOS 0
|
||||
#endif
|
||||
#ifndef EV_OS_ANDROID
|
||||
# define EV_OS_ANDROID 0
|
||||
#endif
|
||||
#if (EV_OS_WINDOWS || EV_OS_LINUX || EV_OS_IOS || EV_OS_MACOS || EV_OS_ANDROID)
|
||||
# define EV_OS_DEFINED 1
|
||||
#else
|
||||
# define EV_OS_DEFINED 0
|
||||
#endif
|
||||
|
||||
#ifndef EV_CC_MSVC
|
||||
# define EV_CC_MSVC 0
|
||||
#endif
|
||||
#ifndef EV_CC_GCC
|
||||
# define EV_CC_GCC 0
|
||||
#endif
|
||||
#ifndef EV_CC_CLANG
|
||||
# define EV_CC_CLANG 0
|
||||
#endif
|
||||
#if (EV_CC_MSVC || EV_CC_GCC || EV_CC_CLANG)
|
||||
# define EV_CC_DEFINED 1
|
||||
#else
|
||||
# define EV_CC_DEFINED 0
|
||||
#endif
|
||||
|
||||
// Operating System Detection
|
||||
#if defined(_WIN32)
|
||||
# define EV_OS_WINDOWS
|
||||
#elif defined(__linux__)
|
||||
# define EV_OS_LINUX
|
||||
#elif defined(__APPLE__)
|
||||
# include "TargetConditionals.h"
|
||||
# if defined(TARGET_OS_IPHONE)
|
||||
# define EV_OS_IOS
|
||||
# elif defined(TARGET_OS_MAC)
|
||||
# define EV_OS_MACOS
|
||||
# elif defined(__ANDROID__)
|
||||
# define EV_OS_ANDROID
|
||||
#if !EV_OS_DEFINED
|
||||
# if defined(_WIN32)
|
||||
# undef EV_OS_WINDOWS
|
||||
# define EV_OS_WINDOWS 1
|
||||
# elif defined(__linux__)
|
||||
# undef EV_OS_LINUX
|
||||
# define EV_OS_LINUX 1
|
||||
# elif defined(__APPLE__)
|
||||
# include "TargetConditionals.h"
|
||||
# if defined(TARGET_OS_IPHONE)
|
||||
# undef EV_OS_IOS
|
||||
# define EV_OS_IOS 1
|
||||
# elif defined(TARGET_OS_MAC)
|
||||
# undef EV_OS_MACOS
|
||||
# define EV_OS_MACOS 1
|
||||
# elif defined(__ANDROID__)
|
||||
# undef EV_OS_ANDROID
|
||||
# define EV_OS_ANDROID 1
|
||||
# endif
|
||||
# else
|
||||
# error EV_OS_UNKNOWN
|
||||
# endif
|
||||
#else
|
||||
# error EV_OS_UNKNOWN
|
||||
#endif
|
||||
|
||||
// Compiler Detection
|
||||
#if defined(_MSC_VER)
|
||||
# define EV_CC_MSVC
|
||||
#elif defined(__GNUC__)
|
||||
# define EV_CC_GCC
|
||||
#elif defined(__clang)
|
||||
# define EV_CC_CLANG
|
||||
#else
|
||||
# error EV_CC_UNKNOWN
|
||||
#if !EV_CC_DEFINED
|
||||
# if defined(_MSC_VER)
|
||||
# undef EV_CC_MSVC
|
||||
# define EV_CC_MSVC 1
|
||||
# elif defined(__GNUC__)
|
||||
# undef EV_CC_GCC
|
||||
# define EV_CC_GCC 1
|
||||
# elif defined(__clang)
|
||||
# undef EV_CC_CLANG
|
||||
# define EV_CC_CLANG 1
|
||||
# else
|
||||
# error EV_CC_UNKNOWN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef EV_BUILDTYPE_DEBUG
|
||||
# define EV_BUILDTYPE_DEBUG 0
|
||||
#endif
|
||||
#ifndef EV_BUILDTYPE_DEBUGOPT
|
||||
# define EV_BUILDTYPE_DEBUGOPT 0
|
||||
#endif
|
||||
#ifndef EV_BUILDTYPE_RELEASE
|
||||
# define EV_BUILDTYPE_RELEASE 0
|
||||
#endif
|
||||
#if (EV_BUILDTYPE_DEBUG || EV_BUILDTYPE_DEBUGOPT || EV_BUILDTYPE_RELEASE)
|
||||
# define EV_BUILDTYPE_DEFINED 1
|
||||
#else
|
||||
# define EV_BUILDTYPE_DEFINED 0
|
||||
#endif
|
||||
|
||||
#if !EV_BUILDTYPE_DEFINED
|
||||
# error "Buildtype not defined. Please define one of `EV_BUILDTYPE_{DEBUG,DEBUGOPT,RELEASE}`"
|
||||
#endif
|
||||
|
||||
#endif // EV_HEADERS_DEFINES_H
|
||||
|
||||
164
ev_hash.h
Normal file
164
ev_hash.h
Normal file
@@ -0,0 +1,164 @@
|
||||
#ifndef EV_HEADERS_HASH_H
|
||||
#define EV_HEADERS_HASH_H
|
||||
|
||||
#include "ev_internal.h"
|
||||
|
||||
/*!
|
||||
* \brief MurmurHash3 64-bit version. Returns 64-bit hash instead of 128
|
||||
*/
|
||||
u64 ev_hash_murmur3(const void *data, u32 len, u64 seed);
|
||||
|
||||
#ifdef EV_HASH_IMPLEMENTATION
|
||||
#undef EV_HASH_IMPLEMENTATION
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||
// domain. The author hereby disclaims copyright to this source code.
|
||||
|
||||
// Note - The x86 and x64 versions do _not_ produce the same results, as the
|
||||
// algorithms are optimized for their respective platforms. You can still
|
||||
// compile and run any of them on any platform, but your performance with the
|
||||
// non-native version will be less than optimal.
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Platform-specific functions and macros
|
||||
|
||||
// Microsoft Visual Studio
|
||||
|
||||
#if EV_CC_MSVC
|
||||
|
||||
#define ROTL64(x,y) _rotl64(x,y)
|
||||
#define BIG_CONSTANT(x) (x)
|
||||
|
||||
// Other compilers
|
||||
|
||||
#else // EV_CC_MSVC
|
||||
|
||||
static inline u64 rotl64 ( u64 x, i8 r )
|
||||
{
|
||||
return (x << r) | (x >> (64 - r));
|
||||
}
|
||||
|
||||
#define ROTL64(x,y) rotl64(x,y)
|
||||
#define BIG_CONSTANT(x) (x##LLU)
|
||||
|
||||
#endif // EV_CC_MSVC
|
||||
|
||||
#include "ev_macros.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Block read - if your platform needs to do endian-swapping or can only
|
||||
// handle aligned reads, do the conversion here
|
||||
|
||||
EV_FORCEINLINE u64 getblock64 ( const u64 * p, u32 i )
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finalization mix - force all bits of a hash block to avalanche
|
||||
|
||||
EV_FORCEINLINE u64 fmix64 ( u64 k )
|
||||
{
|
||||
k ^= k >> 33;
|
||||
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
|
||||
k ^= k >> 33;
|
||||
k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
|
||||
k ^= k >> 33;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void MurmurHash3_x64_128 ( const void * key, const u32 len,
|
||||
const u32 seed, void * out )
|
||||
{
|
||||
const u8 * data = (const u8*)key;
|
||||
const u32 nblocks = len / 16;
|
||||
|
||||
u64 h1 = seed;
|
||||
u64 h2 = seed;
|
||||
|
||||
const u64 c1 = BIG_CONSTANT(0x87c37b91114253d5);
|
||||
const u64 c2 = BIG_CONSTANT(0x4cf5ad432745937f);
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const u64 * blocks = (const u64 *)(data);
|
||||
|
||||
for(u32 i = 0; i < nblocks; i++)
|
||||
{
|
||||
u64 k1 = getblock64(blocks,i*2+0);
|
||||
u64 k2 = getblock64(blocks,i*2+1);
|
||||
|
||||
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
|
||||
|
||||
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
|
||||
|
||||
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
|
||||
|
||||
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const u8 * tail = (const u8*)(data + nblocks*16);
|
||||
|
||||
u64 k1 = 0;
|
||||
u64 k2 = 0;
|
||||
|
||||
switch(len & 15)
|
||||
{
|
||||
case 15: k2 ^= ((u64)tail[14]) << 48;
|
||||
case 14: k2 ^= ((u64)tail[13]) << 40;
|
||||
case 13: k2 ^= ((u64)tail[12]) << 32;
|
||||
case 12: k2 ^= ((u64)tail[11]) << 24;
|
||||
case 11: k2 ^= ((u64)tail[10]) << 16;
|
||||
case 10: k2 ^= ((u64)tail[ 9]) << 8;
|
||||
case 9: k2 ^= ((u64)tail[ 8]) << 0;
|
||||
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
|
||||
|
||||
case 8: k1 ^= ((u64)tail[ 7]) << 56;
|
||||
case 7: k1 ^= ((u64)tail[ 6]) << 48;
|
||||
case 6: k1 ^= ((u64)tail[ 5]) << 40;
|
||||
case 5: k1 ^= ((u64)tail[ 4]) << 32;
|
||||
case 4: k1 ^= ((u64)tail[ 3]) << 24;
|
||||
case 3: k1 ^= ((u64)tail[ 2]) << 16;
|
||||
case 2: k1 ^= ((u64)tail[ 1]) << 8;
|
||||
case 1: k1 ^= ((u64)tail[ 0]) << 0;
|
||||
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len; h2 ^= len;
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
h1 = fmix64(h1);
|
||||
h2 = fmix64(h2);
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
((u64*)out)[0] = h1;
|
||||
((u64*)out)[1] = h2;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
u64 ev_hash_murmur3(const void *data, u32 len, u64 seed)
|
||||
{
|
||||
u64 out[2];
|
||||
MurmurHash3_x64_128(data, len, (u32)seed, out);
|
||||
return *out;
|
||||
}
|
||||
|
||||
#endif // EV_HASH_IMPLEMENTATION
|
||||
|
||||
#endif // EV_HEADERS_HASH_H
|
||||
34
ev_internal.h
Normal file
34
ev_internal.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef EV_HEADERS_INTERNAL_H
|
||||
#define EV_HEADERS_INTERNAL_H
|
||||
|
||||
typedef signed char i8;
|
||||
typedef short int i16;
|
||||
typedef int i32;
|
||||
typedef long long int i64;
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short int u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long int u64;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
typedef _Bool bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
#define i8_const(v) (i8){v}
|
||||
#define i16_const(v) (i16){v}
|
||||
#define i32_const(v) (i32){v}
|
||||
#define i64_const(v) (i64){v}
|
||||
|
||||
#define u8_const(v) (u8){v}
|
||||
#define u16_const(v) (u16){v}
|
||||
#define u32_const(v) (u32){v}
|
||||
#define u64_const(v) (u64){v}
|
||||
|
||||
#define f32_const(v) (f32){v}
|
||||
#define f64_const(v) (f64){v}
|
||||
|
||||
#endif // EV_HEADERS_INTERNAL_H
|
||||
157
ev_macros.h
157
ev_macros.h
@@ -1,7 +1,26 @@
|
||||
#pragma once
|
||||
#ifndef EV_HEADERS_MACROS_H
|
||||
#define EV_HEADERS_MACROS_H
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
// Internal Usage
|
||||
#define __EV_MACRO_IF_ELSE(cond) EV_CAT(__EV_MACRO_IF_,cond)
|
||||
#define __EV_MACRO_IF_1(...) __VA_ARGS__ __EV_MACRO_IF_1_ELSE
|
||||
#define __EV_MACRO_IF_0(...) __EV_MACRO_IF_0_ELSE
|
||||
#define __EV_MACRO_IF_1_ELSE(...)
|
||||
#define __EV_MACRO_IF_0_ELSE(...) __VA_ARGS__
|
||||
|
||||
#define __EV_MACRO_SECOND(a,b,...) b
|
||||
|
||||
#define __EV_MACRO_IS_PROBE(...) __EV_MACRO_SECOND(__VA_ARGS__,0)
|
||||
#define __EV_MACRO_PROBE() ~,1
|
||||
|
||||
#define __EV_MACRO_NOT(x) __EV_MACRO_IS_PROBE(EV_CAT(__EV_MACRO_NOT_,x))
|
||||
#define __EV_MACRO_NOT_0 __EV_MACRO_PROBE()
|
||||
|
||||
#define __EV_MACRO_BOOL(x) __EV_MACRO_NOT(__EV_MACRO_NOT(x))
|
||||
// End Of: Internal Usage
|
||||
|
||||
/*!
|
||||
* \brief Macro to get a type's alignment
|
||||
*/
|
||||
@@ -18,21 +37,42 @@
|
||||
*/
|
||||
#define EV_UNALIGNED
|
||||
|
||||
#if defined(EV_CC_MSVC)
|
||||
#define EV_PRAGMA(...) _Pragma(EV_STRINGIZE(__VA_ARGS__))
|
||||
|
||||
#if ( EV_CC_MSVC )
|
||||
# define EV_WARNING_DISABLE_MSVC(w) EV_PRAGMA(warning(disable:w))
|
||||
# define EV_WARNING_DISABLE_CLANG(...)
|
||||
# define EV_WARNING_DISABLE_GCC(...)
|
||||
# define EV_WARNING_PUSH() EV_PRAGMA(warning(push))
|
||||
# define EV_WARNING_POP() EV_PRAGMA(warning(pop))
|
||||
# define EV_EXPORT __declspec(dllexport)
|
||||
# define EV_IMPORT __declspec(dllimport)
|
||||
# define EV_UNUSED
|
||||
#elif defined(EV_CC_GCC) || defined(EV_CC_CLANG)
|
||||
# define EV_FORCEINLINE __forceinline
|
||||
#elif ( EV_CC_GCC || EV_CC_CLANG )
|
||||
# define EV_EXPORT __attribute__((visibility("default")))
|
||||
# define EV_IMPORT
|
||||
# define EV_UNUSED __attribute__((unused))
|
||||
# define EV_FORCEINLINE inline __attribute__((always_inline))
|
||||
# if ( EV_CC_GCC )
|
||||
# define EV_PRAGMA_CC_NAME GCC
|
||||
# define EV_WARNING_DISABLE_GCC(w) EV_PRAGMA(EV_PRAGMA_CC_NAME diagnostic ignored "-W"w)
|
||||
# define EV_WARNING_DISABLE_CLANG(...)
|
||||
# elif ( EV_CC_CLANG )
|
||||
# define EV_PRAGMA_CC_NAME clang
|
||||
# define EV_WARNING_DISABLE_CLANG(w) EV_PRAGMA(EV_PRAGMA_CC_NAME diagnostic ignored "-W"w)
|
||||
# define EV_WARNING_DISABLE_GCC(...)
|
||||
# endif
|
||||
# define EV_WARNING_PUSH() EV_PRAGMA(EV_PRAGMA_CC_NAME diagnostic push)
|
||||
# define EV_WARNING_POP() EV_PRAGMA(EV_PRAGMA_CC_NAME diagnostic pop)
|
||||
# define EV_WARNING_DISABLE_MSVC(...)
|
||||
#else
|
||||
# error "Unknown Compiler"
|
||||
#endif
|
||||
|
||||
#if defined(EV_CC_MSVC)
|
||||
#if ( EV_CC_MSVC )
|
||||
# define _EV_BREAK_IF(cond) cond ? __debugbreak():0
|
||||
#elif defined(EV_CC_GCC) || defined(EV_CC_CLANG)
|
||||
#elif ( EV_CC_GCC || EV_CC_CLANG )
|
||||
# include <signal.h>
|
||||
# define _EV_BREAK_IF(cond) cond ? raise(SIGTRAP):0
|
||||
#else
|
||||
@@ -43,6 +83,17 @@
|
||||
# define _EV_BREAK_IF(cond)
|
||||
#endif
|
||||
|
||||
#if ( EV_BUILDTYPE_DEBUG || EV_BUILDTYPE_DEBUGOPT )
|
||||
# define EV_DBGBREAK_IF(...) _EV_BREAK_IF(__VA_ARGS__)
|
||||
# define EV_DEBUG(...) __VA_ARGS__
|
||||
#include <assert.h>
|
||||
# define EV_UNIMPLEMENTED() assert(!"Hit an unimplemented path")
|
||||
#else
|
||||
# define EV_DBGBREAK_IF(...)
|
||||
# define EV_DEBUG(...)
|
||||
# define EV_UNIMPLEMENTED()
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief Macro to get the size of a compile-time array.
|
||||
*/
|
||||
@@ -60,6 +111,16 @@
|
||||
#define EV_STRINGIZE(...) EV_STRINGIZE_IMPL(__VA_ARGS__)
|
||||
#define EV_STRINGIZE_IMPL(...) #__VA_ARGS__
|
||||
|
||||
/*!
|
||||
* \brief Returns head of list (a,b,c) -> a
|
||||
*/
|
||||
#define EV_HEAD(h,...) h
|
||||
|
||||
/*!
|
||||
* \brief Returns tail of list (a,b,c) -> b,c
|
||||
*/
|
||||
#define EV_TAIL(h,...) __VA_ARGS__
|
||||
|
||||
// Used for the removal of parenthesis around tokens
|
||||
#define EV_EXPAND(...) __VA_ARGS__
|
||||
|
||||
@@ -70,11 +131,21 @@
|
||||
/*!
|
||||
* \brief Macro that returns the number of arguments passed to it.
|
||||
*/
|
||||
#define EV_VA_ARGS_NARG(...) EV_VA_ARGS_NARG_IMPL(__VA_ARGS__, EV_VA_ARGS_RSEQ_N())
|
||||
#define EV_VA_ARGS_NARG(...) EV_VA_ARGS_NARG_IMPL(_, ## __VA_ARGS__, EV_VA_ARGS_RSEQ_N())
|
||||
#define EV_VA_ARGS_NARG_IMPL(...) EV_VA_ARGS_ARG_N(__VA_ARGS__)
|
||||
#define EV_VA_ARGS_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, N, ...) N
|
||||
#define EV_VA_ARGS_ARG_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, N, ...) N
|
||||
#define EV_VA_ARGS_RSEQ_N() 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
|
||||
/*!
|
||||
* \brief Similar functionality to `__VA_OPT__`
|
||||
* Used as follows:
|
||||
* ```c
|
||||
* #define TEST(...) EV_VA_OPT(__VA_ARGS__)("Not ")"Empty"
|
||||
* ```
|
||||
*/
|
||||
#define EV_VA_OPT(...) __EV_MACRO_IF_ELSE(__EV_MACRO_NOT(EV_VA_ARGS_NARG(__VA_ARGS__)))()
|
||||
#define EV_VA_OPT_ELSE(...) __EV_MACRO_IF_ELSE(__EV_MACRO_BOOL(EV_VA_ARGS_NARG(__VA_ARGS__)))
|
||||
|
||||
/*!
|
||||
* \brief Calls the passed macro for each element.
|
||||
* \note Maximum number of elements to iterate over is 64 elements.
|
||||
@@ -144,3 +215,75 @@
|
||||
#define __EV_INTERNAL_FOREACH62(OP, a, ...) OP(a) __EV_INTERNAL_FOREACH61(OP, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH63(OP, a, ...) OP(a) __EV_INTERNAL_FOREACH62(OP, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH64(OP, a, ...) OP(a) __EV_INTERNAL_FOREACH63(OP, __VA_ARGS__)
|
||||
|
||||
/*!
|
||||
* \brief Same as EV_FOREACH but allows passing a UDATA token
|
||||
* \note Maximum number of elements to iterate over is 64 elements.
|
||||
*/
|
||||
#define EV_FOREACH_UDATA(OP, UDATA, ...) EV_CAT(EV_CAT(__EV_INTERNAL_FOREACH, EV_VA_ARGS_NARG(__VA_ARGS__)),_UDATA)(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH1_UDATA( OP, UDATA, a ) OP(UDATA, a)
|
||||
#define __EV_INTERNAL_FOREACH2_UDATA( OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH1_UDATA( OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH3_UDATA( OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH2_UDATA( OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH4_UDATA( OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH3_UDATA( OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH5_UDATA( OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH4_UDATA( OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH6_UDATA( OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH5_UDATA( OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH7_UDATA( OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH6_UDATA( OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH8_UDATA( OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH7_UDATA( OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH9_UDATA( OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH8_UDATA( OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH10_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH9_UDATA( OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH11_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH10_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH12_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH11_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH13_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH12_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH14_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH13_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH15_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH14_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH16_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH15_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH17_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH16_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH18_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH17_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH19_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH18_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH20_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH19_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH21_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH20_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH22_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH21_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH23_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH22_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH24_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH23_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH25_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH24_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH26_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH25_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH27_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH26_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH28_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH27_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH29_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH28_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH30_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH29_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH31_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH30_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH32_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH31_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH33_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH32_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH34_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH33_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH35_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH34_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH36_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH35_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH37_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH36_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH38_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH37_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH39_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH38_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH40_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH39_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH41_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH40_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH42_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH41_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH43_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH42_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH44_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH43_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH45_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH44_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH46_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH45_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH47_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH46_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH48_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH47_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH49_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH48_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH50_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH49_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH51_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH50_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH52_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH51_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH53_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH52_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH54_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH53_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH55_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH54_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH56_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH55_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH57_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH56_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH58_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH57_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH59_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH58_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH60_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH59_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH61_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH60_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH62_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH61_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH63_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH62_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
#define __EV_INTERNAL_FOREACH64_UDATA(OP, UDATA, a, ...) OP(UDATA, a) __EV_INTERNAL_FOREACH63_UDATA(OP, UDATA, __VA_ARGS__)
|
||||
|
||||
#endif // EV_HEADERS_MACROS_H
|
||||
|
||||
@@ -1,83 +1,100 @@
|
||||
#ifndef EV_HEADERS_LIMITS_H
|
||||
#define EV_HEADERS_LIMITS_H
|
||||
|
||||
#include "ev_types.h"
|
||||
|
||||
struct Int8Data { i8 MIN; i8 MAX; };
|
||||
struct Int16Data { i16 MIN; i16 MAX; };
|
||||
struct Int32Data { i32 MIN; i32 MAX; };
|
||||
struct Int64Data { i64 MIN; i64 MAX; };
|
||||
|
||||
struct UInt8Data { u8 MIN; u8 MAX; };
|
||||
struct UInt16Data { u16 MIN; u16 MAX; };
|
||||
struct UInt32Data { u32 MIN; u32 MAX; };
|
||||
struct UInt64Data { u64 MIN; u64 MAX; };
|
||||
|
||||
struct Float32Data { f32 MIN; f32 MAX; f32 MIN_POS; f32 EPS; };
|
||||
struct Float64Data { f64 MIN; f64 MAX; f64 MIN_POS; f64 EPS; };
|
||||
|
||||
static const struct Int8Data Int8 =
|
||||
{
|
||||
.MIN = -128,
|
||||
.MAX = 127
|
||||
};
|
||||
|
||||
static const struct Int16Data Int16 =
|
||||
{
|
||||
.MIN = -32767-1,
|
||||
.MAX = 32767
|
||||
};
|
||||
|
||||
static const struct Int32Data Int32 =
|
||||
{
|
||||
.MIN = -2147483647-1,
|
||||
.MAX = 2147483647
|
||||
};
|
||||
|
||||
static const struct Int64Data Int64 =
|
||||
{
|
||||
.MIN = -(9223372036854775807LL)-1,
|
||||
.MAX = 9223372036854775807LL
|
||||
};
|
||||
|
||||
static const struct UInt8Data UInt8 =
|
||||
{
|
||||
.MIN = 0,
|
||||
.MAX = 255
|
||||
};
|
||||
|
||||
static const struct UInt16Data UInt16 =
|
||||
{
|
||||
.MIN = 0,
|
||||
.MAX = 65535
|
||||
};
|
||||
|
||||
static const struct UInt32Data UInt32 =
|
||||
{
|
||||
.MIN = 0,
|
||||
.MAX = 4294967295U
|
||||
};
|
||||
|
||||
static const struct UInt64Data UInt64 =
|
||||
{
|
||||
.MIN = 0,
|
||||
.MAX = 18446744073709551615ULL
|
||||
};
|
||||
|
||||
static const struct Float32Data Float32 =
|
||||
{
|
||||
.MIN_POS = 1.175494351e-38,
|
||||
.MIN = -3.402823466e+38,
|
||||
.MAX = 3.402823466e+38,
|
||||
.EPS = 1.192093e-07
|
||||
};
|
||||
|
||||
static const struct Float64Data Float64 =
|
||||
{
|
||||
.MIN_POS = 2.2250738585072014e-308,
|
||||
.MIN = -1.7976931348623158e+308,
|
||||
.MAX = 1.7976931348623158e+308,
|
||||
.EPS = 2.2204460492503131e-016
|
||||
};
|
||||
|
||||
#endif // EV_HEADERS_LIMITS_H
|
||||
#ifndef EV_HEADERS_NUMERIC_H
|
||||
#define EV_HEADERS_NUMERIC_H
|
||||
|
||||
#include "ev_internal.h"
|
||||
#include "ev_types.h"
|
||||
|
||||
// Signed integers
|
||||
TYPEDATA_GEN(i8);
|
||||
TYPEDATA_GEN(i16);
|
||||
TYPEDATA_GEN(i32);
|
||||
TYPEDATA_GEN(i64);
|
||||
|
||||
// Unsigned integers
|
||||
TYPEDATA_GEN(u8 );
|
||||
TYPEDATA_GEN(u16);
|
||||
TYPEDATA_GEN(u32);
|
||||
TYPEDATA_GEN(u64);
|
||||
|
||||
// Floating-Point Numbers
|
||||
TYPEDATA_GEN(f32);
|
||||
TYPEDATA_GEN(f64);
|
||||
|
||||
struct Int8Data { i8 MIN; i8 MAX; };
|
||||
struct Int16Data { i16 MIN; i16 MAX; };
|
||||
struct Int32Data { i32 MIN; i32 MAX; };
|
||||
struct Int64Data { i64 MIN; i64 MAX; };
|
||||
|
||||
struct UInt8Data { u8 MIN; u8 MAX; };
|
||||
struct UInt16Data { u16 MIN; u16 MAX; };
|
||||
struct UInt32Data { u32 MIN; u32 MAX; };
|
||||
struct UInt64Data { u64 MIN; u64 MAX; };
|
||||
|
||||
struct Float32Data { f32 MIN; f32 MAX; f32 MIN_POS; f32 EPS; };
|
||||
struct Float64Data { f64 MIN; f64 MAX; f64 MIN_POS; f64 EPS; };
|
||||
|
||||
static const struct Int8Data Int8 =
|
||||
{
|
||||
.MIN = -128,
|
||||
.MAX = 127
|
||||
};
|
||||
|
||||
static const struct Int16Data Int16 =
|
||||
{
|
||||
.MIN = -32767-1,
|
||||
.MAX = 32767
|
||||
};
|
||||
|
||||
static const struct Int32Data Int32 =
|
||||
{
|
||||
.MIN = -2147483647-1,
|
||||
.MAX = 2147483647
|
||||
};
|
||||
|
||||
static const struct Int64Data Int64 =
|
||||
{
|
||||
.MIN = -(9223372036854775807LL)-1,
|
||||
.MAX = 9223372036854775807LL
|
||||
};
|
||||
|
||||
static const struct UInt8Data UInt8 =
|
||||
{
|
||||
.MIN = 0,
|
||||
.MAX = 255
|
||||
};
|
||||
|
||||
static const struct UInt16Data UInt16 =
|
||||
{
|
||||
.MIN = 0,
|
||||
.MAX = 65535
|
||||
};
|
||||
|
||||
static const struct UInt32Data UInt32 =
|
||||
{
|
||||
.MIN = 0,
|
||||
.MAX = 4294967295U
|
||||
};
|
||||
|
||||
static const struct UInt64Data UInt64 =
|
||||
{
|
||||
.MIN = 0,
|
||||
.MAX = 18446744073709551615ULL
|
||||
};
|
||||
|
||||
static const struct Float32Data Float32 =
|
||||
{
|
||||
.MIN_POS = 1.175494351e-38f,
|
||||
.MIN = -3.402823466e+38f,
|
||||
.MAX = 3.402823466e+38f,
|
||||
.EPS = 1.192093e-07f
|
||||
};
|
||||
|
||||
static const struct Float64Data Float64 =
|
||||
{
|
||||
.MIN_POS = 2.2250738585072014e-308,
|
||||
.MIN = -1.7976931348623158e+308,
|
||||
.MAX = 1.7976931348623158e+308,
|
||||
.EPS = 2.2204460492503131e-016
|
||||
};
|
||||
|
||||
#endif // EV_HEADERS_NUMERIC_H
|
||||
678
ev_str.h
Normal file
678
ev_str.h
Normal file
@@ -0,0 +1,678 @@
|
||||
/*!
|
||||
* \file ev_str.h
|
||||
*/
|
||||
#ifndef EV_STR_HEADER
|
||||
#define EV_STR_HEADER
|
||||
|
||||
#include "ev_types.h"
|
||||
#include "ev_numeric.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define EV_STR_evstring_MAGIC (0x65767374)
|
||||
|
||||
#ifdef EV_STR_SHARED
|
||||
#if defined (EV_STR_IMPL)
|
||||
#define EV_STR_API EV_EXPORT
|
||||
#else
|
||||
#define EV_STR_API EV_IMPORT
|
||||
#endif
|
||||
#else
|
||||
#define EV_STR_API
|
||||
#endif
|
||||
|
||||
#if !defined(ev_str_malloc) && !defined(ev_str_free) && !defined(ev_str_realloc)
|
||||
#include <stdlib.h>
|
||||
#ifndef ev_str_malloc
|
||||
#define ev_str_malloc malloc
|
||||
#endif
|
||||
#ifndef ev_str_free
|
||||
#define ev_str_free free
|
||||
#endif
|
||||
#ifndef ev_str_realloc
|
||||
#define ev_str_realloc realloc
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef EV_STR_GROWTH_FACTOR
|
||||
/*!
|
||||
* \brief Rate at which an evstring grows whenever a resize is needed
|
||||
*/
|
||||
#define EV_STR_GROWTH_FACTOR 3 / 2
|
||||
#endif
|
||||
|
||||
typedef char *evstring;
|
||||
TYPEDATA_GEN(evstring);
|
||||
|
||||
typedef enum {
|
||||
EV_STR_ERR_NONE = 0,
|
||||
EV_STR_ERR_OOM = -1,
|
||||
} evstring_error_t;
|
||||
TYPEDATA_GEN(evstring_error_t, DEFAULT(EV_STR_ERR_NONE));
|
||||
|
||||
struct evstr_meta_t {
|
||||
EV_DEBUG(u64 magic;)
|
||||
u64 length;
|
||||
u64 size;
|
||||
enum {
|
||||
EV_STR_ALLOCATION_TYPE_STACK,
|
||||
EV_STR_ALLOCATION_TYPE_HEAP
|
||||
} allocationType;
|
||||
};
|
||||
|
||||
#define __ev_strlen_const sizeof
|
||||
#define evstr(str) __evstr_impl(str, __ev_strlen_const(str))
|
||||
#define __evstr_impl(str, len) \
|
||||
(( struct { struct evstr_meta_t meta; char data[len]; } ) { \
|
||||
EV_DEBUG(.meta.magic = EV_STR_evstring_MAGIC,) \
|
||||
.meta.length = len-1, \
|
||||
.meta.size = len, \
|
||||
.meta.allocationType = EV_STR_ALLOCATION_TYPE_STACK, \
|
||||
.data = str \
|
||||
}).data
|
||||
|
||||
typedef struct evstring_view {
|
||||
evstring data;
|
||||
u64 offset;
|
||||
u64 len;
|
||||
} evstring_view;
|
||||
|
||||
#define evstring_newGeneric(str) _Generic((str), \
|
||||
evstring_view: evstring_newFromView, \
|
||||
default: evstring_newFromStr\
|
||||
)(str)
|
||||
|
||||
#define evstring_new(str, ...) EV_VA_OPT_ELSE(__VA_ARGS__)(evstring_newFmt(str, __VA_ARGS__))(evstring_newGeneric(str))
|
||||
|
||||
#define evstring_pushGeneric(str, push) _Generic((push), \
|
||||
char: evstring_pushChar, \
|
||||
evstring_view: evstring_pushView, \
|
||||
default: evstring_pushStr \
|
||||
)(str, push)
|
||||
|
||||
#define evstring_push(str, push, ...) \
|
||||
EV_VA_OPT_ELSE(__VA_ARGS__)(evstring_pushFmt(str, push, __VA_ARGS__))(evstring_pushGeneric(str, push))
|
||||
|
||||
EV_STR_API evstring
|
||||
evstring_newFromStr(
|
||||
const char *str);
|
||||
|
||||
EV_STR_API evstring
|
||||
evstring_newFromView(
|
||||
evstring_view v);
|
||||
|
||||
EV_STR_API void
|
||||
evstring_free(
|
||||
evstring s);
|
||||
|
||||
EV_STR_API u64
|
||||
evstring_getLength(
|
||||
const evstring s);
|
||||
|
||||
EV_STR_API evstring_error_t
|
||||
evstring_setLength(
|
||||
evstring *s,
|
||||
size_t newLength);
|
||||
|
||||
EV_STR_API i32
|
||||
evstring_cmp(
|
||||
const evstring s1,
|
||||
const evstring s2);
|
||||
|
||||
EV_STR_API evstring_error_t
|
||||
evstring_pushChar(
|
||||
evstring *s,
|
||||
char c);
|
||||
|
||||
EV_STR_API evstring_error_t
|
||||
evstring_pushStr(
|
||||
evstring *s,
|
||||
const char *data);
|
||||
|
||||
EV_STR_API evstring_error_t
|
||||
evstring_pushFmt(
|
||||
evstring *s,
|
||||
const char *fmt,
|
||||
...);
|
||||
|
||||
EV_STR_API evstring
|
||||
evstring_newFromView(
|
||||
evstring_view view);
|
||||
|
||||
EV_STR_API evstring_view
|
||||
evstring_slice(
|
||||
const evstring s,
|
||||
i64 begin,
|
||||
i64 end);
|
||||
|
||||
EV_STR_API i32
|
||||
evstring_pushView(
|
||||
evstring *s,
|
||||
evstring_view ref);
|
||||
|
||||
EV_STR_API void
|
||||
evstring_clear(
|
||||
evstring *s);
|
||||
|
||||
EV_STR_API evstring
|
||||
evstring_newFmt(
|
||||
const char *fmt,
|
||||
...);
|
||||
|
||||
EV_STR_API u64
|
||||
evstring_findAll(
|
||||
const evstring text,
|
||||
const evstring query,
|
||||
evstring_view *results);
|
||||
|
||||
EV_STR_API evstring_view
|
||||
evstring_findFirst(
|
||||
const evstring text,
|
||||
const evstring query);
|
||||
|
||||
evstring_view
|
||||
__evstring_findFirst_impl(
|
||||
evstring_view text,
|
||||
evstring_view query);
|
||||
|
||||
EV_STR_API evstring
|
||||
evstring_replaceFirst(
|
||||
const evstring text,
|
||||
const evstring query,
|
||||
const evstring replacement);
|
||||
|
||||
EV_STR_API i64
|
||||
evstring_findFirstChar(
|
||||
const evstring text,
|
||||
const char c);
|
||||
|
||||
EV_STR_API i64
|
||||
evstring_findLastChar(
|
||||
const evstring text,
|
||||
const char c);
|
||||
|
||||
#if defined(EV_STR_IMPLEMENTATION)
|
||||
|
||||
#if EV_OS_WINDOWS
|
||||
#pragma comment(lib, "legacy_stdio_definitions.lib")
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define META(s) (((struct evstr_meta_t *)(s)) - 1)
|
||||
|
||||
#if EV_BUILDTYPE_DEBUG || EV_BUILDTYPE_DEBUGOPT
|
||||
#define evstr_asserttype(str) \
|
||||
assert(META(str)->magic == EV_STR_evstring_MAGIC)
|
||||
#else
|
||||
#define evstr_asserttype(str)
|
||||
#endif
|
||||
|
||||
evstring_error_t
|
||||
evstring_addSpace(
|
||||
evstring *s,
|
||||
u64 space);
|
||||
|
||||
evstring_error_t
|
||||
evstring_pushFmt_v(
|
||||
evstring *s,
|
||||
const char *fmt,
|
||||
va_list args);
|
||||
|
||||
evstring
|
||||
evstring_new_impl(
|
||||
const char *data,
|
||||
u64 len)
|
||||
{
|
||||
u64 size = sizeof(struct evstr_meta_t) + len + 1;
|
||||
|
||||
void *p = ev_str_malloc(size);
|
||||
assert(p); // Raised if malloc fails
|
||||
|
||||
struct evstr_meta_t *meta = (struct evstr_meta_t *)p;
|
||||
EV_DEBUG
|
||||
(
|
||||
meta->magic = EV_STR_evstring_MAGIC;
|
||||
)
|
||||
meta->length = len;
|
||||
meta->size = size;
|
||||
meta->allocationType = EV_STR_ALLOCATION_TYPE_HEAP;
|
||||
|
||||
evstring s = (evstring)(meta + 1);
|
||||
if(len > 0) {
|
||||
memcpy(s, data, len);
|
||||
}
|
||||
s[len] = '\0';
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
evstring
|
||||
evstring_newFmt_v(
|
||||
const char *fmt,
|
||||
va_list args)
|
||||
{
|
||||
va_list test;
|
||||
va_copy(test, args);
|
||||
i32 len = vsnprintf(NULL, 0, fmt, test);
|
||||
if(len < 0) {
|
||||
return EV_INVALID(evstring);
|
||||
}
|
||||
evstring res = evstring_new_impl(NULL, 0);
|
||||
evstring_setLength(&res, len);
|
||||
vsnprintf(res, len + 1, fmt, args);
|
||||
|
||||
va_end(test);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
evstring
|
||||
evstring_newFmt(
|
||||
const char *fmt,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
evstring res = evstring_newFmt_v(fmt, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
evstring
|
||||
evstring_newFromStr(
|
||||
const char *str)
|
||||
{
|
||||
u64 len = strlen(str);
|
||||
return evstring_new_impl(str, len);
|
||||
}
|
||||
|
||||
evstring
|
||||
evstring_newFromView(
|
||||
evstring_view v)
|
||||
{
|
||||
return evstring_new_impl(v.data + v.offset, v.len);
|
||||
}
|
||||
|
||||
void
|
||||
evstring_free(
|
||||
evstring s)
|
||||
{
|
||||
evstr_asserttype(s);
|
||||
if(META(s)->allocationType == EV_STR_ALLOCATION_TYPE_HEAP) {
|
||||
free(META(s));
|
||||
}
|
||||
}
|
||||
|
||||
u64
|
||||
evstring_getLength(
|
||||
const evstring s)
|
||||
{
|
||||
evstr_asserttype(s);
|
||||
return META(s)->length;
|
||||
}
|
||||
|
||||
evstring_error_t
|
||||
evstring_setSize(
|
||||
evstring *s,
|
||||
size_t newsize)
|
||||
{
|
||||
evstr_asserttype(*s);
|
||||
struct evstr_meta_t *meta = META(*s);
|
||||
if(meta->allocationType == EV_STR_ALLOCATION_TYPE_STACK) {
|
||||
return EV_STR_ERR_OOM;
|
||||
}
|
||||
|
||||
if(meta->size == newsize) {
|
||||
return EV_STR_ERR_NONE;
|
||||
}
|
||||
|
||||
void *buf = (void*)meta;
|
||||
void *tmp = ev_str_realloc(buf, sizeof(struct evstr_meta_t) + newsize);
|
||||
|
||||
if (!tmp) {
|
||||
return EV_STR_ERR_OOM;
|
||||
}
|
||||
|
||||
if(buf != tmp) { // Reallocation caused memory to be moved
|
||||
buf = tmp;
|
||||
meta = (struct evstr_meta_t *)buf;
|
||||
*s = (evstring)(meta+1);
|
||||
}
|
||||
|
||||
meta->size = newsize;
|
||||
return EV_STR_ERR_NONE;
|
||||
}
|
||||
|
||||
evstring_error_t
|
||||
evstring_grow(
|
||||
evstring *s)
|
||||
{
|
||||
evstr_asserttype(*s);
|
||||
return evstring_setSize(s, META(*s)->size * EV_STR_GROWTH_FACTOR);
|
||||
}
|
||||
|
||||
evstring_error_t
|
||||
evstring_setLength(
|
||||
evstring *s,
|
||||
size_t newlen)
|
||||
{
|
||||
evstr_asserttype(*s);
|
||||
struct evstr_meta_t *meta = META(*s);
|
||||
if(newlen == meta->length) {
|
||||
return EV_STR_ERR_NONE;
|
||||
}
|
||||
|
||||
u64 required_size = sizeof(struct evstr_meta_t) + newlen + 1;
|
||||
while(required_size > meta->size) {
|
||||
evstring_error_t grow_err = evstring_grow(s);
|
||||
if(grow_err) {
|
||||
return grow_err;
|
||||
}
|
||||
meta = META(*s);
|
||||
}
|
||||
meta->length = newlen;
|
||||
|
||||
return EV_STR_ERR_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
evstring_clear(
|
||||
evstring *s)
|
||||
{
|
||||
evstr_asserttype(*s);
|
||||
evstring_setLength(s, 0);
|
||||
}
|
||||
|
||||
i32
|
||||
evstring_cmp(
|
||||
const evstring s1,
|
||||
const evstring s2)
|
||||
{
|
||||
evstr_asserttype(s1);
|
||||
evstr_asserttype(s2);
|
||||
u64 len1 = evstring_getLength(s1);
|
||||
u64 len2 = evstring_getLength(s2);
|
||||
if(len1 != len2) {
|
||||
return 1;
|
||||
}
|
||||
return memcmp(s1, s2, len1);
|
||||
}
|
||||
|
||||
|
||||
evstring_error_t
|
||||
evstring_push_impl(
|
||||
evstring *s,
|
||||
u64 sz,
|
||||
const char *data)
|
||||
{
|
||||
evstr_asserttype(*s);
|
||||
struct evstr_meta_t *meta = META(*s);
|
||||
|
||||
// TODO Find a more efficient approach?
|
||||
u64 required_size = sizeof(struct evstr_meta_t) + meta->length + sz + 1;
|
||||
while(required_size > meta->size) { // `<=` because of the null terminator
|
||||
evstring_error_t grow_err = evstring_grow(s);
|
||||
if(grow_err != EV_STR_ERR_NONE) {
|
||||
return grow_err;
|
||||
}
|
||||
meta = META(*s);
|
||||
}
|
||||
|
||||
memcpy((*s) + meta->length, data, sz);
|
||||
printf("Memcpy: dst = (*s {%p}) + meta->length {%llu}, src = data {%p}, size = sz {%llu}\n", *s, meta->length, data, sz);
|
||||
meta->length += sz;
|
||||
|
||||
(*s)[meta->length] = '\0';
|
||||
return EV_STR_ERR_NONE;
|
||||
}
|
||||
|
||||
evstring_error_t
|
||||
evstring_pushChar(
|
||||
evstring *s,
|
||||
char c)
|
||||
{
|
||||
evstr_asserttype(*s);
|
||||
return evstring_push_impl(s, 1, &c);
|
||||
}
|
||||
|
||||
evstring_error_t
|
||||
evstring_pushStr(
|
||||
evstring *s,
|
||||
const char *data)
|
||||
{
|
||||
evstr_asserttype(*s);
|
||||
// TODO: Check that data is not within the range of *s
|
||||
return evstring_push_impl(s,strlen(data),data);
|
||||
}
|
||||
|
||||
evstring_error_t
|
||||
evstring_pushView(
|
||||
evstring *s,
|
||||
evstring_view v)
|
||||
{
|
||||
evstr_asserttype(*s);
|
||||
assert(*s != v.data && " *s might be realloc'ed in a push operation. This would lead to the view pointing to a free'd block of memory.");
|
||||
return evstring_push_impl(s,v.len,v.data + v.offset);
|
||||
}
|
||||
|
||||
evstring_view
|
||||
evstring_slice(
|
||||
const evstring s,
|
||||
i64 begin,
|
||||
i64 end)
|
||||
{
|
||||
evstr_asserttype(s);
|
||||
|
||||
u64 string_len = evstring_getLength(s);
|
||||
u64 wrapped_begin = begin < 0 ? string_len + 1 + begin : begin;
|
||||
u64 wrapped_end = end < 0 ? string_len + 1 + end : end;
|
||||
|
||||
assert(wrapped_begin >= 0 && wrapped_begin < string_len);
|
||||
assert(wrapped_end > 0 && wrapped_end <= string_len);
|
||||
|
||||
assert(wrapped_begin < wrapped_end);
|
||||
|
||||
return (evstring_view) {
|
||||
.data = s,
|
||||
.offset = wrapped_begin,
|
||||
.len = wrapped_end - wrapped_begin
|
||||
};
|
||||
}
|
||||
|
||||
u64
|
||||
evstring_getSpace(
|
||||
const evstring s)
|
||||
{
|
||||
evstr_asserttype(s);
|
||||
struct evstr_meta_t *meta = META(s);
|
||||
return meta->size - meta->length - 1 - sizeof(struct evstr_meta_t);
|
||||
}
|
||||
|
||||
evstring_error_t
|
||||
evstring_addSpace(
|
||||
evstring *s,
|
||||
u64 space)
|
||||
{
|
||||
evstr_asserttype(*s);
|
||||
return evstring_setSize(s, META(*s)->size + space);
|
||||
}
|
||||
|
||||
evstring_view
|
||||
__evstring_findFirst_impl(
|
||||
evstring_view text,
|
||||
evstring_view query)
|
||||
{
|
||||
u64 found_progress = 0;
|
||||
|
||||
evstring_view result = {
|
||||
.data = text.data,
|
||||
.len = 0,
|
||||
.offset = ~0ull
|
||||
};
|
||||
|
||||
for(u64 i = text.offset; i < text.offset + text.len; i++) {
|
||||
if(text.data[i] == query.data[query.offset + found_progress]) {
|
||||
found_progress++;
|
||||
}
|
||||
if(found_progress == query.len) {
|
||||
result.offset = (i+1) - query.len;
|
||||
result.len = query.len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
evstring_view
|
||||
evstring_findFirst(
|
||||
const evstring text,
|
||||
const evstring query)
|
||||
{
|
||||
evstr_asserttype(text);
|
||||
evstr_asserttype(query);
|
||||
return __evstring_findFirst_impl(evstring_slice(text, 0, -1), evstring_slice(query, 0, -1));
|
||||
}
|
||||
|
||||
evstring
|
||||
evstring_replaceFirst(
|
||||
const evstring text,
|
||||
const evstring query,
|
||||
const evstring replacement)
|
||||
{
|
||||
evstr_asserttype(text);
|
||||
evstr_asserttype(query);
|
||||
evstr_asserttype(replacement);
|
||||
evstring result = NULL;
|
||||
|
||||
evstring_view query_slice = evstring_findFirst(text, query);
|
||||
|
||||
// If the query doesn't actually exist, then we're returning a clone of
|
||||
// the original string.
|
||||
if(query_slice.len == 0) {
|
||||
result = evstring_new_impl(text, evstring_getLength(text));
|
||||
} else {
|
||||
result = evstring_new_impl(NULL,0);
|
||||
|
||||
// If the query doesn't match at the beginning of the string,
|
||||
// then we need to copy the data before it first.
|
||||
if(query_slice.offset != 0) {
|
||||
evstring_push(&result, evstring_slice(text, 0, query_slice.offset));
|
||||
}
|
||||
|
||||
// Then, we simply push the replacement
|
||||
evstring_push_impl(&result, evstring_getLength(replacement), replacement);
|
||||
|
||||
// Followed by the rest of the string
|
||||
evstring_push(&result,
|
||||
evstring_slice(text, query_slice.offset + query_slice.len, -1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
evstring_error_t
|
||||
evstring_pushFmt(
|
||||
evstring *s,
|
||||
const char *fmt,
|
||||
...)
|
||||
{
|
||||
evstr_asserttype(*s);
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
evstring_error_t res = evstring_pushFmt_v(s, fmt, ap);
|
||||
va_end(ap);
|
||||
return res;
|
||||
}
|
||||
|
||||
evstring_error_t
|
||||
evstring_pushFmt_v(
|
||||
evstring *s,
|
||||
const char *fmt,
|
||||
va_list args)
|
||||
{
|
||||
evstr_asserttype(*s);
|
||||
va_list test;
|
||||
va_copy(test, args);
|
||||
int fmt_len = vsnprintf(NULL, 0, fmt, test);
|
||||
size_t old_len = evstring_getLength(*s);
|
||||
evstring_error_t res = evstring_setLength(s, old_len + fmt_len);
|
||||
if(res == EV_STR_ERR_NONE) {
|
||||
int write_res = vsnprintf((*s) + old_len, fmt_len, fmt, args);
|
||||
assert(write_res > 0);
|
||||
assert(write_res == fmt_len);
|
||||
}
|
||||
va_end(test);
|
||||
return res;
|
||||
}
|
||||
|
||||
i64
|
||||
evstring_findFirstChar(
|
||||
const evstring text,
|
||||
const char c)
|
||||
{
|
||||
evstr_asserttype(text);
|
||||
struct evstr_meta_t *meta = META(text);
|
||||
for(int i = 0; i < meta->length; i++) {
|
||||
if(text[i] == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
i64
|
||||
evstring_findLastChar(
|
||||
const evstring text,
|
||||
const char c)
|
||||
{
|
||||
evstr_asserttype(text);
|
||||
struct evstr_meta_t *meta = META(text);
|
||||
int i;
|
||||
for(i = meta->length - 1; i >= 0; i--) {
|
||||
if(text[i] == c) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
u64
|
||||
evstring_findAll(
|
||||
const evstring text,
|
||||
const evstring query,
|
||||
evstring_view *results)
|
||||
{
|
||||
evstr_asserttype(text);
|
||||
evstr_asserttype(query);
|
||||
|
||||
u64 text_len = evstring_getLength(text);
|
||||
u64 query_len = evstring_getLength(query);
|
||||
if(text_len == 0 || query_len == 0 || query_len > text_len) {
|
||||
return 0;
|
||||
}
|
||||
bool check_run = (results == NULL);
|
||||
u64 count = 0;
|
||||
for(evstring_view v = evstring_findFirst(text, query);
|
||||
v.len != 0;
|
||||
v = __evstring_findFirst_impl(
|
||||
evstring_slice(text, v.offset + v.len, -1),
|
||||
evstring_slice(query, 0, -1))) {
|
||||
if(!check_run) {
|
||||
results[count++] = v;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
139
ev_types.h
139
ev_types.h
@@ -1,20 +1,133 @@
|
||||
#ifndef EV_HEADERS_TYPES_H
|
||||
#define EV_HEADERS_TYPES_H
|
||||
|
||||
// Signed integers
|
||||
typedef signed char i8;
|
||||
typedef short int i16;
|
||||
typedef int i32;
|
||||
typedef long long int i64;
|
||||
#include "ev_macros.h"
|
||||
#include "ev_internal.h"
|
||||
#include "ev_hash.h"
|
||||
|
||||
// Unsigned integers
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short int u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long int u64;
|
||||
typedef void(*ev_copy_fn)(void *dst, void *src);
|
||||
typedef void(*ev_free_fn)(void *self);
|
||||
typedef u64(*ev_hash_fn)(void *self, u64 seed);
|
||||
typedef i32(*ev_cmp_fn)(void *self, void *other);
|
||||
|
||||
// Floating-Point Numbers
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
typedef struct {
|
||||
EV_DEBUG(const char *name;)
|
||||
|
||||
u32 size;
|
||||
u32 alignment;
|
||||
|
||||
ev_copy_fn copy_fn;
|
||||
ev_free_fn free_fn;
|
||||
ev_hash_fn hash_fn;
|
||||
ev_cmp_fn cmp_fn;
|
||||
|
||||
void *default_val;
|
||||
void *invalid_val;
|
||||
} EvTypeData;
|
||||
|
||||
#define COPY_FUNCTION(T,name) EV_CAT(EV_CAT(EV_CAT(EV_COPY_FUNCTION_,T),_),name)
|
||||
#define FREE_FUNCTION(T,name) EV_CAT(EV_CAT(EV_CAT(EV_FREE_FUNCTION_,T),_),name)
|
||||
#define HASH_FUNCTION(T,name) EV_CAT(EV_CAT(EV_CAT(EV_HASH_FUNCTION_,T),_),name)
|
||||
#define CMP_FUNCTION(T,name) EV_CAT(EV_CAT(EV_CAT(EV_CMP_FUNCTION_ ,T),_),name)
|
||||
|
||||
#include <string.h>
|
||||
#define DEFINE_COPY_FUNCTION(T,name) void COPY_FUNCTION(T,name)(T *dst, T *src)
|
||||
#define DEFINE_DEFAULT_INTERNAL_COPY_FUNCTION(T) \
|
||||
static inline DEFINE_COPY_FUNCTION(T,__EV_INTERNAL) { memcpy(dst, src, sizeof(T)); }
|
||||
|
||||
#define DEFINE_FREE_FUNCTION(T,name) void FREE_FUNCTION(T,name)(T *self)
|
||||
#define DEFINE_DEFAULT_INTERNAL_FREE_FUNCTION(T) \
|
||||
static inline DEFINE_FREE_FUNCTION(T,__EV_INTERNAL) { (void)self; }
|
||||
|
||||
#define DEFINE_HASH_FUNCTION(T,name) u64 HASH_FUNCTION(T,name)(T *self, u64 seed)
|
||||
#define DEFINE_DEFAULT_INTERNAL_HASH_FUNCTION(T) \
|
||||
static inline DEFINE_HASH_FUNCTION(T,__EV_INTERNAL) { return ev_hash_murmur3(self, sizeof(T), seed); }
|
||||
|
||||
#define DEFINE_CMP_FUNCTION(T,name) i32 CMP_FUNCTION(T,name)(T *self, T *other)
|
||||
#define DEFINE_DEFAULT_INTERNAL_CMP_FUNCTION(T) \
|
||||
static inline DEFINE_CMP_FUNCTION(T,__EV_INTERNAL) { return memcmp(self, other, sizeof(T)); }
|
||||
|
||||
#define DECLARE_COPY_FUNCTION(T,name) DEFINE_COPY_FUNCTION(T,name);
|
||||
#define DECLARE_FREE_FUNCTION(T,name) DEFINE_FREE_FUNCTION(T,name);
|
||||
#define DECLARE_HASH_FUNCTION(T,name) DEFINE_HASH_FUNCTION(T,name);
|
||||
#define DECLARE_CMP_FUNCTION(T,name) DEFINE_CMP_FUNCTION(T,name);
|
||||
|
||||
#define ACTIVE_COPY_FUNCTION(T) __EV_TYPE_INTERNAL_##T##_ACTIVE_COPY_FN
|
||||
#define ACTIVE_FREE_FUNCTION(T) __EV_TYPE_INTERNAL_##T##_ACTIVE_FREE_FN
|
||||
#define ACTIVE_HASH_FUNCTION(T) __EV_TYPE_INTERNAL_##T##_ACTIVE_HASH_FN
|
||||
#define ACTIVE_CMP_FUNCTION(T) __EV_TYPE_INTERNAL_##T##_ACTIVE_CMP_FN
|
||||
|
||||
#define COPY_FUNCTION_TYPE(T) __EV_TYPE_INTERNAL_##T##_COPY_FN_TYPE
|
||||
#define FREE_FUNCTION_TYPE(T) __EV_TYPE_INTERNAL_##T##_FREE_FN_TYPE
|
||||
#define HASH_FUNCTION_TYPE(T) __EV_TYPE_INTERNAL_##T##_HASH_FN_TYPE
|
||||
#define CMP_FUNCTION_TYPE(T) __EV_TYPE_INTERNAL_##T##_CMP_FN_TYPE
|
||||
|
||||
#define DEFINE_FUNCTION_TYPES(T) \
|
||||
typedef void(*COPY_FUNCTION_TYPE(T))(T*,T*); \
|
||||
typedef void(*FREE_FUNCTION_TYPE(T))(T*); \
|
||||
typedef u64(*HASH_FUNCTION_TYPE(T))(T*,u64); \
|
||||
typedef i32(*CMP_FUNCTION_TYPE(T))(T*,T*)
|
||||
|
||||
#define DEFINE_DEFAULT_INTERNAL_FUNCTIONS(T) \
|
||||
DEFINE_DEFAULT_INTERNAL_COPY_FUNCTION(T) \
|
||||
DEFINE_DEFAULT_INTERNAL_FREE_FUNCTION(T) \
|
||||
DEFINE_DEFAULT_INTERNAL_HASH_FUNCTION(T) \
|
||||
DEFINE_DEFAULT_INTERNAL_CMP_FUNCTION(T)
|
||||
|
||||
#define EV_OVERRIDE_VAR(T) EV_CAT(__ev_internal_override_var_,T)
|
||||
#define TypeData(T) EV_CAT(EV_TYPEDATA_,T)
|
||||
#define TYPEDATA_GEN(T, ...) \
|
||||
DEFINE_FUNCTION_TYPES(T); \
|
||||
DEFINE_DEFAULT_INTERNAL_FUNCTIONS(T); \
|
||||
static const COPY_FUNCTION_TYPE(T) ACTIVE_COPY_FUNCTION(T) = COPY_FUNCTION(T,__EV_INTERNAL); \
|
||||
static const FREE_FUNCTION_TYPE(T) ACTIVE_FREE_FUNCTION(T) = FREE_FUNCTION(T,__EV_INTERNAL); \
|
||||
static const HASH_FUNCTION_TYPE(T) ACTIVE_HASH_FUNCTION(T) = HASH_FUNCTION(T,__EV_INTERNAL); \
|
||||
static const CMP_FUNCTION_TYPE(T) ACTIVE_CMP_FUNCTION(T) = CMP_FUNCTION(T,__EV_INTERNAL); \
|
||||
EV_VA_OPT(__VA_ARGS__)(EV_FOREACH_UDATA(__EV_STRUCT_METHOD_DEF, T, __VA_ARGS__)) \
|
||||
EV_WARNING_PUSH(); \
|
||||
EV_WARNING_DISABLE_GCC("override-init"); \
|
||||
EV_WARNING_DISABLE_CLANG("override-init"); \
|
||||
EV_UNUSED static const EvTypeData TypeData(T) = { \
|
||||
EV_DEBUG(.name = EV_STRINGIZE(T),) \
|
||||
.size = sizeof(T), \
|
||||
.alignment = EV_ALIGNOF(T), \
|
||||
.default_val = (void*)&(T){0}, \
|
||||
.invalid_val = (void*)&(T){0}, \
|
||||
.copy_fn = (ev_copy_fn)ACTIVE_COPY_FUNCTION(T), \
|
||||
.free_fn = (ev_free_fn)ACTIVE_FREE_FUNCTION(T), \
|
||||
.hash_fn = (ev_hash_fn)ACTIVE_HASH_FUNCTION(T), \
|
||||
.cmp_fn = (ev_cmp_fn) ACTIVE_CMP_FUNCTION(T) \
|
||||
}; \
|
||||
EV_WARNING_POP(); \
|
||||
EV_UNUSED static T EV_OVERRIDE_VAR(T)
|
||||
|
||||
|
||||
#define COPY(...) (COPY , __VA_ARGS__)
|
||||
#define FREE(...) (FREE , __VA_ARGS__)
|
||||
#define HASH(...) (HASH , __VA_ARGS__)
|
||||
#define CMP(...) (CMP , __VA_ARGS__)
|
||||
#define DEFAULT(...) (DEFAULT, __VA_ARGS__)
|
||||
#define INVALID(...) (INVALID, __VA_ARGS__)
|
||||
|
||||
#define __EV_STRUCT_METHOD_DEF(T, ...) EV_CAT(__EV_,EV_CAT(EV_HEAD __VA_ARGS__,_FN))(T, EV_TAIL __VA_ARGS__)
|
||||
#define __EV_COPY_FN(T,name) ACTIVE_COPY_FUNCTION(T) = (COPY_FUNCTION_TYPE(T)) COPY_FUNCTION(T,name);
|
||||
#define __EV_FREE_FN(T,name) ACTIVE_FREE_FUNCTION(T) = (FREE_FUNCTION_TYPE(T)) FREE_FUNCTION(T,name);
|
||||
#define __EV_HASH_FN(T,name) ACTIVE_HASH_FUNCTION(T) = (HASH_FUNCTION_TYPE(T)) HASH_FUNCTION(T,name);
|
||||
#define __EV_CMP_FN(T,name) ACTIVE_CMP_FUNCTION(T) = (CMP_FUNCTION_TYPE(T)) CMP_FUNCTION(T,name);
|
||||
#define __EV_DEFAULT_FN(T, ...) .default_val = (void*)&(T){ __VA_ARGS__ },
|
||||
#define __EV_INVALID_FN(T, ...) .invalid_val = (void*)&(T){ __VA_ARGS__ },
|
||||
|
||||
#define EV_COPY(T) TypeData(T).copy_fn
|
||||
#define EV_FREE(T) TypeData(T).free_fn
|
||||
#define EV_HASH(T) TypeData(T).hash_fn
|
||||
#define EV_CMP(T) TypeData(T).cmp_fn
|
||||
#define __EV_OVERRIDE_DEFAULT(T, ...) EV_OVERRIDE_VAR(T).__VA_ARGS__,
|
||||
#define __EV_DEFAULT_INTERNAL(T) (*(T*)TypeData(T).default_val)
|
||||
#define EV_DEFAULT(T, ...) EV_VA_OPT_ELSE(__VA_ARGS__) \
|
||||
((EV_OVERRIDE_VAR(T)=__EV_DEFAULT_INTERNAL(T), \
|
||||
EV_FOREACH_UDATA(__EV_OVERRIDE_DEFAULT, T, __VA_ARGS__) \
|
||||
EV_OVERRIDE_VAR(T))) \
|
||||
(__EV_DEFAULT_INTERNAL(T))
|
||||
#define EV_INVALID(T) (*(T*)TypeData(T).invalid_val)
|
||||
|
||||
#endif // EV_HEADERS_TYPES_H
|
||||
|
||||
634
ev_vec.h
Normal file
634
ev_vec.h
Normal file
@@ -0,0 +1,634 @@
|
||||
/*!
|
||||
* \file ev_vec.h
|
||||
*/
|
||||
#ifndef EV_VEC_HEADER
|
||||
#define EV_VEC_HEADER
|
||||
#include "ev_types.h"
|
||||
#include "ev_numeric.h"
|
||||
|
||||
#if defined(EV_VEC_SHARED)
|
||||
# if defined (EV_VEC_IMPL)
|
||||
# define EV_VEC_API EV_EXPORT
|
||||
# else
|
||||
# define EV_VEC_API EV_IMPORT
|
||||
# endif
|
||||
#else
|
||||
# define EV_VEC_API
|
||||
#endif
|
||||
|
||||
#ifndef EV_VEC_INIT_CAP
|
||||
/*!
|
||||
* \brief Initial capacity that is first reserved when a vector is initialized
|
||||
*/
|
||||
#define EV_VEC_INIT_CAP 32
|
||||
#endif
|
||||
|
||||
#ifndef EV_VEC_GROWTH_RATE
|
||||
/*!
|
||||
* \brief Rate at which a vector grows whenever a resize is needed
|
||||
*/
|
||||
#define EV_VEC_GROWTH_RATE 3 / 2
|
||||
#endif
|
||||
|
||||
#if EV_CC_MSVC
|
||||
# define __EV_VEC_EMPTY_ARRAY { 0 }
|
||||
#else
|
||||
# define __EV_VEC_EMPTY_ARRAY { }
|
||||
#endif
|
||||
|
||||
typedef void *ev_vec_t;
|
||||
TYPEDATA_GEN(ev_vec_t);
|
||||
typedef void *ev_svec_t;
|
||||
TYPEDATA_GEN(ev_svec_t);
|
||||
|
||||
typedef enum {
|
||||
EV_VEC_ERR_NONE = 0,
|
||||
EV_VEC_ERR_OOM = 1
|
||||
} ev_vec_error_t;
|
||||
TYPEDATA_GEN(ev_vec_error_t, DEFAULT(EV_VEC_ERR_NONE));
|
||||
|
||||
#if defined(EV_VEC_SHORTNAMES)
|
||||
#define vec_t ev_vec_t
|
||||
#define svec_t ev_svec_t
|
||||
|
||||
#define vec_error_t ev_vec_error_t
|
||||
|
||||
# define vec(T) ev_vec(T)
|
||||
# define svec(T) ev_svec(T)
|
||||
|
||||
# define vec_init ev_vec_init
|
||||
# define svec_init ev_svec_init
|
||||
# define svec_init_w_cap ev_svec_init_w_cap
|
||||
# define vec_iter_begin ev_vec_iter_begin
|
||||
# define vec_iter_end ev_vec_iter_end
|
||||
# define vec_iter_next ev_vec_iter_next
|
||||
# define vec_foreach ev_vec_foreach
|
||||
# define vec_fini ev_vec_fini
|
||||
# define vec_push ev_vec_push
|
||||
# define vec_append ev_vec_append
|
||||
# define vec_last ev_vec_last
|
||||
# define vec_len ev_vec_len
|
||||
# define vec_capacity ev_vec_capacity
|
||||
# define vec_clear ev_vec_clear
|
||||
# define vec_setlen ev_vec_setlen
|
||||
# define vec_setcapacity ev_vec_setcapacity
|
||||
# define vec_grow ev_vec_grow
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief For the sake of readability
|
||||
* \details Sample usage:
|
||||
* ```
|
||||
* ev_vec(int) v = ev_vec_init(int, 0, 0);
|
||||
* ```
|
||||
*/
|
||||
#define ev_vec(T) T*
|
||||
|
||||
/*!
|
||||
* \brief For the sake of readability
|
||||
* \details Sample usage:
|
||||
* ```
|
||||
* ev_svec(int) v = ev_svec_init(int, { 0, 0 });
|
||||
* ```
|
||||
*/
|
||||
#define ev_svec(T) T*
|
||||
|
||||
//! Metadata that is stored with a vector. Unique to each vector.
|
||||
struct ev_vec_meta_t {
|
||||
//! The number of elements in the vector.
|
||||
u64 length;
|
||||
//! The maximum length of the vector before it needs to be resized.
|
||||
u64 capacity;
|
||||
|
||||
//! The type data of the elements
|
||||
EvTypeData typeData;
|
||||
|
||||
enum {
|
||||
EV_VEC_ALLOCATION_TYPE_STACK,
|
||||
EV_VEC_ALLOCATION_TYPE_HEAP
|
||||
} allocationType;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \param typeData The EvTypeData for the element that the vector will contain
|
||||
*
|
||||
* \returns A vector object
|
||||
*/
|
||||
EV_VEC_API ev_vec_t
|
||||
ev_vec_init_impl(
|
||||
EvTypeData typeData);
|
||||
|
||||
/*!
|
||||
* \brief Syntactic sugar for `ev_vec_init_impl()`
|
||||
* \details Sample usage:
|
||||
* ```
|
||||
* ev_vec_init(int); // ev_vec_init_impl(sizeof(int), NULL, NULL);
|
||||
* ev_vec_init(int, fn_destr); // ev_vec_init_impl(sizeof(int), NULL, fn_destr);
|
||||
* ev_vec_init(int, fn_cpy, fn_destr); // ev_vec_init_impl(sizeof(int), fn_cpy, fn_destr);
|
||||
* ```
|
||||
*/
|
||||
#define ev_vec_init(T) ev_vec_init_impl(TypeData(T))
|
||||
|
||||
#define ev_svec_init(T, ...) __ev_svec_init_impl(T, EV_ARRSIZE((T[])__VA_ARGS__), __VA_ARGS__)
|
||||
#define ev_svec_init_w_cap(T, cap) __ev_svec_init_w_cap_impl(T, cap)
|
||||
|
||||
#define __ev_svec_init_impl(T, len, ...) \
|
||||
(ev_svec(T))&((struct { \
|
||||
struct ev_vec_meta_t meta; \
|
||||
EV_ALIGNAS(EV_ALIGNOF(T)) T data[len]; \
|
||||
}) { \
|
||||
.meta.length = len, \
|
||||
.meta.capacity = len, \
|
||||
.meta.typeData.size = sizeof(T), \
|
||||
.meta.typeData.alignment = EV_ALIGNOF(T), \
|
||||
.meta.allocationType = EV_VEC_ALLOCATION_TYPE_STACK, \
|
||||
.data = __VA_ARGS__ \
|
||||
}).data
|
||||
|
||||
#define __ev_svec_init_w_cap_impl(T, cap) \
|
||||
(ev_svec(T))&((struct { \
|
||||
struct ev_vec_meta_t meta; \
|
||||
EV_ALIGNAS(EV_ALIGNOF(T)) T data[cap]; \
|
||||
}) { \
|
||||
.meta.length = 0, \
|
||||
.meta.capacity = cap, \
|
||||
.meta.typeData.size = sizeof(T), \
|
||||
.meta.typeData.alignment = EV_ALIGNOF(T), \
|
||||
.meta.allocationType = EV_VEC_ALLOCATION_TYPE_STACK, \
|
||||
.data = __EV_VEC_EMPTY_ARRAY \
|
||||
}).data
|
||||
|
||||
#define ev_vec_push(v, x) ev_vec_push_impl((ev_vec_t*)&v,&x);
|
||||
|
||||
/*!
|
||||
* \param v The vector that we want an iterator for
|
||||
*
|
||||
* \returns A pointer to the first element in a vector
|
||||
*/
|
||||
EV_VEC_API void *
|
||||
ev_vec_iter_begin(
|
||||
ev_vec_t v);
|
||||
|
||||
/*!
|
||||
* \param v The vector that we want an iterator for
|
||||
*
|
||||
* \returns A pointer to the memory block right after the last element in the vector
|
||||
*/
|
||||
EV_VEC_API void *
|
||||
ev_vec_iter_end(
|
||||
ev_vec_t v);
|
||||
|
||||
/*!
|
||||
* \brief A function that increments an iterator to make it point to the next
|
||||
* element in the vector
|
||||
*
|
||||
* \param v The vector that is being iterated over
|
||||
* \param iter Reference to the iterator that is being incremented
|
||||
*/
|
||||
EV_VEC_API void
|
||||
ev_vec_iter_next(
|
||||
ev_vec_t v,
|
||||
void **iter);
|
||||
|
||||
/*!
|
||||
* \brief A function that destroys a vector object. If a destructor function was
|
||||
* passed while initializing the vector, then this function is called on every
|
||||
* element before all reserved memory is freed.
|
||||
*
|
||||
* *Note*: For stack-allocated vectors (`svec`), destructors are called for
|
||||
* elements but no memory is freed.
|
||||
*
|
||||
* \param v The vector that is being destroyed
|
||||
*/
|
||||
EV_VEC_API void
|
||||
ev_vec_fini(
|
||||
ev_vec_t v);
|
||||
|
||||
/*!
|
||||
* \brief A function that copies a value to the end of a vector. If a copy
|
||||
* function was passed while initializing the vector, then this function is
|
||||
* called to copy the new element into the vector. Otherwise, memcpy is used
|
||||
* with a length of `vec_meta.elemsize`. If a resize is needed but fails due to
|
||||
* 'OOM' issues, then the vector is left unchanged and VEC_ERR_OOM is returned.
|
||||
*
|
||||
* For `svec`, as long as the capacity is more than the current size, a push
|
||||
* operation is permitted. Otherwise, the operation is treated as an OOM.
|
||||
*
|
||||
* \param v Reference to the vector object
|
||||
* \param val A pointer to the element that is to be copied to the end of the
|
||||
* vector
|
||||
*
|
||||
* \returns The index of the element that was just pushed. If the operation
|
||||
* failed, a non-zero (vec_error_t) value is returned.
|
||||
*/
|
||||
EV_VEC_API int
|
||||
ev_vec_push_impl(
|
||||
ev_vec_t *v,
|
||||
void *val);
|
||||
|
||||
/*!
|
||||
* \brief A function that appends the elements of an array to the end of a
|
||||
* vector. If a resize is needed but fails due to 'OOM' issues, then the
|
||||
* vector is left unchanged and a VEC_ERR_OOM is returned.
|
||||
*
|
||||
* For `svec`, as long as the capacity is more than the current size by the
|
||||
* desired amount, an append operation is permitted. Otherwise, the operation
|
||||
* is treated as an OOM.
|
||||
*
|
||||
* *NOTE* The vector's copy function is not used; this is merely a memcpy
|
||||
* operation. If a deep copy is needed, individually pushing the elements of
|
||||
* the array is the way to go.
|
||||
*
|
||||
* \param v Reference to the vector object
|
||||
* \param arr A pointer to the array that is to be copied to the end of the
|
||||
* vector
|
||||
* \param size Number of elements in the array
|
||||
*
|
||||
* \returns The index of the first element that was appended to the vector. If
|
||||
* the operation failed, a non-zero (vec_error_t) value is returned.
|
||||
*/
|
||||
EV_VEC_API u32
|
||||
ev_vec_append(
|
||||
ev_vec_t *v,
|
||||
void **arr,
|
||||
u64 size);
|
||||
|
||||
/*!
|
||||
* \brief A function that copies the value at the end of a vector and removes
|
||||
* it from the vector. If a copy function was passed while initializing the
|
||||
* vector, then this function is used. Otherwise, memcpy is used with a length
|
||||
* of `vec_meta.elemsize`
|
||||
*
|
||||
* \param v Reference to the vector object
|
||||
* \param out A pointer to the memory block at which the popped element will be
|
||||
* copied. If NULL is passed, then the element is destructed. Otherwise, the
|
||||
* element is copied to `out` and the receiving code is responsible for its
|
||||
* destruction.
|
||||
*
|
||||
* \returns An error code. If the operation was successful, then `VEC_ERR_NONE`
|
||||
* is returned.
|
||||
*/
|
||||
EV_VEC_API ev_vec_error_t
|
||||
ev_vec_pop(
|
||||
ev_vec_t *v,
|
||||
void *out);
|
||||
|
||||
/*!
|
||||
* \brief A function that returns the last element in the vector.
|
||||
*
|
||||
* \param v Reference to the vector object
|
||||
*
|
||||
* \returns Pointer to the last element in the vector. NULL if the vector is
|
||||
* empty.
|
||||
*/
|
||||
EV_VEC_API void *
|
||||
ev_vec_last(
|
||||
ev_vec_t v);
|
||||
|
||||
/*!
|
||||
* \brief A function that returns the length of a vector
|
||||
*
|
||||
* \param v The vector object
|
||||
*
|
||||
* \returns Current length of the vector
|
||||
*/
|
||||
EV_VEC_API u64
|
||||
ev_vec_len(
|
||||
ev_vec_t v);
|
||||
|
||||
/*!
|
||||
* \brief A function that returns the capacity of a vector
|
||||
*
|
||||
* \param v The vector object
|
||||
*
|
||||
* \returns Current capacity of the vector
|
||||
*/
|
||||
EV_VEC_API u64
|
||||
ev_vec_capacity(
|
||||
ev_vec_t v);
|
||||
|
||||
/*!
|
||||
* \brief Calls the free operation (if exists) on every element, then sets
|
||||
* the length to 0.
|
||||
*
|
||||
* \param v The vector object
|
||||
*
|
||||
* \returns 0 on success
|
||||
*/
|
||||
EV_VEC_API u32
|
||||
ev_vec_clear(
|
||||
ev_vec_t v);
|
||||
|
||||
/*!
|
||||
* \brief Sets the length of the vector to `len`.
|
||||
*
|
||||
* \details If `len` is less than `v`'s current length, then `v`'s length is
|
||||
* amended. Otherwise, the capacity is checked to make sure that there is enough
|
||||
* space for the new len.
|
||||
*
|
||||
* For `svec`, if the `len` is more than the already allocated capacity, it is
|
||||
* treated as an OOM.
|
||||
*
|
||||
* \param v Reference to the vector object
|
||||
* \param len The desired new length
|
||||
*
|
||||
* \returns `VEC_ERR_NONE` on success
|
||||
*/
|
||||
EV_VEC_API ev_vec_error_t
|
||||
ev_vec_setlen(
|
||||
ev_vec_t *v,
|
||||
u64 len);
|
||||
|
||||
/*!
|
||||
* \brief Sets the capacity of the vector to `cap`.
|
||||
*
|
||||
* \param v Reference to the vector object
|
||||
* \param cap The desired new capacity
|
||||
*
|
||||
* For stack-allocated vectors, `VEC_ERR_OOM` is returned
|
||||
*
|
||||
* \returns `VEC_ERR_NONE` on success, `VEC_ERR_OOM` on OOM
|
||||
*/
|
||||
EV_VEC_API ev_vec_error_t
|
||||
ev_vec_setcapacity(
|
||||
ev_vec_t *v,
|
||||
u64 cap);
|
||||
|
||||
/*!
|
||||
* \brief Grows the vector's capacity by a factor of `VEC_GROWTH_RATE`
|
||||
*
|
||||
* \param Reference to the vector object
|
||||
*
|
||||
* \returns `VEC_ERR_NONE` on success
|
||||
*/
|
||||
EV_VEC_API ev_vec_error_t
|
||||
ev_vec_grow(
|
||||
ev_vec_t *v);
|
||||
|
||||
#ifdef EV_VEC_IMPLEMENTATION
|
||||
#undef EV_VEC_IMPLEMENTATION
|
||||
|
||||
#ifdef EV_VEC_API_CHECK
|
||||
#define EV_VEC_CHECK(x) do { x; } while(0)
|
||||
#else
|
||||
#define EV_VEC_CHECK(x)
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ev_vec_meta(v) \
|
||||
((struct ev_vec_meta_t *)v) - 1
|
||||
|
||||
#define __ev_vec_getmeta(v) \
|
||||
struct ev_vec_meta_t *metadata = ((struct ev_vec_meta_t *)(v)) - 1;
|
||||
|
||||
#define __ev_vec_syncmeta(v) \
|
||||
metadata = ((struct ev_vec_meta_t *)(v)) - 1;
|
||||
|
||||
ev_vec_t
|
||||
ev_vec_init_impl(
|
||||
EvTypeData typeData)
|
||||
{
|
||||
void *v = malloc(sizeof(struct ev_vec_meta_t) + (EV_VEC_INIT_CAP * typeData.size));
|
||||
if (!v)
|
||||
return NULL;
|
||||
|
||||
struct ev_vec_meta_t *metadata = (struct ev_vec_meta_t *)v;
|
||||
*metadata = (struct ev_vec_meta_t){
|
||||
.length = 0,
|
||||
.capacity = EV_VEC_INIT_CAP,
|
||||
.allocationType = EV_VEC_ALLOCATION_TYPE_HEAP,
|
||||
.typeData = typeData
|
||||
};
|
||||
|
||||
return metadata + 1;
|
||||
}
|
||||
|
||||
void
|
||||
ev_vec_fini(
|
||||
ev_vec_t v)
|
||||
{
|
||||
__ev_vec_getmeta(v)
|
||||
|
||||
if (metadata->typeData.free_fn) {
|
||||
for (void *elem = ev_vec_iter_begin(v); elem != ev_vec_iter_end(v);
|
||||
ev_vec_iter_next(v, &elem)) {
|
||||
metadata->typeData.free_fn(elem);
|
||||
}
|
||||
}
|
||||
if(metadata->allocationType == EV_VEC_ALLOCATION_TYPE_HEAP) {
|
||||
free(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ev_vec_push_impl(
|
||||
ev_vec_t *v,
|
||||
void *val)
|
||||
{
|
||||
__ev_vec_getmeta(*v)
|
||||
|
||||
if (metadata->length == metadata->capacity) {
|
||||
ev_vec_error_t grow_err = ev_vec_grow(v);
|
||||
if(grow_err) {
|
||||
return grow_err;
|
||||
} else {
|
||||
__ev_vec_syncmeta(*v)
|
||||
}
|
||||
}
|
||||
|
||||
void *dst = ((char *)*v) + (metadata->length * metadata->typeData.size);
|
||||
if (metadata->typeData.copy_fn) {
|
||||
metadata->typeData.copy_fn(dst, val);
|
||||
} else {
|
||||
memcpy(dst, val, metadata->typeData.size);
|
||||
}
|
||||
|
||||
return (int)metadata->length++;
|
||||
}
|
||||
|
||||
void *
|
||||
ev_vec_iter_begin(
|
||||
ev_vec_t v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
void *
|
||||
ev_vec_iter_end(
|
||||
ev_vec_t v)
|
||||
{
|
||||
__ev_vec_getmeta(v)
|
||||
|
||||
return ((char *)v) + (metadata->typeData.size * metadata->length);
|
||||
}
|
||||
|
||||
void
|
||||
ev_vec_iter_next(
|
||||
ev_vec_t v,
|
||||
void **iter)
|
||||
{
|
||||
__ev_vec_getmeta(v)
|
||||
*iter = ((char*)*iter) + metadata->typeData.size;
|
||||
}
|
||||
|
||||
EV_VEC_API u32
|
||||
ev_vec_append(
|
||||
ev_vec_t *v,
|
||||
void **arr,
|
||||
u64 size)
|
||||
{
|
||||
__ev_vec_getmeta(*v)
|
||||
size_t old_len = metadata->length;
|
||||
size_t req_len = old_len + size;
|
||||
|
||||
ev_vec_error_t setlen_err = ev_vec_setlen(v, req_len);
|
||||
if(setlen_err) {
|
||||
return setlen_err;
|
||||
}
|
||||
__ev_vec_syncmeta(*v)
|
||||
|
||||
void *dst = ((char *)*v) + (old_len * metadata->typeData.size);
|
||||
memcpy(dst, *arr, metadata->typeData.size * size);
|
||||
|
||||
return (int)old_len;
|
||||
}
|
||||
|
||||
ev_vec_error_t
|
||||
ev_vec_pop(
|
||||
ev_vec_t *v,
|
||||
void *out)
|
||||
{
|
||||
__ev_vec_getmeta(*v)
|
||||
|
||||
if(out != NULL) {
|
||||
void *src = ((char *)*v) + ((metadata->length-1) * metadata->typeData.size);
|
||||
if (metadata->typeData.copy_fn) {
|
||||
metadata->typeData.copy_fn(out, src);
|
||||
} else {
|
||||
memcpy(out, src, metadata->typeData.size);
|
||||
}
|
||||
} else {
|
||||
void *elem = ((char *)*v) + ((metadata->length-1) * metadata->typeData.size);
|
||||
if (metadata->typeData.free_fn) {
|
||||
metadata->typeData.free_fn(elem);
|
||||
}
|
||||
}
|
||||
|
||||
metadata->length--;
|
||||
|
||||
return EV_VEC_ERR_NONE;
|
||||
}
|
||||
|
||||
void *
|
||||
ev_vec_last(
|
||||
ev_vec_t v)
|
||||
{
|
||||
__ev_vec_getmeta(v)
|
||||
|
||||
if(metadata->length == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ((char *)v) + ((metadata->length-1) * metadata->typeData.size);
|
||||
}
|
||||
|
||||
u64
|
||||
ev_vec_len(
|
||||
ev_vec_t v)
|
||||
{
|
||||
__ev_vec_getmeta(v)
|
||||
return metadata->length;
|
||||
}
|
||||
|
||||
u64
|
||||
ev_vec_capacity(
|
||||
ev_vec_t v)
|
||||
{
|
||||
__ev_vec_getmeta(v)
|
||||
return metadata->capacity;
|
||||
}
|
||||
|
||||
u32
|
||||
ev_vec_clear(
|
||||
ev_vec_t v)
|
||||
{
|
||||
__ev_vec_getmeta(v)
|
||||
|
||||
if (metadata->typeData.free_fn) {
|
||||
for (void *elem = ev_vec_iter_begin(v); elem != ev_vec_iter_end(v);
|
||||
ev_vec_iter_next(v, &elem)) {
|
||||
metadata->typeData.free_fn(elem);
|
||||
}
|
||||
}
|
||||
|
||||
metadata->length = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ev_vec_error_t
|
||||
ev_vec_setlen(
|
||||
ev_vec_t *v,
|
||||
u64 len)
|
||||
{
|
||||
__ev_vec_getmeta(*v)
|
||||
|
||||
while(len > metadata->capacity) {
|
||||
ev_vec_error_t grow_err = ev_vec_grow(v);
|
||||
if(grow_err) {
|
||||
return grow_err;
|
||||
}
|
||||
__ev_vec_syncmeta(*v)
|
||||
}
|
||||
|
||||
// TODO if new_len < old_len:
|
||||
// vec_pop(old_len - new_len)
|
||||
|
||||
metadata->length = len;
|
||||
return EV_VEC_ERR_NONE;
|
||||
}
|
||||
|
||||
ev_vec_error_t
|
||||
ev_vec_setcapacity(
|
||||
ev_vec_t *v,
|
||||
u64 cap)
|
||||
{
|
||||
__ev_vec_getmeta(*v)
|
||||
|
||||
if(metadata->allocationType == EV_VEC_ALLOCATION_TYPE_STACK) {
|
||||
return EV_VEC_ERR_OOM;
|
||||
}
|
||||
|
||||
if(metadata->capacity == cap) {
|
||||
return EV_VEC_ERR_NONE;
|
||||
}
|
||||
|
||||
void *buf = ((char *)(*v) - sizeof(struct ev_vec_meta_t));
|
||||
void *tmp = realloc(buf, sizeof(struct ev_vec_meta_t) + (cap * metadata->typeData.size));
|
||||
|
||||
if (!tmp) {
|
||||
return EV_VEC_ERR_OOM;
|
||||
}
|
||||
|
||||
if(buf != tmp) {
|
||||
buf = tmp;
|
||||
metadata = (struct ev_vec_meta_t *)buf;
|
||||
*v = (char *)buf + sizeof(struct ev_vec_meta_t);
|
||||
}
|
||||
|
||||
metadata->capacity = cap;
|
||||
return EV_VEC_ERR_NONE;
|
||||
}
|
||||
|
||||
ev_vec_error_t
|
||||
ev_vec_grow(
|
||||
ev_vec_t *v)
|
||||
{
|
||||
__ev_vec_getmeta(*v)
|
||||
return ev_vec_setcapacity(v, metadata->capacity * EV_VEC_GROWTH_RATE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
39
meson.build
Normal file
39
meson.build
Normal file
@@ -0,0 +1,39 @@
|
||||
project('evol-headers', 'c',
|
||||
default_options : [ 'c_std=gnu17' ])
|
||||
|
||||
headers_include = include_directories('.')
|
||||
|
||||
evh_c_args = []
|
||||
buildtype = get_option('buildtype')
|
||||
if buildtype == 'debug'
|
||||
evh_c_args += '-DEV_BUILDTYPE_DEBUG=1'
|
||||
elif buildtype == 'debugoptimized'
|
||||
evh_c_args += '-DEV_BUILDTYPE_DEBUGOPT=1'
|
||||
else
|
||||
evh_c_args += '-DEV_BUILDTYPE_RELEASE=1'
|
||||
endif
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
if cc.get_id() == 'msvc'
|
||||
evh_c_args += '/Zc:preprocessor'
|
||||
endif
|
||||
|
||||
# All other targets should follow the same template
|
||||
str_lib = static_library('ev_str', files('buildfiles/ev_str.c'), c_args: evh_c_args)
|
||||
vec_lib = static_library('ev_vec', files('buildfiles/ev_vec.c'), c_args: evh_c_args)
|
||||
|
||||
str_dep = declare_dependency(link_with: str_lib, include_directories: headers_include)
|
||||
vec_dep = declare_dependency(link_with: vec_lib, include_directories: headers_include)
|
||||
|
||||
headers_dep = declare_dependency(
|
||||
dependencies: [
|
||||
str_dep,
|
||||
vec_dep,
|
||||
]
|
||||
)
|
||||
|
||||
if meson.version().version_compare('>= 0.54.0')
|
||||
meson.override_dependency('ev_vec', vec_dep)
|
||||
meson.override_dependency('ev_str', str_dep)
|
||||
meson.override_dependency('evol-headers', headers_dep)
|
||||
endif
|
||||
60
str_test.c
Normal file
60
str_test.c
Normal file
@@ -0,0 +1,60 @@
|
||||
#define EV_STR_IMPLEMENTATION
|
||||
#include "ev_str.h"
|
||||
|
||||
evstring global_str = evstr("Global 'Hello, World!'");
|
||||
|
||||
int main()
|
||||
{
|
||||
const evstring stack_str = evstr("Stack 'Hello, World!'");
|
||||
printf("Stack String: %s, Length: %llu\n", stack_str, evstring_getLength(stack_str));
|
||||
printf("Global String: %s, Length: %llu\n", global_str, evstring_getLength(global_str));
|
||||
|
||||
evstring heap_str = evstring_new("Heap 'Hello, World!'");
|
||||
printf("Heap String: %s, Length: %llu\n", heap_str, evstring_getLength(heap_str));
|
||||
|
||||
evstring_view view = evstring_slice(stack_str, 0, -1);
|
||||
printf("String View: %.*s\n", (i32)view.len, view.data + view.offset);
|
||||
printf("View length: %llu\n", view.len);
|
||||
|
||||
evstring heap_str2 = evstring_new(view);
|
||||
printf("Heap String 2: %s, Length: %llu\n", heap_str2, evstring_getLength(heap_str2));
|
||||
evstring_free(heap_str2);
|
||||
|
||||
|
||||
evstring_error_t push_str_res = evstring_push(&heap_str, "Hello, Sisyphus! %f", 0.001f);
|
||||
printf("Push char*: %s, New Length: %llu\n", heap_str, evstring_getLength(heap_str));
|
||||
assert(push_str_res == EV_STR_ERR_NONE);
|
||||
|
||||
evstring_error_t push_char_res = evstring_push(&heap_str, (char)'X');
|
||||
printf("Push char: %s, New Length: %llu\n", heap_str, evstring_getLength(heap_str));
|
||||
assert(push_char_res == EV_STR_ERR_NONE);
|
||||
|
||||
evstring_error_t push_view_res = evstring_push(&heap_str, view);
|
||||
printf("Push view: %s, New Length: %llu\n", heap_str, evstring_getLength(heap_str));
|
||||
assert(push_view_res == EV_STR_ERR_NONE);
|
||||
|
||||
evstring str_fmt = evstring_new("%d, %d, %.*s", 1, 0, view.len, view.data + view.offset);
|
||||
printf("Formatted String: %s\n", str_fmt);
|
||||
|
||||
evstring rep_str = evstring_replaceFirst(heap_str, evstr("Hello"), evstr("Bye"));
|
||||
printf("Replaced String: %s\n", rep_str);
|
||||
evstring_free(rep_str);
|
||||
|
||||
evstring_free(str_fmt);
|
||||
evstring_free(heap_str);
|
||||
|
||||
evstring_view search_results[8];
|
||||
evstring search_string = evstr("Hello, this is me saying `Hello` like someone who says 'Hello'");
|
||||
assert(evstring_findAll(search_string, evstr("Hello"), search_results) == 3);
|
||||
assert(search_results[0].data == search_string);
|
||||
assert(search_results[1].data == search_string);
|
||||
assert(search_results[2].data == search_string);
|
||||
assert(search_results[0].len == 5);
|
||||
assert(search_results[1].len == 5);
|
||||
assert(search_results[2].len == 5);
|
||||
assert(search_results[0].offset == 0);
|
||||
assert(search_results[1].offset == 26);
|
||||
assert(search_results[2].offset == 56);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user