kerep-headers

This commit is contained in:
2023-07-12 11:34:41 +03:00
parent d3525f66d4
commit 683395983c
49 changed files with 2003 additions and 20 deletions

17
kerep-headers/base/base.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "std.h"
#include "errors.h"
#include "cptr.h"
#include "optime.h"
#include "type_system/type_system.h"
#include "../kprint/kprintf.h"
#include "endian.h"
#if __cplusplus
}
#endif

94
kerep-headers/base/cptr.h Normal file
View File

@@ -0,0 +1,94 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "std.h"
// returns length of char buffer (without \0)
u32 cptr_length(const char* str);
// allocates new char[] and copies src there
char* cptr_copy(const char* src);
bool cptr_equals(const char* key0, const char* key1);
bool cptr_startsWith(const char* src, const char* fragment);
bool cptr_endsWith(const char* src, const char* fragment);
// multiplies char n times
char* char_multiply(char c, u32 n);
/// @param startIndex 0 ... src length
/// @param seekLength 0 ... -1
/// @return pos of first <fragment> inclusion in <src> or -1 if not found
i32 cptr_seek(const char* src, const char* fragment, u32 startIndex, u32 seekLength);
/// @param startIndex -1 ... src length
/// @param seekLength 0 ... -1
/// @return pos of first <fragment> inclusion in <src> or -1 if not found
i32 cptr_seekReverse(const char* src, const char* fragment, u32 startIndex, u32 seekLength);
/// @param startIndex 0 ... src length
/// @param seekLength 0 ... -1
/// @return pos of first <fragment> inclusion in <src> or -1 if not found
i32 cptr_seekChar(const char* src, char fragment, u32 startIndex, u32 seekLength);
/// @param startIndex -1 ... src length
/// @param seekLength 0 ... -1
/// @return pos of first <fragment> inclusion in <src> or -1 if not found
i32 cptr_seekCharReverse(const char* src, char fragment, u32 startIndex, u32 seekLength);
/// @brief search for <fragment> in <ptr>
/// @return index of first <fragment> inclusion or -1 if not found
static inline i32 cptr_indexOf(const char* src, const char* fragment)
{ return cptr_seek(src, fragment, 0, -1); }
/// @brief search for <fragment> in <ptr>
/// @return index of first <fragment> inclusion or -1 if not found
static inline i32 cptr_indexOfChar(const char* src, char fragment)
{ return cptr_seekChar(src, fragment, 0, -1); }
/// @brief search for <fragment> in <ptr>
/// @return index of last <fragment> inclusion or -1 if not found
static inline i32 cptr_lastIndexOf(const char* src, const char* fragment)
{ return cptr_seekReverse(src, fragment, -1, -1); }
/// @brief search for <fragment> in <ptr>
/// @return index of last <fragment> inclusion or -1 if not found
static inline i32 cptr_lastIndexOfChar(const char* src, char fragment)
{ return cptr_seekCharReverse(src, fragment, -1, -1); }
static inline bool cptr_contains(const char* src, const char* fragment){
return cptr_seek(src, fragment, 0, -1) +1;
}
void memcopy(void* from, void* to, u32 size);
char* __cptr_concat(u32 n, ...);
#define cptr_concat(STR...) __cptr_concat(count_args(STR), STR)
char* cptr_toLower(const char* src);
char* cptr_toUpper(const char* src);
/// @param startIndex 0 ... src length
/// @param seekLength 0 ... -1
/// @return <src> with <str_old> replaced by <str_new> or empty cstring if <str_old> not found
char* cptr_replaceIn(const char* src, const char* str_old, const char* str_new, u32 startIndex, u32 seekLength);
/// @param startIndex 0 ... src length
/// @param seekLength 0 ... -1
/// @return <src> with <c_old> replaced by <c_new> or empty cstring if <str_old> not found
char* cptr_replaceCharIn(const char* src, char c_old, char c_new, u32 startIndex, u32 seekLength);
static inline char* cptr_replace(const char* src, const char* str_old, const char* str_new)
{ return cptr_replaceIn(src, str_old, str_new, 0, -1); }
static inline char* cptr_replaceChar(const char* src, char c_old, char c_new)
{ return cptr_replaceCharIn(src, c_old, c_new, 0, -1); }
#if __cplusplus
}
#endif

