Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 89b34bf63c | |||
| e3d47ebc67 | |||
| d403ebb0df | |||
| 32c2134245 | |||
| 0bf963b21c | |||
| 0886535722 | |||
| 7b8bac2b55 | |||
| 2c74b727ef | |||
| 7c4768a3dd | |||
| 82abc8fee5 | |||
| 396e2c1e52 | |||
| 0f62e962c9 | |||
| e7c6cc507c | |||
| 8b6c7ec42a | |||
| a0f16f8ca0 | |||
| 81a5b4a3c8 | |||
| 96131f8188 | |||
| a4fa298d95 | |||
| b992f8c223 | |||
| f085ce2fa4 | |||
| c38e5784e9 | |||
| 7663c76329 | |||
| 76a5bf0afa | |||
| 701a3807b6 | |||
| b5b2df24aa | |||
| b845e72902 | |||
| dcd1beae8a | |||
| ea9d45625d | |||
| 2dcc69e692 | |||
| eb271ae2a8 | |||
| d3bbc155af | |||
| 77a594b36b | |||
| 8410e66eb5 | |||
| 2daeb8652c | |||
| fe5b9a131f |
@@ -0,0 +1,37 @@
|
|||||||
|
name: Run tests
|
||||||
|
run-name: Running Tests
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Run tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
container:
|
||||||
|
image: git.neosisyphus.com/evol3d/evol-testbed:latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Configure
|
||||||
|
run: meson setup build
|
||||||
|
# run: meson setup -Db_coverage=true build
|
||||||
|
|
||||||
|
- name: Run Tests
|
||||||
|
run: meson test -C build
|
||||||
|
|
||||||
|
- name: Run Memory Tests
|
||||||
|
if: always()
|
||||||
|
run: meson test -C build --wrapper=valgrind
|
||||||
|
|
||||||
|
# - name: Generate coverage report
|
||||||
|
# if: always()
|
||||||
|
# run: ninja coverage-html -C build
|
||||||
|
|
||||||
|
- name: Upload Logs
|
||||||
|
if: always()
|
||||||
|
uses: https://git.neosisyphus.com/mo7sen/upload-artifact-gitea@v7
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
build/meson-logs/meson-log.txt
|
||||||
|
build/meson-logs/meson-setup.txt
|
||||||
|
build/meson-logs/testlog.txt
|
||||||
|
archive: false
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
.cache
|
||||||
|
build
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[binaries]
|
||||||
|
c = 'clang-19'
|
||||||
|
c_ld = 'lld-19'
|
||||||
|
cpp = 'clang++-19'
|
||||||
|
cpp_ld = 'lld-19'
|
||||||
|
|
||||||
|
[properties]
|
||||||
|
c_args = ['-DEV_CC_CLANG=1','-fcolor-diagnostics', '-fansi-escape-codes']
|
||||||
|
|
||||||
|
[cmake]
|
||||||
|
CMAKE_C_COMPILER = 'clang-19'
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[binaries]
|
||||||
|
c = 'clang.exe'
|
||||||
|
c_ld = 'lld'
|
||||||
|
cpp = 'clang++.exe'
|
||||||
|
cpp_ld = 'lld'
|
||||||
|
|
||||||
|
[properties]
|
||||||
|
c_args = ['-DEV_CC_CLANG=1','-fcolor-diagnostics', '-fansi-escape-codes']
|
||||||
|
|
||||||
|
[cmake]
|
||||||
|
CMAKE_C_COMPILER = 'clang.exe'
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#define EV_LOG_IMPLEMENTATION
|
||||||
|
#include "../ev_log.h"
|
||||||
@@ -67,18 +67,18 @@
|
|||||||
# if defined(_MSC_VER)
|
# if defined(_MSC_VER)
|
||||||
# undef EV_CC_MSVC
|
# undef EV_CC_MSVC
|
||||||
# define EV_CC_MSVC 1
|
# define EV_CC_MSVC 1
|
||||||
# elif defined(__GNUC__)
|
|
||||||
# undef EV_CC_GCC
|
|
||||||
# define EV_CC_GCC 1
|
|
||||||
# elif defined(__clang)
|
# elif defined(__clang)
|
||||||
# undef EV_CC_CLANG
|
# undef EV_CC_CLANG
|
||||||
# define EV_CC_CLANG 1
|
# define EV_CC_CLANG 1
|
||||||
|
# elif defined(__GNUC__)
|
||||||
|
# undef EV_CC_GCC
|
||||||
|
# define EV_CC_GCC 1
|
||||||
# else
|
# else
|
||||||
# error EV_CC_UNKNOWN
|
# error EV_CC_UNKNOWN
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(EV_BUILDTYPE_DEBUG) && !defined(EV_BUILDTYPE_DEBUG_OPT) && !defined(EV_BUILDTYPE_RELEASE)
|
#if !defined(EV_BUILDTYPE_DEBUG) && !defined(EV_BUILDTYPE_DEBUGOPT) && !defined(EV_BUILDTYPE_RELEASE)
|
||||||
#define EV_BUILDTYPE_RELEASE 1
|
#define EV_BUILDTYPE_RELEASE 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/*!
|
/*!
|
||||||
* \brief MurmurHash3 64-bit version. Returns 64-bit hash instead of 128
|
* \brief MurmurHash3 64-bit version. Returns 64-bit hash instead of 128
|
||||||
*/
|
*/
|
||||||
u64 ev_hash_murmur3(const void *data, u32 len, u64 seed);
|
u64 ev_hash_murmur3(const void *data, u32 len, u32 seed);
|
||||||
|
|
||||||
#ifdef EV_HASH_IMPLEMENTATION
|
#ifdef EV_HASH_IMPLEMENTATION
|
||||||
#undef EV_HASH_IMPLEMENTATION
|
#undef EV_HASH_IMPLEMENTATION
|
||||||
@@ -151,7 +151,7 @@ void MurmurHash3_x64_128 ( const void * key, const u32 len,
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
u64 ev_hash_murmur3(const void *data, u32 len, u64 seed)
|
u64 ev_hash_murmur3(const void *data, u32 len, u32 seed)
|
||||||
{
|
{
|
||||||
u64 out[2];
|
u64 out[2];
|
||||||
MurmurHash3_x64_128(data, len, (u32)seed, out);
|
MurmurHash3_x64_128(data, len, (u32)seed, out);
|
||||||
|
|||||||
+7
-1
@@ -23,12 +23,18 @@ evstring_readFile(
|
|||||||
#ifdef EV_HELPERS_IMPLEMENTATION
|
#ifdef EV_HELPERS_IMPLEMENTATION
|
||||||
#undef EV_HELPERS_IMPLEMENTATION
|
#undef EV_HELPERS_IMPLEMENTATION
|
||||||
|
|
||||||
|
|
||||||
evstring
|
evstring
|
||||||
evstring_readFile(
|
evstring_readFile(
|
||||||
evstring filePath)
|
evstring filePath)
|
||||||
{
|
{
|
||||||
FILE* f = fopen(filePath, "rb");
|
FILE* f = NULL;
|
||||||
|
#if EV_OS_WINDOWS
|
||||||
|
if(fopen_s(&f,filePath,"rb")) return EV_INVALID(evstring);
|
||||||
|
#else
|
||||||
|
f = fopen(filePath, "rb");
|
||||||
if(f == NULL) return EV_INVALID(evstring);
|
if(f == NULL) return EV_INVALID(evstring);
|
||||||
|
#endif
|
||||||
|
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
u32 buflen = ftell(f);
|
u32 buflen = ftell(f);
|
||||||
|
|||||||
+10
-8
@@ -1,15 +1,17 @@
|
|||||||
#ifndef EV_HEADERS_INTERNAL_H
|
#ifndef EV_HEADERS_INTERNAL_H
|
||||||
#define EV_HEADERS_INTERNAL_H
|
#define EV_HEADERS_INTERNAL_H
|
||||||
|
|
||||||
typedef signed char i8;
|
#include <stdint.h>
|
||||||
typedef short int i16;
|
|
||||||
typedef int i32;
|
|
||||||
typedef long long int i64;
|
|
||||||
|
|
||||||
typedef unsigned char u8;
|
typedef int8_t i8;
|
||||||
typedef unsigned short int u16;
|
typedef int16_t i16;
|
||||||
typedef unsigned int u32;
|
typedef int32_t i32;
|
||||||
typedef unsigned long long int u64;
|
typedef int64_t i64;
|
||||||
|
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
|
||||||
typedef float f32;
|
typedef float f32;
|
||||||
typedef double f64;
|
typedef double f64;
|
||||||
|
|||||||
@@ -0,0 +1,202 @@
|
|||||||
|
#ifndef EV_HEADERS_LOG_H
|
||||||
|
#define EV_HEADERS_LOG_H
|
||||||
|
|
||||||
|
#define EV_LOG_USE_COLOR
|
||||||
|
|
||||||
|
#include "ev_internal.h"
|
||||||
|
|
||||||
|
#include "stdarg.h"
|
||||||
|
#include "stdbool.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "time.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
va_list ap;
|
||||||
|
const char* fmt;
|
||||||
|
const char* file;
|
||||||
|
struct tm* time;
|
||||||
|
void* udata;
|
||||||
|
int line;
|
||||||
|
int level;
|
||||||
|
} ev_log_event_t;
|
||||||
|
|
||||||
|
typedef void (*ev_log_log_fn)(ev_log_event_t* ev);
|
||||||
|
typedef void (*ev_log_lock_fn)(bool lock, void* udata);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EV_LOG_TRACE,
|
||||||
|
EV_LOG_DEBUG,
|
||||||
|
EV_LOG_INFO ,
|
||||||
|
EV_LOG_WARN ,
|
||||||
|
EV_LOG_ERROR,
|
||||||
|
EV_LOG_FATAL,
|
||||||
|
} ev_log_level;
|
||||||
|
|
||||||
|
#define ev_log_trace(...) ev_log(EV_LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define ev_log_debug(...) ev_log(EV_LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define ev_log_info(...) ev_log(EV_LOG_INFO , __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define ev_log_warn(...) ev_log(EV_LOG_WARN , __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define ev_log_error(...) ev_log(EV_LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define ev_log_fatal(...) ev_log(EV_LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
|
||||||
|
const char* ev_log_level_string(ev_log_level level);
|
||||||
|
void ev_log_set_lock(ev_log_lock_fn fn, void* udata);
|
||||||
|
void ev_log_set_level(ev_log_level level);
|
||||||
|
void ev_log_set_quiet(bool enable);
|
||||||
|
i32 ev_log_add_callback(ev_log_log_fn fn, void* udata, ev_log_level level);
|
||||||
|
i32 ev_log_add_fp(FILE *fp, ev_log_level level);
|
||||||
|
|
||||||
|
void ev_log(ev_log_level level, const char* file, u32 line, const char* fmt, ...);
|
||||||
|
|
||||||
|
#ifdef EV_LOG_IMPLEMENTATION
|
||||||
|
#undef EV_LOG_IMPLEMENTATION
|
||||||
|
|
||||||
|
#define MAX_CALLBACKS 32
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ev_log_log_fn fn;
|
||||||
|
void* udata;
|
||||||
|
ev_log_level level;
|
||||||
|
} ev_log_callback_t;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
void* udata;
|
||||||
|
ev_log_lock_fn lock;
|
||||||
|
ev_log_level level;
|
||||||
|
bool quiet;
|
||||||
|
ev_log_callback_t callbacks[MAX_CALLBACKS];
|
||||||
|
} G;
|
||||||
|
|
||||||
|
static const char* level_strings[] = {
|
||||||
|
"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* level_colors[] = {
|
||||||
|
"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ev_log_stdout_callback(ev_log_event_t* ev)
|
||||||
|
{
|
||||||
|
char buf[16];
|
||||||
|
buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0';
|
||||||
|
#ifdef EV_LOG_USE_COLOR
|
||||||
|
fprintf(
|
||||||
|
ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ",
|
||||||
|
buf, level_colors[ev->level], level_strings[ev->level],
|
||||||
|
ev->file, ev->line);
|
||||||
|
#else
|
||||||
|
fprintf(
|
||||||
|
ev->udata, "%s %-5s %s:%d: ",
|
||||||
|
buf, level_strings[ev->level], ev->file, ev->line);
|
||||||
|
#endif
|
||||||
|
vfprintf(ev->udata, ev->fmt, ev->ap);
|
||||||
|
fprintf(ev->udata, "\n");
|
||||||
|
fflush(ev->udata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ev_log_file_callback(ev_log_event_t* ev)
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
|
||||||
|
fprintf(
|
||||||
|
ev->udata, "%s %-5s %s:%d: ",
|
||||||
|
buf, level_strings[ev->level], ev->file, ev->line);
|
||||||
|
vfprintf(ev->udata, ev->fmt, ev->ap);
|
||||||
|
fprintf(ev->udata, "\n");
|
||||||
|
fflush(ev->udata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lock(void)
|
||||||
|
{
|
||||||
|
if(G.lock)
|
||||||
|
G.lock(true, G.udata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unlock(void)
|
||||||
|
{
|
||||||
|
if(G.lock)
|
||||||
|
G.lock(false, G.udata);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ev_log_level_string(ev_log_level level)
|
||||||
|
{
|
||||||
|
return level_strings[level];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ev_log_set_lock(ev_log_lock_fn fn, void* udata)
|
||||||
|
{
|
||||||
|
G.lock = fn;
|
||||||
|
G.udata = udata;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ev_log_set_level(ev_log_level level)
|
||||||
|
{
|
||||||
|
G.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ev_log_set_quiet(bool enable)
|
||||||
|
{
|
||||||
|
G.quiet = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 ev_log_add_callback(ev_log_log_fn fn, void* udata, ev_log_level level)
|
||||||
|
{
|
||||||
|
for (i32 i = 0; i < MAX_CALLBACKS; i++) {
|
||||||
|
if (!G.callbacks[i].fn) {
|
||||||
|
G.callbacks[i] = (ev_log_callback_t) { fn, udata, level };
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
i32 ev_log_add_fp(FILE *fp, ev_log_level level)
|
||||||
|
{
|
||||||
|
return ev_log_add_callback(ev_log_file_callback, fp, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void init_event(ev_log_event_t* ev, void* udata)
|
||||||
|
{
|
||||||
|
if (!ev->time) {
|
||||||
|
time_t t = time(NULL);
|
||||||
|
ev->time = localtime(&t);
|
||||||
|
}
|
||||||
|
ev->udata = udata;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ev_log(ev_log_level level, const char* file, u32 line, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
ev_log_event_t ev = {
|
||||||
|
.fmt = fmt,
|
||||||
|
.file = file,
|
||||||
|
.line = line,
|
||||||
|
.level = level,
|
||||||
|
};
|
||||||
|
|
||||||
|
lock();
|
||||||
|
|
||||||
|
if (!G.quiet && level >= G.level) {
|
||||||
|
init_event(&ev, stderr);
|
||||||
|
va_start(ev.ap, fmt);
|
||||||
|
ev_log_stdout_callback(&ev);
|
||||||
|
va_end(ev.ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i32 i = 0; i < MAX_CALLBACKS && G.callbacks[i].fn; i++) {
|
||||||
|
ev_log_callback_t* cb = &G.callbacks[i];
|
||||||
|
if (level >= cb->level) {
|
||||||
|
init_event(&ev, cb->udata);
|
||||||
|
va_start(ev.ap, fmt);
|
||||||
|
cb->fn(&ev);
|
||||||
|
va_end(ev.ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
+1
-1
@@ -143,7 +143,7 @@
|
|||||||
/*!
|
/*!
|
||||||
* \brief Macro that returns the number of arguments passed to it.
|
* \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_OPT__(,__VA_ARGS__), EV_VA_ARGS_RSEQ_N())
|
||||||
#define EV_VA_ARGS_NARG_IMPL(...) EV_VA_ARGS_ARG_N(__VA_ARGS__)
|
#define EV_VA_ARGS_NARG_IMPL(...) EV_VA_ARGS_ARG_N(__VA_ARGS__)
|
||||||
#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_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
|
#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
|
||||||
|
|||||||
+21
-10
@@ -5,20 +5,20 @@
|
|||||||
#include "ev_types.h"
|
#include "ev_types.h"
|
||||||
|
|
||||||
// Signed integers
|
// Signed integers
|
||||||
TYPEDATA_GEN(i8);
|
TYPEDATA_GEN(i8)
|
||||||
TYPEDATA_GEN(i16);
|
TYPEDATA_GEN(i16)
|
||||||
TYPEDATA_GEN(i32);
|
TYPEDATA_GEN(i32)
|
||||||
TYPEDATA_GEN(i64);
|
TYPEDATA_GEN(i64)
|
||||||
|
|
||||||
// Unsigned integers
|
// Unsigned integers
|
||||||
TYPEDATA_GEN(u8 );
|
TYPEDATA_GEN(u8 )
|
||||||
TYPEDATA_GEN(u16);
|
TYPEDATA_GEN(u16)
|
||||||
TYPEDATA_GEN(u32);
|
TYPEDATA_GEN(u32)
|
||||||
TYPEDATA_GEN(u64);
|
TYPEDATA_GEN(u64)
|
||||||
|
|
||||||
// Floating-Point Numbers
|
// Floating-Point Numbers
|
||||||
TYPEDATA_GEN(f32);
|
TYPEDATA_GEN(f32)
|
||||||
TYPEDATA_GEN(f64);
|
TYPEDATA_GEN(f64)
|
||||||
|
|
||||||
struct Int8Data { i8 MIN; i8 MAX; };
|
struct Int8Data { i8 MIN; i8 MAX; };
|
||||||
struct Int16Data { i16 MIN; i16 MAX; };
|
struct Int16Data { i16 MIN; i16 MAX; };
|
||||||
@@ -97,4 +97,15 @@ static const struct Float64Data Float64 =
|
|||||||
.EPS = 2.2204460492503131e-016
|
.EPS = 2.2204460492503131e-016
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if !EV_OS_WINDOWS
|
||||||
|
#define max(a,b) \
|
||||||
|
({ __typeof__(a) _a = (a); \
|
||||||
|
__typeof__(b) _b = (b); \
|
||||||
|
_a > _b ? _a : _b; })
|
||||||
|
#define min(a,b) \
|
||||||
|
({ __typeof__(a) _a = (a); \
|
||||||
|
__typeof__(b) _b = (b); \
|
||||||
|
_a < _b ? _a : _b; })
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // EV_HEADERS_NUMERIC_H
|
#endif // EV_HEADERS_NUMERIC_H
|
||||||
|
|||||||
@@ -43,18 +43,25 @@
|
|||||||
#define EV_STR_GROWTH_FACTOR 3 / 2
|
#define EV_STR_GROWTH_FACTOR 3 / 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef EV_STR_MIN_CAPACITY
|
||||||
|
/*!
|
||||||
|
* \brief Rate at which an evstring grows whenever a resize is needed
|
||||||
|
*/
|
||||||
|
#define EV_STR_MIN_CAPACITY 4
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef char *evstring;
|
typedef char *evstring;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
EV_STR_ERR_NONE = 0,
|
EV_STR_ERR_NONE = 0,
|
||||||
EV_STR_ERR_OOM = -1,
|
EV_STR_ERR_OOM = -1,
|
||||||
} evstring_error_t;
|
} evstring_error_t;
|
||||||
TYPEDATA_GEN(evstring_error_t, DEFAULT(EV_STR_ERR_NONE));
|
TYPEDATA_GEN(evstring_error_t, DEFAULT(EV_STR_ERR_NONE))
|
||||||
|
|
||||||
struct evstr_meta_t {
|
struct evstr_meta_t {
|
||||||
EV_DEBUG(u64 magic;)
|
EV_DEBUG(u64 magic;)
|
||||||
u64 length;
|
u64 length;
|
||||||
u64 size;
|
u64 capacity;
|
||||||
enum {
|
enum {
|
||||||
EV_STR_ALLOCATION_TYPE_STACK,
|
EV_STR_ALLOCATION_TYPE_STACK,
|
||||||
EV_STR_ALLOCATION_TYPE_HEAP
|
EV_STR_ALLOCATION_TYPE_HEAP
|
||||||
@@ -67,7 +74,7 @@ struct evstr_meta_t {
|
|||||||
(( struct { struct evstr_meta_t meta; char data[len]; } ) { \
|
(( struct { struct evstr_meta_t meta; char data[len]; } ) { \
|
||||||
EV_DEBUG(.meta.magic = EV_STR_evstring_MAGIC,) \
|
EV_DEBUG(.meta.magic = EV_STR_evstring_MAGIC,) \
|
||||||
.meta.length = len-1, \
|
.meta.length = len-1, \
|
||||||
.meta.size = len, \
|
.meta.capacity = len, \
|
||||||
.meta.allocationType = EV_STR_ALLOCATION_TYPE_STACK, \
|
.meta.allocationType = EV_STR_ALLOCATION_TYPE_STACK, \
|
||||||
.data = str \
|
.data = str \
|
||||||
}).data
|
}).data
|
||||||
@@ -120,6 +127,11 @@ evstring_cmp(
|
|||||||
const evstring s1,
|
const evstring s1,
|
||||||
const evstring s2);
|
const evstring s2);
|
||||||
|
|
||||||
|
EV_STR_API i32
|
||||||
|
evstring_view_cmp(
|
||||||
|
const evstring_view v1,
|
||||||
|
const evstring_view v2);
|
||||||
|
|
||||||
EV_STR_API evstring_error_t
|
EV_STR_API evstring_error_t
|
||||||
evstring_pushChar(
|
evstring_pushChar(
|
||||||
evstring *s,
|
evstring *s,
|
||||||
@@ -146,7 +158,7 @@ evstring_slice(
|
|||||||
i64 begin,
|
i64 begin,
|
||||||
i64 end);
|
i64 end);
|
||||||
|
|
||||||
EV_STR_API i32
|
EV_STR_API evstring_error_t
|
||||||
evstring_pushView(
|
evstring_pushView(
|
||||||
evstring *s,
|
evstring *s,
|
||||||
evstring_view ref);
|
evstring_view ref);
|
||||||
@@ -171,11 +183,6 @@ evstring_findFirst(
|
|||||||
const evstring text,
|
const evstring text,
|
||||||
const evstring query);
|
const evstring query);
|
||||||
|
|
||||||
evstring_view
|
|
||||||
__evstring_findFirst_impl(
|
|
||||||
evstring_view text,
|
|
||||||
evstring_view query);
|
|
||||||
|
|
||||||
EV_STR_API evstring
|
EV_STR_API evstring
|
||||||
evstring_replaceFirst(
|
evstring_replaceFirst(
|
||||||
const evstring text,
|
const evstring text,
|
||||||
@@ -197,9 +204,30 @@ DEFINE_EQUAL_FUNCTION(evstring, Default)
|
|||||||
return evstring_cmp(*(evstring*)self, *(evstring*)other) == 0;
|
return evstring_cmp(*(evstring*)self, *(evstring*)other) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_COPY_FUNCTION(evstring, Default)
|
||||||
|
{
|
||||||
|
*(evstring*)dst = evstring_newFromStr(*src);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_FREE_FUNCTION(evstring, Default)
|
||||||
|
{
|
||||||
|
evstring_free(*self);
|
||||||
|
}
|
||||||
|
|
||||||
TYPEDATA_GEN(evstring,
|
TYPEDATA_GEN(evstring,
|
||||||
EQUAL(Default)
|
EQUAL(Default),
|
||||||
);
|
COPY(Default),
|
||||||
|
FREE(Default)
|
||||||
|
)
|
||||||
|
|
||||||
|
DEFINE_EQUAL_FUNCTION(evstring_view, Default)
|
||||||
|
{
|
||||||
|
return evstring_view_cmp(*self, *other) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPEDATA_GEN(evstring_view,
|
||||||
|
EQUAL(Default),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
#if defined(EV_STR_IMPLEMENTATION)
|
#if defined(EV_STR_IMPLEMENTATION)
|
||||||
@@ -237,9 +265,10 @@ evstring_new_impl(
|
|||||||
const char *data,
|
const char *data,
|
||||||
u64 len)
|
u64 len)
|
||||||
{
|
{
|
||||||
u64 size = sizeof(struct evstr_meta_t) + len + 1;
|
u64 str_cap = len + 1;
|
||||||
|
u64 alloc_size = sizeof(struct evstr_meta_t) + str_cap;
|
||||||
|
|
||||||
void *p = ev_str_malloc(size);
|
void *p = ev_str_malloc(alloc_size);
|
||||||
assert(p); // Raised if malloc fails
|
assert(p); // Raised if malloc fails
|
||||||
|
|
||||||
struct evstr_meta_t *meta = (struct evstr_meta_t *)p;
|
struct evstr_meta_t *meta = (struct evstr_meta_t *)p;
|
||||||
@@ -248,7 +277,7 @@ EV_DEBUG
|
|||||||
meta->magic = EV_STR_evstring_MAGIC;
|
meta->magic = EV_STR_evstring_MAGIC;
|
||||||
)
|
)
|
||||||
meta->length = len;
|
meta->length = len;
|
||||||
meta->size = size;
|
meta->capacity = str_cap;
|
||||||
meta->allocationType = EV_STR_ALLOCATION_TYPE_HEAP;
|
meta->allocationType = EV_STR_ALLOCATION_TYPE_HEAP;
|
||||||
|
|
||||||
evstring s = (evstring)(meta + 1);
|
evstring s = (evstring)(meta + 1);
|
||||||
@@ -269,10 +298,11 @@ evstring_newFmt_v(
|
|||||||
{
|
{
|
||||||
va_list test;
|
va_list test;
|
||||||
va_copy(test, args);
|
va_copy(test, args);
|
||||||
i32 len = vsnprintf(NULL, 0, fmt, test);
|
i32 expected_len = vsnprintf(NULL, 0, fmt, test);
|
||||||
if(len < 0) {
|
if(expected_len < 0) {
|
||||||
return EV_INVALID(evstring);
|
return EV_INVALID(evstring);
|
||||||
}
|
}
|
||||||
|
size_t len = (size_t)expected_len;
|
||||||
evstring res = evstring_new_impl(NULL, 0);
|
evstring res = evstring_new_impl(NULL, 0);
|
||||||
evstring_setLength(&res, len);
|
evstring_setLength(&res, len);
|
||||||
vsnprintf(res, len + 1, fmt, args);
|
vsnprintf(res, len + 1, fmt, args);
|
||||||
@@ -318,7 +348,7 @@ evstring_free(
|
|||||||
{
|
{
|
||||||
evstr_asserttype(s);
|
evstr_asserttype(s);
|
||||||
if(META(s)->allocationType == EV_STR_ALLOCATION_TYPE_HEAP) {
|
if(META(s)->allocationType == EV_STR_ALLOCATION_TYPE_HEAP) {
|
||||||
free(META(s));
|
ev_str_free(META(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,9 +361,9 @@ evstring_getLength(
|
|||||||
}
|
}
|
||||||
|
|
||||||
evstring_error_t
|
evstring_error_t
|
||||||
evstring_setSize(
|
evstring_setCapacity(
|
||||||
evstring *s,
|
evstring *s,
|
||||||
size_t newsize)
|
size_t new_capacity)
|
||||||
{
|
{
|
||||||
evstr_asserttype(*s);
|
evstr_asserttype(*s);
|
||||||
struct evstr_meta_t *meta = META(*s);
|
struct evstr_meta_t *meta = META(*s);
|
||||||
@@ -341,12 +371,12 @@ evstring_setSize(
|
|||||||
return EV_STR_ERR_OOM;
|
return EV_STR_ERR_OOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(meta->size == newsize) {
|
if(meta->capacity == new_capacity) {
|
||||||
return EV_STR_ERR_NONE;
|
return EV_STR_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *buf = (void*)meta;
|
void *buf = (void*)meta;
|
||||||
void *tmp = ev_str_realloc(buf, sizeof(struct evstr_meta_t) + newsize);
|
void *tmp = ev_str_realloc(buf, sizeof(struct evstr_meta_t) + new_capacity);
|
||||||
|
|
||||||
if (!tmp) {
|
if (!tmp) {
|
||||||
return EV_STR_ERR_OOM;
|
return EV_STR_ERR_OOM;
|
||||||
@@ -358,7 +388,7 @@ evstring_setSize(
|
|||||||
*s = (evstring)(meta+1);
|
*s = (evstring)(meta+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
meta->size = newsize;
|
meta->capacity = new_capacity;
|
||||||
return EV_STR_ERR_NONE;
|
return EV_STR_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +397,8 @@ evstring_grow(
|
|||||||
evstring *s)
|
evstring *s)
|
||||||
{
|
{
|
||||||
evstr_asserttype(*s);
|
evstr_asserttype(*s);
|
||||||
return evstring_setSize(s, META(*s)->size * EV_STR_GROWTH_FACTOR);
|
u64 new_cap = max(EV_STR_MIN_CAPACITY, META(*s)->capacity * EV_STR_GROWTH_FACTOR);
|
||||||
|
return evstring_setCapacity(s, new_cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
evstring_error_t
|
evstring_error_t
|
||||||
@@ -381,8 +412,8 @@ evstring_setLength(
|
|||||||
return EV_STR_ERR_NONE;
|
return EV_STR_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 required_size = sizeof(struct evstr_meta_t) + newlen + 1;
|
u64 required_capacity = newlen + 1;
|
||||||
while(required_size > meta->size) {
|
while(required_capacity > meta->capacity) {
|
||||||
evstring_error_t grow_err = evstring_grow(s);
|
evstring_error_t grow_err = evstring_grow(s);
|
||||||
if(grow_err) {
|
if(grow_err) {
|
||||||
return grow_err;
|
return grow_err;
|
||||||
@@ -390,6 +421,7 @@ evstring_setLength(
|
|||||||
meta = META(*s);
|
meta = META(*s);
|
||||||
}
|
}
|
||||||
meta->length = newlen;
|
meta->length = newlen;
|
||||||
|
(*s)[newlen] = 0;
|
||||||
|
|
||||||
return EV_STR_ERR_NONE;
|
return EV_STR_ERR_NONE;
|
||||||
}
|
}
|
||||||
@@ -417,6 +449,19 @@ evstring_cmp(
|
|||||||
return memcmp(s1, s2, len1);
|
return memcmp(s1, s2, len1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i32
|
||||||
|
evstring_view_cmp(
|
||||||
|
const evstring_view v1,
|
||||||
|
const evstring_view v2)
|
||||||
|
{
|
||||||
|
evstr_asserttype(v1.data);
|
||||||
|
evstr_asserttype(v2.data);
|
||||||
|
if(v1.len != v2.len) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return memcmp(v1.data+v1.offset, v2.data+v2.offset, v1.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
evstring_error_t
|
evstring_error_t
|
||||||
evstring_push_impl(
|
evstring_push_impl(
|
||||||
@@ -427,9 +472,18 @@ evstring_push_impl(
|
|||||||
evstr_asserttype(*s);
|
evstr_asserttype(*s);
|
||||||
struct evstr_meta_t *meta = META(*s);
|
struct evstr_meta_t *meta = META(*s);
|
||||||
|
|
||||||
|
// Overlapping ranges, need to copy `data` to keep it alive after growing
|
||||||
|
if(*s < data + sz && data < *s + meta->length)
|
||||||
|
{
|
||||||
|
char *old_data = data;
|
||||||
|
data = ev_str_malloc(sz);
|
||||||
|
if(data == NULL) return EV_STR_ERR_OOM;
|
||||||
|
memcpy(data, old_data, sz);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Find a more efficient approach?
|
// TODO Find a more efficient approach?
|
||||||
u64 required_size = sizeof(struct evstr_meta_t) + meta->length + sz + 1;
|
u64 required_capacity = meta->length + sz + 1;
|
||||||
while(required_size > meta->size) { // `<=` because of the null terminator
|
while(required_capacity > meta->capacity) { // `<=` because of the null terminator
|
||||||
evstring_error_t grow_err = evstring_grow(s);
|
evstring_error_t grow_err = evstring_grow(s);
|
||||||
if(grow_err != EV_STR_ERR_NONE) {
|
if(grow_err != EV_STR_ERR_NONE) {
|
||||||
return grow_err;
|
return grow_err;
|
||||||
@@ -486,10 +540,13 @@ evstring_slice(
|
|||||||
u64 wrapped_begin = begin < 0 ? string_len + 1 + begin : begin;
|
u64 wrapped_begin = begin < 0 ? string_len + 1 + begin : begin;
|
||||||
u64 wrapped_end = end < 0 ? string_len + 1 + end : end;
|
u64 wrapped_end = end < 0 ? string_len + 1 + end : end;
|
||||||
|
|
||||||
|
// In this case, the assertions don't matter
|
||||||
|
if(wrapped_begin != wrapped_end)
|
||||||
|
{
|
||||||
assert(wrapped_begin >= 0 && wrapped_begin < string_len);
|
assert(wrapped_begin >= 0 && wrapped_begin < string_len);
|
||||||
assert(wrapped_end > 0 && wrapped_end <= string_len);
|
assert(wrapped_end > 0 && wrapped_end <= string_len);
|
||||||
|
|
||||||
assert(wrapped_begin < wrapped_end);
|
assert(wrapped_begin < wrapped_end);
|
||||||
|
}
|
||||||
|
|
||||||
return (evstring_view) {
|
return (evstring_view) {
|
||||||
.data = s,
|
.data = s,
|
||||||
@@ -504,7 +561,7 @@ evstring_getSpace(
|
|||||||
{
|
{
|
||||||
evstr_asserttype(s);
|
evstr_asserttype(s);
|
||||||
struct evstr_meta_t *meta = META(s);
|
struct evstr_meta_t *meta = META(s);
|
||||||
return meta->size - meta->length - 1 - sizeof(struct evstr_meta_t);
|
return meta->capacity - meta->length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
evstring_error_t
|
evstring_error_t
|
||||||
@@ -513,32 +570,34 @@ evstring_addSpace(
|
|||||||
u64 space)
|
u64 space)
|
||||||
{
|
{
|
||||||
evstr_asserttype(*s);
|
evstr_asserttype(*s);
|
||||||
return evstring_setSize(s, META(*s)->size + space);
|
return evstring_setCapacity(s, META(*s)->capacity + space);
|
||||||
}
|
}
|
||||||
|
|
||||||
evstring_view
|
evstring_view
|
||||||
__evstring_findFirst_impl(
|
evstring_findFirst_impl(
|
||||||
evstring_view text,
|
evstring_view text,
|
||||||
evstring_view query)
|
evstring_view query)
|
||||||
{
|
{
|
||||||
u64 found_progress = 0;
|
|
||||||
|
|
||||||
evstring_view result = {
|
evstring_view result = {
|
||||||
.data = text.data,
|
.data = text.data,
|
||||||
.len = 0,
|
.len = 0,
|
||||||
.offset = ~0ull
|
.offset = ~0ull
|
||||||
};
|
};
|
||||||
|
|
||||||
for(u64 i = text.offset; i < text.offset + text.len; i++) {
|
if(query.len == 0 || query.len > text.len)
|
||||||
if(text.data[i] == query.data[query.offset + found_progress]) {
|
return result;
|
||||||
found_progress++;
|
|
||||||
}
|
for(u64 l = text.offset; l <= text.offset + text.len - query.len; l++)
|
||||||
if(found_progress == query.len) {
|
{
|
||||||
result.offset = (i+1) - query.len;
|
evstring_view curr_view = {
|
||||||
result.len = query.len;
|
.data = text.data,
|
||||||
break;
|
.len = query.len,
|
||||||
}
|
.offset = l
|
||||||
|
};
|
||||||
|
if(EV_EQUAL(evstring_view)(&curr_view, &query))
|
||||||
|
return curr_view;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,7 +608,7 @@ evstring_findFirst(
|
|||||||
{
|
{
|
||||||
evstr_asserttype(text);
|
evstr_asserttype(text);
|
||||||
evstr_asserttype(query);
|
evstr_asserttype(query);
|
||||||
return __evstring_findFirst_impl(evstring_slice(text, 0, -1), evstring_slice(query, 0, -1));
|
return evstring_findFirst_impl(evstring_slice(text, 0, -1), evstring_slice(query, 0, -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
evstring
|
evstring
|
||||||
@@ -668,17 +727,25 @@ evstring_findAll(
|
|||||||
if(text_len == 0 || query_len == 0 || query_len > text_len) {
|
if(text_len == 0 || query_len == 0 || query_len > text_len) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
bool check_run = (results == NULL);
|
|
||||||
|
evstring_view query_view = evstring_slice(query, 0, -1);
|
||||||
|
|
||||||
u64 count = 0;
|
u64 count = 0;
|
||||||
for(evstring_view v = evstring_findFirst(text, query);
|
|
||||||
v.len != 0;
|
for(u64 l = 0; l <= text_len - query_len; l++)
|
||||||
v = __evstring_findFirst_impl(
|
{
|
||||||
evstring_slice(text, v.offset + v.len, -1),
|
evstring_view curr_view = {
|
||||||
evstring_slice(query, 0, -1))) {
|
.data = text,
|
||||||
if(!check_run) {
|
.len = query_len,
|
||||||
results[count++] = v;
|
.offset = l
|
||||||
|
};
|
||||||
|
if(EV_EQUAL(evstring_view)(&curr_view, &query_view))
|
||||||
|
{
|
||||||
|
if(results) results[count] = curr_view;
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-13
@@ -30,12 +30,12 @@ typedef struct {
|
|||||||
void *invalid_val;
|
void *invalid_val;
|
||||||
} EvTypeData;
|
} EvTypeData;
|
||||||
|
|
||||||
#define COPY_FUNCTION(T,name) EV_CATN(EV_COPY_FUNCTION_,T,_,name)
|
#define COPY_FUNCTION(T ,name) EV_CAT(EV_CAT(EV_CAT(EV_COPY_FUNCTION_ ,T),_),name)
|
||||||
#define FREE_FUNCTION(T,name) EV_CATN(EV_FREE_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_CATN(EV_HASH_FUNCTION_,T,_,name)
|
#define HASH_FUNCTION(T ,name) EV_CAT(EV_CAT(EV_CAT(EV_HASH_FUNCTION_ ,T),_),name)
|
||||||
#define EQUAL_FUNCTION(T,name) EV_CATN(EV_EQUAL_FUNCTION_,T,_,name)
|
#define EQUAL_FUNCTION(T ,name) EV_CAT(EV_CAT(EV_CAT(EV_EQUAL_FUNCTION_ ,T),_),name)
|
||||||
#define TOSTR_FUNCTION(T,name) EV_CATN(EV_TOSTR_FUNCTION_,T,_,name)
|
#define TOSTR_FUNCTION(T ,name) EV_CAT(EV_CAT(EV_CAT(EV_TOSTR_FUNCTION_ ,T),_),name)
|
||||||
#define TOSTRLEN_FUNCTION(T,name) EV_CATN(EV_TOSTRLEN_FUNCTION_,T,_,name)
|
#define TOSTRLEN_FUNCTION(T,name) EV_CAT(EV_CAT(EV_CAT(EV_TOSTRLEN_FUNCTION_,T),_),name)
|
||||||
|
|
||||||
#define DEFINE_COPY_FUNCTION(T,name) static inline void COPY_FUNCTION(T,name)(T *dst, T *src)
|
#define DEFINE_COPY_FUNCTION(T,name) static inline void COPY_FUNCTION(T,name)(T *dst, T *src)
|
||||||
#define DEFINE_DEFAULT_COPY_FUNCTION(T) \
|
#define DEFINE_DEFAULT_COPY_FUNCTION(T) \
|
||||||
@@ -80,9 +80,10 @@ typedef struct {
|
|||||||
#define EV_OVERRIDE_VAR(T) EV_CAT(__ev_internal_override_var_,T)
|
#define EV_OVERRIDE_VAR(T) EV_CAT(__ev_internal_override_var_,T)
|
||||||
#define TypeData(T) EV_CAT(EV_TYPEDATA_,T)
|
#define TypeData(T) EV_CAT(EV_TYPEDATA_,T)
|
||||||
#define TYPEDATA_GEN(T, ...) \
|
#define TYPEDATA_GEN(T, ...) \
|
||||||
EV_WARNING_PUSH(); \
|
EV_WARNING_PUSH() \
|
||||||
EV_WARNING_DISABLE_GCC("override-init"); \
|
EV_WARNING_DISABLE_GCC("override-init") \
|
||||||
EV_WARNING_DISABLE_CLANG("initializer-overrides"); \
|
EV_WARNING_DISABLE_CLANG("initializer-overrides") \
|
||||||
|
EV_WARNING_DISABLE_CLANG("reserved-identifier") \
|
||||||
EV_UNUSED static const EvTypeData TypeData(T) = { \
|
EV_UNUSED static const EvTypeData TypeData(T) = { \
|
||||||
EV_DEBUG(.name = EV_STRINGIZE(T),) \
|
EV_DEBUG(.name = EV_STRINGIZE(T),) \
|
||||||
.size = sizeof(T), \
|
.size = sizeof(T), \
|
||||||
@@ -91,10 +92,10 @@ typedef struct {
|
|||||||
.invalid_val = (void*)&(T){0}, \
|
.invalid_val = (void*)&(T){0}, \
|
||||||
EV_VA_OPT(__VA_ARGS__)(EV_FOREACH_UDATA(__EV_STRUCT_METHOD_DEF, T, __VA_ARGS__)) \
|
EV_VA_OPT(__VA_ARGS__)(EV_FOREACH_UDATA(__EV_STRUCT_METHOD_DEF, T, __VA_ARGS__)) \
|
||||||
}; \
|
}; \
|
||||||
EV_WARNING_POP(); \
|
EV_UNUSED static T EV_OVERRIDE_VAR(T); \
|
||||||
EV_UNUSED static T EV_OVERRIDE_VAR(T)
|
EV_WARNING_POP()
|
||||||
|
|
||||||
#define __EV_STRUCT_METHOD_DEF(T, ...) EV_CATN(__EV_,EV_HEAD __VA_ARGS__,_FN)(T, EV_TAIL __VA_ARGS__)
|
#define __EV_STRUCT_METHOD_DEF(T, ...) EV_CAT(EV_CAT(__EV_,EV_HEAD __VA_ARGS__),_FN)(T, EV_TAIL __VA_ARGS__)
|
||||||
|
|
||||||
#define COPY(...) (COPY , __VA_ARGS__)
|
#define COPY(...) (COPY , __VA_ARGS__)
|
||||||
#define FREE(...) (FREE , __VA_ARGS__)
|
#define FREE(...) (FREE , __VA_ARGS__)
|
||||||
@@ -152,6 +153,6 @@ DEFINE_TOSTR_FUNCTION(EvTypeData, EvTypeDataStringize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TYPEDATA_GEN(EvTypeData,
|
TYPEDATA_GEN(EvTypeData,
|
||||||
TOSTR(EvTypeDataStringize));
|
TOSTR(EvTypeDataStringize))
|
||||||
|
|
||||||
#endif // EV_HEADERS_TYPES_H
|
#endif // EV_HEADERS_TYPES_H
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
#include "ev_types.h"
|
#include "ev_types.h"
|
||||||
#include "ev_numeric.h"
|
#include "ev_numeric.h"
|
||||||
|
|
||||||
|
#if !EV_CC_MSVC
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(EV_VEC_SHARED)
|
#if defined(EV_VEC_SHARED)
|
||||||
# if defined (EV_VEC_IMPL)
|
# if defined (EV_VEC_IMPL)
|
||||||
# define EV_VEC_API EV_EXPORT
|
# define EV_VEC_API EV_EXPORT
|
||||||
@@ -30,6 +34,14 @@
|
|||||||
#define EV_VEC_GROWTH_RATE 3 / 2
|
#define EV_VEC_GROWTH_RATE 3 / 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef EV_VEC_MIN_CAPACITY
|
||||||
|
/*!
|
||||||
|
* \brief Minimum capacity used by vector when growing
|
||||||
|
*/
|
||||||
|
#define EV_VEC_MIN_CAPACITY 4
|
||||||
|
#endif
|
||||||
|
|
||||||
#if EV_CC_MSVC
|
#if EV_CC_MSVC
|
||||||
# define __EV_VEC_EMPTY_ARRAY { 0 }
|
# define __EV_VEC_EMPTY_ARRAY { 0 }
|
||||||
#else
|
#else
|
||||||
@@ -41,7 +53,8 @@ typedef void *ev_svec_t;
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
EV_VEC_ERR_NONE = 0,
|
EV_VEC_ERR_NONE = 0,
|
||||||
EV_VEC_ERR_OOM = 1
|
EV_VEC_ERR_OOM = -1,
|
||||||
|
EV_VEC_ERR_INVALID_OP = -2
|
||||||
} ev_vec_error_t;
|
} ev_vec_error_t;
|
||||||
TYPEDATA_GEN(ev_vec_error_t, DEFAULT(EV_VEC_ERR_NONE));
|
TYPEDATA_GEN(ev_vec_error_t, DEFAULT(EV_VEC_ERR_NONE));
|
||||||
|
|
||||||
@@ -99,8 +112,12 @@ TYPEDATA_GEN(ev_vec_overrides_t);
|
|||||||
*/
|
*/
|
||||||
#define ev_svec(T) T*
|
#define ev_svec(T) T*
|
||||||
|
|
||||||
|
#define EV_VEC_MAGIC (0x65765F7665635F74)
|
||||||
|
|
||||||
//! Metadata that is stored with a vector. Unique to each vector.
|
//! Metadata that is stored with a vector. Unique to each vector.
|
||||||
struct ev_vec_meta_t {
|
struct ev_vec_meta_t {
|
||||||
|
u64 _magic;
|
||||||
|
|
||||||
//! The number of elements in the vector.
|
//! The number of elements in the vector.
|
||||||
u64 length;
|
u64 length;
|
||||||
//! The maximum length of the vector before it needs to be resized.
|
//! The maximum length of the vector before it needs to be resized.
|
||||||
@@ -140,15 +157,19 @@ ev_vec_init_impl(
|
|||||||
|
|
||||||
static struct ev_vec_meta_t *__svec_interm_md;
|
static struct ev_vec_meta_t *__svec_interm_md;
|
||||||
#define __ev_svec_init_impl(T, len, cap, ...) ( \
|
#define __ev_svec_init_impl(T, len, cap, ...) ( \
|
||||||
__svec_interm_md = (u8[sizeof(T)*cap + sizeof(struct ev_vec_meta_t)]){}, \
|
EV_WARNING_PUSH() \
|
||||||
|
EV_WARNING_DISABLE_CLANG("unsequenced") \
|
||||||
|
__svec_interm_md = (void*)(u8[sizeof(T)*cap + sizeof(struct ev_vec_meta_t)]){}, \
|
||||||
*__svec_interm_md = (struct ev_vec_meta_t){ \
|
*__svec_interm_md = (struct ev_vec_meta_t){ \
|
||||||
|
._magic = EV_VEC_MAGIC, \
|
||||||
.length = len, \
|
.length = len, \
|
||||||
.capacity = cap, \
|
.capacity = cap, \
|
||||||
.typeData = TypeData(T), \
|
.typeData = TypeData(T), \
|
||||||
.allocationType = EV_VEC_ALLOCATION_TYPE_STACK, \
|
.allocationType = EV_VEC_ALLOCATION_TYPE_STACK, \
|
||||||
}, \
|
}, \
|
||||||
EV_VA_OPT(__VA_ARGS__)(memcpy(&__svec_interm_md[1], (T[])__VA_ARGS__, sizeof((T[])__VA_ARGS__)),) \
|
EV_VA_OPT(__VA_ARGS__)(memcpy(&__svec_interm_md[1], (T[])__VA_ARGS__, sizeof((T[])__VA_ARGS__)),) \
|
||||||
&(__svec_interm_md[1]) \
|
(void*)&(__svec_interm_md[1]) \
|
||||||
|
EV_WARNING_POP() \
|
||||||
)
|
)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -165,50 +186,50 @@ static struct ev_vec_meta_t *__svec_interm_md;
|
|||||||
* *Note* This is possibly replaceable with a variadic function.
|
* *Note* This is possibly replaceable with a variadic function.
|
||||||
*/
|
*/
|
||||||
#define ev_vec_push(v, ...) \
|
#define ev_vec_push(v, ...) \
|
||||||
EV_FOREACH_UDATA(__ev_vec_internal_push, v, __VA_ARGS__);
|
EV_FOREACH_UDATA(__ev_vec_internal_push, v, __VA_ARGS__)
|
||||||
#define __ev_vec_internal_push(v, var) ev_vec_push_impl((ev_vec_t*)v, var);
|
#define __ev_vec_internal_push(v, var) ev_vec_push_impl((ev_vec_t*)v, var)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \param v A pointer to the vector that we want an iterator for
|
* \param vec_p A pointer to the vector that we want an iterator for
|
||||||
*
|
*
|
||||||
* \returns A pointer to the first element in a vector
|
* \returns A pointer to the first element in a vector
|
||||||
*/
|
*/
|
||||||
EV_VEC_API void *
|
EV_VEC_API void *
|
||||||
ev_vec_iter_begin(
|
ev_vec_iter_begin(
|
||||||
const ev_vec_t* v);
|
const void* vec_p);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \param v A pointer to the vector that we want an iterator for
|
* \param vec_p A pointer to the vector that we want an iterator for
|
||||||
*
|
*
|
||||||
* \returns A pointer to the memory block right after the last element in the vector
|
* \returns A pointer to the memory block right after the last element in the vector
|
||||||
*/
|
*/
|
||||||
EV_VEC_API void *
|
EV_VEC_API void *
|
||||||
ev_vec_iter_end(
|
ev_vec_iter_end(
|
||||||
const ev_vec_t* v);
|
const void* vec_p);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A function that increments an iterator to make it point to the next
|
* \brief A function that increments an iterator to make it point to the next
|
||||||
* element in the vector
|
* element in the vector
|
||||||
*
|
*
|
||||||
* \param v A pointer to the vector that is being iterated over
|
* \param vec_p A pointer to the vector that is being iterated over
|
||||||
* \param iter Reference to the iterator that is being incremented
|
* \param iter Reference to the iterator that is being incremented
|
||||||
*/
|
*/
|
||||||
EV_VEC_API void
|
EV_VEC_API void
|
||||||
ev_vec_iter_next(
|
ev_vec_iter_next(
|
||||||
const ev_vec_t* v,
|
const void* vec_p,
|
||||||
void **iter);
|
void **iter);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A function that looks for the index of `val` in `v`
|
* \brief A function that looks for the index of `val` in `v`
|
||||||
*
|
*
|
||||||
* \param v A pointer to the vector that is being iterated over
|
* \param vec_p A pointer to the vector that is being iterated over
|
||||||
* \param val A pointer to the object that will be compared with vector elements
|
* \param val A pointer to the object that will be compared with vector elements
|
||||||
*
|
*
|
||||||
* \returns If found, index of element in vector. Otherwise, -1.
|
* \returns If found, index of element in vector. Otherwise, -1.
|
||||||
*/
|
*/
|
||||||
EV_VEC_API i32
|
EV_VEC_API i32
|
||||||
ev_vec_find(
|
ev_vec_find(
|
||||||
const ev_vec_t* v,
|
const void* vec_p,
|
||||||
void* val);
|
void* val);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -219,11 +240,11 @@ ev_vec_find(
|
|||||||
* *Note*: For stack-allocated vectors (`svec`), destructors are called for
|
* *Note*: For stack-allocated vectors (`svec`), destructors are called for
|
||||||
* elements but no memory is freed.
|
* elements but no memory is freed.
|
||||||
*
|
*
|
||||||
* \param v A pointer to the vector that is being destroyed
|
* \param vec_p A pointer to the vector that is being destroyed
|
||||||
*/
|
*/
|
||||||
EV_VEC_API void
|
EV_VEC_API void
|
||||||
ev_vec_fini(
|
ev_vec_fini(
|
||||||
ev_vec_t* v);
|
void* vec_p);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A function that copies a value to the end of a vector. If the element
|
* \brief A function that copies a value to the end of a vector. If the element
|
||||||
@@ -235,16 +256,16 @@ ev_vec_fini(
|
|||||||
* For `svec`, as long as the capacity is more than the current size, a push
|
* 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.
|
* operation is permitted. Otherwise, the operation is treated as an OOM.
|
||||||
*
|
*
|
||||||
* \param v Reference to the vector object
|
* \param vec_p Reference to the vector object
|
||||||
* \param val A pointer to the element that is to be copied to the end of the
|
* \param val A pointer to the element that is to be copied to the end of the
|
||||||
* vector
|
* vector
|
||||||
*
|
*
|
||||||
* \returns The index of the element that was just pushed. If the operation
|
* \returns The index of the element that was just pushed. If the operation
|
||||||
* failed, a non-zero (vec_error_t) value is returned.
|
* failed, a less-than-zero (vec_error_t) value is returned.
|
||||||
*/
|
*/
|
||||||
EV_VEC_API int
|
EV_VEC_API int
|
||||||
ev_vec_push_impl(
|
ev_vec_push_impl(
|
||||||
ev_vec_t *v,
|
void* vec_p,
|
||||||
void *val);
|
void *val);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -260,7 +281,7 @@ ev_vec_push_impl(
|
|||||||
* operation. If a deep copy is needed, individually pushing the elements of
|
* operation. If a deep copy is needed, individually pushing the elements of
|
||||||
* the array is the way to go.
|
* the array is the way to go.
|
||||||
*
|
*
|
||||||
* \param v Reference to the vector object
|
* \param vec_p Reference to the vector object
|
||||||
* \param arr A pointer to the array that is to be copied to the end of the
|
* \param arr A pointer to the array that is to be copied to the end of the
|
||||||
* vector
|
* vector
|
||||||
* \param size Number of elements in the array
|
* \param size Number of elements in the array
|
||||||
@@ -270,17 +291,32 @@ ev_vec_push_impl(
|
|||||||
*/
|
*/
|
||||||
EV_VEC_API u32
|
EV_VEC_API u32
|
||||||
ev_vec_append(
|
ev_vec_append(
|
||||||
ev_vec_t *v,
|
void* vec_p,
|
||||||
void **arr,
|
void **arr,
|
||||||
u64 size);
|
u64 size);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief A function that duplicates the passed vector into a new one and returns it.
|
||||||
|
*
|
||||||
|
* \param vec_p Reference to the vector object
|
||||||
|
*
|
||||||
|
* \returns The newly created vector.
|
||||||
|
*/
|
||||||
|
EV_VEC_API ev_vec_t
|
||||||
|
ev_vec_dup(
|
||||||
|
const void* vec_p);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A function that copies the value at the end of a vector and removes
|
* \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
|
* 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
|
* vector, then this function is used. Otherwise, memcpy is used with a length
|
||||||
* of `vec_meta.elemsize`
|
* of `vec_meta.elemsize`
|
||||||
*
|
*
|
||||||
* \param v Reference to the vector object
|
* \warning Having a free_fn defined for the elemtype but no copy_fn could have some
|
||||||
|
* unwanted side effects as the free function will be called on the popped element
|
||||||
|
* after copying it to `out`
|
||||||
|
*
|
||||||
|
* \param vec_p Reference to the vector object
|
||||||
* \param out A pointer to the memory block at which the popped element will be
|
* \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
|
* 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
|
* element is copied to `out` and the receiving code is responsible for its
|
||||||
@@ -291,54 +327,54 @@ ev_vec_append(
|
|||||||
*/
|
*/
|
||||||
EV_VEC_API ev_vec_error_t
|
EV_VEC_API ev_vec_error_t
|
||||||
ev_vec_pop(
|
ev_vec_pop(
|
||||||
ev_vec_t *v,
|
void* vec_p,
|
||||||
void *out);
|
void *out);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A function that returns the last element in the vector.
|
* \brief A function that returns the last element in the vector.
|
||||||
*
|
*
|
||||||
* \param v A pointer to the vector object
|
* \param vec_p A pointer to the vector object
|
||||||
*
|
*
|
||||||
* \returns Pointer to the last element in the vector. NULL if the vector is
|
* \returns Pointer to the last element in the vector. NULL if the vector is
|
||||||
* empty.
|
* empty.
|
||||||
*/
|
*/
|
||||||
EV_VEC_API void *
|
EV_VEC_API void *
|
||||||
ev_vec_last(
|
ev_vec_last(
|
||||||
const ev_vec_t* v);
|
const void* v);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A function that returns the length of a vector
|
* \brief A function that returns the length of a vector
|
||||||
*
|
*
|
||||||
* \param v A pointer to the vector object
|
* \param vec_p A pointer to the vector object
|
||||||
*
|
*
|
||||||
* \returns Current length of the vector
|
* \returns Current length of the vector
|
||||||
*/
|
*/
|
||||||
EV_VEC_API u64
|
EV_VEC_API u64
|
||||||
ev_vec_len(
|
ev_vec_len(
|
||||||
const ev_vec_t* v);
|
void* vec_p);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A function that returns the capacity of a vector
|
* \brief A function that returns the capacity of a vector
|
||||||
*
|
*
|
||||||
* \param v A pointer to the vector object
|
* \param vec_p A pointer to the vector object
|
||||||
*
|
*
|
||||||
* \returns Current capacity of the vector
|
* \returns Current capacity of the vector
|
||||||
*/
|
*/
|
||||||
EV_VEC_API u64
|
EV_VEC_API u64
|
||||||
ev_vec_capacity(
|
ev_vec_capacity(
|
||||||
const ev_vec_t* v);
|
const void* vec_p);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Calls the free operation (if exists) on every element, then sets
|
* \brief Calls the free operation (if exists) on every element, then sets
|
||||||
* the length to 0.
|
* the length to 0.
|
||||||
*
|
*
|
||||||
* \param v A pointer to the vector object
|
* \param vec_p A pointer to the vector object
|
||||||
*
|
*
|
||||||
* \returns 0 on success
|
* \returns 0 on success
|
||||||
*/
|
*/
|
||||||
EV_VEC_API u32
|
EV_VEC_API u32
|
||||||
ev_vec_clear(
|
ev_vec_clear(
|
||||||
const ev_vec_t* v);
|
const void* vec_p);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Sets the length of the vector to `len`.
|
* \brief Sets the length of the vector to `len`.
|
||||||
@@ -350,20 +386,20 @@ ev_vec_clear(
|
|||||||
* For `svec`, if the `len` is more than the already allocated capacity, it is
|
* For `svec`, if the `len` is more than the already allocated capacity, it is
|
||||||
* treated as an OOM.
|
* treated as an OOM.
|
||||||
*
|
*
|
||||||
* \param v Reference to the vector object
|
* \param vec_p Reference to the vector object
|
||||||
* \param len The desired new length
|
* \param len The desired new length
|
||||||
*
|
*
|
||||||
* \returns `VEC_ERR_NONE` on success
|
* \returns `VEC_ERR_NONE` on success
|
||||||
*/
|
*/
|
||||||
EV_VEC_API ev_vec_error_t
|
EV_VEC_API ev_vec_error_t
|
||||||
ev_vec_setlen(
|
ev_vec_setlen(
|
||||||
ev_vec_t *v,
|
void* vec_p,
|
||||||
u64 len);
|
u64 len);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Sets the capacity of the vector to `cap`.
|
* \brief Sets the capacity of the vector to `cap`.
|
||||||
*
|
*
|
||||||
* \param v Reference to the vector object
|
* \param vec_p Reference to the vector object
|
||||||
* \param cap The desired new capacity
|
* \param cap The desired new capacity
|
||||||
*
|
*
|
||||||
* For stack-allocated vectors, `VEC_ERR_OOM` is returned
|
* For stack-allocated vectors, `VEC_ERR_OOM` is returned
|
||||||
@@ -372,25 +408,26 @@ ev_vec_setlen(
|
|||||||
*/
|
*/
|
||||||
EV_VEC_API ev_vec_error_t
|
EV_VEC_API ev_vec_error_t
|
||||||
ev_vec_setcapacity(
|
ev_vec_setcapacity(
|
||||||
ev_vec_t *v,
|
void* vec_p,
|
||||||
u64 cap);
|
u64 cap);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Grows the vector's capacity by a factor of `VEC_GROWTH_RATE`
|
* \brief Grows the vector's capacity by a factor of `VEC_GROWTH_RATE`
|
||||||
*
|
*
|
||||||
* \param Reference to the vector object
|
* \param vec_p Reference to the vector object
|
||||||
*
|
*
|
||||||
* \returns `VEC_ERR_NONE` on success
|
* \returns `VEC_ERR_NONE` on success
|
||||||
*/
|
*/
|
||||||
EV_VEC_API ev_vec_error_t
|
EV_VEC_API ev_vec_error_t
|
||||||
ev_vec_grow(
|
ev_vec_grow(
|
||||||
ev_vec_t *v);
|
void* vec_p);
|
||||||
|
|
||||||
static const ev_vec_t EV_VEC_EMPTY =
|
static const ev_vec_t EV_VEC_EMPTY =
|
||||||
(ev_vec(i32))&((struct {
|
(ev_vec(i32))&((struct {
|
||||||
struct ev_vec_meta_t meta;
|
struct ev_vec_meta_t meta;
|
||||||
EV_ALIGNAS(EV_ALIGNOF(i32)) i32 data[0];
|
EV_ALIGNAS(EV_ALIGNOF(i32)) i32 data[0];
|
||||||
}) {
|
}) {
|
||||||
|
.meta._magic = EV_VEC_MAGIC,
|
||||||
.meta.length = 0,
|
.meta.length = 0,
|
||||||
.meta.capacity = 0,
|
.meta.capacity = 0,
|
||||||
.meta.typeData = TypeData(i32),
|
.meta.typeData = TypeData(i32),
|
||||||
@@ -412,6 +449,7 @@ TYPEDATA_GEN(
|
|||||||
#ifdef EV_VEC_IMPLEMENTATION
|
#ifdef EV_VEC_IMPLEMENTATION
|
||||||
#undef EV_VEC_IMPLEMENTATION
|
#undef EV_VEC_IMPLEMENTATION
|
||||||
|
|
||||||
|
|
||||||
#ifdef EV_VEC_API_CHECK
|
#ifdef EV_VEC_API_CHECK
|
||||||
#define EV_VEC_CHECK(x) do { x; } while (0)
|
#define EV_VEC_CHECK(x) do { x; } while (0)
|
||||||
#else
|
#else
|
||||||
@@ -425,7 +463,8 @@ TYPEDATA_GEN(
|
|||||||
((struct ev_vec_meta_t *)v) - 1
|
((struct ev_vec_meta_t *)v) - 1
|
||||||
|
|
||||||
#define __ev_vec_getmeta(v) \
|
#define __ev_vec_getmeta(v) \
|
||||||
struct ev_vec_meta_t *metadata = ((struct ev_vec_meta_t *)(v)) - 1;
|
struct ev_vec_meta_t *metadata = ((struct ev_vec_meta_t *)(v)) - 1; \
|
||||||
|
assert(metadata->_magic == EV_VEC_MAGIC);
|
||||||
|
|
||||||
#define __ev_vec_syncmeta(v) \
|
#define __ev_vec_syncmeta(v) \
|
||||||
metadata = ((struct ev_vec_meta_t *)(v)) - 1;
|
metadata = ((struct ev_vec_meta_t *)(v)) - 1;
|
||||||
@@ -450,6 +489,7 @@ ev_vec_init_impl(
|
|||||||
|
|
||||||
struct ev_vec_meta_t *metadata = (struct ev_vec_meta_t *)v;
|
struct ev_vec_meta_t *metadata = (struct ev_vec_meta_t *)v;
|
||||||
*metadata = (struct ev_vec_meta_t){
|
*metadata = (struct ev_vec_meta_t){
|
||||||
|
._magic = EV_VEC_MAGIC,
|
||||||
.length = 0,
|
.length = 0,
|
||||||
.capacity = EV_VEC_INIT_CAP,
|
.capacity = EV_VEC_INIT_CAP,
|
||||||
.allocationType = EV_VEC_ALLOCATION_TYPE_HEAP,
|
.allocationType = EV_VEC_ALLOCATION_TYPE_HEAP,
|
||||||
@@ -461,9 +501,10 @@ ev_vec_init_impl(
|
|||||||
|
|
||||||
i32
|
i32
|
||||||
ev_vec_find(
|
ev_vec_find(
|
||||||
const ev_vec_t* v,
|
const void* vec_p,
|
||||||
void *val)
|
void *val)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
if(metadata->typeData.equal_fn) {
|
if(metadata->typeData.equal_fn) {
|
||||||
for (void *elem = ev_vec_iter_begin(v); elem != ev_vec_iter_end(v); ev_vec_iter_next(v, &elem)) {
|
for (void *elem = ev_vec_iter_begin(v); elem != ev_vec_iter_end(v); ev_vec_iter_next(v, &elem)) {
|
||||||
@@ -486,8 +527,9 @@ ev_vec_find(
|
|||||||
|
|
||||||
void
|
void
|
||||||
ev_vec_fini(
|
ev_vec_fini(
|
||||||
ev_vec_t* v)
|
void* vec_p)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
|
|
||||||
if (metadata->typeData.free_fn) {
|
if (metadata->typeData.free_fn) {
|
||||||
@@ -505,9 +547,10 @@ ev_vec_fini(
|
|||||||
|
|
||||||
int
|
int
|
||||||
ev_vec_push_impl(
|
ev_vec_push_impl(
|
||||||
ev_vec_t *v,
|
void* vec_p,
|
||||||
void *val)
|
void *val)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
|
|
||||||
if (metadata->length == metadata->capacity) {
|
if (metadata->length == metadata->capacity) {
|
||||||
@@ -531,15 +574,16 @@ ev_vec_push_impl(
|
|||||||
|
|
||||||
void *
|
void *
|
||||||
ev_vec_iter_begin(
|
ev_vec_iter_begin(
|
||||||
const ev_vec_t* v)
|
const void* vec_p)
|
||||||
{
|
{
|
||||||
return *v;
|
return *(void**)vec_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
ev_vec_iter_end(
|
ev_vec_iter_end(
|
||||||
const ev_vec_t* v)
|
const void* vec_p)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
|
|
||||||
return ((char *)*v) + (metadata->typeData.size * metadata->length);
|
return ((char *)*v) + (metadata->typeData.size * metadata->length);
|
||||||
@@ -547,19 +591,21 @@ ev_vec_iter_end(
|
|||||||
|
|
||||||
void
|
void
|
||||||
ev_vec_iter_next(
|
ev_vec_iter_next(
|
||||||
const ev_vec_t* v,
|
const void* vec_p,
|
||||||
void **iter)
|
void **iter)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
*iter = ((char*)*iter) + metadata->typeData.size;
|
*iter = ((char*)*iter) + metadata->typeData.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
EV_VEC_API u32
|
EV_VEC_API u32
|
||||||
ev_vec_append(
|
ev_vec_append(
|
||||||
ev_vec_t *v,
|
void* vec_p,
|
||||||
void **arr,
|
void **arr,
|
||||||
u64 size)
|
u64 size)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
size_t old_len = metadata->length;
|
size_t old_len = metadata->length;
|
||||||
size_t req_len = old_len + size;
|
size_t req_len = old_len + size;
|
||||||
@@ -576,26 +622,51 @@ ev_vec_append(
|
|||||||
return (int)old_len;
|
return (int)old_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EV_VEC_API ev_vec_t
|
||||||
|
ev_vec_dup(
|
||||||
|
const void* vec_p)
|
||||||
|
{
|
||||||
|
ev_vec_t v_orig = *(ev_vec_t*)vec_p;
|
||||||
|
__ev_vec_getmeta(v_orig)
|
||||||
|
ev_vec_t v_new = ev_vec_init_impl(metadata->typeData, (ev_vec_overrides_t){0});
|
||||||
|
ev_vec_setcapacity(&v_new, metadata->length);
|
||||||
|
|
||||||
|
if(metadata->typeData.copy_fn)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < metadata->length; i++)
|
||||||
|
ev_vec_push_impl(&v_new, (u8*)v_orig + (metadata->typeData.size * i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ev_vec_setlen(&v_new, metadata->length);
|
||||||
|
memcpy(v_new, v_orig, metadata->length * metadata->typeData.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return v_new;
|
||||||
|
}
|
||||||
|
|
||||||
ev_vec_error_t
|
ev_vec_error_t
|
||||||
ev_vec_pop(
|
ev_vec_pop(
|
||||||
ev_vec_t *v,
|
void* vec_p,
|
||||||
void *out)
|
void *out)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
|
|
||||||
if(out != NULL) {
|
if(metadata->length == 0) return EV_VEC_ERR_INVALID_OP;
|
||||||
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);
|
void *elem = ((char *)*v) + ((metadata->length-1) * metadata->typeData.size);
|
||||||
|
if(out != NULL) {
|
||||||
|
if (metadata->typeData.copy_fn) {
|
||||||
|
metadata->typeData.copy_fn(out, elem);
|
||||||
|
} else {
|
||||||
|
memcpy(out, elem, metadata->typeData.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (metadata->typeData.free_fn) {
|
if (metadata->typeData.free_fn) {
|
||||||
metadata->typeData.free_fn(elem);
|
metadata->typeData.free_fn(elem);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
metadata->length--;
|
metadata->length--;
|
||||||
|
|
||||||
@@ -604,8 +675,9 @@ ev_vec_pop(
|
|||||||
|
|
||||||
void *
|
void *
|
||||||
ev_vec_last(
|
ev_vec_last(
|
||||||
const ev_vec_t* v)
|
const void* vec_p)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
|
|
||||||
if(metadata->length == 0) {
|
if(metadata->length == 0) {
|
||||||
@@ -617,24 +689,27 @@ ev_vec_last(
|
|||||||
|
|
||||||
u64
|
u64
|
||||||
ev_vec_len(
|
ev_vec_len(
|
||||||
const ev_vec_t* v)
|
void* vec_p)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
return metadata->length;
|
return metadata->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64
|
u64
|
||||||
ev_vec_capacity(
|
ev_vec_capacity(
|
||||||
const ev_vec_t* v)
|
const void* vec_p)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
return metadata->capacity;
|
return metadata->capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32
|
u32
|
||||||
ev_vec_clear(
|
ev_vec_clear(
|
||||||
const ev_vec_t* v)
|
const void* vec_p)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
|
|
||||||
if (metadata->typeData.free_fn) {
|
if (metadata->typeData.free_fn) {
|
||||||
@@ -650,11 +725,15 @@ ev_vec_clear(
|
|||||||
|
|
||||||
ev_vec_error_t
|
ev_vec_error_t
|
||||||
ev_vec_setlen(
|
ev_vec_setlen(
|
||||||
ev_vec_t *v,
|
void* vec_p,
|
||||||
u64 len)
|
u64 len)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
|
|
||||||
|
while(metadata->length > len)
|
||||||
|
ev_vec_pop(vec_p, NULL);
|
||||||
|
|
||||||
while(len > metadata->capacity) {
|
while(len > metadata->capacity) {
|
||||||
ev_vec_error_t grow_err = ev_vec_grow(v);
|
ev_vec_error_t grow_err = ev_vec_grow(v);
|
||||||
if(grow_err) {
|
if(grow_err) {
|
||||||
@@ -669,9 +748,10 @@ ev_vec_setlen(
|
|||||||
|
|
||||||
ev_vec_error_t
|
ev_vec_error_t
|
||||||
ev_vec_setcapacity(
|
ev_vec_setcapacity(
|
||||||
ev_vec_t *v,
|
void* vec_p,
|
||||||
u64 cap)
|
u64 cap)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
|
|
||||||
if(metadata->allocationType == EV_VEC_ALLOCATION_TYPE_STACK) {
|
if(metadata->allocationType == EV_VEC_ALLOCATION_TYPE_STACK) {
|
||||||
@@ -682,6 +762,10 @@ ev_vec_setcapacity(
|
|||||||
return EV_VEC_ERR_NONE;
|
return EV_VEC_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(metadata->length > cap) {
|
||||||
|
ev_vec_setlen(vec_p, cap);
|
||||||
|
}
|
||||||
|
|
||||||
void *buf = ((char *)(*v) - sizeof(struct ev_vec_meta_t));
|
void *buf = ((char *)(*v) - sizeof(struct ev_vec_meta_t));
|
||||||
void *tmp = realloc(buf, sizeof(struct ev_vec_meta_t) + (cap * metadata->typeData.size));
|
void *tmp = realloc(buf, sizeof(struct ev_vec_meta_t) + (cap * metadata->typeData.size));
|
||||||
|
|
||||||
@@ -701,10 +785,12 @@ ev_vec_setcapacity(
|
|||||||
|
|
||||||
ev_vec_error_t
|
ev_vec_error_t
|
||||||
ev_vec_grow(
|
ev_vec_grow(
|
||||||
ev_vec_t *v)
|
void* vec_p)
|
||||||
{
|
{
|
||||||
|
ev_vec_t* v = (ev_vec_t*)vec_p;
|
||||||
__ev_vec_getmeta(*v)
|
__ev_vec_getmeta(*v)
|
||||||
return ev_vec_setcapacity(v, metadata->capacity * EV_VEC_GROWTH_RATE);
|
u64 new_cap = max(EV_VEC_MIN_CAPACITY, metadata->capacity * EV_VEC_GROWTH_RATE);
|
||||||
|
return ev_vec_setcapacity(v, new_cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
[binaries]
|
|
||||||
c = 'clang.exe'
|
|
||||||
c_ld = 'lld'
|
|
||||||
cpp = 'clang++.exe'
|
|
||||||
+31
-9
@@ -1,8 +1,24 @@
|
|||||||
project('evol-headers', 'c',
|
project('evol-headers', 'c',
|
||||||
default_options : [ 'c_std=gnu23' ])
|
default_options : [
|
||||||
|
'c_std=c23',
|
||||||
|
# 'warning_level=everything',
|
||||||
|
# 'werror=true'
|
||||||
|
],
|
||||||
|
meson_version: '>=1.1',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
headers_include = include_directories('.')
|
headers_include = include_directories('.')
|
||||||
|
|
||||||
|
disabled_warnings = {
|
||||||
|
'clang': [
|
||||||
|
'unused-macros',
|
||||||
|
'reserved-macro-identifier',
|
||||||
|
'pre-c11-compat',
|
||||||
|
'pre-c23-compat',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
evh_c_args = []
|
evh_c_args = []
|
||||||
buildtype = get_option('buildtype')
|
buildtype = get_option('buildtype')
|
||||||
if buildtype == 'debug'
|
if buildtype == 'debug'
|
||||||
@@ -20,30 +36,36 @@ elif cc.get_id() == 'clang'
|
|||||||
evh_c_args += '-DEV_CC_CLANG=1'
|
evh_c_args += '-DEV_CC_CLANG=1'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
foreach w:disabled_warnings[cc.get_id()]
|
||||||
|
evh_c_args += '-Wno-'+w
|
||||||
|
endforeach
|
||||||
|
|
||||||
# All other targets should follow the same template
|
# All other targets should follow the same template
|
||||||
str_lib = static_library('ev_str', files('buildfiles/ev_str.c'), c_args: evh_c_args)
|
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)
|
vec_lib = static_library('ev_vec', files('buildfiles/ev_vec.c'), c_args: evh_c_args)
|
||||||
helpers_lib = static_library('ev_helpers', files('buildfiles/ev_helpers.c'), c_args: evh_c_args)
|
helpers_lib = static_library('ev_helpers', files('buildfiles/ev_helpers.c'), c_args: evh_c_args)
|
||||||
|
log_lib = static_library('ev_log', files('buildfiles/ev_log.c'), c_args: evh_c_args)
|
||||||
|
|
||||||
str_dep = declare_dependency(link_with: str_lib, include_directories: headers_include)
|
str_dep = declare_dependency(link_with: str_lib, include_directories: headers_include)
|
||||||
vec_dep = declare_dependency(link_with: vec_lib, include_directories: headers_include)
|
vec_dep = declare_dependency(link_with: vec_lib, include_directories: headers_include)
|
||||||
helpers_dep = declare_dependency(link_with: helpers_lib, include_directories: headers_include)
|
helpers_dep = declare_dependency(link_with: helpers_lib, include_directories: headers_include)
|
||||||
|
log_dep = declare_dependency(link_with: log_lib, include_directories: headers_include)
|
||||||
|
|
||||||
headers_dep = declare_dependency(
|
headers_dep = declare_dependency(
|
||||||
dependencies: [
|
dependencies: [
|
||||||
str_dep,
|
str_dep,
|
||||||
vec_dep,
|
vec_dep,
|
||||||
helpers_dep,
|
helpers_dep,
|
||||||
|
log_dep
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Tests
|
meson.override_dependency('ev_vec', vec_dep)
|
||||||
str_test = executable('str_test', 'str_test.c', dependencies: [str_dep], c_args: evh_c_args)
|
meson.override_dependency('ev_str', str_dep)
|
||||||
test('evstr', str_test)
|
meson.override_dependency('ev_helpers', helpers_dep)
|
||||||
|
meson.override_dependency('ev_log', log_dep)
|
||||||
|
meson.override_dependency('evol-headers', headers_dep)
|
||||||
|
|
||||||
if meson.version().version_compare('>= 0.54.0')
|
if get_option('build_tests')
|
||||||
meson.override_dependency('ev_vec', vec_dep)
|
subdir('tests')
|
||||||
meson.override_dependency('ev_str', str_dep)
|
|
||||||
meson.override_dependency('ev_helpers', helpers_dep)
|
|
||||||
meson.override_dependency('evol-headers', headers_dep)
|
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
option('build_tests', type: 'boolean', value: true, description: 'Build the tests')
|
||||||
-81
@@ -1,81 +0,0 @@
|
|||||||
#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);
|
|
||||||
|
|
||||||
{ // PushFmt Bug
|
|
||||||
printf("PushFmt Bug");
|
|
||||||
evstring heap_str = evstring_new("Heap 'Hello, World!'");
|
|
||||||
printf("Heap String: %s, Length: %llu\n", heap_str, evstring_getLength(heap_str));
|
|
||||||
|
|
||||||
evstring_error_t res = evstring_push(&heap_str, "%.05f", 1.0f);
|
|
||||||
printf("Push Fmt #1: %s, New Length: %llu\n", heap_str, evstring_getLength(heap_str));
|
|
||||||
assert(evstring_getLength(heap_str) == 27);
|
|
||||||
assert(strcmp(heap_str, "Heap 'Hello, World!'1.00000") == 0);
|
|
||||||
assert(res == EV_STR_ERR_NONE);
|
|
||||||
|
|
||||||
/*evstring_push(&heap_str, "%.05f, %.05f, %.05f", 1.0f, 2.0f, 3.0f);*/
|
|
||||||
res = evstring_push(&heap_str, "Something");
|
|
||||||
printf("Push Fmt #2: %s, New Length: %llu\n", heap_str, evstring_getLength(heap_str));
|
|
||||||
assert(evstring_getLength(heap_str) == 36);
|
|
||||||
assert(strcmp(heap_str, "Heap 'Hello, World!'1.00000Something") == 0);
|
|
||||||
assert(res == EV_STR_ERR_NONE);
|
|
||||||
|
|
||||||
evstring_free(heap_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
tests = [
|
||||||
|
]
|
||||||
|
|
||||||
|
foreach t : tests
|
||||||
|
exec = executable(t, t+'.c', include_directories: headers_include, c_args: evh_c_args)
|
||||||
|
test(t, exec, suite: 'hash')
|
||||||
|
endforeach
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#define EV_LOG_IMPLEMENTATION
|
||||||
|
#include "ev_log.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
ev_log_trace("Trace Log");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
tests = [
|
||||||
|
'basic_log',
|
||||||
|
]
|
||||||
|
|
||||||
|
foreach t : tests
|
||||||
|
exec = executable(t, t+'.c', dependencies: [log_dep], c_args: evh_c_args)
|
||||||
|
test(t, exec, suite: 'log')
|
||||||
|
endforeach
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring text = evstr("Hello, this is me saying `Hello` like someone who says 'Hello'");
|
||||||
|
|
||||||
|
assert(evstring_findAll(text, evstr("Hello"), NULL) == 3);
|
||||||
|
assert(evstring_findAll(evstr("abc"), evstr("abc"), NULL) == 1);
|
||||||
|
assert(evstring_findAll(evstr("abcx"), evstr("abc"), NULL) == 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring_view search_results[1];
|
||||||
|
evstring text = evstr("abc");
|
||||||
|
evstring query = evstr("abc");
|
||||||
|
|
||||||
|
assert(evstring_findAll(text, query, search_results) == 1);
|
||||||
|
assert(search_results[0].data == text);
|
||||||
|
assert(search_results[0].len == 3);
|
||||||
|
assert(search_results[0].offset == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring_view search_results[1];
|
||||||
|
evstring text = evstr("Hello, this is me saying `Hello` like someone who says 'Hello'");
|
||||||
|
|
||||||
|
assert(evstring_findAll(text, evstr(""), search_results) == 0);
|
||||||
|
assert(evstring_findAll(text, evstr("Goodbye"), search_results) == 0);
|
||||||
|
assert(evstring_findAll(evstr("ab"), evstr("abc"), search_results) == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring_view search_results[2];
|
||||||
|
evstring text = evstr("aaa");
|
||||||
|
evstring query = evstr("aa");
|
||||||
|
|
||||||
|
assert(evstring_findAll(text, query, search_results) == 2);
|
||||||
|
|
||||||
|
assert(search_results[0].data == text);
|
||||||
|
assert(search_results[0].len == 2);
|
||||||
|
assert(search_results[0].offset == 0);
|
||||||
|
|
||||||
|
assert(search_results[1].data == text);
|
||||||
|
assert(search_results[1].len == 2);
|
||||||
|
assert(search_results[1].offset == 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring_view search_results[1];
|
||||||
|
evstring text = evstr("abcx");
|
||||||
|
evstring query = evstr("abc");
|
||||||
|
|
||||||
|
assert(evstring_findAll(text, query, search_results) == 1);
|
||||||
|
assert(search_results[0].data == text);
|
||||||
|
assert(search_results[0].len == 3);
|
||||||
|
assert(search_results[0].offset == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring text = evstr("abc");
|
||||||
|
evstring query = evstr("");
|
||||||
|
|
||||||
|
evstring_view match = evstring_findFirst(text, query);
|
||||||
|
|
||||||
|
assert(match.len == 0);
|
||||||
|
assert(match.offset == ~0ull);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring text = evstr("");
|
||||||
|
evstring query = evstr("a");
|
||||||
|
|
||||||
|
evstring_view match = evstring_findFirst(text, query);
|
||||||
|
|
||||||
|
assert(match.len == 0);
|
||||||
|
assert(match.offset == ~0ull);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring text = evstr("aab");
|
||||||
|
evstring query = evstr("ab");
|
||||||
|
evstring_view match = evstring_findFirst(text, query);
|
||||||
|
|
||||||
|
assert(match.len == 2);
|
||||||
|
assert(match.offset == 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring text = evstr("aaab");
|
||||||
|
evstring query = evstr("aab");
|
||||||
|
evstring_view match = evstring_findFirst(text, query);
|
||||||
|
|
||||||
|
assert(match.len == 3);
|
||||||
|
assert(match.offset == 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring text = evstr("ab");
|
||||||
|
evstring query = evstr("abc");
|
||||||
|
|
||||||
|
evstring_view match = evstring_findFirst(text, query);
|
||||||
|
|
||||||
|
assert(match.len == 0);
|
||||||
|
assert(match.offset == ~0ull);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
tests = [
|
||||||
|
'stack_global_heap',
|
||||||
|
'slice',
|
||||||
|
'push_variants',
|
||||||
|
'new_format',
|
||||||
|
'replace_first',
|
||||||
|
'find_all',
|
||||||
|
'find_all_exact_match',
|
||||||
|
'find_all_short_suffix',
|
||||||
|
'find_all_count_only',
|
||||||
|
'find_all_no_matches',
|
||||||
|
'find_all_overlapping',
|
||||||
|
'push_fmt_float',
|
||||||
|
'find_first_mismatch',
|
||||||
|
'find_first_overlapping_prefix',
|
||||||
|
'stack_get_space',
|
||||||
|
'overlapping_push',
|
||||||
|
'find_first_empty_query',
|
||||||
|
'find_first_query_too_long',
|
||||||
|
'find_first_empty_text',
|
||||||
|
'replace_first_query_too_long',
|
||||||
|
]
|
||||||
|
|
||||||
|
foreach t : tests
|
||||||
|
exec = executable(t, t+'.c', dependencies: [str_dep], c_args: evh_c_args)
|
||||||
|
test(t, exec, suite: 'str')
|
||||||
|
endforeach
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring source = evstr("Stack 'Hello, World!'");
|
||||||
|
evstring_view view = evstring_slice(source, 0, -1);
|
||||||
|
|
||||||
|
evstring str_fmt = evstring_new("%d, %d, %.*s", 1, 0, view.len, view.data + view.offset);
|
||||||
|
assert(str_fmt != NULL);
|
||||||
|
assert(strcmp(str_fmt, "1, 0, Stack 'Hello, World!'") == 0);
|
||||||
|
|
||||||
|
evstring_free(str_fmt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring s = evstring_newFromStr("abc");
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
evstring_error_t err = evstring_pushStr(&s, s);
|
||||||
|
assert(err == EV_STR_ERR_NONE);
|
||||||
|
assert(strcmp(s, "abcabc") == 0);
|
||||||
|
|
||||||
|
evstring_free(s);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring heap_str = evstring_new("Heap 'Hello, World!'");
|
||||||
|
assert(heap_str != NULL);
|
||||||
|
|
||||||
|
evstring_error_t res = evstring_push(&heap_str, "%.05f", 1.0f);
|
||||||
|
assert(res == EV_STR_ERR_NONE);
|
||||||
|
assert(evstring_getLength(heap_str) == 27);
|
||||||
|
assert(strcmp(heap_str, "Heap 'Hello, World!'1.00000") == 0);
|
||||||
|
|
||||||
|
res = evstring_push(&heap_str, "Something");
|
||||||
|
assert(res == EV_STR_ERR_NONE);
|
||||||
|
assert(evstring_getLength(heap_str) == 36);
|
||||||
|
assert(strcmp(heap_str, "Heap 'Hello, World!'1.00000Something") == 0);
|
||||||
|
|
||||||
|
evstring_free(heap_str);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring heap_str = evstring_new("Heap 'Hello, World!'");
|
||||||
|
assert(heap_str != NULL);
|
||||||
|
|
||||||
|
evstring_error_t push_str_res = evstring_push(&heap_str, "Hello, Sisyphus! %f", 0.001f);
|
||||||
|
assert(push_str_res == EV_STR_ERR_NONE);
|
||||||
|
assert(strcmp(heap_str, "Heap 'Hello, World!'Hello, Sisyphus! 0.001000") == 0);
|
||||||
|
|
||||||
|
evstring_error_t push_char_res = evstring_push(&heap_str, (char)'X');
|
||||||
|
assert(push_char_res == EV_STR_ERR_NONE);
|
||||||
|
assert(strcmp(heap_str, "Heap 'Hello, World!'Hello, Sisyphus! 0.001000X") == 0);
|
||||||
|
|
||||||
|
evstring source = evstr("Stack 'Hello, World!'");
|
||||||
|
evstring_view view = evstring_slice(source, 0, -1);
|
||||||
|
evstring_error_t push_view_res = evstring_push(&heap_str, view);
|
||||||
|
assert(push_view_res == EV_STR_ERR_NONE);
|
||||||
|
assert(strcmp(heap_str, "Heap 'Hello, World!'Hello, Sisyphus! 0.001000XStack 'Hello, World!'") == 0);
|
||||||
|
|
||||||
|
evstring_free(heap_str);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring text = evstring_new("Hello, Hello!");
|
||||||
|
assert(text != NULL);
|
||||||
|
|
||||||
|
evstring rep_str = evstring_replaceFirst(text, evstr("Hello"), evstr("Bye"));
|
||||||
|
assert(rep_str != NULL);
|
||||||
|
assert(strcmp(rep_str, "Bye, Hello!") == 0);
|
||||||
|
|
||||||
|
evstring_free(rep_str);
|
||||||
|
evstring_free(text);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring text = evstr("ab");
|
||||||
|
evstring replacement = evstr("x");
|
||||||
|
evstring query = evstr("abc");
|
||||||
|
|
||||||
|
evstring result = evstring_replaceFirst(text, query, replacement);
|
||||||
|
|
||||||
|
assert(EV_EQUAL(evstring)(&result, &text));
|
||||||
|
|
||||||
|
evstring_free(result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const evstring stack_str = evstr("Stack 'Hello, World!'");
|
||||||
|
|
||||||
|
evstring_view view = evstring_slice(stack_str, 0, -1);
|
||||||
|
assert(view.data == stack_str);
|
||||||
|
assert(view.offset == 0);
|
||||||
|
assert(view.len == evstring_getLength(stack_str));
|
||||||
|
|
||||||
|
evstring heap_str = evstring_new(view);
|
||||||
|
assert(heap_str != NULL);
|
||||||
|
assert(strcmp(heap_str, stack_str) == 0);
|
||||||
|
assert(evstring_getLength(heap_str) == evstring_getLength(stack_str));
|
||||||
|
|
||||||
|
evstring_free(heap_str);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
evstring stack_str = evstr("abc");
|
||||||
|
assert(evstring_getSpace(stack_str) == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#define EV_STR_IMPLEMENTATION
|
||||||
|
#include "ev_str.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static evstring global_str = evstr("Global 'Hello, World!'");
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const evstring stack_str = evstr("Stack 'Hello, World!'");
|
||||||
|
assert(strcmp(stack_str, "Stack 'Hello, World!'") == 0);
|
||||||
|
assert(evstring_getLength(stack_str) == 21);
|
||||||
|
|
||||||
|
assert(strcmp(global_str, "Global 'Hello, World!'") == 0);
|
||||||
|
assert(evstring_getLength(global_str) == 22);
|
||||||
|
|
||||||
|
evstring heap_str = evstring_new("Heap 'Hello, World!'");
|
||||||
|
assert(heap_str != NULL);
|
||||||
|
assert(strcmp(heap_str, "Heap 'Hello, World!'") == 0);
|
||||||
|
assert(evstring_getLength(heap_str) == 20);
|
||||||
|
|
||||||
|
evstring_free(heap_str);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
tests = [
|
||||||
|
'tostr',
|
||||||
|
]
|
||||||
|
|
||||||
|
foreach t : tests
|
||||||
|
exec = executable(t, t+'.c', include_directories: headers_include, c_args: evh_c_args)
|
||||||
|
test(t, exec, suite: 'types')
|
||||||
|
endforeach
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
tests = [
|
||||||
|
'zero_cap_grow',
|
||||||
|
'reducecap_updatelen',
|
||||||
|
'reducecap_free_elems',
|
||||||
|
'reducelen_free_elems',
|
||||||
|
'pop_out_frees_vector_owned_elem',
|
||||||
|
]
|
||||||
|
|
||||||
|
foreach t : tests
|
||||||
|
exec = executable(t, t+'.c', dependencies: [vec_dep], c_args: evh_c_args)
|
||||||
|
test(t, exec, suite: 'vec')
|
||||||
|
endforeach
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#define EV_VEC_IMPLEMENTATION
|
||||||
|
#include "ev_vec.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static int free_calls = 0;
|
||||||
|
|
||||||
|
typedef struct OwningInt {
|
||||||
|
int *ptr;
|
||||||
|
} OwningInt;
|
||||||
|
|
||||||
|
DEFINE_COPY_FUNCTION(OwningInt, Default)
|
||||||
|
{
|
||||||
|
dst->ptr = malloc(sizeof(*dst->ptr));
|
||||||
|
assert(dst->ptr != NULL);
|
||||||
|
*dst->ptr = *src->ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_FREE_FUNCTION(OwningInt, Default)
|
||||||
|
{
|
||||||
|
assert(self->ptr != NULL);
|
||||||
|
free(self->ptr);
|
||||||
|
self->ptr = NULL;
|
||||||
|
free_calls++;
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPEDATA_GEN(OwningInt, COPY(Default), FREE(Default));
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
ev_vec(OwningInt) v = ev_vec_init(OwningInt);
|
||||||
|
assert(v != NULL);
|
||||||
|
|
||||||
|
OwningInt original = { .ptr = malloc(sizeof(*original.ptr)) };
|
||||||
|
assert(original.ptr != NULL);
|
||||||
|
*original.ptr = 42;
|
||||||
|
|
||||||
|
assert(ev_vec_push_impl(&v, &original) == 0);
|
||||||
|
free(original.ptr);
|
||||||
|
|
||||||
|
OwningInt out = {0};
|
||||||
|
assert(ev_vec_pop(&v, &out) == EV_VEC_ERR_NONE);
|
||||||
|
assert(out.ptr != NULL);
|
||||||
|
assert(*out.ptr == 42);
|
||||||
|
|
||||||
|
FREE_FUNCTION(OwningInt, Default)(&out);
|
||||||
|
|
||||||
|
/* Popping with an output copy transfers no pointer from the vector element.
|
||||||
|
The vector's own deep-copied element must still be destroyed. */
|
||||||
|
assert(free_calls == 2);
|
||||||
|
|
||||||
|
ev_vec_fini(&v);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#define EV_VEC_IMPLEMENTATION
|
||||||
|
#include "ev_vec.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
static int free_calls = 0;
|
||||||
|
|
||||||
|
static void count_free(void *self)
|
||||||
|
{
|
||||||
|
(void)self;
|
||||||
|
free_calls++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
ev_vec(i32) v = ev_vec_init(i32, free = count_free);
|
||||||
|
assert(v != NULL);
|
||||||
|
|
||||||
|
for(i32 i = 0; i < 5; i++) {
|
||||||
|
assert(ev_vec_push_impl(&v, &i) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_calls = 0;
|
||||||
|
assert(ev_vec_setcapacity(&v, 3) == EV_VEC_ERR_NONE);
|
||||||
|
assert(free_calls == 2);
|
||||||
|
|
||||||
|
ev_vec_fini(&v);
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#define EV_VEC_IMPLEMENTATION
|
||||||
|
#include "ev_vec.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
ev_vec(i32) v = ev_vec_init(i32);
|
||||||
|
assert(v != NULL);
|
||||||
|
|
||||||
|
for(i32 i = 0; i < 5; i++) {
|
||||||
|
assert(ev_vec_push_impl(&v, &i) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ev_vec_error_t err = ev_vec_setcapacity(&v, 2);
|
||||||
|
assert(err != EV_VEC_ERR_NONE || ev_vec_len(&v) <= ev_vec_capacity(&v));
|
||||||
|
|
||||||
|
ev_vec_fini(&v);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#define EV_VEC_IMPLEMENTATION
|
||||||
|
#include "ev_vec.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
static int free_calls = 0;
|
||||||
|
|
||||||
|
static void count_free(void *self)
|
||||||
|
{
|
||||||
|
(void)self;
|
||||||
|
free_calls++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
ev_vec(i32) v = ev_vec_init(i32, free = count_free);
|
||||||
|
assert(v != NULL);
|
||||||
|
|
||||||
|
free_calls = 0;
|
||||||
|
assert(ev_vec_setlen(&v, 3) == EV_VEC_ERR_NONE);
|
||||||
|
assert(ev_vec_setlen(&v, 1) == EV_VEC_ERR_NONE);
|
||||||
|
assert(free_calls == 2);
|
||||||
|
|
||||||
|
ev_vec_fini(&v);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#define EV_VEC_IMPLEMENTATION
|
||||||
|
#include "ev_vec.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
ev_vec(i32) v = ev_vec_init(i32);
|
||||||
|
assert(v != NULL);
|
||||||
|
|
||||||
|
assert(ev_vec_setcapacity(&v, 0) == EV_VEC_ERR_NONE);
|
||||||
|
assert(ev_vec_capacity(&v) == 0);
|
||||||
|
assert(ev_vec_grow(&v) == EV_VEC_ERR_NONE);
|
||||||
|
assert(ev_vec_capacity(&v) > 0);
|
||||||
|
|
||||||
|
ev_vec_fini(&v);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
subdir('ev_hash')
|
||||||
|
subdir('ev_log')
|
||||||
|
subdir('ev_str')
|
||||||
|
subdir('ev_types')
|
||||||
|
subdir('ev_vec')
|
||||||
Reference in New Issue
Block a user