kerep sources
This commit is contained in:
17
kerep/src/base/base.h
Normal file
17
kerep/src/base/base.h
Normal 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
|
||||
217
kerep/src/base/cptr.c
Normal file
217
kerep/src/base/cptr.c
Normal file
@@ -0,0 +1,217 @@
|
||||
#include "base.h"
|
||||
#include "../String/StringBuilder.h"
|
||||
#include <ctype.h>
|
||||
|
||||
// returns length of char buffer (without \0)
|
||||
u32 cptr_length(const char* str){
|
||||
const char *const str_first=str;
|
||||
while(*str)
|
||||
str++;
|
||||
return str-str_first;
|
||||
}
|
||||
|
||||
// allocates new char[] and copies src there
|
||||
char* cptr_copy(const char* src){
|
||||
u32 len=cptr_length(src)+1;
|
||||
char* dst=malloc(len);
|
||||
while(len--!=0)
|
||||
dst[len]=src[len];
|
||||
return dst;
|
||||
}
|
||||
|
||||
// multiplies char n times
|
||||
char* char_multiply(char c, u32 n){
|
||||
char* rez=malloc(n+1);
|
||||
rez[n]=0;
|
||||
while(n--!=0)
|
||||
rez[n]=c;
|
||||
return rez;
|
||||
}
|
||||
|
||||
bool cptr_equals(const char* key0, const char* key1){
|
||||
char c0=*key0;
|
||||
char c1=*key1;
|
||||
bool eq=c0==c1;
|
||||
while(c0 && c1 && eq) {
|
||||
c0=*++key0;
|
||||
c1=*++key1;
|
||||
eq=c0==c1;
|
||||
}
|
||||
return eq;
|
||||
}
|
||||
|
||||
bool cptr_startsWith(const char* src, const char* fragment){
|
||||
char c0=*src;
|
||||
char c1=*fragment;
|
||||
bool eq=c0==c1 && c0 !=0 && c1!=0;
|
||||
while(c0 && c1 && eq) {
|
||||
c0=*++src;
|
||||
c1=*++fragment;
|
||||
eq=c0==c1;
|
||||
if(c1==0)
|
||||
return true;
|
||||
}
|
||||
return eq;
|
||||
}
|
||||
|
||||
bool cptr_endsWith(const char* src, const char* fragment){
|
||||
u32 src_len=cptr_length(src);
|
||||
u32 fr_len=cptr_length(fragment);
|
||||
if(src_len<fr_len || src_len==0 || fr_len==0)
|
||||
return false;
|
||||
src+=src_len-fr_len;
|
||||
return cptr_equals(src, fragment);
|
||||
}
|
||||
|
||||
|
||||
i32 cptr_seek(const char* src, const char* fragment, u32 startIndex, u32 seekLength){
|
||||
char sc=*src, fc=*fragment;
|
||||
if(sc==0 || fc==0)
|
||||
return -1;
|
||||
u32 fr_start=startIndex;
|
||||
for(u32 si=startIndex; si-startIndex<seekLength && sc!=0; si++){
|
||||
sc=src[si];
|
||||
fc=fragment[si-fr_start];
|
||||
if(fc==0)
|
||||
return fr_start;
|
||||
if(sc!=fc)
|
||||
fr_start++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
i32 cptr_seekReverse(const char* src, const char* fragment, u32 startIndex, u32 seekLength){
|
||||
char sc=*src, fc=*fragment;
|
||||
if(sc==0 || fc==0)
|
||||
return -1;
|
||||
i32 len=cptr_length(src);
|
||||
if(startIndex==(u32)-1)
|
||||
startIndex=len-1;
|
||||
u32 fr_len=cptr_length(fragment);
|
||||
for(u32 si=startIndex; si<(u32)-1 && si!=len-1-seekLength; si--){
|
||||
if(si+1<fr_len)
|
||||
return -1;
|
||||
sc=src[si];
|
||||
fc=fragment[0];
|
||||
u32 fr_start=si;
|
||||
for(u32 fi=0; fc==sc ; fi++){
|
||||
if(fi==fr_len)
|
||||
return fr_start;
|
||||
fc=fragment[fi];
|
||||
sc=src[si--];
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
i32 cptr_seekChar(const char* src, char fragment, u32 startIndex, u32 seekLength){
|
||||
char sc=*src;
|
||||
if(sc==0 || fragment==0)
|
||||
return -1;
|
||||
for(u32 si=startIndex; si-startIndex<seekLength && sc!=0; si++){
|
||||
sc=src[si];
|
||||
if(sc==fragment)
|
||||
return si;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
i32 cptr_seekCharReverse(const char* src, char fragment, u32 startIndex, u32 seekLength){
|
||||
char sc=*src;
|
||||
if(sc==0 || fragment==0)
|
||||
return -1;
|
||||
i32 len=cptr_length(src);
|
||||
if(startIndex==(u32)-1)
|
||||
startIndex=len-1;
|
||||
for(u32 si=startIndex; si<(u32)-1 && si!=len-1-seekLength; si--){
|
||||
sc=src[si];
|
||||
if(sc==fragment)
|
||||
return si;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void memcopy(void* from, void* to, u32 size){
|
||||
if(from==NULL || to==NULL)
|
||||
throw(ERR_NULLPTR);
|
||||
for(u32 i=0; i<size; i++)
|
||||
((char*)to)[i]=((char*)from)[i];
|
||||
}
|
||||
|
||||
char* __cptr_concat(u32 n, ...){
|
||||
char** strs=(char**)malloc(n*sizeof(char*));
|
||||
u32* lengths=malloc(n*sizeof(u32));
|
||||
u32 totalLength=0;
|
||||
|
||||
// reading args from va_list
|
||||
va_list vl;
|
||||
va_start(vl, n);
|
||||
for(u16 i=0; i<n; i++){
|
||||
char* str=va_arg(vl,char*);
|
||||
i16 length=cptr_length(str);
|
||||
strs[i]=str;
|
||||
lengths[i]=length;
|
||||
totalLength+=length;
|
||||
}
|
||||
va_end(vl);
|
||||
|
||||
// allocating memory for output value
|
||||
char* totality=malloc(totalLength+1);
|
||||
char* output=totality;
|
||||
totality[totalLength]=0;
|
||||
|
||||
// copying content of all strings to rezult
|
||||
for(u16 k=0; k<n; k++){
|
||||
memcopy(strs[k], totality, lengths[k]);
|
||||
totality+=lengths[k];
|
||||
}
|
||||
|
||||
free(strs);
|
||||
free(lengths);
|
||||
return output;
|
||||
}
|
||||
|
||||
char* cptr_toLower(const char* src) {
|
||||
u32 length=cptr_length(src);
|
||||
char *p=malloc(length+1);
|
||||
p[length]=0;
|
||||
for(u32 i=0; i<length; i++)
|
||||
p[i]=tolower(src[i]);
|
||||
return p;
|
||||
}
|
||||
|
||||
char* cptr_toUpper(const char* src) {
|
||||
u32 length=cptr_length(src);
|
||||
char *p=malloc(length+1);
|
||||
p[length]=0;
|
||||
for(u32 i=0; i<length; i++)
|
||||
p[i]=toupper(src[i]);
|
||||
return p;
|
||||
}
|
||||
|
||||
char* cptr_replaceCharIn(const char* src, char c_old, char c_new, u32 startIndex, u32 seekLength){
|
||||
char* rzlt=cptr_copy(src);
|
||||
for(u32 i=startIndex; i!=seekLength && src[i]!=0; i++){
|
||||
if(src[i]==c_old)
|
||||
rzlt[i]=c_new;
|
||||
}
|
||||
return rzlt;
|
||||
}
|
||||
|
||||
char* cptr_replaceIn(const char* src, const char* str_old, const char* str_new, u32 startIndex, u32 seekLength){
|
||||
StringBuilder* sb=StringBuilder_create();
|
||||
const u32 str_old_len=cptr_length(str_old);
|
||||
const u32 str_new_len=cptr_length(str_new);
|
||||
i32 i=startIndex;
|
||||
while( (i=cptr_seek(src, str_old, startIndex, seekLength)) !=-1 ){
|
||||
if(i!=0)
|
||||
StringBuilder_append_string(sb, (string){.ptr=(char*)src, .length=i});
|
||||
StringBuilder_append_string(sb, (string){.ptr=str_new, .length=str_new_len});
|
||||
src+=i+str_old_len;
|
||||
}
|
||||
u32 src_remains_len=cptr_length(src);
|
||||
if(src_remains_len>0)
|
||||
StringBuilder_append_string(sb, (string){.ptr=(char*)src, .length=src_remains_len});
|
||||
string rezult=StringBuilder_build(sb);
|
||||
return rezult.ptr;
|
||||
}
|
||||
94
kerep/src/base/cptr.h
Normal file
94
kerep/src/base/cptr.h
Normal 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
|
||||
13
kerep/src/base/endian.c
Normal file
13
kerep/src/base/endian.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "endian.h"
|
||||
|
||||
static const union
|
||||
{
|
||||
u16 number;
|
||||
Endian bytes[2];
|
||||
} _endian_union={ .number=0x0102 };
|
||||
|
||||
Endian getEndian(){
|
||||
// if 0x0102 == { 1, 2 } then BigEndian
|
||||
// if 0x0102 == { 2, 1 } then LittleEndian
|
||||
return _endian_union.bytes[1];
|
||||
}
|
||||
20
kerep/src/base/endian.h
Normal file
20
kerep/src/base/endian.h
Normal 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
|
||||
59
kerep/src/base/errors.c
Normal file
59
kerep/src/base/errors.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "std.h"
|
||||
#include "errors.h"
|
||||
#include "cptr.h"
|
||||
#include "../kprint/kprintf.h"
|
||||
|
||||
char* errname(ErrorId err){
|
||||
switch(err){
|
||||
case SUCCESS: return nameof(SUCCESS);
|
||||
case ERR_MAXLENGTH: return nameof(ERR_MAXLENGTH);
|
||||
case ERR_WRONGTYPE: return nameof(ERR_WRONGTYPE);
|
||||
case ERR_WRONGINDEX: return nameof(ERR_WRONGINDEX);
|
||||
case ERR_NOTIMPLEMENTED: return nameof(ERR_NOTIMPLEMENTED);
|
||||
case ERR_NULLPTR: return nameof(ERR_NULLPTR);
|
||||
case ERR_ENDOFSTR: return nameof(ERR_ENDOFSTR);
|
||||
case ERR_KEYNOTFOUND: return nameof(ERR_KEYNOTFOUND);
|
||||
case ERR_FORMAT: return nameof(ERR_FORMAT);
|
||||
case ERR_UNEXPECTEDVAL: return nameof(ERR_UNEXPECTEDVAL);
|
||||
case ERR_IO: return nameof(ERR_IO);
|
||||
case ERR_IO_EOF: return nameof(ERR_IO_EOF);
|
||||
default: return "UNKNOWN_ERROR";
|
||||
}
|
||||
}
|
||||
|
||||
#define ERRMSG_MAXLENGTH 1024
|
||||
|
||||
char* __genErrMsg(const char* errmsg, const char* srcfile, i32 line, const char* funcname){
|
||||
size_t bufsize=ERRMSG_MAXLENGTH;
|
||||
char* rezult=malloc(bufsize);
|
||||
IFMSC(
|
||||
sprintf_s(rezult,bufsize,"[%s:%d] %s() throwed error: %s",srcfile,line,funcname,errmsg),
|
||||
sprintf(rezult,"[%s:%d] %s() throwed error: %s",srcfile,line,funcname,errmsg)
|
||||
);
|
||||
return rezult;
|
||||
}
|
||||
|
||||
char* __extendErrMsg(const char* errmsg, const char* srcfile, i32 line, const char* funcname){
|
||||
size_t bufsize=cptr_length(errmsg)+ERRMSG_MAXLENGTH;
|
||||
char* rezult=malloc(bufsize);
|
||||
IFMSC(
|
||||
sprintf_s(rezult,bufsize,"%s\n \\___[%s:%d] %s()",errmsg,srcfile,line,funcname),
|
||||
sprintf(rezult,"%s\n \\___[%s:%d] %s()",errmsg,srcfile,line,funcname)
|
||||
);
|
||||
free(errmsg);
|
||||
return rezult;
|
||||
}
|
||||
|
||||
void Maybe_free(Maybe e){
|
||||
free(e.errmsg);
|
||||
Unitype_free(e.value);
|
||||
}
|
||||
|
||||
void printMaybe(Maybe e){
|
||||
if(e.errmsg) kprintf("%s\n",e.errmsg);
|
||||
else printuni(e.value);
|
||||
}
|
||||
|
||||
char* __doNothing(char* a) {return a;}
|
||||
|
||||
char* __unknownErr() {return "UNKNOWN ERROR";}
|
||||
90
kerep/src/base/errors.h
Normal file
90
kerep/src/base/errors.h
Normal 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
|
||||
41
kerep/src/base/optime.h
Normal file
41
kerep/src/base/optime.h
Normal 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
|
||||
139
kerep/src/base/std.h
Normal file
139
kerep/src/base/std.h
Normal file
@@ -0,0 +1,139 @@
|
||||
#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
|
||||
|
||||
#ifndef typeof
|
||||
#define typeof __typeof__
|
||||
#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
|
||||
34
kerep/src/base/type_system/README.md
Normal file
34
kerep/src/base/type_system/README.md
Normal 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)
|
||||
238
kerep/src/base/type_system/base_toString.c
Normal file
238
kerep/src/base/type_system/base_toString.c
Normal file
@@ -0,0 +1,238 @@
|
||||
#include "base_toString.h"
|
||||
#include "../base.h"
|
||||
#include "../../kprint/kprint_format.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) {
|
||||
// *c=char*
|
||||
if(kp_fmt_dataFormat(fmt)==kp_s){
|
||||
return cptr_copy((char*)c); // to avoid segmentation fault on free() when *c allocalet on stack
|
||||
}
|
||||
// *c=char
|
||||
if(kp_fmt_dataFormat(fmt)==kp_c){
|
||||
char* cc=malloc(2);
|
||||
cc[0]=*(char*)c;
|
||||
cc[1]=0;
|
||||
return cc;
|
||||
}
|
||||
else throw(ERR_FORMAT);
|
||||
}
|
||||
|
||||
char* __toString_bool(void* c, u32 fmt) {
|
||||
static const char _strbool[4][6]={ "false", "true\0", "False", "True\0" };
|
||||
u8 strind=*(bool*)c==1 + kp_fmt_isUpper(fmt)*2;
|
||||
char* rez=malloc(6);
|
||||
rez[0]=_strbool[strind][0];
|
||||
rez[1]=_strbool[strind][1];
|
||||
rez[2]=_strbool[strind][2];
|
||||
rez[3]=_strbool[strind][3];
|
||||
rez[4]=_strbool[strind][4];
|
||||
rez[5]=0;
|
||||
return rez;
|
||||
}
|
||||
|
||||
char* toString_i64(i64 n){
|
||||
i64 d=n<0 ? -1*n : n;
|
||||
char str[32];
|
||||
u8 i=sizeof(str);
|
||||
str[--i]=0;
|
||||
if(d==0)
|
||||
str[--i]='0';
|
||||
else while(d!=0){
|
||||
str[--i]='0' + d%10;
|
||||
d/=10;
|
||||
}
|
||||
if(n<0)
|
||||
str[--i]='-';
|
||||
return cptr_copy((char*)str+i);
|
||||
}
|
||||
|
||||
char* toString_u64(u64 n, bool withPostfix, bool uppercase){
|
||||
char str[32];
|
||||
u8 i=sizeof(str);
|
||||
str[--i]=0;
|
||||
if(withPostfix)
|
||||
str[--i]= uppercase ? 'U' : 'u';
|
||||
if(n==0)
|
||||
str[--i]='0';
|
||||
else while(n!=0){
|
||||
str[--i]='0' + n%10;
|
||||
n/=10;
|
||||
}
|
||||
return cptr_copy((char*)str+i);
|
||||
}
|
||||
|
||||
#define _toString_float_impl(bufsize, maxPrecision) { \
|
||||
char str[bufsize]; \
|
||||
if(precision>maxPrecision) \
|
||||
throw("too big precision"); \
|
||||
if(precision==0) \
|
||||
precision=toString_float_default_precision; \
|
||||
i32 cn=IFMSC( \
|
||||
sprintf_s(str, bufsize, "%.*f", precision, n), \
|
||||
sprintf(str, "%.*f", precision, n) \
|
||||
); \
|
||||
/* remove trailing zeroes except .0*/ \
|
||||
while(str[cn-1]=='0' && str[cn-2]!='.') \
|
||||
cn--; \
|
||||
if(withPostfix) \
|
||||
str[cn++]= uppercase ? 'F' : 'f'; \
|
||||
str[cn]='\0'; \
|
||||
return cptr_copy(str); \
|
||||
}
|
||||
|
||||
char* toString_f32(f32 n, u8 precision, bool withPostfix, bool uppercase)
|
||||
_toString_float_impl(48, toString_f32_max_precision)
|
||||
|
||||
char* toString_f64(f64 n, u8 precision, bool withPostfix, bool uppercase)
|
||||
_toString_float_impl(512, toString_f64_max_precision)
|
||||
|
||||
#define byte_to_bits(byte) { \
|
||||
str[cn++]='0' + (u8)((byte>>7)&1); /* 8th bit */ \
|
||||
str[cn++]='0' + (u8)((byte>>6)&1); /* 7th bit */ \
|
||||
str[cn++]='0' + (u8)((byte>>5)&1); /* 6th bit */ \
|
||||
str[cn++]='0' + (u8)((byte>>4)&1); /* 5th bit */ \
|
||||
str[cn++]='0' + (u8)((byte>>3)&1); /* 4th bit */ \
|
||||
str[cn++]='0' + (u8)((byte>>2)&1); /* 3th bit */ \
|
||||
str[cn++]='0' + (u8)((byte>>1)&1); /* 2th bit */ \
|
||||
str[cn++]='0' + (u8)((byte>>0)&1); /* 1th bit */ \
|
||||
}
|
||||
|
||||
char* toString_bin(void* _bytes, u32 size, bool inverse, bool withPrefix){
|
||||
char* bytes=_bytes;
|
||||
char* str=malloc(size*8 + (withPrefix?2:0) +1);
|
||||
u32 cn=0; // char number
|
||||
if(withPrefix){
|
||||
str[cn++]='0';
|
||||
str[cn++]='b';
|
||||
}
|
||||
if(inverse){
|
||||
// byte number
|
||||
for(i32 bn=size-1; bn>=0; bn--)
|
||||
byte_to_bits(bytes[bn])
|
||||
} else {
|
||||
for(u32 bn=0; bn<size; bn++)
|
||||
byte_to_bits(bytes[bn])
|
||||
}
|
||||
str[cn]=0;
|
||||
return str;
|
||||
}
|
||||
|
||||
// converts number from 0 to F to char
|
||||
char _4bitsHex(u8 u, bool uppercase){
|
||||
switch(u){
|
||||
case 0: case 1: case 2: case 3: case 4:
|
||||
case 5: case 6: case 7: case 8: case 9:
|
||||
return '0'+u;
|
||||
case 0xA: case 0xB: case 0xC:
|
||||
case 0xD: case 0xE: case 0xF:
|
||||
return (uppercase ? 'A' : 'a') + u -10;
|
||||
default:
|
||||
dbg(u);
|
||||
throw("incorrect number");
|
||||
return 219;
|
||||
}
|
||||
}
|
||||
|
||||
char* toString_hex(void* _bytes, u32 size, bool inverse, bool withPrefix, bool uppercase){
|
||||
char* bytes=_bytes;
|
||||
char* str=malloc(size*2 + (withPrefix?2:0) + 1);
|
||||
u32 cn=0; // char number
|
||||
if(withPrefix){
|
||||
str[cn++]='0';
|
||||
str[cn++]='x';
|
||||
}
|
||||
// left to right
|
||||
if(inverse){
|
||||
// byte number
|
||||
for(i32 bn=size-1; bn>=0; bn--){
|
||||
unsigned char byte=bytes[bn];
|
||||
str[cn++]=_4bitsHex(byte/16, uppercase);
|
||||
str[cn++]=_4bitsHex(byte%16, uppercase);
|
||||
}
|
||||
}
|
||||
// right to left
|
||||
else {
|
||||
for(u32 bn=0; bn<size; bn++){ // byte number
|
||||
unsigned char byte=bytes[bn];
|
||||
str[cn++]=_4bitsHex(byte/16, uppercase);
|
||||
str[cn++]=_4bitsHex(byte%16, uppercase);
|
||||
}
|
||||
}
|
||||
str[cn]=0;
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
#define __toString_i32_def(BITS) char* __toString_i##BITS(void* _n, u32 f){ \
|
||||
switch(kp_fmt_dataFormat(f)){ \
|
||||
case kp_i: ; \
|
||||
i##BITS n=*(i##BITS*)_n; \
|
||||
return toString_i64(n); \
|
||||
case kp_b: \
|
||||
return toString_bin(_n, BITS/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f)); \
|
||||
case kp_h: \
|
||||
return toString_hex(_n, BITS/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f), kp_fmt_isUpper(f)); \
|
||||
default: \
|
||||
kprintf("\n%u\n", kp_fmt_dataFormat(f)); \
|
||||
throw(ERR_FORMAT); \
|
||||
return NULL; \
|
||||
} \
|
||||
}
|
||||
__toString_i32_def(8)
|
||||
__toString_i32_def(16)
|
||||
__toString_i32_def(32)
|
||||
__toString_i32_def(64)
|
||||
|
||||
#define __toString_u_def(BITS) char* __toString_u##BITS(void* _n, u32 f){ \
|
||||
switch(kp_fmt_dataFormat(f)){ \
|
||||
case kp_u: ; \
|
||||
u##BITS n=*(u##BITS*)_n; \
|
||||
return toString_u64(n, kp_fmt_withPostfix(f), kp_fmt_isUpper(f)); \
|
||||
case kp_b: \
|
||||
return toString_bin(_n, BITS/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f)); \
|
||||
case kp_h: \
|
||||
return toString_hex(_n, BITS/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f), kp_fmt_isUpper(f)); \
|
||||
default: \
|
||||
kprintf("\n%u\n", kp_fmt_dataFormat(f)); \
|
||||
throw(ERR_FORMAT); \
|
||||
return NULL; \
|
||||
} \
|
||||
}
|
||||
__toString_u_def(8)
|
||||
__toString_u_def(16)
|
||||
__toString_u_def(32)
|
||||
// __toString_u_def(64)
|
||||
char* __toString_u64(void* _n, u32 f){
|
||||
switch(kp_fmt_dataFormat(f)){
|
||||
case kp_u: ;
|
||||
u64 n=*(u64*)_n;
|
||||
return toString_u64(n, kp_fmt_withPostfix(f), kp_fmt_isUpper(f));
|
||||
case kp_b:
|
||||
return toString_bin(_n, 64/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f));
|
||||
case kp_h:
|
||||
return toString_hex(_n, 64/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f), kp_fmt_isUpper(f));
|
||||
default:
|
||||
kprintf("\n%u\n", kp_fmt_dataFormat(f)); throw(ERR_FORMAT); return NULL; }
|
||||
}
|
||||
|
||||
#define __toString_float_def(BITS) char* __toString_f##BITS(void* _n, u32 f){ \
|
||||
switch(kp_fmt_dataFormat(f)){ \
|
||||
case kp_f: ; \
|
||||
f##BITS n=*(f##BITS*)_n; \
|
||||
return toString_f64(n, toString_float_default_precision, kp_fmt_withPostfix(f), kp_fmt_isUpper(f)); \
|
||||
case kp_b: \
|
||||
return toString_bin(_n, BITS/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f)); \
|
||||
case kp_h: \
|
||||
return toString_hex(_n, BITS/8, getEndian()==LittleEndian, kp_fmt_withPrefix(f), kp_fmt_isUpper(f)); \
|
||||
default: \
|
||||
kprintf("\n%u\n", kp_fmt_dataFormat(f)); \
|
||||
throw(ERR_FORMAT); \
|
||||
return NULL; \
|
||||
} \
|
||||
}
|
||||
|
||||
__toString_float_def(32)
|
||||
__toString_float_def(64)
|
||||
47
kerep/src/base/type_system/base_toString.h
Normal file
47
kerep/src/base/type_system/base_toString.h
Normal 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
|
||||
65
kerep/src/base/type_system/init.c
Normal file
65
kerep/src/base/type_system/init.c
Normal file
@@ -0,0 +1,65 @@
|
||||
#include "../base.h"
|
||||
#include "../../Autoarr/Autoarr.h"
|
||||
#include "../../Hashtable/Hashtable.h"
|
||||
#include "../../String/StringBuilder.h"
|
||||
#include "../../Filesystem/filesystem.h"
|
||||
#include "base_toString.h"
|
||||
|
||||
void kt_initKerepTypes(){
|
||||
// base types
|
||||
kt_register(Pointer);
|
||||
if(ktid_Pointer!=0) // this can break UnitypeNull
|
||||
throw("ktid_Pointer!=0, you must init kerep types before any other types");
|
||||
|
||||
kt_register(char);
|
||||
kt_register(bool);
|
||||
kt_register(f32);
|
||||
kt_register(f64);
|
||||
kt_register(i8);
|
||||
kt_register(u8);
|
||||
kt_register(i16);
|
||||
kt_register(u16);
|
||||
kt_register(i32);
|
||||
kt_register(u32);
|
||||
kt_register(i64);
|
||||
kt_register(u64);
|
||||
|
||||
// ktDescriptor
|
||||
kt_register(ktDescriptor);
|
||||
|
||||
// base type autoarrs
|
||||
kt_register(Autoarr_Pointer);
|
||||
kt_register(Autoarr_char);
|
||||
kt_register(Autoarr_bool);
|
||||
kt_register(Autoarr_f32);
|
||||
kt_register(Autoarr_f64);
|
||||
kt_register(Autoarr_i8);
|
||||
kt_register(Autoarr_u8);
|
||||
kt_register(Autoarr_i16);
|
||||
kt_register(Autoarr_u16);
|
||||
kt_register(Autoarr_i32);
|
||||
kt_register(Autoarr_u32);
|
||||
kt_register(Autoarr_i64);
|
||||
kt_register(Autoarr_u64);
|
||||
|
||||
// Unitype
|
||||
kt_register(Unitype);
|
||||
kt_register(Autoarr_Unitype);
|
||||
|
||||
// KeyValuePair
|
||||
kt_register(KVPair);
|
||||
kt_register(Autoarr_KVPair);
|
||||
|
||||
// Hashtable
|
||||
kt_register(Hashtable);
|
||||
|
||||
// string
|
||||
kt_register(string);
|
||||
kt_register(Autoarr_string);
|
||||
|
||||
// StringBuilder
|
||||
kt_register(StringBuilder);
|
||||
|
||||
//File
|
||||
kt_register(FileHandle);
|
||||
}
|
||||
12
kerep/src/base/type_system/init.h
Normal file
12
kerep/src/base/type_system/init.h
Normal 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
|
||||
51
kerep/src/base/type_system/ktDescriptor.h
Normal file
51
kerep/src/base/type_system/ktDescriptor.h
Normal 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
|
||||
90
kerep/src/base/type_system/kt_functions.c
Normal file
90
kerep/src/base/type_system/kt_functions.c
Normal file
@@ -0,0 +1,90 @@
|
||||
#include "../../Autoarr/Autoarr.h"
|
||||
#include "type_system.h"
|
||||
#include "base_toString.h"
|
||||
|
||||
kt_define(Pointer, NULL, __toString_u64);
|
||||
kt_define(char,NULL, __toString_char);
|
||||
kt_define(bool,NULL, __toString_bool);
|
||||
kt_define(f32, NULL, __toString_f32);
|
||||
kt_define(f64, NULL, __toString_f64);
|
||||
kt_define(i8, NULL, __toString_i8);
|
||||
kt_define(u8, NULL, __toString_u8);
|
||||
kt_define(i16, NULL, __toString_i16);
|
||||
kt_define(u16, NULL, __toString_u16);
|
||||
kt_define(i32, NULL, __toString_i32);
|
||||
kt_define(u32, NULL, __toString_u32);
|
||||
kt_define(i64, NULL, __toString_i64);
|
||||
kt_define(u64, NULL, __toString_u64);
|
||||
|
||||
|
||||
char* ktDescriptor_toString(ktDescriptor* d){
|
||||
const char* n="null";
|
||||
char *s0 = toString_u64(d->id, 0,0);
|
||||
char *s1 = toString_u64(d->size, 0,0);
|
||||
char *s2 = d->toString ? toString_hex(d->toString, sizeof(void*), 0,1,0) : n;
|
||||
char *s3 = d->freeMembers ? toString_hex(d->freeMembers, sizeof(void*), 0,1,0) : n;
|
||||
char *rez=cptr_concat("ktDescriptor {"
|
||||
" name:", d->name,
|
||||
" id:",s0,
|
||||
" size:",s1,
|
||||
" toString:",s2,
|
||||
" freeMembers:",s3,
|
||||
" }");
|
||||
free(s0);
|
||||
free(s1);
|
||||
if(s2!=n) free(s2);
|
||||
if(s3!=n) free(s3);
|
||||
return rez;
|
||||
}
|
||||
|
||||
char* _ktDescriptor_toString(void* _d, u32 fmt) { return ktDescriptor_toString(_d); }
|
||||
|
||||
kt_define(ktDescriptor, NULL, _ktDescriptor_toString);
|
||||
|
||||
typedef ktDescriptor* ktDescriptor_Ptr;
|
||||
|
||||
// type descriptors are stored here during initialization
|
||||
Autoarr(Pointer)* __descriptorPointers=NULL;
|
||||
// here type descriptors are stored when initialization is complited
|
||||
ktDescriptor** typeDescriptors=NULL;
|
||||
ktid ktid_last=-1;
|
||||
|
||||
ENUM(ktDescriptorsState,
|
||||
NotInitialized, Initializing, Initialized
|
||||
)
|
||||
ktDescriptorsState initState=NotInitialized;
|
||||
|
||||
void kt_beginInit(){
|
||||
#if DEBUG
|
||||
kprintf("\e[94mtype descriptors initializing...\n");
|
||||
#endif
|
||||
__descriptorPointers=Autoarr_create(Pointer, 256, 256);
|
||||
}
|
||||
|
||||
void kt_endInit(){
|
||||
if(__descriptorPointers==NULL)
|
||||
throw(ERR_NULLPTR);
|
||||
typeDescriptors=(ktDescriptor**)Autoarr_toArray(__descriptorPointers);
|
||||
Autoarr_free(__descriptorPointers,true);
|
||||
if(typeDescriptors==NULL) throw(ERR_NULLPTR);
|
||||
#if DEBUG
|
||||
kprintf("\e[92minitialized %u type descriptors\n", ktid_last);
|
||||
#endif
|
||||
}
|
||||
|
||||
void __kt_register(ktDescriptor* descriptor){
|
||||
descriptor->id=++ktid_last;
|
||||
Autoarr_add(__descriptorPointers, descriptor);
|
||||
}
|
||||
|
||||
ktDescriptor* ktDescriptor_get(ktid id){
|
||||
if(id>ktid_last || id==ktid_undefined) {
|
||||
kprintf("\ntype id: %u\n",id);
|
||||
throw("invalid type id");
|
||||
}
|
||||
return typeDescriptors[id];
|
||||
}
|
||||
|
||||
void kt_free(){
|
||||
free(typeDescriptors);
|
||||
}
|
||||
49
kerep/src/base/type_system/kt_functions.h
Normal file
49
kerep/src/base/type_system/kt_functions.h
Normal 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
|
||||
28
kerep/src/base/type_system/ktid.h
Normal file
28
kerep/src/base/type_system/ktid.h
Normal 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
|
||||
8
kerep/src/base/type_system/type_system.h
Normal file
8
kerep/src/base/type_system/type_system.h
Normal 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"
|
||||
15
kerep/src/base/type_system/typedef_macros.h
Normal file
15
kerep/src/base/type_system/typedef_macros.h
Normal 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);
|
||||
100
kerep/src/base/type_system/unitype.c
Normal file
100
kerep/src/base/type_system/unitype.c
Normal file
@@ -0,0 +1,100 @@
|
||||
#include "../../kprint/kprint_format.h"
|
||||
#include "../base.h"
|
||||
|
||||
char *__Unitype_toString(void *_u, u32 fmt)
|
||||
{
|
||||
return Unitype_toString(*(Unitype *)_u, fmt);
|
||||
}
|
||||
|
||||
kt_define(Unitype, __UnitypePtr_free, __Unitype_toString);
|
||||
|
||||
void Unitype_free(Unitype u)
|
||||
{
|
||||
if (u.typeId == ktid_undefined)
|
||||
{
|
||||
if (u.VoidPtr != NULL)
|
||||
throw("unitype with undefined typeId has value");
|
||||
return;
|
||||
}
|
||||
|
||||
ktDescriptor *type = ktDescriptor_get(u.typeId);
|
||||
if (type->freeMembers)
|
||||
type->freeMembers(u.VoidPtr);
|
||||
if (u.allocatedInHeap)
|
||||
free(u.VoidPtr);
|
||||
}
|
||||
void __UnitypePtr_free(void *u)
|
||||
{
|
||||
Unitype_free(*(Unitype *)u);
|
||||
}
|
||||
|
||||
char *Unitype_toString(Unitype u, u32 fmt)
|
||||
{
|
||||
if (u.typeId == ktid_undefined)
|
||||
{
|
||||
if (u.VoidPtr != NULL)
|
||||
throw("unitype with undefined typeId has value");
|
||||
return cptr_copy("{ERROR_TYPE}");
|
||||
}
|
||||
|
||||
if (fmt == 0)
|
||||
{
|
||||
if (u.typeId == ktid_name(bool) || u.typeId == ktid_name(i8) || u.typeId == ktid_name(i16) ||
|
||||
u.typeId == ktid_name(i32) || u.typeId == ktid_name(i64))
|
||||
{
|
||||
// auto format set
|
||||
fmt = kp_i;
|
||||
// replaces value with pointer to value to pass into toString_i64(void*, u32)
|
||||
i64 value = u.Int64;
|
||||
u.VoidPtr = &value;
|
||||
}
|
||||
else if (u.typeId == ktid_name(u8) || u.typeId == ktid_name(u16) || u.typeId == ktid_name(u32) ||
|
||||
u.typeId == ktid_name(u64))
|
||||
{
|
||||
fmt = kp_u;
|
||||
u64 value = u.UInt64;
|
||||
u.VoidPtr = &value;
|
||||
}
|
||||
else if (u.typeId == ktid_name(f32) || u.typeId == ktid_name(f64))
|
||||
{
|
||||
fmt = kp_f;
|
||||
f64 value = u.Float64;
|
||||
u.VoidPtr = &value;
|
||||
}
|
||||
else if (u.typeId == ktid_name(char))
|
||||
{
|
||||
fmt = kp_c;
|
||||
i64 value = u.Int64;
|
||||
u.VoidPtr = &value;
|
||||
}
|
||||
else if (u.typeId == ktid_ptrName(char))
|
||||
{
|
||||
fmt = kp_s;
|
||||
}
|
||||
else if (u.typeId == ktid_name(Pointer))
|
||||
{
|
||||
if (u.VoidPtr == NULL)
|
||||
return cptr_copy("{ UniNull }");
|
||||
fmt = kp_h;
|
||||
}
|
||||
}
|
||||
|
||||
ktDescriptor *type = ktDescriptor_get(u.typeId);
|
||||
char *valuestr;
|
||||
if (type->toString)
|
||||
valuestr = type->toString(u.VoidPtr, fmt);
|
||||
else
|
||||
valuestr = "ERR_NO_TOSTRING_FUNC";
|
||||
char *rezult = cptr_concat("{ type: ", type->name, ", allocated on heap: ", (u.allocatedInHeap ? "true" : "false"),
|
||||
", value:", valuestr, " }");
|
||||
if (type->toString)
|
||||
free(valuestr);
|
||||
return rezult;
|
||||
}
|
||||
|
||||
void printuni(Unitype v)
|
||||
{
|
||||
char *s = Unitype_toString(v, 0);
|
||||
fputs(s, stdout);
|
||||
free(s);
|
||||
}
|
||||
55
kerep/src/base/type_system/unitype.h
Normal file
55
kerep/src/base/type_system/unitype.h
Normal 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
|
||||
Reference in New Issue
Block a user