View File

@@ -0,0 +1,20 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "std.h"
#include "type_system/typedef_macros.h"
PACKED_ENUM(Endian,
UnknownEndian=0,
LittleEndian=1,
BigEndian=2
)
Endian getEndian();
#if __cplusplus
}
#endif

View File

@@ -0,0 +1,90 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "std.h"
#include "type_system/type_system.h"
PACKED_ENUM(ErrorId,
SUCCESS, // not an error
ERR_MAXLENGTH, ERR_WRONGTYPE, ERR_WRONGINDEX,
ERR_NOTIMPLEMENTED, ERR_NULLPTR, ERR_ENDOFSTR,
ERR_KEYNOTFOUND, ERR_FORMAT, ERR_UNEXPECTEDVAL,
ERR_IO, ERR_IO_EOF
)
char* errname(ErrorId err);
char* __genErrMsg(const char* errmsg, const char* srcfile, i32 line, const char* funcname);
char* __extendErrMsg(const char* errmsg, const char* srcfile, i32 line, const char* funcname);
STRUCT(Maybe,
Unitype value;
char* errmsg;
)
// return it if func doesn't return anything
// .value .errmsg
#define MaybeNull (Maybe){UniNull, NULL}
void Maybe_free(Maybe e);
void printMaybe(Maybe e);
#define SUCCESS(REZLT) (Maybe){.errmsg=NULL, .value=REZLT}
#define __RETURN_EXCEPTION(ERRMSG) return (Maybe){.value=UniNull, .errmsg=ERRMSG}
#define __EXIT(ERRMSG) ({ kprintf("\e[91m%s\e[0m \n", ERRMSG); free(ERRMSG); exit(128); })
char* __doNothing(char* a);
char* __unknownErr( );
#define __stringify_err(E) _Generic( \
(E), \
char*: __doNothing, \
int: errname, \
default: __unknownErr \
)(E)
#if __cplusplus
#define throw_id(E) __EXIT(((char*)__genErrMsg(errname(E), __FILE__,__LINE__,__func__)))
#define throw_msg(E) __EXIT(((char*)__genErrMsg(E, __FILE__,__LINE__,__func__)))
#define safethrow_id(E, FREEMEM) { FREEMEM; \
__RETURN_EXCEPTION(((char*)__genErrMsg(errname(E), __FILE__,__LINE__,__func__))); \
}
#define safethrow_msg(E, FREEMEM) { FREEMEM; \
__RETURN_EXCEPTION(((char*)__genErrMsg(E, __FILE__,__LINE__,__func__))); \
}
#define try_cpp(_funcCall, _rezult, freeMem) Maybe _rezult=_funcCall; if(_rezult.errmsg){ \
freeMem; \
_rezult.errmsg=__extendErrMsg(_rezult.errmsg, __FILE__,__LINE__,__func__); \
return _rezult; \
}
#else
#define throw(E) __EXIT(((char*)__genErrMsg((__stringify_err(E)), __FILE__,__LINE__,__func__)))
#define safethrow(E, FREEMEM) { FREEMEM; \
__RETURN_EXCEPTION(((char*)__genErrMsg((__stringify_err(E)), __FILE__,__LINE__,__func__))); \
}
#define try(_funcCall, _rezult, freeMem) Maybe _rezult=_funcCall; if(_rezult.errmsg){ \
freeMem; \
_rezult.errmsg=__extendErrMsg(_rezult.errmsg, __FILE__,__LINE__,__func__); \
return _rezult; \
}
#endif
#define tryLast(_funcCall, _rezult, ON_EXIT) Maybe _rezult=_funcCall; if(_rezult.errmsg){ \
_rezult.errmsg=__extendErrMsg(_rezult.errmsg, __FILE__,__LINE__,__func__); \
__EXIT(_rezult.errmsg); \
}
#if __cplusplus
}
#endif

View File

@@ -0,0 +1,41 @@
#pragma once
#include "std.h"
#define __optime_print(opname, t) \
char tnames[3][3]={"s\0","ms","us"}; \
i32 tni=0; \
if(t>1000000){ \
t/=1000000; \
tni=0; \
} else if(t>1000){ \
t/=1000; \
tni=1; \
} else tni=2; \
kprintf("\e[93moperation \e[94m%s\e[93m lasted \e[94m%f \e[93m%s\n", \
opname, t, tnames[tni]);
#ifdef CLOCK_REALTIME
/// executes codeblock and prints execution time
/// u64 op_i is counter of the internal loop
/// uses non-standard high-precision clock
#define optime(opname, repeats, codeblock...) { \
struct timespec start, stop; \
clock_gettime(CLOCK_REALTIME, &start); \
for(u64 op_i=0;op_i<(u64)repeats;op_i++) \
{ codeblock; } \
clock_gettime(CLOCK_REALTIME, &stop); \
f64 t=(f64)(stop.tv_sec-start.tv_sec)*1000000+(f64)(stop.tv_nsec-start.tv_nsec)/1000; \
__optime_print(opname,t); \
}
#else
/// uses standard low precision clock
#define optime(opname, repeats, codeblock...) { \
clock_t start=clock(); \
for(u64 op_i=0;op_i<(u64)repeats;op_i++) \
{ codeblock; } \
clock_t stop=clock(); \
f64 t=(f64)(stop-start)/CLOCKS_PER_SEC*1000000; \
__optime_print(opname,t); \
}
#endif

135
kerep-headers/base/std.h Normal file
View File

@@ -0,0 +1,135 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <stddef.h>
#include <locale.h>
#include <time.h>
#include <setjmp.h>
#include <signal.h>
#include <math.h>
typedef int8_t i8;
typedef uint8_t u8;
typedef int16_t i16;
typedef uint16_t u16;
typedef int32_t i32;
typedef uint32_t u32;
typedef int64_t i64;
typedef uint64_t u64;
typedef float f32;
typedef double f64;
/// anonymous pointer without specified freeMembers() func
typedef void* Pointer;
// Usually bool from stdbool.h is defined as macro,
// so in other macros like ktid_##TYPE it will be replaced by _Bool.
// ktid__Bool will be created instead of ktid_bool
// In C++ bool is a keyword, so there is no need to redefine it.
#if !__cplusplus
typedef u8 bool;
#define true 1
#define false 0
#endif
#define dbg(N) kprintf("\e[95m%d\n",N)
#define nameof(V) #V
#ifdef _MSC_VER
#pragma comment(lib, "mincore_downlevel.lib") // Support OS older than SDK
#define _CRT_SECURE_NO_WARNINGS 1
#define EXPORT __declspec(dllexport)
#define CALL __cdecl
#elif defined(__GNUC__)
#define EXPORT __attribute__((visibility("default")))
#if __SIZEOF_POINTER__ == 4
#define CALL __attribute__((__cdecl__))
#else
#define CALL
#endif
#ifndef typeof
#define typeof(X) __typeof__(X)
#endif
#else
#pragma GCC error "unknown compiler"
#endif
#ifdef _MSC_VER
#define IFWIN(YES, NO) YES
#define IFMSC(YES, NO) YES
#elif defined(_WIN64) || defined(_WIN32)
#define IFWIN(YES, NO) YES
#define IFMSC(YES, NO) NO
#elif defined(__GNUC__)
#define IFWIN(YES, NO) NO
#define IFMSC(YES, NO) NO
#else
#pragma GCC error "unknown compiler"
#endif
#ifndef sprintf_s
#define sprintf_s(BUF, BUFSIZE, FORMAT, ...) sprintf(BUF, FORMAT, ## __VA_ARGS__)
#endif
#define __count_args( \
a0, a1, a2, a3, a4, a5, a6, a7 , \
a8, a9, a10,a11,a12,a13,a14,a15, \
a16,a17,a18,a19,a20,a21,a22,a23, \
a24,a25,a26,a27,a28,a29,a30,a31, \
a32,a33,a34,a35,a36,a37,a38,a39, \
a40,a41,a42,a43,a44,a45,a46,a47, \
a48,a49,a50,a51,a52,a53,a54,a55, \
a56,a57,a58,a59,a60,a61,a62,a63, \
a64,...) a64
// Macro for counting variadic arguments (max 64)
// (see usage in kprint.h)
#define count_args(ARGS...) __count_args( \
ARGS, \
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)
/*
Cross-platform warning supression.
WARNING_DISABLE( W_EXAMPLE,
some code producing W_EXAMPLE;
);
You can even embed it into macro in header (see kprint.h)
*/
#ifdef _MSC_VER
#define PRAGMA_WARNING_PUSH __pragma(warning( push ))
#define DISABLE_WARNING(wNumber) __pragma(warning( disable : wNumber ))
#define PRAGMA_WARNING_POP __pragma(warning( pop ))
#else
#define _PRAGMA(P) _Pragma(#P)
#define PRAGMA_WARNING_PUSH _PRAGMA(GCC diagnostic push)
#define PRAGMA_WARNING_DISABLE(wName) _PRAGMA(GCC diagnostic ignored wName)
#define PRAGMA_WARNING_POP _PRAGMA(GCC diagnostic pop)
#define W_INT_CONVERSION "-Wint-conversion"
#define W_IMPLICIT_FALLTHROUGH "-Wimplicit-fallthrough"
#endif
#define WARNING_DISABLE(WARNING, CODE...) \
PRAGMA_WARNING_PUSH \
PRAGMA_WARNING_DISABLE(WARNING) \
CODE; \
PRAGMA_WARNING_POP
/// gcc throws warning on unused function return value
#define WARN_UNUSED_REZULT __attribute__((warn_unused_result))
#if __cplusplus
}
#endif

View File

@@ -0,0 +1,34 @@
# kerep type system
For using some kerep capabilities, such as generic structs, unitype, and kprint, types should be *registered*.
## type id
Every registered type has its own `ktDescriptor` and `ktid` is an index of the descriptor in descriptors array.
Descriptor should be declared in header file.
Following macro declares `typedef struct` and `ktDescriptor`
```c
//someStruct.h
STRUCT(someStruct,
i32 i; i32 j; i32 k;
);
```
then you need to define descriptor in a source file
```c
//someStruct.c
kt_define(someStruct);
```
and register it.
## type descriptors
Every registered type should have it's own descriptor (`ktDescriptor`). It's a struct, which contains some information about type and pointers to some specific functions for this type (`toString`, `freeMembers`).
## type registration
To finally register a type, you should call macro `kt_register()` between `kt_beginInit()` and `kt_endInit()`. Better do it at the start of your program. To register all types from kerep, call `kt_initKerepTypes()`.
You can free internal ktDescriptors storage by calling `kt_free()` at exit, if your debugger (valgrind in my case) sees a memory leak.
Examples:
+ [kerep types registration](src/base/type_system/init.c)
+ [kt_initKerepTypes()](tests/main.cpp)

View File

@@ -0,0 +1,47 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "../errors.h"
// accepts char* (ptr to char) and char* (ptr to string)
// uses format kp_s and kp_c to determine what type is <c> argument
char* __toString_char(void* c, u32 fmt);
// bool
char* __toString_bool(void* c, u32 fmt);
// signed int
char* toString_i64(i64 n);
char* __toString_i8(void* n, u32 fmt);
char* __toString_i16(void* n, u32 fmt);
char* __toString_i32(void* n, u32 fmt);
char* __toString_i64(void* n, u32 fmt);
// unsigned int
char* toString_u64(u64 n, bool withPostfix, bool uppercase);
char* __toString_u8(void* n, u32 fmt);
char* __toString_u16(void* n, u32 fmt);
char* __toString_u32(void* n, u32 fmt);
char* __toString_u64(void* n, u32 fmt);
// float
#define toString_f32_max_precision 6
#define toString_f64_max_precision 15
#define toString_float_default_precision 6
char* toString_f32(f32 n, u8 precision, bool withPostfix, bool uppercase); // uses sprintf
char* toString_f64(f64 n, u8 precision, bool withPostfix, bool uppercase); // uses sprintf
char* __toString_f32(void* n, u32 fmt);
char* __toString_f64(void* n, u32 fmt);
///@param inverse set to true for little endian numbers (their bytes are in reverse order)
char* toString_bin(void* bytes, u32 size, bool inverse, bool withPrefix);
///@param inverse set to true for little endian numbers (their bytes are in reverse order)
char* toString_hex(void* bytes, u32 size, bool inverse, bool withPrefix, bool uppercase);
#if __cplusplus
}
#endif

View File

@@ -0,0 +1,12 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
// call this between kt_beginInit() and kt_endInit()
void kt_initKerepTypes();
#if __cplusplus
}
#endif

View File

@@ -0,0 +1,51 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "../std.h"
#include "ktid.h"
#include "typedef_macros.h"
#define kt_declare(TYPE)\
ktid_declare(TYPE);\
extern ktDescriptor ktDescriptor_##TYPE; \
extern ktDescriptor ktDescriptor_##TYPE##_Ptr;
#define kt_define(TYPE, FREE_MEMBERS_F, TOSTRING_F)\
ktid_define(TYPE); \
ktDescriptor ktDescriptor_##TYPE={ \
.name=#TYPE, \
.id=ktid_undefined, \
.size=sizeof(TYPE), \
.freeMembers=FREE_MEMBERS_F, \
.toString=TOSTRING_F \
}; \
ktDescriptor ktDescriptor_##TYPE##_Ptr={\
.name=#TYPE "_Ptr", \
.id=ktid_undefined, \
.size=sizeof(TYPE), \
.freeMembers=FREE_MEMBERS_F, \
.toString=TOSTRING_F \
};
typedef void (*freeMembers_t)(void*);
typedef char* (*toString_t)(void* obj, u32 fmt);
STRUCT(ktDescriptor,
char* name;
ktid id;
u16 size;
freeMembers_t freeMembers; // NULL or function which frees all struct members
toString_t toString; // NULL or function which generates string representaion of object
)
/// gets descriptor for TYPE
#define ktDescriptor_name(TYPE) ktDescriptor_##TYPE
/// gets descriptor for pointer to TYPE
#define ktDescriptor_namePtr(TYPE) ktDescriptor_##TYPE##_Ptr
#if __cplusplus
}
#endif

View File

@@ -0,0 +1,49 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "../std.h"
#include "ktid.h"
#include "ktDescriptor.h"
extern ktid ktid_last;
void __kt_register(ktDescriptor* descriptor);
#define kt_register(TYPE) \
__kt_register(&ktDescriptor_##TYPE); \
ktid_##TYPE=ktid_last; \
__kt_register(&ktDescriptor_##TYPE##_Ptr); \
ktid_##TYPE##_Ptr=ktid_last;
void kt_beginInit();
void kt_endInit();
/// @param id id of registered type
ktDescriptor* ktDescriptor_get(ktid id);
char* ktDescriptor_toString(ktDescriptor* d);
// call it to free heap-allocated ktDescriptors array
void kt_free();
kt_declare(Pointer);
kt_declare(char);
kt_declare(bool);
kt_declare(f32);
kt_declare(f64);
kt_declare(i8);
kt_declare(u8);
kt_declare(i16);
kt_declare(u16);
kt_declare(i32);
kt_declare(u32);
kt_declare(i64);
kt_declare(u64);
kt_declare(ktDescriptor);
#if __cplusplus
}
#endif

View File

@@ -0,0 +1,28 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "../std.h"
#include "typedef_macros.h"
typedef u16 ktid;
static const ktid ktid_undefined=-1;
/// gets descriptor id for TYPE
#define ktid_name(TYPE) ktid_##TYPE
/// gets descriptor id for pointer to TYPE
#define ktid_ptrName(TYPE) ktid_##TYPE##_Ptr
#define ktid_declare(TYPE) \
extern ktid ktid_##TYPE; \
extern ktid ktid_##TYPE##_Ptr;
#define ktid_define(TYPE) \
ktid ktid_##TYPE=-1; \
ktid ktid_##TYPE##_Ptr=-1;
#if __cplusplus
}
#endif

View File

@@ -0,0 +1,8 @@
#pragma once
#include "init.h"
#include "ktid.h"
#include "ktDescriptor.h"
#include "kt_functions.h"
#include "unitype.h"
#include "typedef_macros.h"

View File

@@ -0,0 +1,15 @@
#pragma once
#define ENUM(ENUM_NAME, ENUM_MEMBERS...) typedef enum ENUM_NAME { \
ENUM_MEMBERS \
} ENUM_NAME;
#define PACKED_ENUM(ENUM_NAME, ENUM_MEMBERS...) typedef enum ENUM_NAME { \
ENUM_MEMBERS \
} __attribute__((__packed__)) ENUM_NAME;
#define STRUCT(STRUCT_NAME, STRUCT_MEMBERS...) typedef struct STRUCT_NAME STRUCT_NAME; \
typedef struct STRUCT_NAME { \
STRUCT_MEMBERS \
} STRUCT_NAME; \
kt_declare(STRUCT_NAME);

View File

@@ -0,0 +1,55 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "ktid.h"
#include "typedef_macros.h"
STRUCT(Unitype,
union {
i64 Int64;
u64 UInt64;
f64 Float64;
bool Bool;
void* VoidPtr;
char Bytes[8];
};
ktid typeId;
bool allocatedInHeap; // should Unitype_free call free() to VoidPtr*
)
#define __UniDef(FIELD, TYPE, VAL) ((Unitype){ \
.FIELD=VAL, .typeId=ktid_name(TYPE), .allocatedInHeap=false})
#define UniInt64(VAL) __UniDef(Int64, i64, VAL)
#define UniUInt64(VAL) __UniDef(UInt64, u64, VAL)
#define UniFloat64(VAL) __UniDef(Float64, f64, VAL)
#define UniBool(VAL) __UniDef(Bool, bool, VAL)
#define UniPtr(TYPE_ID, VAL, ALLOCATED_ON_HEAP)((Unitype){ \
.VoidPtr=VAL, .typeId=TYPE_ID, .allocatedInHeap=ALLOCATED_ON_HEAP })
#define UniStackPtr(TYPE, VAL) UniPtr(ktid_ptrName(TYPE), VAL, false)
#define UniHeapPtr(TYPE, VAL) UniPtr(ktid_ptrName(TYPE), VAL, true)
// 0==ktid_Pointer
#define UniNull ((Unitype){.Int64=0, .typeId=0, .allocatedInHeap=false})
#define UniTrue UniBool(true)
#define UniFalse UniBool(false)
#define Unitype_isUniNull(UNI) (UNI.typeId==0 && UNI.Int64==0)
#define UniCheckTypeId(UNI, TYPE_ID) (UNI.typeId==TYPE_ID)
#define UniCheckType(UNI, TYPE) UniCheckTypeId(UNI, ktid_name(TYPE))
#define UniCheckTypePtr(UNI, TYPE) UniCheckTypeId(UNI, ktid_ptrName(TYPE))
// frees VoidPtr value or does nothing if type isn't pointer
void Unitype_free(Unitype u);
void __UnitypePtr_free(void* u);
char* Unitype_toString(Unitype v, u32 fmt);
void printuni(Unitype v);
#if __cplusplus
}
#endif