kerep sources
This commit is contained in:
17
kerep/src/Autoarr/Autoarr.c
Normal file
17
kerep/src/Autoarr/Autoarr.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "Autoarr.h"
|
||||
|
||||
Autoarr_define(Pointer, true)
|
||||
Autoarr_define(char, false)
|
||||
Autoarr_define(bool, false)
|
||||
Autoarr_define(f32, false)
|
||||
Autoarr_define(f64, false)
|
||||
Autoarr_define(u8, false)
|
||||
Autoarr_define(i8, false)
|
||||
Autoarr_define(u16, false)
|
||||
Autoarr_define(i16, false)
|
||||
Autoarr_define(u32, false)
|
||||
Autoarr_define(i32, false)
|
||||
Autoarr_define(u64, false)
|
||||
Autoarr_define(i64, false)
|
||||
|
||||
Autoarr_define(Unitype, false)
|
||||
43
kerep/src/Autoarr/Autoarr.h
Normal file
43
kerep/src/Autoarr/Autoarr.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "Autoarr_declare.h"
|
||||
#include "Autoarr_define.h"
|
||||
|
||||
Autoarr_declare(Pointer)
|
||||
Autoarr_declare(char)
|
||||
Autoarr_declare(bool)
|
||||
Autoarr_declare(f32)
|
||||
Autoarr_declare(f64)
|
||||
Autoarr_declare(i8)
|
||||
Autoarr_declare(u8)
|
||||
Autoarr_declare(i16)
|
||||
Autoarr_declare(u16)
|
||||
Autoarr_declare(i32)
|
||||
Autoarr_declare(u32)
|
||||
Autoarr_declare(i64)
|
||||
Autoarr_declare(u64)
|
||||
|
||||
Autoarr_declare(Unitype)
|
||||
|
||||
#define Autoarr_foreach(ar, elem, codeblock...) { \
|
||||
if(ar->blocks_count>0) { \
|
||||
typeof(**ar->values) elem; \
|
||||
for(u16 blockI=0;blockI<ar->blocks_count-1;blockI++) \
|
||||
for(u32 elemI=0;elemI<ar->max_block_length;elemI++){ \
|
||||
elem=ar->values[blockI][elemI]; \
|
||||
{ codeblock; } \
|
||||
} \
|
||||
for(u16 elemI=0;elemI<ar->block_length;elemI++){ \
|
||||
elem=ar->values[ar->blocks_count-1][elemI]; \
|
||||
{ codeblock; } \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
74
kerep/src/Autoarr/Autoarr_declare.h
Normal file
74
kerep/src/Autoarr/Autoarr_declare.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../base/base.h"
|
||||
|
||||
#define Autoarr_declare(type) \
|
||||
\
|
||||
struct Autoarr_##type; \
|
||||
\
|
||||
typedef struct __Autoarr_##type##_functions_list_t { \
|
||||
void (*add)(struct Autoarr_##type* ar, type element); \
|
||||
type (*get)(struct Autoarr_##type* ar, u32 index); \
|
||||
type* (*getPtr)(struct Autoarr_##type* ar, u32 index); \
|
||||
void (*set)(struct Autoarr_##type* ar, u32 index, type element); \
|
||||
void (*freeWithMembers)(struct Autoarr_##type* ar, bool freePtr); \
|
||||
void (*freeWithoutMembers)(struct Autoarr_##type* ar, bool freePtr); \
|
||||
type* (*toArray)(struct Autoarr_##type* ar); \
|
||||
} __Autoarr_##type##_functions_list_t; \
|
||||
\
|
||||
extern __Autoarr_##type##_functions_list_t __Autoarr_##type##_functions_list; \
|
||||
\
|
||||
STRUCT(Autoarr_##type, \
|
||||
u16 blocks_count; \
|
||||
u16 max_blocks_count; \
|
||||
u16 block_length; \
|
||||
u16 max_block_length; \
|
||||
type** values; \
|
||||
__Autoarr_##type##_functions_list_t* functions; \
|
||||
) \
|
||||
\
|
||||
Autoarr_##type* __Autoarr_##type##_create(u16 max_blocks_count, u16 max_block_length); \
|
||||
void __Autoarr_##type##_freeWithMembers(Autoarr_##type* ar, bool freePtr); \
|
||||
void ____Autoarr_##type##_freeWithMembers(void* ar);
|
||||
|
||||
#define Autoarr(type) Autoarr_##type
|
||||
|
||||
#define Autoarr_create(type, max_blocks_count, max_block_length) \
|
||||
__Autoarr_##type##_create(max_blocks_count, max_block_length)
|
||||
#define Autoarr_add(autoarr, element) \
|
||||
autoarr->functions->add(autoarr, element)
|
||||
#define Autoarr_get(autoarr, index) \
|
||||
autoarr->functions->get(autoarr,index)
|
||||
#define Autoarr_getPtr(autoarr, index) \
|
||||
autoarr->functions->getPtr(autoarr,index)
|
||||
#define Autoarr_set(autoarr, index, element) \
|
||||
autoarr->functions->set(autoarr, index, element)
|
||||
#define Autoarr_free(autoarr, freePtr) \
|
||||
autoarr->functions->freeWithMembers(autoarr, freePtr)
|
||||
#define Autoarr_freeWithoutMembers(autoarr, freePtr) \
|
||||
autoarr->functions->freeWithoutMembers(autoarr, freePtr)
|
||||
#define Autoarr_toArray(autoarr) \
|
||||
autoarr->functions->toArray(autoarr)
|
||||
|
||||
#define Autoarr_length(autoarr) \
|
||||
(u32)(!autoarr->blocks_count ? 0 : \
|
||||
autoarr->max_block_length*(autoarr->blocks_count-1)+autoarr->block_length)
|
||||
#define Autoarr_max_length(autoarr) \
|
||||
(u32)(autoarr->max_block_length*autoarr->max_blocks_count)
|
||||
|
||||
#define Autoarr_pop(AR){ \
|
||||
if(AR->block_length==1){ \
|
||||
AR->blocks_count--; \
|
||||
AR->block_length=AR->max_block_length; \
|
||||
free(AR->values[AR->blocks_count]); \
|
||||
} \
|
||||
else AR->block_length--; \
|
||||
}
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
100
kerep/src/Autoarr/Autoarr_define.h
Normal file
100
kerep/src/Autoarr/Autoarr_define.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../base/base.h"
|
||||
|
||||
#define Autoarr_define(type, TYPE_IS_PTR) \
|
||||
\
|
||||
kt_define(Autoarr_##type, ____Autoarr_##type##_freeWithMembers, NULL); \
|
||||
\
|
||||
void __Autoarr_##type##_add(Autoarr_##type* ar, type element){ \
|
||||
if(!ar->values){ \
|
||||
ar->values=malloc(ar->max_blocks_count*sizeof(type*)); \
|
||||
goto create_block; \
|
||||
} \
|
||||
if(ar->block_length==ar->max_block_length){ \
|
||||
if (ar->blocks_count>=ar->max_blocks_count) throw(ERR_MAXLENGTH); \
|
||||
ar->block_length=0; \
|
||||
create_block: \
|
||||
ar->values[ar->blocks_count]=malloc(ar->max_block_length*sizeof(type)); \
|
||||
ar->blocks_count++; \
|
||||
} \
|
||||
ar->values[ar->blocks_count-1][ar->block_length]=element; \
|
||||
ar->block_length++; \
|
||||
} \
|
||||
\
|
||||
type __Autoarr_##type##_get(Autoarr_##type* ar, u32 index){ \
|
||||
if(index>=Autoarr_length(ar)) throw(ERR_WRONGINDEX); \
|
||||
return ar->values[index/ar->max_block_length][index%ar->max_block_length]; \
|
||||
} \
|
||||
\
|
||||
type* __Autoarr_##type##_getPtr(Autoarr_##type* ar, u32 index){ \
|
||||
if(index>=Autoarr_length(ar)) throw(ERR_WRONGINDEX); \
|
||||
return ar->values[index/ar->max_block_length]+(index%ar->max_block_length); \
|
||||
} \
|
||||
\
|
||||
void __Autoarr_##type##_set(Autoarr_##type* ar, u32 index, type element){ \
|
||||
if(index>=Autoarr_length(ar)) throw(ERR_WRONGINDEX); \
|
||||
ar->values[index/ar->max_block_length][index%ar->max_block_length]=element; \
|
||||
} \
|
||||
\
|
||||
void __Autoarr_##type##_freeWithoutMembers(Autoarr_##type* ar, bool freePtr){ \
|
||||
for(u16 i=0; i<ar->blocks_count;i++) \
|
||||
free(ar->values[i]); \
|
||||
free(ar->values); \
|
||||
if(freePtr) free(ar); \
|
||||
} \
|
||||
\
|
||||
void __Autoarr_##type##_freeWithMembers(Autoarr_##type* ar, bool freePtr){ \
|
||||
if(ktDescriptor_##type.freeMembers!=NULL) { \
|
||||
Autoarr_foreach(ar, el, \
|
||||
void* members_ptr=⪙ \
|
||||
if(TYPE_IS_PTR) members_ptr=*(type**)members_ptr; \
|
||||
ktDescriptor_##type.freeMembers(members_ptr); \
|
||||
); \
|
||||
} \
|
||||
__Autoarr_##type##_freeWithoutMembers(ar, freePtr);\
|
||||
} \
|
||||
void ____Autoarr_##type##_freeWithMembers(void* ar){ \
|
||||
__Autoarr_##type##_freeWithMembers((Autoarr_##type*)ar, false); \
|
||||
} \
|
||||
\
|
||||
type* __Autoarr_##type##_toArray(Autoarr_##type* ar){ \
|
||||
u32 length=Autoarr_length(ar); \
|
||||
if(length==0) \
|
||||
return NULL; \
|
||||
type* array=malloc(length * sizeof(type)); \
|
||||
for(u32 i=0; i<length; i++) \
|
||||
array[i]=__Autoarr_##type##_get(ar, i); \
|
||||
return array; \
|
||||
} \
|
||||
\
|
||||
__Autoarr_##type##_functions_list_t __Autoarr_##type##_functions_list={ \
|
||||
&__Autoarr_##type##_add, \
|
||||
&__Autoarr_##type##_get, \
|
||||
&__Autoarr_##type##_getPtr, \
|
||||
&__Autoarr_##type##_set, \
|
||||
&__Autoarr_##type##_freeWithMembers, \
|
||||
&__Autoarr_##type##_freeWithoutMembers, \
|
||||
&__Autoarr_##type##_toArray \
|
||||
}; \
|
||||
\
|
||||
Autoarr_##type* __Autoarr_##type##_create(u16 max_blocks_count, u16 max_block_length){ \
|
||||
Autoarr_##type* ar=malloc(sizeof(Autoarr_##type)); \
|
||||
*ar=(Autoarr_##type){ \
|
||||
.max_blocks_count=max_blocks_count, \
|
||||
.blocks_count=0, \
|
||||
.max_block_length=max_block_length, \
|
||||
.block_length=0, \
|
||||
.values=NULL, \
|
||||
.functions=&__Autoarr_##type##_functions_list \
|
||||
}; \
|
||||
return ar; \
|
||||
}
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
9
kerep/src/Autoarr/README.md
Normal file
9
kerep/src/Autoarr/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Autoarr struct
|
||||
`Autoarr` means Automatically resizing array. It is my implementation of dyynamic array. If you want to use `Autoarr` of some type, it should be declared in header file by macro `Autoarr_declare` and defined in source file by `Autoarr_define`.
|
||||
|
||||
Examples:
|
||||
[Hashtable.h](src/Hashtable/Hashtable.h)
|
||||
[Hashtable.c](src/Hashtable/Hashtable.c)
|
||||
|
||||
### Autoarr_*_exported
|
||||
Contains definitions for functions, exported for using in C# kerep wrapper.
|
||||
17
kerep/src/DtsodParser/DtsodV24.h
Normal file
17
kerep/src/DtsodParser/DtsodV24.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../Hashtable/Hashtable.h"
|
||||
|
||||
// parses text to binary values
|
||||
Maybe DtsodV24_deserialize(char* text);
|
||||
|
||||
// creates text representation of dtsod
|
||||
Maybe DtsodV24_serialize(Hashtable* dtsod);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
344
kerep/src/DtsodParser/DtsodV24_deserialize.c
Normal file
344
kerep/src/DtsodParser/DtsodV24_deserialize.c
Normal file
@@ -0,0 +1,344 @@
|
||||
#include "DtsodV24.h"
|
||||
#include "../String/StringBuilder.h"
|
||||
|
||||
#define ARR_BC 64
|
||||
#define ARR_BL 1024
|
||||
|
||||
|
||||
typedef struct DeserializeSharedData{
|
||||
const char* sh_text_first;
|
||||
char* sh_text;
|
||||
bool sh_partOfDollarList;
|
||||
bool sh_calledRecursively;
|
||||
} DeserializeSharedData;
|
||||
|
||||
#define text shared->sh_text
|
||||
#define partOfDollarList shared->sh_partOfDollarList
|
||||
#define calledRecursively shared->sh_calledRecursively
|
||||
|
||||
|
||||
// special func for throwing error messages about wrong characters in deserializing text
|
||||
Maybe ERROR_WRONGCHAR(const char c, char* _text, char* text_first, const char* srcfile, i32 line, const char* funcname){
|
||||
char errBuf[68];
|
||||
for(u8 n=0; n<sizeof(errBuf);n++)
|
||||
errBuf[n]='\0';
|
||||
char* errText=_text-32;
|
||||
u8 cplace=32;
|
||||
if(errText<text_first) {
|
||||
cplace=_text-text_first;
|
||||
errText=text_first;
|
||||
}
|
||||
u8 i=0;
|
||||
for(; i<cplace; i++){
|
||||
// writes 32 chars before the wrongchar
|
||||
errBuf[i]=errText[i];
|
||||
}
|
||||
//prints wrongchar in braces
|
||||
errBuf[i++]='<';
|
||||
errBuf[i++]=c;
|
||||
errBuf[i++]='>';
|
||||
for(; i<cplace+3+32; i++){
|
||||
// writes 32 chars after the wrongchar
|
||||
char _c=errText[i-2];
|
||||
errBuf[i]=_c;
|
||||
if(!_c) break;
|
||||
}
|
||||
char errmsg[1024];
|
||||
IFMSC(
|
||||
sprintf_s(errmsg,1024, "unexpected <%c> at:\n"
|
||||
" \"%s\"\n"
|
||||
"\\___[%s:%d] %s()",
|
||||
c,errBuf, srcfile,line,funcname),
|
||||
sprintf(errmsg, "unexpected <%c> at:\n"
|
||||
" \"%s\"\n"
|
||||
" \\___[%s:%d] %s()",
|
||||
c,errBuf, srcfile,line,funcname)
|
||||
);
|
||||
safethrow(errmsg,;);
|
||||
}
|
||||
#define safethrow_wrongchar(C, freeMem) { freeMem; return ERROR_WRONGCHAR(C, text, shared->sh_text_first, __FILE__,__LINE__,__func__); }
|
||||
|
||||
|
||||
Maybe __SkipComment(DeserializeSharedData* shared) {
|
||||
char c;
|
||||
|
||||
while ((c=*++text) != '\n')
|
||||
if (!c) safethrow(ERR_ENDOFSTR,;);
|
||||
|
||||
return MaybeNull;
|
||||
}
|
||||
#define SkipComment() __SkipComment(shared)
|
||||
|
||||
Maybe __ReadName(DeserializeSharedData* shared){
|
||||
char c;
|
||||
string nameStr={text+1,0};
|
||||
|
||||
while ((c=*++text)) switch (c){
|
||||
case ' ': case '\t':
|
||||
case '\r': case '\n':
|
||||
if(nameStr.length!=0)
|
||||
safethrow_wrongchar(c,;);
|
||||
nameStr.ptr++;
|
||||
break;
|
||||
case '=': case ';':
|
||||
case '\'': case '"':
|
||||
case '[': case ']':
|
||||
case '{':
|
||||
safethrow_wrongchar(c,;);
|
||||
case '#': ;
|
||||
char _c=c;
|
||||
char* _text=text;
|
||||
try(SkipComment(),_,;);
|
||||
if(nameStr.length!=0){
|
||||
text=_text;
|
||||
safethrow_wrongchar(_c,;);
|
||||
}
|
||||
nameStr.ptr=text+1; // skips '\n'
|
||||
break;
|
||||
case '}':
|
||||
if(!calledRecursively || nameStr.length!=0)
|
||||
safethrow_wrongchar(c,;);
|
||||
return SUCCESS(UniHeapPtr(char,NULL));
|
||||
case ':':
|
||||
return SUCCESS(UniHeapPtr(char,string_extract(nameStr)));
|
||||
case '$':
|
||||
if(nameStr.length!=0)
|
||||
safethrow_wrongchar(c,;);
|
||||
nameStr.ptr++;
|
||||
partOfDollarList=true;
|
||||
break;
|
||||
default:
|
||||
nameStr.length++;
|
||||
break;
|
||||
}
|
||||
|
||||
if(nameStr.length>0) safethrow(ERR_ENDOFSTR,;);
|
||||
return SUCCESS(UniHeapPtr(char,NULL));
|
||||
}
|
||||
#define ReadName() __ReadName(shared)
|
||||
|
||||
Maybe __deserialize(char** _text, bool _calledRecursively);
|
||||
Maybe __ReadValue(DeserializeSharedData* shared, bool* readingList);
|
||||
#define ReadValue(rL) __ReadValue(shared, rL)
|
||||
|
||||
// returns part of <text> without quotes
|
||||
Maybe __ReadString(DeserializeSharedData* shared){
|
||||
char c;
|
||||
bool prevIsBackslash=false;
|
||||
StringBuilder* b=StringBuilder_create();
|
||||
|
||||
while ((c=*++text)){
|
||||
if(c=='"') {
|
||||
if(prevIsBackslash) {
|
||||
// replacing <\"> with <">
|
||||
StringBuilder_rmchar(b);
|
||||
StringBuilder_append_char(b,c);
|
||||
prevIsBackslash=false;
|
||||
}
|
||||
else {
|
||||
char* str=StringBuilder_build(b).ptr;
|
||||
return SUCCESS(UniHeapPtr(char,str));
|
||||
}
|
||||
}
|
||||
else {
|
||||
prevIsBackslash= c=='\\' && !prevIsBackslash;
|
||||
StringBuilder_append_char(b,c);
|
||||
}
|
||||
}
|
||||
|
||||
safethrow(ERR_ENDOFSTR, StringBuilder_free(b));
|
||||
}
|
||||
#define ReadString() __ReadString(shared)
|
||||
|
||||
Maybe __ReadList(DeserializeSharedData* shared){
|
||||
Autoarr(Unitype)* list=Autoarr_create(Unitype,ARR_BC,ARR_BL);
|
||||
bool readingList=true;
|
||||
while (true){
|
||||
try(ReadValue((&readingList)), m_val, Autoarr_free(list, true))
|
||||
Autoarr_add(list,m_val.value);
|
||||
if (!readingList){
|
||||
if(Unitype_isUniNull(m_val.value))
|
||||
Autoarr_pop(list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS(UniHeapPtr(Autoarr_Unitype,list));
|
||||
};
|
||||
#define ReadList() __ReadList(shared)
|
||||
|
||||
Maybe __ParseValue(DeserializeSharedData* shared, string str){
|
||||
const string trueStr={"true",4};
|
||||
const string falseStr={"false",5};
|
||||
|
||||
switch(str.ptr[str.length-1]){
|
||||
// Bool
|
||||
case 'e':
|
||||
if(string_compare(str,trueStr))
|
||||
return SUCCESS(UniTrue);
|
||||
else if(string_compare(str,falseStr))
|
||||
return SUCCESS(UniFalse);
|
||||
else safethrow_wrongchar(*str.ptr,;);
|
||||
// Float64
|
||||
case 'f': {
|
||||
char* _c=string_extract(str);
|
||||
Unitype rez=UniFloat64(strtod(_c,NULL));
|
||||
free(_c);
|
||||
return SUCCESS(rez);
|
||||
}
|
||||
// UInt64
|
||||
case 'u': {
|
||||
u64 lu=0;
|
||||
char* _c=string_extract(str);
|
||||
if(sscanf(_c, IFWIN("%llu", "%lu"), &lu)!=1){
|
||||
char err[64];
|
||||
IFMSC(
|
||||
sprintf_s(err,64,"can't parse to int: <%s>",_c),
|
||||
sprintf(err,"can't parse to int: <%s>",_c)
|
||||
);
|
||||
safethrow(err,free(_c));
|
||||
}
|
||||
free(_c);
|
||||
return SUCCESS(UniUInt64(lu));
|
||||
}
|
||||
// Int64
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9': {
|
||||
i64 li=0;
|
||||
char* _c=string_extract(str);
|
||||
if(sscanf(_c, IFWIN("%lli", "%li"), &li)!=1){
|
||||
char err[64];
|
||||
IFMSC(
|
||||
sprintf_s(err,64,"can't parse to int: <%s>",_c),
|
||||
sprintf(err,"can't parse to int: <%s>",_c)
|
||||
);
|
||||
safethrow(err,free(_c));
|
||||
}
|
||||
free(_c);
|
||||
return SUCCESS(UniInt64(li));
|
||||
}
|
||||
// wrong type
|
||||
default:
|
||||
safethrow_wrongchar(str.ptr[str.length-1],;);
|
||||
}
|
||||
|
||||
safethrow(ERR_ENDOFSTR,;);
|
||||
};
|
||||
#define ParseValue(str) __ParseValue(shared, str)
|
||||
|
||||
Maybe __ReadValue(DeserializeSharedData* shared, bool* readingList){
|
||||
char c;
|
||||
string valueStr={text+1,0};
|
||||
Unitype value=UniNull;
|
||||
bool spaceAfterVal=false;
|
||||
|
||||
while ((c=*++text)) switch (c){
|
||||
case ' ': case '\t':
|
||||
case '\r': case '\n':
|
||||
if(valueStr.length!=0)
|
||||
spaceAfterVal=true;
|
||||
else valueStr.ptr++;
|
||||
break;
|
||||
case '=': case ':':
|
||||
case '}': case '$':
|
||||
case '\'':
|
||||
safethrow_wrongchar(c,Unitype_free(value));
|
||||
case '#':;
|
||||
char _c=c;
|
||||
char* _text=text;
|
||||
try(SkipComment(),_,;);
|
||||
if(valueStr.length!=0){
|
||||
text=_text;
|
||||
safethrow_wrongchar(_c,Unitype_free(value));
|
||||
}
|
||||
valueStr.ptr=text+1; // skips '\n'
|
||||
break;
|
||||
case '"':
|
||||
if(valueStr.length!=0) safethrow_wrongchar(c,Unitype_free(value));
|
||||
try(ReadString(),maybeString,;)
|
||||
value=maybeString.value;
|
||||
break;
|
||||
case '{':
|
||||
if(valueStr.length!=0) safethrow_wrongchar(c,Unitype_free(value));
|
||||
++text; // skips '{'
|
||||
try(__deserialize(&text,true), val,Unitype_free(value))
|
||||
value=val.value;
|
||||
break;
|
||||
case '[':
|
||||
if(valueStr.length!=0) safethrow_wrongchar(c,Unitype_free(value));
|
||||
try(ReadList(),maybeList,Unitype_free(value))
|
||||
value=maybeList.value;
|
||||
break;
|
||||
case ']':
|
||||
if(!readingList) safethrow_wrongchar(c,Unitype_free(value));
|
||||
*readingList=false;
|
||||
goto return_value;
|
||||
case ';':
|
||||
case ',':
|
||||
return_value:
|
||||
if(valueStr.length!=0){
|
||||
if(!Unitype_isUniNull(value))
|
||||
safethrow_wrongchar(c,Unitype_free(value));
|
||||
try(ParseValue(valueStr),maybeParsed,;)
|
||||
value=maybeParsed.value;
|
||||
}
|
||||
return SUCCESS(value);
|
||||
default:
|
||||
if(spaceAfterVal)
|
||||
safethrow_wrongchar(c,Unitype_free(value));
|
||||
valueStr.length++;
|
||||
break;
|
||||
}
|
||||
|
||||
safethrow(ERR_ENDOFSTR,;);
|
||||
}
|
||||
|
||||
|
||||
Maybe __deserialize(char** _text, bool _calledRecursively) {
|
||||
DeserializeSharedData _shared={
|
||||
.sh_text_first=*_text,
|
||||
.sh_text=*_text,
|
||||
.sh_partOfDollarList=false,
|
||||
.sh_calledRecursively=_calledRecursively
|
||||
};
|
||||
DeserializeSharedData* shared=&_shared;
|
||||
Hashtable* dict=Hashtable_create();
|
||||
|
||||
text--;
|
||||
while(true){
|
||||
try(ReadName(), maybeName, Hashtable_free(dict))
|
||||
if(!maybeName.value.VoidPtr) // end of file or '}' in recursive call
|
||||
goto END;
|
||||
char* nameCPtr=maybeName.value.VoidPtr;
|
||||
try(ReadValue(NULL), val, {
|
||||
Hashtable_free(dict);
|
||||
free(nameCPtr);
|
||||
}) {
|
||||
if(partOfDollarList){
|
||||
partOfDollarList=false;
|
||||
Autoarr(Unitype)* list;
|
||||
Unitype lu;
|
||||
if(Hashtable_tryGet(dict,nameCPtr, &lu)){
|
||||
list=(Autoarr(Unitype)*)lu.VoidPtr;
|
||||
// Key is not used in that case, because it is already added
|
||||
// to the table with the first dollar list item.
|
||||
free(nameCPtr);
|
||||
}
|
||||
else{
|
||||
list=Autoarr_create(Unitype,ARR_BC,ARR_BL);
|
||||
Hashtable_add(dict,nameCPtr,UniHeapPtr(Autoarr_Unitype,list));
|
||||
}
|
||||
Autoarr_add(list,val.value);
|
||||
}
|
||||
else Hashtable_add(dict,nameCPtr,val.value);
|
||||
}
|
||||
}
|
||||
|
||||
END:
|
||||
*_text=text;
|
||||
return SUCCESS(UniHeapPtr(Hashtable,dict));
|
||||
}
|
||||
|
||||
Maybe DtsodV24_deserialize(char* _text) {
|
||||
return __deserialize(&_text, false);
|
||||
}
|
||||
130
kerep/src/DtsodParser/DtsodV24_serialize.c
Normal file
130
kerep/src/DtsodParser/DtsodV24_serialize.c
Normal file
@@ -0,0 +1,130 @@
|
||||
#include "DtsodV24.h"
|
||||
#include "../String/StringBuilder.h"
|
||||
|
||||
|
||||
STRUCT(SerializeSharedData,
|
||||
StringBuilder* sh_builder;
|
||||
u8 sh_tabs;
|
||||
)
|
||||
#define b shared->sh_builder
|
||||
#define tabs shared->sh_tabs
|
||||
|
||||
Maybe __serialize(StringBuilder* _b, u8 _tabs, Hashtable* dtsod);
|
||||
|
||||
#define addc(C) StringBuilder_append_char(b,C)
|
||||
|
||||
|
||||
void __AppendTabs(SerializeSharedData* shared) {
|
||||
for (u8 t = 0; t < tabs; t++)
|
||||
addc( '\t');
|
||||
};
|
||||
#define AppendTabs() __AppendTabs(shared)
|
||||
|
||||
Maybe __AppendValue(SerializeSharedData* shared, Unitype u);
|
||||
#define AppendValue(UNI) __AppendValue(shared, UNI)
|
||||
Maybe __AppendValue(SerializeSharedData* shared, Unitype u){
|
||||
if(u.typeId==ktid_name(i64)){
|
||||
StringBuilder_append_i64(b,u.Int64);
|
||||
}
|
||||
else if(u.typeId==ktid_name(u64)){
|
||||
StringBuilder_append_u64(b,u.UInt64);
|
||||
addc('u');
|
||||
}
|
||||
else if(u.typeId==ktid_name(f64)){
|
||||
StringBuilder_append_f64(b,u.Float64);
|
||||
addc('f');
|
||||
}
|
||||
else if(u.typeId==ktid_ptrName(char)){
|
||||
addc('"');
|
||||
char c;
|
||||
while((c=*(char*)(u.VoidPtr++))){
|
||||
if(c=='\"') addc('\\');
|
||||
addc(c);
|
||||
}
|
||||
addc('"');
|
||||
}
|
||||
else if(u.typeId==ktid_name(bool)){
|
||||
StringBuilder_append_cptr(b, u.Bool ? "true" : "false");
|
||||
}
|
||||
else if(Unitype_isUniNull(u)){
|
||||
safethrow("Null isn't supported in DtsodV24",;);
|
||||
}
|
||||
else if(u.typeId==ktid_ptrName(Autoarr_Unitype)){
|
||||
if(Autoarr_length(((Autoarr_Unitype*)(u.VoidPtr)))){
|
||||
addc('\n');
|
||||
AppendTabs();
|
||||
addc('[');
|
||||
tabs++;
|
||||
Autoarr_foreach(((Autoarr_Unitype*)(u.VoidPtr)), e,
|
||||
addc('\n');
|
||||
AppendTabs();
|
||||
try(AppendValue(e),__,;);
|
||||
addc(',');
|
||||
);
|
||||
StringBuilder_rmchar(b);
|
||||
addc('\n');
|
||||
tabs--;
|
||||
AppendTabs();
|
||||
addc(']');
|
||||
}
|
||||
else {
|
||||
addc('[');
|
||||
addc(']');
|
||||
}
|
||||
}
|
||||
else if(u.typeId==ktid_ptrName(Hashtable)){
|
||||
// check hashtable is blank
|
||||
bool hashtableNotBlank=false;
|
||||
Hashtable_foreach(((Hashtable*)u.VoidPtr), __,
|
||||
hashtableNotBlank=true;
|
||||
if(__.key) {} // weird way to disable warning
|
||||
break;
|
||||
);
|
||||
|
||||
if(hashtableNotBlank){
|
||||
addc('\n');
|
||||
AppendTabs();
|
||||
addc('{');
|
||||
addc('\n');
|
||||
try(__serialize(b,tabs+1,u.VoidPtr),___,;);
|
||||
AppendTabs();
|
||||
addc('}');
|
||||
}
|
||||
else {
|
||||
addc('{');
|
||||
addc('}');
|
||||
}
|
||||
}
|
||||
else {
|
||||
dbg((u.typeId));
|
||||
safethrow(ERR_WRONGTYPE,;);
|
||||
}
|
||||
return MaybeNull;
|
||||
};
|
||||
|
||||
Maybe __serialize(StringBuilder* _b, u8 _tabs, Hashtable* dtsod){
|
||||
SerializeSharedData _shared={
|
||||
.sh_builder=_b,
|
||||
.sh_tabs=_tabs
|
||||
};
|
||||
SerializeSharedData* shared=&_shared;
|
||||
|
||||
Hashtable_foreach(dtsod, p,
|
||||
AppendTabs();
|
||||
StringBuilder_append_cptr(b,p.key);
|
||||
addc(':');
|
||||
addc(' ');
|
||||
try(AppendValue(p.value),__,;);
|
||||
addc(';');
|
||||
addc('\n');
|
||||
);
|
||||
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
Maybe DtsodV24_serialize(Hashtable* dtsod){
|
||||
StringBuilder* sb=StringBuilder_create();
|
||||
try(__serialize(sb,0,dtsod),__, StringBuilder_free(sb));
|
||||
char* str=StringBuilder_build(sb).ptr;
|
||||
return SUCCESS(UniHeapPtr(char, str));
|
||||
}
|
||||
13
kerep/src/DtsodParser/README.md
Normal file
13
kerep/src/DtsodParser/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# DtsodC
|
||||
|
||||
DtsodV23 parser in C# works too slow, so i wrote V24 parser in C
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
## Building on Linux
|
||||
**Required packages:** gcc
|
||||
|
||||
```bash
|
||||
make build
|
||||
````
|
||||
69
kerep/src/Filesystem/dir.c
Normal file
69
kerep/src/Filesystem/dir.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "filesystem.h"
|
||||
#include "io_includes.h"
|
||||
#include "../kprint/kprint.h"
|
||||
|
||||
bool dir_exists(const char* path){
|
||||
if(path[0]=='.'){
|
||||
if(path[1]==0 || (path[1]==path_sep && path[1]==0))
|
||||
return true; // dir . or ./ always exists
|
||||
// else if(path[1]=='.' && path[2]==path_sep)
|
||||
//TODO path_resolve because windows doesnt recognize .\ pattern
|
||||
}
|
||||
#if KFS_USE_WINDOWS_H
|
||||
DWORD dwAttrib = GetFileAttributes(path);
|
||||
return (bool)(
|
||||
(dwAttrib != INVALID_FILE_ATTRIBUTES) && // file exists
|
||||
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); // file is a directory
|
||||
#else
|
||||
struct stat stats;
|
||||
i32 rez=stat(path, &stats);
|
||||
return (bool)(
|
||||
(rez!=-1) && // file exists
|
||||
(S_ISDIR(stats.st_mode))); // file is a directory
|
||||
#endif
|
||||
}
|
||||
|
||||
Maybe dir_create(const char* path){
|
||||
if (dir_exists(path))
|
||||
return MaybeNull;
|
||||
char* parentDir=path_parentDir(path);
|
||||
dir_create(parentDir);
|
||||
free(parentDir);
|
||||
#if KFS_USE_WINDOWS_H
|
||||
if(!CreateDirectory(path, NULL))
|
||||
#else
|
||||
if(mkdir(path, 0777) == -1)
|
||||
#endif
|
||||
{
|
||||
char err[512];
|
||||
IFWIN(
|
||||
sprintf_s(err, 512, "can't create dicectory <%s>", path),
|
||||
sprintf(err, "can't create dicectory <%s>", path));
|
||||
safethrow(err,;);
|
||||
}
|
||||
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
Maybe dir_delete(const char* path){
|
||||
throw(ERR_NOTIMPLEMENTED);
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
Maybe dir_getFiles(const char* path, bool recursive){
|
||||
throw(ERR_NOTIMPLEMENTED);
|
||||
return MaybeNull;
|
||||
}
|
||||
Maybe dir_getDirs(const char* path, bool recursive){
|
||||
throw(ERR_NOTIMPLEMENTED);
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
Maybe dir_findFiles(const char* path, char* searchPattern, bool recursive){
|
||||
throw(ERR_NOTIMPLEMENTED);
|
||||
return MaybeNull;
|
||||
}
|
||||
Maybe dir_findDirs(const char* path, char* searchPattern, bool recursive){
|
||||
throw(ERR_NOTIMPLEMENTED);
|
||||
return MaybeNull;
|
||||
}
|
||||
28
kerep/src/Filesystem/dir.h
Normal file
28
kerep/src/Filesystem/dir.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../base/base.h"
|
||||
#include "file.h"
|
||||
|
||||
bool dir_exists(const char* path);
|
||||
///@return Maybe<void>
|
||||
Maybe dir_create(const char* path);
|
||||
///@return Maybe<void>
|
||||
Maybe dir_delete(const char* path);
|
||||
|
||||
///@return Maybe<char**>
|
||||
Maybe dir_getFiles(const char* path, bool recursive);
|
||||
///@return Maybe<char**>
|
||||
Maybe dir_getDirs(const char* path, bool recursive);
|
||||
|
||||
///@return Maybe<char**>
|
||||
Maybe dir_findFiles(const char* path, char* searchPattern, bool recursive);
|
||||
///@return Maybe<char**>
|
||||
Maybe dir_findDirs(const char* path, char* searchPattern, bool recursive);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
138
kerep/src/Filesystem/file.c
Normal file
138
kerep/src/Filesystem/file.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "filesystem.h"
|
||||
#include "../String/StringBuilder.h"
|
||||
#include "io_includes.h"
|
||||
|
||||
void __file_freeMembers(void* _f){ fclose((FileHandle)_f); }
|
||||
|
||||
kt_define(FileHandle, __file_freeMembers, NULL)
|
||||
|
||||
bool file_exists(const char* path){
|
||||
if(path[0]=='.'){
|
||||
if(path[1]==0 || (path[1]==path_sep && path[2]==0))
|
||||
return false; // . or ./ is not a file
|
||||
// else if(path[1]=='.' && path[2]==path_sep)
|
||||
//TODO path_resolve because windows doesnt recognize .\ pattern
|
||||
}
|
||||
|
||||
#if KFS_USE_WINDOWS_H
|
||||
DWORD dwAttrib = GetFileAttributes(path);
|
||||
return (bool)(
|
||||
(dwAttrib != INVALID_FILE_ATTRIBUTES) && // file exists
|
||||
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); // file is not directory
|
||||
#else
|
||||
struct stat stats;
|
||||
i32 rez=stat(path, &stats);
|
||||
return (bool)(
|
||||
(rez!=-1) && // file exists
|
||||
!(S_ISDIR(stats.st_mode))); // file is not directory
|
||||
#endif
|
||||
}
|
||||
|
||||
Maybe file_delete(const char* path, bool recursive){
|
||||
throw(ERR_NOTIMPLEMENTED);
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
char* FileOpenMode_toStr(FileOpenMode m){
|
||||
char* p;
|
||||
switch(m){
|
||||
case FileOpenMode_Read: p="rb"; break;
|
||||
case FileOpenMode_Write: p="wb"; break;
|
||||
case FileOpenMode_Append: p="ab"; break;
|
||||
case FileOpenMode_ReadWrite: p="wb+"; break;
|
||||
case FileOpenMode_ReadAppend: p="ab+"; break;
|
||||
default:
|
||||
dbg(m);
|
||||
throw(ERR_UNEXPECTEDVAL);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
Maybe file_open(const char* path, FileOpenMode mode){
|
||||
FileHandle file=fopen(path, FileOpenMode_toStr(mode));
|
||||
if(!file)
|
||||
safethrow(cptr_concat("can't open file ", (char*)path),;);
|
||||
return SUCCESS(UniHeapPtr(FileHandle,file));
|
||||
}
|
||||
|
||||
Maybe file_close(FileHandle file){
|
||||
if(!file)
|
||||
safethrow(ERR_NULLPTR,;);
|
||||
if(fclose(file))
|
||||
safethrow(ERR_IO,;);
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
#define ioWriteCheck() \
|
||||
if(rezult==EOF) \
|
||||
safethrow(ERR_IO_EOF,;); \
|
||||
if(rezult!=0) \
|
||||
safethrow(ERR_IO,;);
|
||||
|
||||
Maybe file_writeChar(FileHandle file, char byte){
|
||||
i32 rezult=fputc(byte, file);
|
||||
ioWriteCheck();
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
Maybe file_writeBuffer(FileHandle file, char* buffer, u64 length){
|
||||
i32 rezult=0;
|
||||
for(u64 i=0; i<length && !rezult; i++)
|
||||
rezult=fputc(buffer[i], file);
|
||||
ioWriteCheck();
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
Maybe file_writeCptr(FileHandle file, char* cptr){
|
||||
i32 rezult=fputs(cptr, file);
|
||||
ioWriteCheck();
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
|
||||
Maybe file_readChar(FileHandle file){
|
||||
i32 rezult=fgetc(file);
|
||||
if(feof(file)) safethrow(ERR_IO_EOF,;);
|
||||
if(ferror(file)) safethrow(ERR_IO,;);
|
||||
return SUCCESS(UniUInt64(rezult));
|
||||
}
|
||||
|
||||
Maybe file_readBuffer(FileHandle file, char* buffer, u64 length){
|
||||
i32 rezult=0;
|
||||
u64 i=0;
|
||||
for(; i<length && rezult!=EOF; i++){
|
||||
rezult=fgetc(file);
|
||||
buffer[i]=(char)rezult;
|
||||
}
|
||||
if(ferror(file)) safethrow(ERR_IO,;);
|
||||
return SUCCESS(UniUInt64(i));
|
||||
}
|
||||
|
||||
Maybe file_readAll(FileHandle file, char** allBytes){
|
||||
i32 rezult=0;
|
||||
char buffer[256];
|
||||
string bufStr={.ptr=buffer, .length=sizeof(buffer)};
|
||||
StringBuilder* sb=StringBuilder_create();
|
||||
u64 i=0;
|
||||
while(true){
|
||||
rezult=fgetc(file);
|
||||
if(rezult==EOF){
|
||||
if(ferror(file))
|
||||
safethrow(ERR_IO, StringBuilder_free(sb));
|
||||
break;
|
||||
}
|
||||
buffer[i%sizeof(buffer)]=(char)rezult;
|
||||
i++;
|
||||
if(!(i%sizeof(buffer)))
|
||||
StringBuilder_append_string(sb,bufStr);
|
||||
}
|
||||
bufStr.length=i%sizeof(buffer);
|
||||
if(bufStr.length!=0)
|
||||
StringBuilder_append_string(sb,bufStr);
|
||||
string str=StringBuilder_build(sb);
|
||||
*allBytes=str.ptr;
|
||||
// i dont know how can it happen, but if it will have, it will be very dangerous
|
||||
if(i!=str.length)
|
||||
throw(ERR_UNEXPECTEDVAL);
|
||||
return SUCCESS(UniUInt64(i));
|
||||
}
|
||||
75
kerep/src/Filesystem/file.h
Normal file
75
kerep/src/Filesystem/file.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../base/base.h"
|
||||
#include "../String/string.h"
|
||||
|
||||
typedef FILE* FileHandle;
|
||||
kt_declare(FileHandle);
|
||||
|
||||
bool file_exists(const char* path);
|
||||
|
||||
///@return Maybe<void>
|
||||
Maybe file_delete(const char* path, bool recursive);
|
||||
|
||||
PACKED_ENUM(FileOpenMode,
|
||||
// open a file for reading
|
||||
FileOpenMode_Read=1,
|
||||
// (re)create a file for writing
|
||||
FileOpenMode_Write=2,
|
||||
// opens file for writing additional data to the end / creates new file
|
||||
FileOpenMode_Append=4,
|
||||
// (re)creates file for reading/writing
|
||||
FileOpenMode_ReadWrite=FileOpenMode_Read|FileOpenMode_Write,
|
||||
// opens file for readng/writing additional data to the end / creates new file
|
||||
FileOpenMode_ReadAppend=FileOpenMode_Read|FileOpenMode_Append
|
||||
)
|
||||
|
||||
/// @brief opens file
|
||||
/// @param path path to file
|
||||
/// @param mode Read/Write/Append/ReadWrite/ReadAppend
|
||||
/// @return Maybe<FileHandle>
|
||||
Maybe file_open(const char* path, FileOpenMode mode);
|
||||
|
||||
/// @brief closes file descriptor
|
||||
/// @return Maybe<void>
|
||||
Maybe file_close(FileHandle file);
|
||||
|
||||
/// @brief closes file descriptor
|
||||
/// @param byte byte to write
|
||||
/// @return Maybe<void>
|
||||
Maybe file_writeChar(FileHandle file, char byte);
|
||||
|
||||
/// @brief closes file descriptor
|
||||
/// @param buffer bytes to write
|
||||
/// @param length buffer length
|
||||
/// @return Maybe<void>
|
||||
Maybe file_writeBuffer(FileHandle file, char* buffer, u64 length);
|
||||
|
||||
/// @brief writes all cstring array content to file
|
||||
/// @param cptr zero-terminated cstring
|
||||
/// @return Maybe<void>
|
||||
Maybe file_writeCptr(FileHandle file, char* cptr);
|
||||
|
||||
|
||||
/// @brief reads single byte from file
|
||||
/// @return Maybe<char>
|
||||
Maybe file_readChar(FileHandle file);
|
||||
|
||||
/// @brief reads byte array of specofied length
|
||||
/// @param buffer buffer that will be filled with file bytes
|
||||
/// @param length buffer length
|
||||
/// @return Maybe<u64> total number of successfully read bytes (<=length)
|
||||
Maybe file_readBuffer(FileHandle file, char* buffer, u64 length);
|
||||
|
||||
/// @brief reads all bytes from file
|
||||
/// @param allBytes ptr to the file's content will be pushed there
|
||||
/// @return Maybe<u64> total number of successfully read bytes
|
||||
Maybe file_readAll(FileHandle file, char** allBytes);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
3
kerep/src/Filesystem/filesystem.h
Normal file
3
kerep/src/Filesystem/filesystem.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "path.h"
|
||||
#include "dir.h"
|
||||
#include "file.h"
|
||||
15
kerep/src/Filesystem/io_includes.h
Normal file
15
kerep/src/Filesystem/io_includes.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "../base/std.h"
|
||||
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
#define KFS_USE_WINDOWS_H 1
|
||||
#else
|
||||
#define KFS_USE_WINDOWS_H 0
|
||||
#endif
|
||||
|
||||
#if KFS_USE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
84
kerep/src/Filesystem/path.c
Normal file
84
kerep/src/Filesystem/path.c
Normal file
@@ -0,0 +1,84 @@
|
||||
#include "filesystem.h"
|
||||
|
||||
char* __path_concat(u32 n, ...){
|
||||
char** parts=(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* part=va_arg(vl,char*);
|
||||
i16 length=cptr_length(part);
|
||||
parts[i]=part;
|
||||
lengths[i]=length;
|
||||
totalLength+=length;
|
||||
}
|
||||
va_end(vl);
|
||||
|
||||
// allocating memory for output value
|
||||
char* totality=malloc(totalLength+1);
|
||||
const char* output=totality;
|
||||
totality[totalLength]=0;
|
||||
|
||||
// copying content of all strings to rezult
|
||||
u16 k=0;
|
||||
for(; k<n-1; k++){
|
||||
memcopy(parts[k], totality, lengths[k]);
|
||||
totality+=lengths[k];
|
||||
*totality=path_sep;
|
||||
totality++;
|
||||
}
|
||||
memcopy(parts[k], totality, lengths[k]);
|
||||
|
||||
free(parts);
|
||||
free(lengths);
|
||||
return output;
|
||||
}
|
||||
|
||||
char* path_fixSeparators(const char* path){
|
||||
char* pathCopy=cptr_copy(path);
|
||||
char c;
|
||||
while((c=*pathCopy)){
|
||||
if(c==path_notSep)
|
||||
*pathCopy=path_sep;
|
||||
pathCopy++;
|
||||
}
|
||||
return pathCopy;
|
||||
}
|
||||
|
||||
Maybe path_throwIfEscapes(const char* path){
|
||||
if(cptr_contains(path,".."))
|
||||
safethrow(cptr_concat("path <",path,"> uses <..>, that's not allowed"),);
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
char* path_parentDir(char* dir){
|
||||
char* copy=cptr_copy(dir);
|
||||
i32 length=cptr_length(copy);
|
||||
i32 i=cptr_lastIndexOfChar(copy,path_sep);
|
||||
if(i!=-1 && i==length-1){
|
||||
copy[length-1]=0;
|
||||
i=cptr_lastIndexOfChar(copy,path_sep);
|
||||
}
|
||||
if(i==-1){
|
||||
free(copy);
|
||||
copy=malloc(2);
|
||||
copy[0]='.';
|
||||
copy[1]=0;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
char* path_basename(char* path, bool with_extension){
|
||||
i32 nameIndex=cptr_lastIndexOfChar(path, path_sep)+1;
|
||||
string rezult=string_fromCptr(path+nameIndex);
|
||||
if(!with_extension){
|
||||
i32 extIndex=cptr_lastIndexOfChar(rezult.ptr, '.');
|
||||
if(extIndex!=0 && extIndex!=-1)
|
||||
rezult.length=extIndex;
|
||||
}
|
||||
return string_extract(rezult);
|
||||
}
|
||||
42
kerep/src/Filesystem/path.h
Normal file
42
kerep/src/Filesystem/path.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../base/base.h"
|
||||
|
||||
#if defined(_WIN32) || defined (_WIN64)
|
||||
static const char path_sep='\\';
|
||||
static const char path_notSep='/';
|
||||
#else
|
||||
static const char path_sep='/';
|
||||
static const char path_notSep='\\';
|
||||
#endif
|
||||
|
||||
char* __path_concat(u32 n, ...);
|
||||
/// @brief merges path parts together and puts <path_sep> between them
|
||||
/// @return new cstr
|
||||
#define path_concat(PATH_PARTS...) __path_concat(count_args(PATH_PARTS), PATH_PARTS)
|
||||
|
||||
/// @brief fixes path separators
|
||||
/// @param cstr where can be <path_notSep>
|
||||
/// @return new cstr with correct separators
|
||||
char* path_fixSeparators(const char* path);
|
||||
|
||||
#define path_resolve(PATH_PARTS...) path_fixSeparators(path_concat(PATH_PARTS))
|
||||
|
||||
/// @brief calls safethrow() if finds escape sequense in path
|
||||
/// @param path cstr where can be <..>
|
||||
/// @return Maybe<void>
|
||||
Maybe path_throwIfEscapes(const char* path);
|
||||
|
||||
///@return path of parent dir
|
||||
char* path_parentDir(char* path);
|
||||
|
||||
///@return file name
|
||||
char* path_basename(char* path, bool with_extension);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
111
kerep/src/HashFunctions/hash.c
Normal file
111
kerep/src/HashFunctions/hash.c
Normal file
@@ -0,0 +1,111 @@
|
||||
#include "hash.h"
|
||||
|
||||
u32 hash_sdbm32(u32 oldhash, void* buf, u32 len){
|
||||
u8* ubuf=(u8*)buf;
|
||||
register u32 hash=oldhash;
|
||||
for (; len ; len--, ubuf++)
|
||||
hash=(hash<<6)+(hash<<16)-hash+*ubuf;
|
||||
return hash;
|
||||
}
|
||||
|
||||
static const u32 crc_32_tab[]={
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
|
||||
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
|
||||
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
|
||||
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
|
||||
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
|
||||
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
|
||||
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
|
||||
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
|
||||
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
|
||||
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
|
||||
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
|
||||
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
|
||||
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
|
||||
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
|
||||
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
|
||||
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
|
||||
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
|
||||
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
|
||||
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
|
||||
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
u32 hash_crc32(u32 oldhash, void* buf, u32 len){
|
||||
u8* ubuf=(u8*)buf;
|
||||
register u32 crc=oldhash;
|
||||
for (; len; --len, ++ubuf)
|
||||
crc=crc_32_tab[(crc^(*ubuf)) & 0xff] ^ (crc>>8);
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
|
||||
// bool hashf_crc32c(char *name, u32 *crc, long *charcnt) {
|
||||
// register FILE *fin;
|
||||
// register u32 oldcrc32;
|
||||
// register i32 c;
|
||||
|
||||
// oldcrc32 = 0xFFFFFFFF; *charcnt = 0;
|
||||
// if ((fin=fopen(name, "r"))==NULL) {
|
||||
// perror(name);
|
||||
// return false;
|
||||
// }
|
||||
// while ((c=getc(fin))!=EOF) {
|
||||
// ++*charcnt;
|
||||
// oldcrc32 = UPDC32(c, oldcrc32);
|
||||
// }
|
||||
|
||||
// if (ferror(fin)) {
|
||||
// perror(name);
|
||||
// *charcnt = -1;
|
||||
// }
|
||||
|
||||
// fclose(fin);
|
||||
|
||||
// *crc = oldcrc32 = ~oldcrc32;
|
||||
// return true;
|
||||
// }
|
||||
17
kerep/src/HashFunctions/hash.h
Normal file
17
kerep/src/HashFunctions/hash.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../base/base.h"
|
||||
|
||||
#define hashb(FUNC, BUF, LEN) FUNC(0xFFFFFFFF, BUF, LEN)
|
||||
#define hashs(FUNC, STR) FUNC(0xFFFFFFFF, STR, cptr_length(STR))
|
||||
|
||||
u32 hash_sdbm32(u32 oldhash, void* buf, u32 len);
|
||||
u32 hash_crc32(u32 oldhash, void* buf, u32 len);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
133
kerep/src/Hashtable/Hashtable.c
Normal file
133
kerep/src/Hashtable/Hashtable.c
Normal file
@@ -0,0 +1,133 @@
|
||||
#include "Hashtable.h"
|
||||
|
||||
kt_define(Hashtable, __Hashtable_free, NULL);
|
||||
|
||||
// amount of rows
|
||||
static const u16 HT_HEIGHTS[]={17,61,257,1021,4099,16381,65521};
|
||||
#define HT_HEIN_MIN 0
|
||||
#define HT_HEIN_MAX 6
|
||||
|
||||
#define ARR_BC 2
|
||||
#define ARR_BL 8
|
||||
|
||||
Hashtable* Hashtable_create(){
|
||||
Hashtable* ht=malloc(sizeof(Hashtable));
|
||||
ht->hein=HT_HEIN_MIN;
|
||||
ht->rows=malloc(HT_HEIGHTS[HT_HEIN_MIN]*sizeof(Autoarr(KVPair)*));
|
||||
for(u16 i=0;i<HT_HEIGHTS[HT_HEIN_MIN];i++)
|
||||
ht->rows[i]=Autoarr_create(KVPair,ARR_BC,ARR_BL);
|
||||
return ht;
|
||||
}
|
||||
|
||||
void __Hashtable_free(void* _ht){
|
||||
Hashtable* ht=_ht;
|
||||
for(u16 i=0;i<HT_HEIGHTS[ht->hein];i++)
|
||||
Autoarr_free(ht->rows[i], true);
|
||||
free(ht->rows);
|
||||
}
|
||||
void Hashtable_free(Hashtable* ht){
|
||||
__Hashtable_free(ht);
|
||||
free(ht);
|
||||
}
|
||||
|
||||
u16 Hashtable_height(Hashtable* ht) { return HT_HEIGHTS[ht->hein]; }
|
||||
|
||||
|
||||
void Hashtable_expand(Hashtable* ht){
|
||||
if(ht->hein>=HT_HEIN_MAX) throw(ERR_MAXLENGTH);
|
||||
|
||||
Autoarr(KVPair)** newrows=malloc(HT_HEIGHTS[++ht->hein]*sizeof(Autoarr(KVPair)*));
|
||||
for(u16 i=0;i<HT_HEIGHTS[ht->hein];i++)
|
||||
newrows[i]=Autoarr_create(KVPair,ARR_BC,ARR_BL);
|
||||
|
||||
for(u16 i=0;i<HT_HEIGHTS[ht->hein-1];i++){
|
||||
Autoarr(KVPair)* ar=ht->rows[i];
|
||||
u32 arlen=Autoarr_length(ar);
|
||||
for(u32 k=0;k<arlen;k++){
|
||||
KVPair p=Autoarr_get(ar,k);
|
||||
u16 newrown=hashs(hash_sdbm32, p.key)%HT_HEIGHTS[ht->hein];
|
||||
Autoarr(KVPair)* newar=newrows[newrown];
|
||||
Autoarr_add(newar,p);
|
||||
}
|
||||
// there is no need to free array values, because they are copied into new array
|
||||
// so dont replace this incorrect auto-generated function
|
||||
Autoarr_freeWithoutMembers(ar, true);
|
||||
}
|
||||
|
||||
free(ht->rows);
|
||||
ht->rows=newrows;
|
||||
}
|
||||
|
||||
Autoarr(KVPair)* getrow(Hashtable* ht, char* key, bool can_expand){
|
||||
u32 hash=hashs(hash_sdbm32, key);
|
||||
Autoarr(KVPair)* ar=ht->rows[hash%HT_HEIGHTS[ht->hein]];
|
||||
if(can_expand && Autoarr_length(ar)==Autoarr_max_length(ar))
|
||||
Hashtable_expand(ht);
|
||||
ar=ht->rows[hash%HT_HEIGHTS[ht->hein]];
|
||||
return ar;
|
||||
}
|
||||
|
||||
/// @param key must be heap allocated
|
||||
/// Hashtable_free will free this pointer
|
||||
void Hashtable_add(Hashtable* ht, char* key, Unitype u){
|
||||
KVPair p={ .key=key, .value=u };
|
||||
Autoarr_add(getrow(ht,key,true),p);
|
||||
}
|
||||
|
||||
void Hashtable_addMany(Hashtable* ht, KVPair* pair_array, u32 count){
|
||||
for(u32 i=0; i<count; i++){
|
||||
Hashtable_add(ht, pair_array[i].key, pair_array[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
// returns null or pointer to value in hashtable
|
||||
Unitype* Hashtable_getPtr(Hashtable* ht, char* key){
|
||||
Autoarr(KVPair)* ar=getrow(ht,key,false);
|
||||
u32 arlen=Autoarr_length(ar);
|
||||
for(u32 i=0;i<arlen;i++){
|
||||
KVPair* p=Autoarr_getPtr(ar,i);
|
||||
if(cptr_equals(key,p->key)) return &p->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Unitype Hashtable_get(Hashtable* ht, char* key){
|
||||
Autoarr(KVPair)* ar=getrow(ht,key,false);
|
||||
u32 arlen=Autoarr_length(ar);
|
||||
for(u32 i=0;i<arlen;i++){
|
||||
KVPair p=Autoarr_get(ar,i);
|
||||
if(cptr_equals(key,p.key)) return p.value;
|
||||
}
|
||||
return UniNull;
|
||||
}
|
||||
|
||||
bool Hashtable_tryGet(Hashtable* ht, char* key, Unitype* output){
|
||||
Unitype u=Hashtable_get(ht,key);
|
||||
*output=u;
|
||||
return !Unitype_isUniNull(u);
|
||||
}
|
||||
|
||||
|
||||
bool Hashtable_trySet(Hashtable* ht, char* key, Unitype u){
|
||||
Unitype* val=Hashtable_getPtr(ht,key);
|
||||
if(val==NULL)
|
||||
return false;
|
||||
*val=u;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Hashtable_tryAdd(Hashtable* ht, char* key, Unitype u){
|
||||
Unitype* val=Hashtable_getPtr(ht,key);
|
||||
if(val==NULL){
|
||||
Hashtable_add(ht, key, u);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Hashtable_addOrSet(Hashtable* ht, char* key, Unitype u){
|
||||
Unitype* val=Hashtable_getPtr(ht, key);
|
||||
if(val==NULL)
|
||||
Hashtable_add(ht, key, u); // add
|
||||
else *val=u; // set
|
||||
}
|
||||
49
kerep/src/Hashtable/Hashtable.h
Normal file
49
kerep/src/Hashtable/Hashtable.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../base/base.h"
|
||||
#include "../HashFunctions/hash.h"
|
||||
#include "KeyValuePair.h"
|
||||
|
||||
STRUCT(Hashtable,
|
||||
u8 hein; // height=HT_HEIGHTS[hein]
|
||||
Autoarr(KVPair)** rows; // Autoarr[height]
|
||||
)
|
||||
|
||||
Hashtable* Hashtable_create();
|
||||
void Hashtable_free(Hashtable* ht);
|
||||
void __Hashtable_free(void* ht);
|
||||
|
||||
// amount of rows
|
||||
u16 Hashtable_height(Hashtable* ht);
|
||||
|
||||
// don't add pairs with the same keys,
|
||||
// or something weird will happen
|
||||
// if not sure, use Hashtable_addOrSet()
|
||||
void Hashtable_add(Hashtable* ht, char* key, Unitype u);
|
||||
|
||||
void Hashtable_addOrSet(Hashtable* ht, char* key, Unitype u);
|
||||
void Hashtable_addMany(Hashtable* ht, KVPair* pair_array, u32 count);
|
||||
bool Hashtable_tryAdd(Hashtable* ht, char* key, Unitype u);
|
||||
bool Hashtable_trySet(Hashtable* ht, char* key, Unitype u);
|
||||
|
||||
// returns null or pointer to value in hashtable
|
||||
Unitype* Hashtable_getPtr(Hashtable* ht, char* key);
|
||||
|
||||
Unitype Hashtable_get(Hashtable* ht, char* key);
|
||||
bool Hashtable_tryGet(Hashtable* ht, char* key, Unitype* output);
|
||||
|
||||
#define Hashtable_foreach(HT, EL, codeblock...) { \
|
||||
u16 hmax=Hashtable_height(HT); \
|
||||
for(u16 h=0; h<hmax; h++){ \
|
||||
Autoarr(KVPair)* AR=HT->rows[h]; \
|
||||
Autoarr_foreach(AR, EL, codeblock); \
|
||||
} \
|
||||
}
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
18
kerep/src/Hashtable/KeyValuePair.c
Normal file
18
kerep/src/Hashtable/KeyValuePair.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "KeyValuePair.h"
|
||||
|
||||
kt_define(KVPair, __KVPair_free, NULL);
|
||||
|
||||
Autoarr_define(KVPair, false)
|
||||
|
||||
// proper way to clean a KVP
|
||||
void KVPair_free(KVPair p){
|
||||
free(p.key);
|
||||
Unitype_free(p.value);
|
||||
}
|
||||
void __KVPair_free(void* p){ KVPair_free(*(KVPair*)p); }
|
||||
|
||||
void printkvp(KVPair p){
|
||||
kprintf("{\"%s\", ",p.key);
|
||||
printuni(p.value);
|
||||
kprintf("}");
|
||||
}
|
||||
25
kerep/src/Hashtable/KeyValuePair.h
Normal file
25
kerep/src/Hashtable/KeyValuePair.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../base/base.h"
|
||||
#include "../Autoarr/Autoarr.h"
|
||||
|
||||
STRUCT(KVPair,
|
||||
char* key;
|
||||
Unitype value;
|
||||
)
|
||||
|
||||
Autoarr_declare(KVPair)
|
||||
|
||||
// proper way to clean a KVP
|
||||
void KVPair_free(KVPair p);
|
||||
void __KVPair_free(void* p);
|
||||
|
||||
void printkvp(KVPair p);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
147
kerep/src/String/StringBuilder.c
Normal file
147
kerep/src/String/StringBuilder.c
Normal file
@@ -0,0 +1,147 @@
|
||||
#include "StringBuilder.h"
|
||||
|
||||
kt_define(StringBuilder, __StringBuilder_free, NULL);
|
||||
|
||||
#define BL_C 32
|
||||
#define BL_L 1024
|
||||
|
||||
|
||||
void complete_buf(StringBuilder* b){
|
||||
if(!b->compl_bufs)
|
||||
b->compl_bufs=Autoarr_create(string,BL_C,BL_L);
|
||||
u32 len=Autoarr_length(b->curr_buf);
|
||||
if(!len) return;
|
||||
string str={.length=len, .ptr=malloc(len)};
|
||||
u32 i=0;
|
||||
Autoarr_foreach(b->curr_buf, c,
|
||||
str.ptr[i++]=c;
|
||||
);
|
||||
Autoarr_add(b->compl_bufs,str);
|
||||
Autoarr_free(b->curr_buf, true);
|
||||
b->curr_buf=Autoarr_create(i8,BL_C,BL_L);
|
||||
}
|
||||
|
||||
void try_complete_buf(StringBuilder* b){
|
||||
if(b->curr_buf->blocks_count==BL_C)
|
||||
complete_buf(b);
|
||||
}
|
||||
|
||||
|
||||
StringBuilder* StringBuilder_create(){
|
||||
StringBuilder* b=malloc(sizeof(StringBuilder));
|
||||
b->compl_bufs=NULL;
|
||||
b->curr_buf=Autoarr_create(i8,BL_C,BL_L);
|
||||
return b;
|
||||
}
|
||||
|
||||
void __StringBuilder_free(void* _b){
|
||||
StringBuilder* b=_b;
|
||||
if(b->compl_bufs) Autoarr_free(b->compl_bufs, true);
|
||||
Autoarr_free(b->curr_buf, true);
|
||||
}
|
||||
void StringBuilder_free(StringBuilder* b){
|
||||
__StringBuilder_free(b);
|
||||
free(b);
|
||||
}
|
||||
|
||||
string StringBuilder_build(StringBuilder* b){
|
||||
complete_buf(b);
|
||||
u32 len=0;
|
||||
Autoarr_foreach(b->compl_bufs, cs,
|
||||
len+=cs.length;
|
||||
);
|
||||
string str= { .length=len, .ptr=malloc(len+1) };
|
||||
str.ptr[len]='\0';
|
||||
u32 i=0;
|
||||
Autoarr_foreach(b->compl_bufs, cs,
|
||||
for(u32 n=0;n<cs.length;n++)
|
||||
str.ptr[i++]=cs.ptr[n];
|
||||
free(cs.ptr);
|
||||
);
|
||||
StringBuilder_free(b);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
void StringBuilder_rmchar(StringBuilder* b){
|
||||
if(b->curr_buf->block_length!=0)
|
||||
Autoarr_pop(b->curr_buf)
|
||||
else {
|
||||
if(!b->compl_bufs) throw(ERR_NULLPTR);
|
||||
string* lastcb=Autoarr_getPtr(b->compl_bufs, (Autoarr_length(b->compl_bufs)-1));
|
||||
lastcb->length--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void StringBuilder_append_char(StringBuilder* b, char c){
|
||||
try_complete_buf(b);
|
||||
Autoarr_add(b->curr_buf,c);
|
||||
}
|
||||
|
||||
|
||||
void StringBuilder_append_string(StringBuilder* b, string s){
|
||||
complete_buf(b);
|
||||
Autoarr_add(b->compl_bufs, string_copy(s));
|
||||
}
|
||||
|
||||
void StringBuilder_append_cptr(StringBuilder* b, char* s){
|
||||
string str={
|
||||
.ptr=s,
|
||||
.length=cptr_length(s)
|
||||
};
|
||||
StringBuilder_append_string(b,str);
|
||||
}
|
||||
|
||||
void curr_buf_add_string(StringBuilder* b, string s){
|
||||
for(u32 i=0; i<s.length; i++)
|
||||
Autoarr_add(b->curr_buf,s.ptr[i]);
|
||||
}
|
||||
|
||||
void StringBuilder_append_i64(StringBuilder* b, i64 a){
|
||||
try_complete_buf(b);
|
||||
u8 i=0;
|
||||
if(a==0){
|
||||
Autoarr_add(b->curr_buf,'0');
|
||||
return;
|
||||
}
|
||||
else if(a<0){
|
||||
Autoarr_add(b->curr_buf,'-');
|
||||
a=-a;
|
||||
}
|
||||
char buf[24];
|
||||
while(a!=0){
|
||||
buf[i++]='0'+a%10;
|
||||
a/=10;
|
||||
}
|
||||
string rev=string_reverse((string){buf,i});
|
||||
curr_buf_add_string(b,rev);
|
||||
free(rev.ptr);
|
||||
}
|
||||
|
||||
void StringBuilder_append_u64(StringBuilder* b, u64 a){
|
||||
try_complete_buf(b);
|
||||
u8 i=0;
|
||||
if(a==0){
|
||||
Autoarr_add(b->curr_buf,'0');
|
||||
return;
|
||||
}
|
||||
char buf[24];
|
||||
while(a!=0){
|
||||
buf[i++]='0'+a%10;
|
||||
a/=10;
|
||||
}
|
||||
string rev=string_reverse((string){buf,i});
|
||||
curr_buf_add_string(b,rev);
|
||||
free(rev.ptr);
|
||||
}
|
||||
|
||||
void StringBuilder_append_f64(StringBuilder* b, f64 a){
|
||||
try_complete_buf(b);
|
||||
char buf[32];
|
||||
IFMSC(
|
||||
sprintf_s(buf,32,"%lf",a),
|
||||
sprintf(buf,"%lf",a)
|
||||
);
|
||||
curr_buf_add_string(b, (string){.ptr=buf, .length=cptr_length(buf)});
|
||||
}
|
||||
34
kerep/src/String/StringBuilder.h
Normal file
34
kerep/src/String/StringBuilder.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../Autoarr/Autoarr.h"
|
||||
#include "string.h"
|
||||
|
||||
STRUCT(StringBuilder,
|
||||
Autoarr(string)* compl_bufs;
|
||||
Autoarr(i8)* curr_buf;
|
||||
)
|
||||
|
||||
StringBuilder* StringBuilder_create(void);
|
||||
void StringBuilder_free(StringBuilder* b);
|
||||
void __StringBuilder_free(void* b);
|
||||
// Joins all strings from compl_bufs.
|
||||
// Returns zero-terminated string.
|
||||
// No need to call string_extract()!
|
||||
// Frees StringBuilder.
|
||||
string StringBuilder_build(StringBuilder* b);
|
||||
// removes last char
|
||||
void StringBuilder_rmchar(StringBuilder* b);
|
||||
void StringBuilder_append_char(StringBuilder* b, char c);
|
||||
void StringBuilder_append_cptr(StringBuilder* b, char* s);
|
||||
void StringBuilder_append_string(StringBuilder* b, string s);
|
||||
void StringBuilder_append_i64(StringBuilder* b, i64 a);
|
||||
void StringBuilder_append_u64(StringBuilder* b, u64 a);
|
||||
void StringBuilder_append_f64(StringBuilder* b, f64 a);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
47
kerep/src/String/string.c
Normal file
47
kerep/src/String/string.c
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "string.h"
|
||||
|
||||
kt_define(string, NULL, NULL);
|
||||
Autoarr_define(string, false);
|
||||
|
||||
// copies str content to new char pointer value (adding '\0' at the end)
|
||||
char* string_extract(string str){
|
||||
if(str.length==0) return NULL;
|
||||
char* cptr=malloc(str.length*sizeof(char)+1);
|
||||
cptr[str.length]=0;
|
||||
while(str.length-->0)
|
||||
cptr[str.length]=str.ptr[str.length];
|
||||
return cptr;
|
||||
}
|
||||
|
||||
// copies src.ptr content to new string and adds \0 at the end
|
||||
string string_copy(string src){
|
||||
if(!src.ptr)
|
||||
return src;
|
||||
string nstr;
|
||||
nstr.length=src.length;
|
||||
nstr.ptr=malloc(nstr.length+1);
|
||||
for(u32 i=0;i<nstr.length;i++)
|
||||
nstr.ptr[i]=src.ptr[i];
|
||||
nstr.ptr[nstr.length]='\0';
|
||||
return nstr;
|
||||
}
|
||||
|
||||
// compares two strings, NullPtr-friendly
|
||||
bool string_compare(string str0, string str1){
|
||||
if(str0.length!=str1.length) return false;
|
||||
if(!str0.ptr) return str1.ptr ? false : true;
|
||||
else if(!str1.ptr) return false;
|
||||
while(str0.length-->0)
|
||||
if(*str0.ptr++ != *str1.ptr++)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// creates new string which is reversed variant of <s>
|
||||
string string_reverse(string s){
|
||||
if(s.length==0) return s;
|
||||
string r={malloc(s.length), s.length};
|
||||
for(u32 i=0; i<s.length; i++)
|
||||
r.ptr[i]=s.ptr[s.length-i-1];
|
||||
return r;
|
||||
}
|
||||
38
kerep/src/String/string.h
Normal file
38
kerep/src/String/string.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../base/base.h"
|
||||
#include "../Autoarr/Autoarr.h"
|
||||
|
||||
// my fixed length string struct
|
||||
// doesn't store '\0' at the end
|
||||
STRUCT(string,
|
||||
char* ptr; // char pointer
|
||||
u64 length; // amount of chars in ptr value
|
||||
)
|
||||
|
||||
Autoarr_declare(string)
|
||||
|
||||
static const string stringNull={NULL,0};
|
||||
|
||||
/// wraps pointer without copy
|
||||
#define string_fromCptr(CPTR) (string){ .ptr=CPTR, .length=cptr_length(CPTR) }
|
||||
|
||||
// copies str content to new char pointer value (adding '\0' at the end)
|
||||
char* string_extract(string str);
|
||||
|
||||
// copies src.ptr content to new string and adds \0 at the end
|
||||
string string_copy(string src);
|
||||
|
||||
// compares two strings, NullPtr-friendly
|
||||
bool string_compare(string str0, string str1);
|
||||
|
||||
// creates new string which is reversed variant of <s>
|
||||
string string_reverse(string s);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
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
|
||||
52
kerep/src/kprint/README.md
Normal file
52
kerep/src/kprint/README.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# kprintf
|
||||
It is just my cross-plaform variant of printf.
|
||||
Unlike in standard printf, `%l...` and `%ll...` placeholders dont depend on size of `long int` and `long long int`. And you can change terminal colors by unix codes (`\e[92m`) even on Windows.
|
||||
|
||||
| type | placeholder |
|
||||
|----------------|-------------------------|
|
||||
| i8 / i16 / i32 | %i / %d |
|
||||
| i64 | %li / %ld / %lld / %lli |
|
||||
| u8 / u16 / u32 | %u |
|
||||
| u64 | %lu / %llu |
|
||||
| f32 / f64 | %f |
|
||||
| char | %c |
|
||||
| char[] | %s |
|
||||
| void\* | %p |
|
||||
| 32bit or less | %x |
|
||||
| 64bit | %lx |
|
||||
|
||||
<br>
|
||||
|
||||
# kprint
|
||||
I don't really like printf function (and its variants), so i made safer and more convinient replacement.
|
||||
|
||||
| function | returns | arguments |
|
||||
|----------|---------|-----------|
|
||||
| kprint | void/throw | kp_fmt, void\*, kp_fmt, void\*... |
|
||||
| ksprint | Maybe<char\*>| kp_fmt, void\*, kp_fmt, void\*... |
|
||||
| kfprint | Maybe<void> | FILE\*, kp_fmt, void\*, kp_fmt, void\*... |
|
||||
|
||||
## how to use it:
|
||||
+ **format construction:**
|
||||
```
|
||||
kp_fmt fmt= kp_fgColor | kp_bgColor | kp_dataFmt | flags | ktid;
|
||||
```
|
||||
[more about `kp_fmt`](kp_fmt.md)
|
||||
+ fgColor and bgColor can be set to change console output color
|
||||
+ you should set dataFormat for `int`/`uint`/`float`/`char\*` arguments and ktid for other types
|
||||
+ flags can be set to modify TypeDescriptor.toString() behavior
|
||||
+ don't forget to set TypeDescriptor.toString when registering type, or kprint will crash
|
||||
|
||||
+ **using base type arguments:**
|
||||
you can just put them into a function
|
||||
```
|
||||
kprint(kp_h|kp_upper|kp_prefix, 255);
|
||||
```
|
||||
output: 0xFF
|
||||
+ **using other registered types:**
|
||||
should be sent as pointers
|
||||
```
|
||||
Maybe m=MaybeNull;
|
||||
kprint(kp_fgBlue|kp_s, "Maybe: ", kp_fgGreen|ktid_MaybePtr, &m);
|
||||
```
|
||||
output: <span style="color:blue">Maybe:</span> <span style="color:lightgreen">{value: { Pointer, 0x0 }}</span>
|
||||
211
kerep/src/kprint/kprint.c
Normal file
211
kerep/src/kprint/kprint.c
Normal file
@@ -0,0 +1,211 @@
|
||||
#include "../String/StringBuilder.h"
|
||||
#include "kprint.h"
|
||||
|
||||
ktid __typeFromFormat(kp_fmt f){
|
||||
ktid typeId=kp_fmt_ktid(f);
|
||||
if(typeId)
|
||||
return typeId;
|
||||
switch(kp_fmt_dataFormat(f)){
|
||||
case kp_i:
|
||||
case kp_h:
|
||||
case kp_b:
|
||||
return ktid_name(i64);
|
||||
case kp_u:
|
||||
return ktid_name(u64);
|
||||
case kp_f:
|
||||
return ktid_name(f64);
|
||||
case kp_c:
|
||||
return ktid_name(char);
|
||||
case kp_s:
|
||||
return ktid_ptrName(char);
|
||||
default:
|
||||
return ktid_undefined;
|
||||
}
|
||||
}
|
||||
|
||||
Maybe __next_toString(kp_fmt f, void* object){
|
||||
// detecting type
|
||||
ktid typeId=__typeFromFormat(f);
|
||||
if(typeId==ktid_undefined)
|
||||
safethrow("typeId is undefined, can't autodetect type",;);
|
||||
|
||||
if(typeId==ktid_ptrName(char))
|
||||
object=*(char**)object; // dereferencing char** to char*
|
||||
|
||||
ktDescriptor* type=ktDescriptor_get(typeId);
|
||||
if(!type->toString)
|
||||
safethrow("type descriptor doesnt have toString() func",;);
|
||||
return SUCCESS(UniHeapPtr(char, type->toString(object, f)));
|
||||
}
|
||||
|
||||
Maybe check_argsN(u8 n){
|
||||
if(n%2 != 0) safethrow("kprint recieved non-even number of arguments",;);
|
||||
if(n > 32) safethrow("kprint recieved >32 number of arguments",;);
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
Maybe __ksprint(u8 n, kp_fmt* formats, __kp_value_union* objects){
|
||||
try(check_argsN(n), _,;);
|
||||
n/=2;
|
||||
StringBuilder* strb=StringBuilder_create();
|
||||
for(u8 i=0; i<n; i++){
|
||||
try(__next_toString(formats[i], &objects[i]),mStr,;);
|
||||
StringBuilder_append_cptr(strb, mStr.value.VoidPtr);
|
||||
Unitype_free(mStr.value);
|
||||
}
|
||||
char* rezult=StringBuilder_build(strb).ptr;
|
||||
return SUCCESS(UniHeapPtr(char, rezult));
|
||||
}
|
||||
|
||||
Maybe __kfprint(FILE* file, u8 n, kp_fmt* formats, __kp_value_union* objects){
|
||||
try(check_argsN(n), _,;);
|
||||
n/=2;
|
||||
for(u8 i=0; i<n; i++){
|
||||
try(__next_toString(formats[i], &objects[i]),maybeStr,;);
|
||||
if(fputs(maybeStr.value.VoidPtr, file)==EOF)
|
||||
safethrow("can't write string to file", Unitype_free(maybeStr.value));
|
||||
Unitype_free(maybeStr.value);
|
||||
}
|
||||
fflush(file);
|
||||
return MaybeNull;
|
||||
}
|
||||
|
||||
void __kprint(u8 n, kp_fmt* formats, __kp_value_union* objects){
|
||||
tryLast(check_argsN(n), _,;);
|
||||
n/=2;
|
||||
for(u8 i=0; i<n; i++){
|
||||
kp_fmt fmt=formats[i];
|
||||
kprint_setColor(fmt);
|
||||
tryLast(__next_toString(fmt, &objects[i]),maybeStr, kprint_setColor(kp_bgBlack|kp_fgGray));
|
||||
if(fputs(maybeStr.value.VoidPtr, stdout)==EOF) \
|
||||
throw("can't write string to stdout");
|
||||
//, Unitype_free(maybeStr.value)
|
||||
Unitype_free(maybeStr.value);
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)|| defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#define FOREGROUND_YELLOW FOREGROUND_GREEN | FOREGROUND_RED
|
||||
|
||||
DWORD kp_fgColor_toWin(kp_fgColor f){
|
||||
//kprintf("fg: %x\n", f);
|
||||
switch(f){
|
||||
case kp_fgBlack: return 0;
|
||||
case kp_fgRedD: return FOREGROUND_RED;
|
||||
case kp_fgGreenD: return FOREGROUND_GREEN;
|
||||
case kp_fgYellowD: return FOREGROUND_GREEN | FOREGROUND_RED;
|
||||
case kp_fgBlueD: return FOREGROUND_BLUE;
|
||||
case kp_fgMagentaD: return FOREGROUND_RED | FOREGROUND_BLUE;
|
||||
case kp_fgCyanD: return FOREGROUND_BLUE | FOREGROUND_GREEN;
|
||||
case kp_fgGray: return FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
|
||||
case kp_fgGrayD: return FOREGROUND_INTENSITY;
|
||||
case kp_fgRed: return FOREGROUND_RED | FOREGROUND_INTENSITY;
|
||||
case kp_fgGreen: return FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||
case kp_fgYellow: return FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
|
||||
case kp_fgBlue: return FOREGROUND_BLUE | FOREGROUND_INTENSITY;
|
||||
case kp_fgMagenta: return FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
|
||||
case kp_fgCyan: return FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||
case kp_fgWhite: return FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||
default: throw(ERR_FORMAT);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD kp_bgColor_toWin(kp_bgColor f){
|
||||
//kprintf("bg: %x\n", f);
|
||||
switch(f){
|
||||
case kp_bgBlack: return 0;
|
||||
case kp_bgRedD: return BACKGROUND_RED;
|
||||
case kp_bgGreenD: return BACKGROUND_GREEN;
|
||||
case kp_bgYellowD: return BACKGROUND_GREEN | BACKGROUND_RED;
|
||||
case kp_bgBlueD: return BACKGROUND_BLUE;
|
||||
case kp_bgMagentaD: return BACKGROUND_RED | BACKGROUND_BLUE;
|
||||
case kp_bgCyanD: return BACKGROUND_BLUE | BACKGROUND_GREEN;
|
||||
case kp_bgGray: return BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
|
||||
case kp_bgGrayD: return BACKGROUND_INTENSITY;
|
||||
case kp_bgRed: return BACKGROUND_RED | BACKGROUND_INTENSITY;
|
||||
case kp_bgGreen: return BACKGROUND_GREEN | BACKGROUND_INTENSITY;
|
||||
case kp_bgYellow: return BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
|
||||
case kp_bgBlue: return BACKGROUND_BLUE | BACKGROUND_INTENSITY;
|
||||
case kp_bgMagenta: return BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
|
||||
case kp_bgCyan: return BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
|
||||
case kp_bgWhite: return BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
|
||||
default: throw(ERR_FORMAT);
|
||||
}
|
||||
}
|
||||
|
||||
void kprint_setColor(kp_fmt f){
|
||||
DWORD color=0;
|
||||
if(!kp_fmt_fgColorSet(f) & !kp_fmt_bgColorSet(f))
|
||||
return;
|
||||
if(kp_fmt_fgColorSet(f))
|
||||
color+=kp_fgColor_toWin(kp_fmt_fgColor(f));
|
||||
if(kp_fmt_bgColorSet(f))
|
||||
color+=kp_bgColor_toWin(kp_fmt_bgColor(f));
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(hConsole, color);
|
||||
}
|
||||
#else
|
||||
void kprint_setColor(kp_fmt f){
|
||||
if(kp_fmt_fgColorSet(f)){
|
||||
u8 fg=(f&0x0f000000)>>24;
|
||||
if(fg<8) fg+=30;
|
||||
else fg+=90-8;
|
||||
printf("\e[%um", fg);
|
||||
}
|
||||
if(kp_fmt_bgColorSet(f)){
|
||||
u8 bg=(f&0x00f00000)>>20;
|
||||
if(bg<8) bg+=40;
|
||||
else bg+=100-8;
|
||||
printf("\e[%um", bg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Maybe ksprint_ar(u32 count, kp_fmt format, ktid typeId, void* array){
|
||||
ktDescriptor* type=ktDescriptor_get(format.typeId);
|
||||
if(!type->toString)
|
||||
safethrow("type descriptor doesnt have toString() func",;);
|
||||
StringBuilder* strb=StringBuilder_create();
|
||||
StringBuilder_append_char(strb, '[');
|
||||
for (u16 e=1; e<count; e++){
|
||||
StringBuilder_append_char(strb, ' ');
|
||||
char* elStr=type->toString(array+type->size*e, &format);
|
||||
StringBuilder_append_cptr(strb, elStr);
|
||||
StringBuilder_append_char(strb, ',');
|
||||
}
|
||||
StringBuilder_rmchar(strb);
|
||||
StringBuilder_append_char(strb, ' ');
|
||||
StringBuilder_append_char(strb, ']');
|
||||
} */
|
||||
|
||||
static const char* _kp_colorNames[16]={
|
||||
"black",
|
||||
"dark_red",
|
||||
"dark_green",
|
||||
"dark_yellow",
|
||||
"dark_blue",
|
||||
"dark_magenta",
|
||||
"dark_cyan",
|
||||
"gray",
|
||||
"dark_gray",
|
||||
"red",
|
||||
"green",
|
||||
"yellow",
|
||||
"blue",
|
||||
"magenta",
|
||||
"cyan",
|
||||
"white"
|
||||
};
|
||||
|
||||
char* kp_bgColor_toString(kp_bgColor c){
|
||||
u32 color_index=(c&0x00f00000)>>20;
|
||||
if(color_index>15) throw(ERR_WRONGINDEX);
|
||||
return _kp_colorNames[color_index];
|
||||
}
|
||||
char* kp_fgColor_toString(kp_fgColor c){
|
||||
u32 color_index=(c&0x00f00000)>>24;
|
||||
if(color_index>15) throw(ERR_WRONGINDEX);
|
||||
return _kp_colorNames[color_index];
|
||||
}
|
||||
102
kerep/src/kprint/kprint.h
Normal file
102
kerep/src/kprint/kprint.h
Normal file
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../base/errors.h"
|
||||
#include "kprint_format.h"
|
||||
|
||||
/*
|
||||
|
||||
This file looks like a mess, but all cotnent here just solves the problem of putting variadic arguments to array of formats and array of objects.
|
||||
|
||||
*/
|
||||
|
||||
typedef union {
|
||||
i64 i64;
|
||||
u64 u64;
|
||||
f64 f64;
|
||||
void* ptr;
|
||||
} __kp_value_union;
|
||||
|
||||
|
||||
static inline __kp_value_union __kpVU_f(f64 f) { return (__kp_value_union){ .f64=f }; }
|
||||
static inline __kp_value_union __kpVU_i(i64 f) { return (__kp_value_union){ .i64=f }; }
|
||||
|
||||
#define __kpVU_selectType(V) _Generic(V, float: __kpVU_f, f64: __kpVU_f, default: __kpVU_i)(V)
|
||||
|
||||
#define __kpVU(V) __kpVU_selectType(V)
|
||||
|
||||
#define __kp_argsToFmts8( \
|
||||
a0, a1, a2, a3, a4, a5, a6, a7,...) \
|
||||
((i32[]){ a0,a2,a4,a6 })
|
||||
#define __kp_argsToObjs8( \
|
||||
a0, a1, a2, a3, a4, a5, a6, a7,...) \
|
||||
((__kp_value_union[]){ __kpVU(a1),__kpVU(a3),__kpVU(a5),__kpVU(a7) })
|
||||
|
||||
#define __kp_argsToFmts16( \
|
||||
a0, a1, a2, a3, a4, a5, a6, a7, \
|
||||
a8, a9, a10,a11,a12,a13,a14,a15,...) \
|
||||
((i32[]){ a0,a2,a4,a6,a8,a10,a12,a14 })
|
||||
#define __kp_argsToObjs16( \
|
||||
a0, a1, a2, a3, a4, a5, a6, a7, \
|
||||
a8, a9, a10,a11,a12,a13,a14,a15,...) \
|
||||
((__kp_value_union[]){ __kpVU(a1),__kpVU(a3),__kpVU(a5),__kpVU(a7),__kpVU(a9),__kpVU(a11),__kpVU(a13),__kpVU(a15) })
|
||||
|
||||
#define __kp_argsToFmts32( \
|
||||
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,...) \
|
||||
((i32[]){ a0,a2,a4,a6,a8,a10,a12,a14,a16,a18,a20,a22,a24,a26,a28,a30 })
|
||||
#define __kp_argsToObjs32( \
|
||||
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,...) \
|
||||
((__kp_value_union[]){ __kpVU(a1),__kpVU(a3),__kpVU(a5),__kpVU(a7),__kpVU(a9),__kpVU(a11),__kpVU(a13),__kpVU(a15),__kpVU(a17),__kpVU(a19),__kpVU(a21),__kpVU(a23),__kpVU(a25),__kpVU(a27),__kpVU(a29),__kpVU(a31) })
|
||||
|
||||
#define __32zeroes 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
|
||||
#define __kp_argsToArrs(COUNT,ARGS...) \
|
||||
(kp_fmt*)( \
|
||||
COUNT<=8 ? __kp_argsToFmts8(ARGS) : \
|
||||
COUNT<=16 ? __kp_argsToFmts16(ARGS) : \
|
||||
__kp_argsToFmts32(ARGS)), \
|
||||
(__kp_value_union*)( \
|
||||
COUNT<=8 ? __kp_argsToObjs8(ARGS) : \
|
||||
COUNT<=16 ? __kp_argsToObjs16(ARGS) : \
|
||||
__kp_argsToObjs32(ARGS))
|
||||
|
||||
|
||||
Maybe __ksprint(u8 n, kp_fmt* formats, __kp_value_union* objects);
|
||||
|
||||
/// @param ARGS kp_fmt, value, kp_fmt, value...
|
||||
///@returns Maybe<char*>
|
||||
#define ksprint(ARGS...) WARNING_DISABLE( W_INT_CONVERSION, \
|
||||
__ksprint(count_args(ARGS), __kp_argsToArrs(count_args(ARGS),ARGS, __32zeroes)) \
|
||||
)
|
||||
/*-Wint-conversion warning was produced during value to __kp_value_union conversion*/
|
||||
|
||||
Maybe __kfprint(FILE* fd, u8 n, kp_fmt* formats, __kp_value_union* objects);
|
||||
|
||||
/// @param FD FILE*
|
||||
/// @param ARGS kp_fmt, value, kp_fmt, value...
|
||||
///@returns Maybe<void>
|
||||
#define kfprint(FD, ARGS...) WARNING_DISABLE( W_INT_CONVERSION, \
|
||||
__kfprint(FD, count_args(ARGS), __kp_argsToArrs(count_args(ARGS),ARGS, __32zeroes)) \
|
||||
)
|
||||
|
||||
void __kprint(u8 n, kp_fmt* formats, __kp_value_union* objects);
|
||||
|
||||
///can use non-catchable throw !!!
|
||||
///@param ARGS kp_fmt, value, kp_fmt, value...
|
||||
///@returns void
|
||||
#define kprint(ARGS...) WARNING_DISABLE( W_INT_CONVERSION, \
|
||||
__kprint(count_args(ARGS), __kp_argsToArrs(count_args(ARGS),ARGS, __32zeroes)) \
|
||||
)
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
89
kerep/src/kprint/kprint_colors.h
Normal file
89
kerep/src/kprint/kprint_colors.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// 10000000 00000000 00000000 00000000
|
||||
// ^ ^^^^
|
||||
// | color num
|
||||
// fgColorSet flag
|
||||
PACKED_ENUM(kp_fgColor,
|
||||
/// black foreground
|
||||
kp_fgBlack = 0x80000000,
|
||||
/// dark red foreground
|
||||
kp_fgRedD = 0x81000000,
|
||||
/// dark green foreground
|
||||
kp_fgGreenD = 0x82000000,
|
||||
/// dark yellow foreground
|
||||
kp_fgYellowD = 0x83000000,
|
||||
/// dark blue foreground
|
||||
kp_fgBlueD = 0x84000000,
|
||||
/// dark magenta foreground
|
||||
kp_fgMagentaD= 0x85000000,
|
||||
/// dark cyan foreground
|
||||
kp_fgCyanD = 0x86000000,
|
||||
/// gray foreground
|
||||
kp_fgGray = 0x87000000,
|
||||
/// dark gray foreground
|
||||
kp_fgGrayD = 0x88000000,
|
||||
/// red foreground
|
||||
kp_fgRed = 0x89000000,
|
||||
/// green foreground
|
||||
kp_fgGreen = 0x8a000000,
|
||||
/// yellow foreground
|
||||
kp_fgYellow = 0x8b000000,
|
||||
/// blue foreground
|
||||
kp_fgBlue = 0x8c000000,
|
||||
/// magenta foreground
|
||||
kp_fgMagenta = 0x8d000000,
|
||||
/// cyan foreground
|
||||
kp_fgCyan = 0x8e000000,
|
||||
/// white foreground
|
||||
kp_fgWhite = 0x8f000000
|
||||
)
|
||||
|
||||
// 01000000 00000000 00000000 00000000
|
||||
// ^ ^^^^
|
||||
// bgColorSet flag color num
|
||||
PACKED_ENUM(kp_bgColor,
|
||||
/// black background
|
||||
kp_bgBlack = 0x40000000,
|
||||
/// dark red background
|
||||
kp_bgRedD = 0x40100000,
|
||||
/// dark green background
|
||||
kp_bgGreenD = 0x40200000,
|
||||
/// dark yellow background
|
||||
kp_bgYellowD = 0x40300000,
|
||||
/// dark blue background
|
||||
kp_bgBlueD = 0x40400000,
|
||||
/// dark magenta background
|
||||
kp_bgMagentaD= 0x40500000,
|
||||
/// dark cyan background
|
||||
kp_bgCyanD = 0x40600000,
|
||||
/// gray background
|
||||
kp_bgGray = 0x40700000,
|
||||
/// dark gray background
|
||||
kp_bgGrayD = 0x40800000,
|
||||
/// red background
|
||||
kp_bgRed = 0x40900000,
|
||||
/// green background
|
||||
kp_bgGreen = 0x40a00000,
|
||||
/// yellow background
|
||||
kp_bgYellow = 0x40b00000,
|
||||
/// blue background
|
||||
kp_bgBlue = 0x40c00000,
|
||||
/// magenta background
|
||||
kp_bgMagenta = 0x40d00000,
|
||||
/// cyan background
|
||||
kp_bgCyan = 0x40e00000,
|
||||
/// white background
|
||||
kp_bgWhite = 0x40f00000
|
||||
)
|
||||
|
||||
char* kp_bgColor_toString(kp_bgColor c);
|
||||
char* kp_fgColor_toString(kp_fgColor c);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
53
kerep/src/kprint/kprint_format.h
Normal file
53
kerep/src/kprint/kprint_format.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../base/std.h"
|
||||
#include "../base/type_system/ktid.h"
|
||||
#include "kprint_colors.h"
|
||||
|
||||
/// kprint_format
|
||||
typedef u32 kp_fmt;
|
||||
|
||||
PACKED_ENUM(kp_dataFmt,
|
||||
// 00000000 00000000 00000000 00000000
|
||||
// ^^^^
|
||||
// type
|
||||
kp_i = 0x00000000,
|
||||
kp_u = 0x00010000,
|
||||
kp_h = 0x00020000,
|
||||
kp_b = 0x00030000,
|
||||
kp_f = 0x00040000,
|
||||
kp_c = 0x00050000,
|
||||
kp_s = 0x00060000,
|
||||
|
||||
// 00100000 00000000 00000000 00000000
|
||||
// ^
|
||||
// prefix/postfix flag
|
||||
kp_pre=0x20000000,
|
||||
kp_post=kp_pre,
|
||||
|
||||
// 00010000 00000000 00000000 00000000
|
||||
// ^
|
||||
// uppercase flag
|
||||
kp_upper=0x10000000
|
||||
)
|
||||
|
||||
#define kp_fmt_fgColorSet(FMT) (bool)((FMT&0x80000000)!=0)
|
||||
#define kp_fmt_bgColorSet(FMT) (bool)((FMT&0x40000000)!=0)
|
||||
#define kp_fmt_withPrefix(FMT) (bool)((FMT&kp_pre)!=0)
|
||||
#define kp_fmt_withPostfix(FMT) (bool)((FMT&kp_post)!=0)
|
||||
#define kp_fmt_isUpper(FMT) (bool)((FMT&kp_upper)!=0)
|
||||
#define kp_fmt_fgColor(FMT) (kp_fgColor)(FMT&0x8f000000)
|
||||
#define kp_fmt_bgColor(FMT) (kp_bgColor)(FMT&0x40f00000)
|
||||
#define kp_fmt_dataFormat(FMT) (kp_dataFmt)(FMT&0x000f0000)
|
||||
#define kp_fmt_ktid(FMT) (ktid)(FMT&0x0000ffff)
|
||||
|
||||
///@param f bgColor | fgColor
|
||||
void kprint_setColor(kp_fmt f);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
74
kerep/src/kprint/kprint_format.md
Normal file
74
kerep/src/kprint/kprint_format.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# kerep_format
|
||||
|
||||
```
|
||||
00000000 00000000 00000000 00000000
|
||||
fgColorSet┘│││└┼┴┘ └┼┴┘└┴┴┤ ktid
|
||||
bgColorSet─┘││ │ bgColor └data format
|
||||
prefix┬────┘│ └fgColor
|
||||
postfix └uppercase
|
||||
|
||||
```
|
||||
|
||||
## Console colors
|
||||
### *Foreground*
|
||||
|
||||
| kp_fg | hex | bin |
|
||||
|-------|-----|-----|
|
||||
| Black | 0x80000000 | 10000000 00000000... |
|
||||
| RedD | 0x81000000 | 10000001 00000000... |
|
||||
| GreenD | 0x82000000 | 10000010 00000000... |
|
||||
| YellowD | 0x83000000 | 10000011 00000000... |
|
||||
| BlueD | 0x84000000 | 10000100 00000000... |
|
||||
| MagentaD | 0x85000000 | 10000101 00000000... |
|
||||
| CyanD | 0x86000000 | 10000110 00000000... |
|
||||
| Gray | 0x87000000 | 10000111 00000000... |
|
||||
| GrayD | 0x88000000 | 10001000 00000000... |
|
||||
| Red | 0x89000000 | 10001001 00000000... |
|
||||
| Green | 0x8a000000 | 10001010 00000000... |
|
||||
| Yellow | 0x8b000000 | 10001011 00000000... |
|
||||
| Blue | 0x8c000000 | 10001100 00000000... |
|
||||
| Magenta | 0x8d000000 | 10001101 00000000... |
|
||||
| Cyan | 0x8e000000 | 10001110 00000000... |
|
||||
| White | 0x8f000000 | 10001111 00000000... |
|
||||
|
||||
### *Background*
|
||||
| kp_bg | hex | bin |
|
||||
|-------|-----|-----|
|
||||
| Black | 0x40000000 | 01000000 00000000... |
|
||||
| RedD | 0x40100000 | 01000000 00010000... |
|
||||
| GreenD | 0x40200000 | 01000000 00100000... |
|
||||
| YellowD | 0x40300000 | 01000000 00110000... |
|
||||
| BlueD | 0x40400000 | 01000000 01000000... |
|
||||
| MagentaD | 0x40500000 | 01000000 01010000... |
|
||||
| CyanD | 0x40600000 | 01000000 01100000... |
|
||||
| Gray | 0x40700000 | 01000000 01110000... |
|
||||
| GrayD | 0x40800000 | 01000000 10000000... |
|
||||
| Red | 0x40900000 | 01000000 10010000... |
|
||||
| Green | 0x40a00000 | 01000000 10100000... |
|
||||
| Yellow | 0x40b00000 | 01000000 10110000... |
|
||||
| Blue | 0x40c00000 | 01000000 11000000... |
|
||||
| Magenta | 0x40d00000 | 01000000 11010000... |
|
||||
| Cyan | 0x40e00000 | 01000000 11100000... |
|
||||
| White | 0x40f00000 | 01000000 11110000... |
|
||||
|
||||
|
||||
## Data format
|
||||
|
||||
| format | possible flags | data types | hex value | bin value |
|
||||
|-----------|----------------|------------|------------|-----------|
|
||||
| kp_i | | i8... i64 | 0x00000000 | 00000000 00000000... |
|
||||
| kp_u | Postfix, Upper | u8... u64 | 0x00010000 | 00000000 00000001... |
|
||||
| kp_h | Prefix, Upper | any | 0x00020000 | 00000000 00000010... |
|
||||
| kp_b | Prefix | any | 0x00030000 | 00000000 00000011... |
|
||||
| kp_f | Postfix, Upper | f32, f64 | 0x00040000 | 00000000 00000100... |
|
||||
| kp_c | | char | 0x00050000 | 00000000 00000101... |
|
||||
| kp_string | | char* | 0x00060000 | 00000000 00000110... |
|
||||
|
||||
P.S. `any` means you must add `kpid` to `kp_fmt` if data type is not base type
|
||||
|
||||
### *Flags*
|
||||
| flag | hex value | bin value |
|
||||
|------|------------|-----------|
|
||||
| kp_pre | 0x20000000 | 00100000 00000000... |
|
||||
| kp_post | 0x20000000 | 00100000 00000000... |
|
||||
| kp_upper | 0x10000000 | 00010000 00000000... |
|
||||
155
kerep/src/kprint/kprintf.c
Normal file
155
kerep/src/kprint/kprintf.c
Normal file
@@ -0,0 +1,155 @@
|
||||
#include "kprintf.h"
|
||||
#include "../base/base.h"
|
||||
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
WORD unixColorToWin(u8 c){
|
||||
switch(c){
|
||||
//foreground
|
||||
case 30: return 0;
|
||||
case 31: return FOREGROUND_RED;
|
||||
case 32: return FOREGROUND_GREEN;
|
||||
case 33: return FOREGROUND_GREEN | FOREGROUND_RED;
|
||||
case 34: return FOREGROUND_BLUE;
|
||||
case 35: return FOREGROUND_RED | FOREGROUND_BLUE;
|
||||
case 36: return FOREGROUND_BLUE | FOREGROUND_GREEN;
|
||||
case 37: return FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
|
||||
case 90: return FOREGROUND_INTENSITY;
|
||||
case 91: return FOREGROUND_RED | FOREGROUND_INTENSITY;
|
||||
case 92: return FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||
case 93: return FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
|
||||
case 94: return FOREGROUND_BLUE | FOREGROUND_INTENSITY;
|
||||
case 95: return FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
|
||||
case 96: return FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||
case 97: return FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||
//background
|
||||
case 40: return 0;
|
||||
case 41: return BACKGROUND_RED;
|
||||
case 42: return BACKGROUND_GREEN;
|
||||
case 43: return BACKGROUND_GREEN | BACKGROUND_RED;
|
||||
case 44: return BACKGROUND_BLUE;
|
||||
case 45: return BACKGROUND_RED | BACKGROUND_BLUE;
|
||||
case 46: return BACKGROUND_BLUE | BACKGROUND_GREEN;
|
||||
case 47: return BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
|
||||
case 100: return BACKGROUND_INTENSITY;
|
||||
case 101: return BACKGROUND_RED | BACKGROUND_INTENSITY;
|
||||
case 102: return BACKGROUND_GREEN | BACKGROUND_INTENSITY;
|
||||
case 103: return BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
|
||||
case 104: return BACKGROUND_BLUE | BACKGROUND_INTENSITY;
|
||||
case 105: return BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
|
||||
case 106: return BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
|
||||
case 107: return BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void kprintf(const char* format, ...){
|
||||
va_list vl;
|
||||
va_start(vl, format);
|
||||
u32 i=0;
|
||||
for(char c=format[i++]; c!=0; c=format[i++]){
|
||||
// value format specifiers
|
||||
if(c=='%'){
|
||||
char* argstr=NULL;
|
||||
bool l=false;
|
||||
c=format[i++];
|
||||
format_escape_seq:
|
||||
switch (c) {
|
||||
case 'u':
|
||||
argstr=toString_u64(
|
||||
l ? va_arg(vl, u64) : va_arg(vl, u32)
|
||||
,0,0);
|
||||
break;
|
||||
case 'i': case 'd':
|
||||
argstr=toString_i64(
|
||||
l ? va_arg(vl, i64) : va_arg(vl, i32)
|
||||
);
|
||||
break;
|
||||
case 'f':
|
||||
// f32 is promoted to f64 when passed through '...'
|
||||
argstr=toString_f64(va_arg(vl, f64), toString_float_default_precision,0,0);
|
||||
break;
|
||||
case 'l':
|
||||
l=true;
|
||||
if((c=format[i++]))
|
||||
goto format_escape_seq;
|
||||
break;
|
||||
case 'p': ;
|
||||
void* phex=va_arg(vl, void*);
|
||||
argstr=toString_hex(&phex,getEndian()==LittleEndian,sizeof(phex),1,0);
|
||||
break;
|
||||
case 'x': ;
|
||||
if(l){
|
||||
u64 xhex=va_arg(vl, u64);
|
||||
argstr=toString_hex(&xhex,getEndian()==LittleEndian,sizeof(xhex),0,1);
|
||||
}
|
||||
else {
|
||||
u32 xhex=va_arg(vl, u32);
|
||||
argstr=toString_hex(&xhex,getEndian()==LittleEndian,sizeof(xhex),0,1);
|
||||
}
|
||||
break;
|
||||
case 's': ;
|
||||
char* cptr=va_arg(vl,char*);
|
||||
if(!cptr)
|
||||
cptr="<nullstr>";
|
||||
if(*cptr)
|
||||
fputs(cptr, stdout);
|
||||
break;
|
||||
case 'c':
|
||||
argstr=malloc(2);
|
||||
argstr[0]=(char)va_arg(vl,int);
|
||||
argstr[1]=0;
|
||||
break;
|
||||
default:
|
||||
putc('\n',stdout);
|
||||
putc('<',stdout);
|
||||
putc(c,stdout);
|
||||
putc('>',stdout);
|
||||
throw(ERR_FORMAT);
|
||||
}
|
||||
if(argstr){
|
||||
fputs(argstr, stdout);
|
||||
free(argstr);
|
||||
}
|
||||
}
|
||||
// escape sequences
|
||||
else if(c=='\e'){
|
||||
IFWIN(
|
||||
/* WINDOWS */
|
||||
({
|
||||
if((c=format[i++])=='['){
|
||||
u8 colorUnix=0;
|
||||
for(i8 n=0; n<6 && c!=0; n++){
|
||||
c=format[i++];
|
||||
switch (c){
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
colorUnix=colorUnix*10+c-'0';
|
||||
break;
|
||||
case 'm': ;
|
||||
WORD colorWin=unixColorToWin(colorUnix);
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
SetConsoleTextAttribute(hConsole, colorWin);
|
||||
goto end_iteration;
|
||||
default:
|
||||
goto end_iteration;
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
/* UNIX */
|
||||
putc(c,stdout);
|
||||
);
|
||||
}
|
||||
// common characters
|
||||
else {
|
||||
putc(c,stdout);
|
||||
}
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
end_iteration:;
|
||||
#endif
|
||||
}
|
||||
va_end(vl);
|
||||
}
|
||||
14
kerep/src/kprint/kprintf.h
Normal file
14
kerep/src/kprint/kprintf.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../base/type_system/base_toString.h"
|
||||
|
||||
// cross-platform printf analog
|
||||
void kprintf(const char* format, ...);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
72
kerep/src/random/krandom.h
Normal file
72
kerep/src/random/krandom.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../base/std.h"
|
||||
#include "splitmix64/splitmix64.h"
|
||||
#include "xoroshiro/xoroshiro.h"
|
||||
#include "xoshiro/xoshiro.h"
|
||||
|
||||
/*
|
||||
You can choose any algorithm that has required functions:
|
||||
|
||||
some_alg32_statePtr some_alg32_init(u32 seed);
|
||||
u32 some_alg32_next(some_alg32_statePtr);
|
||||
void some_alg32_free(some_alg32_statePtr);
|
||||
|
||||
#define KRAND_ALG32_init some_alg32_init
|
||||
#define KRAND_ALG32_next some_alg32_next
|
||||
#define KRAND_ALG32_free some_alg32_free
|
||||
#include "kerep/random/krandom.h"
|
||||
|
||||
The same way it works for 64-bit RNGs
|
||||
*/
|
||||
|
||||
// default rng_next function
|
||||
#ifndef KRAND_ALG32_next
|
||||
#define KRAND_ALG32_next xoshiro128plus##_next
|
||||
#endif
|
||||
#ifndef KRAND_ALG32_init
|
||||
#define KRAND_ALG32_init xoshiro128plus##_init
|
||||
#endif
|
||||
#ifndef KRAND_ALG32_free
|
||||
#define KRAND_ALG32_free xoshiro128plus##_free
|
||||
#endif
|
||||
#ifndef KRAND_ALG64_next
|
||||
#define KRAND_ALG64_next xoshiro256plus##_next
|
||||
#endif
|
||||
#ifndef KRAND_ALG64_init
|
||||
#define KRAND_ALG64_init xoshiro256plus##_init
|
||||
#endif
|
||||
#ifndef KRAND_ALG64_free
|
||||
#define KRAND_ALG64_free xoshiro256plus##_free
|
||||
#endif
|
||||
|
||||
typedef void* krand_statePtr;
|
||||
#define KRAND_ALG32_initFromTime xoshiro128plus##_initFromTime
|
||||
#define KRAND_ALG64_initFromTime xoshiro256plus##_initFromTime
|
||||
|
||||
#define __krand_next_definition(VALUE_SIZE) { return from+KRAND_ALG##VALUE_SIZE##_next(state)%(to-from); }
|
||||
|
||||
// ready-to-use functions
|
||||
static inline i8 krand_next8 (krand_statePtr state, i8 from, i8 to) __krand_next_definition(32)
|
||||
static inline i16 krand_next16(krand_statePtr state, i16 from, i16 to) __krand_next_definition(32)
|
||||
static inline i32 krand_next32(krand_statePtr state, i32 from, i32 to) __krand_next_definition(32)
|
||||
static inline i64 krand_next64(krand_statePtr state, i64 from, i64 to) __krand_next_definition(64)
|
||||
|
||||
// divides random number by 2^64 to return a value between 0 and 1
|
||||
static inline f32 krand_nextFloat32(krand_statePtr state) {return (u32)KRAND_ALG32_next(state)/0xffffffff; }
|
||||
static inline f64 krand_nextFloat64(krand_statePtr state) {return KRAND_ALG64_next(state)/0xffffffff; }
|
||||
|
||||
|
||||
///@param chance (0-1.0) is probability of success
|
||||
static inline bool fate(krand_statePtr state,float chance){
|
||||
i32 limit=1/chance + 0.01f;
|
||||
return KRAND_ALG32_next(state)%limit == 0;
|
||||
}
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
34
kerep/src/random/splitmix64/splitmix64.c
Normal file
34
kerep/src/random/splitmix64/splitmix64.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "splitmix64.h"
|
||||
|
||||
/*
|
||||
This is a fixed-increment version of Java 8's SplittableRandom generator
|
||||
See http://dx.doi.org/10.1145/2714064.2660195 and
|
||||
http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html
|
||||
It is a very fast generator passing BigCrush, and it can be useful if
|
||||
for some reason you absolutely want 64 bits of state; otherwise, we
|
||||
rather suggest to use a xoroshiro128+ (for moderately parallel
|
||||
computations) or xorshift1024* (for massively parallel computations)
|
||||
generator.
|
||||
*/
|
||||
|
||||
// The state can be seeded with any (upto) 64 bit integer value.
|
||||
|
||||
void* splitmix64_init(u64 seed){
|
||||
splitmix64_state* state=malloc(sizeof(splitmix64_state));
|
||||
*state=seed;
|
||||
return state;
|
||||
}
|
||||
|
||||
u64 splitmix64_next(void* _state) {
|
||||
splitmix64_state* state=_state;
|
||||
// increment the state variable
|
||||
*state += 0x9e3779b97f4a7c15;
|
||||
// copy the state to a working variable
|
||||
u64 z = *state;
|
||||
// xor the variable with the variable right bit shifted 30 then multiply by a constant
|
||||
z = (z ^ (z>>30)) * 0xbf58476d1ce4e5b9;
|
||||
// xor the variable with the variable right bit shifted 27 then multiply by a constant
|
||||
z = (z ^ (z>>27)) * 0x94d049bb133111eb;
|
||||
// return the variable xored with itself right bit shifted 31
|
||||
return z ^ (z>>31);
|
||||
}
|
||||
22
kerep/src/random/splitmix64/splitmix64.h
Normal file
22
kerep/src/random/splitmix64/splitmix64.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../../base/base.h"
|
||||
|
||||
typedef u64 splitmix64_state;
|
||||
typedef void* splitmix64_statePtr;
|
||||
|
||||
splitmix64_statePtr splitmix64_init(u64 seed);
|
||||
static inline splitmix64_statePtr splitmix64_initFromTime(void) { return splitmix64_init(time(NULL)); }
|
||||
|
||||
u64 splitmix64_next(splitmix64_statePtr);
|
||||
static inline void splitmix64_free(splitmix64_statePtr state) {
|
||||
free(state);
|
||||
}
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
35
kerep/src/random/xoroshiro/32bitValue/xoroshiro64.h
Normal file
35
kerep/src/random/xoroshiro/32bitValue/xoroshiro64.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../../../base/std.h"
|
||||
#include "../../splitmix64/splitmix64.h"
|
||||
|
||||
typedef union {
|
||||
u64 merged;
|
||||
u32 s[2];
|
||||
} xoroshiro64_state;
|
||||
typedef void* xoroshiro64_statePtr;
|
||||
|
||||
xoroshiro64_statePtr xoroshiro64_init(u64 seed);
|
||||
#define xoroshiro64star_init xoroshiro64_init
|
||||
#define xoroshiro64starstar_init xoroshiro64_init
|
||||
|
||||
static inline xoroshiro64_statePtr xoroshiro64_initFromTime(void) { return xoroshiro64_init(time(NULL)); }
|
||||
#define xoroshiro64star_initFromTime xoroshiro64_initFromTime
|
||||
#define xoroshiro64starstar_initFromTime xoroshiro64_initFromTime
|
||||
|
||||
u32 xoroshiro64star_next(xoroshiro64_statePtr);
|
||||
u32 xoroshiro64starstar_next(xoroshiro64_statePtr);
|
||||
|
||||
static inline void xoroshiro64_free(xoroshiro64_statePtr state) {
|
||||
free(state);
|
||||
}
|
||||
#define xoroshiro64star_free xoroshiro64_free
|
||||
#define xoroshiro64starstar_free xoroshiro64_free
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
49
kerep/src/random/xoroshiro/32bitValue/xoroshiro64star.c
Normal file
49
kerep/src/random/xoroshiro/32bitValue/xoroshiro64star.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/* Written in 2016 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
||||
|
||||
To the extent possible under law, the author has dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
|
||||
|
||||
#include "xoroshiro64.h"
|
||||
|
||||
/*
|
||||
This is xoroshiro64* 1.0, our best and fastest 32-bit small-state
|
||||
generator for 32-bit floating-poi32 numbers. We suggest to use its
|
||||
upper bits for floating-poi32 generation, as it is slightly faster than
|
||||
xoroshiro64**. It passes all tests we are aware of except for linearity
|
||||
tests, as the lowest six bits have low linear complexity, so if low
|
||||
linear complexity is not considered an issue (as it is usually the
|
||||
case) it can be used to generate 32-bit outputs, too.
|
||||
|
||||
We suggest to use a sign test to extract a random Boolean value, and
|
||||
right shifts to extract subsets of bits.
|
||||
|
||||
The state must be seeded so that it is not everywhere zero.
|
||||
*/
|
||||
|
||||
static inline u32 rotl(const u32 x, i32 k) {
|
||||
return (x << k) | (x >> (32 - k));
|
||||
}
|
||||
|
||||
u32 xoroshiro64star_next(void* _state) {
|
||||
xoroshiro64_state* state=_state;
|
||||
const u32 s0 = state->s[0];
|
||||
u32 s1 = state->s[1];
|
||||
const u32 result = s0 * 0x9E3779BB;
|
||||
|
||||
s1 ^= s0;
|
||||
state->s[0] = rotl(s0, 26) ^ s1 ^ (s1 << 9); // a, b
|
||||
state->s[1] = rotl(s1, 13); // c
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void* xoroshiro64_init(u64 seed){
|
||||
xoroshiro64_state* state=malloc(sizeof(xoroshiro64_state));
|
||||
splitmix64_state* splitmix=splitmix64_init(seed);
|
||||
state->merged=splitmix64_next(splitmix);
|
||||
splitmix64_free(splitmix);
|
||||
return state;
|
||||
}
|
||||
37
kerep/src/random/xoroshiro/32bitValue/xoroshiro64starstar.c
Normal file
37
kerep/src/random/xoroshiro/32bitValue/xoroshiro64starstar.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
||||
|
||||
To the extent possible under law, the author has dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
|
||||
|
||||
#include "xoroshiro64.h"
|
||||
|
||||
/* This is xoroshiro64** 1.0, our 32-bit all-purpose, rock-solid,
|
||||
small-state generator. It is extremely fast and it passes all tests we
|
||||
are aware of, but its state space is not large enough for any parallel
|
||||
application.
|
||||
|
||||
For generating just single-precision (i.e., 32-bit) floating-point
|
||||
numbers, xoroshiro64* is even faster.
|
||||
|
||||
The state must be seeded so that it is not everywhere zero. */
|
||||
|
||||
|
||||
static inline u32 rotl(const u32 x, i32 k) {
|
||||
return (x << k) | (x >> (32 - k));
|
||||
}
|
||||
|
||||
u32 xoroshiro64starstar_next(void* _state) {
|
||||
xoroshiro64_state* state=_state;
|
||||
const u32 s0 = state->s[0];
|
||||
u32 s1 = state->s[1];
|
||||
const u32 result = rotl(s0 * 0x9E3779BB, 5) * 5;
|
||||
|
||||
s1 ^= s0;
|
||||
state->s[0] = rotl(s0, 26) ^ s1 ^ (s1 << 9); // a, b
|
||||
state->s[1] = rotl(s1, 13); // c
|
||||
|
||||
return result;
|
||||
}
|
||||
39
kerep/src/random/xoroshiro/64bitValue/xoroshiro128.h
Normal file
39
kerep/src/random/xoroshiro/64bitValue/xoroshiro128.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../../../base/std.h"
|
||||
#include "../../splitmix64/splitmix64.h"
|
||||
|
||||
|
||||
typedef union {
|
||||
u32 s[2];
|
||||
} xoroshiro128_state;
|
||||
typedef void* xoroshiro128_statePtr;
|
||||
|
||||
xoroshiro128_statePtr xoroshiro128_init(u64 seed);
|
||||
#define xoroshiro128plus_init xoroshiro128_init
|
||||
#define xoroshiro128plusplus_init xoroshiro128_init
|
||||
#define xoroshiro128starstar_init xoroshiro128_init
|
||||
|
||||
static inline xoroshiro128_statePtr xoroshiro128_initFromTime(void) { return xoroshiro128_init(time(NULL)); }
|
||||
#define xoroshiro128plus_initFromTime xoroshiro128_initFromTime
|
||||
#define xoroshiro128plusplus_initFromTime xoroshiro128_initFromTime
|
||||
#define xoroshiro128starstar_initFromTime xoroshiro128_initFromTime
|
||||
|
||||
u64 xoroshiro128plus_next(xoroshiro128_statePtr);
|
||||
u64 xoroshiro128plusplus_next(xoroshiro128_statePtr);
|
||||
u64 xoroshiro128starstar_next(xoroshiro128_statePtr);
|
||||
|
||||
static inline void xoroshiro128_free(xoroshiro128_statePtr state) {
|
||||
free(state);
|
||||
}
|
||||
#define xoroshiro128plus_free xoroshiro128_free
|
||||
#define xoroshiro128plusplus_free xoroshiro128_free
|
||||
#define xoroshiro128starstar_free xoroshiro128_free
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
59
kerep/src/random/xoroshiro/64bitValue/xoroshiro128plus.c
Normal file
59
kerep/src/random/xoroshiro/64bitValue/xoroshiro128plus.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/* Written in 2016-2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
||||
|
||||
To the extent possible under law, the author has dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
|
||||
|
||||
#include "xoroshiro128.h"
|
||||
|
||||
/* This is xoroshiro128+ 1.0, our best and fastest small-state generator
|
||||
for floating-poi32 numbers, but its state space is large enough only
|
||||
for mild parallelism. We suggest to use its upper bits for
|
||||
floating-poi32 generation, as it is slightly faster than
|
||||
xoroshiro128++/xoroshiro128**. It passes all tests we are aware of
|
||||
except for the four lower bits, which might fail linearity tests (and
|
||||
just those), so if low linear complexity is not considered an issue (as
|
||||
it is usually the case) it can be used to generate 64-bit outputs, too;
|
||||
moreover, this generator has a very mild Hamming-weight dependency
|
||||
making our test (http://prng.di.unimi.it/hwd.php) fail after 5 TB of
|
||||
output; we believe this slight bias cannot affect any application. If
|
||||
you are concerned, use xoroshiro128++, xoroshiro128** or xoshiro256+.
|
||||
|
||||
We suggest to use a sign test to extract a random Boolean value, and
|
||||
right shifts to extract subsets of bits.
|
||||
|
||||
The state must be seeded so that it is not everywhere zero. If you have
|
||||
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
|
||||
output to fill s.
|
||||
|
||||
NOTE: the parameters (a=24, b=16, b=37) of this version give slightly
|
||||
better results in our test than the 2016 version (a=55, b=14, c=36).
|
||||
*/
|
||||
|
||||
static inline u64 rotl(const u64 x, i32 k) {
|
||||
return (x << k) | (x >> (64 - k));
|
||||
}
|
||||
|
||||
u64 xoroshiro128plus_next(void* _state){
|
||||
xoroshiro128_state* state=_state;
|
||||
const u64 s0 = state->s[0];
|
||||
u64 s1 = state->s[1];
|
||||
const u64 result = s0 + s1;
|
||||
|
||||
s1 ^= s0;
|
||||
state->s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b
|
||||
state->s[1] = rotl(s1, 37); // c
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void* xoroshiro128_init(u64 seed){
|
||||
xoroshiro128_state* state=malloc(sizeof(xoroshiro128_state));
|
||||
splitmix64_state* splitmix=splitmix64_init(seed);
|
||||
state->s[0]=splitmix64_next(splitmix);
|
||||
state->s[1]=splitmix64_next(splitmix);
|
||||
splitmix64_free(splitmix);
|
||||
return state;
|
||||
}
|
||||
39
kerep/src/random/xoroshiro/64bitValue/xoroshiro128plusplus.c
Normal file
39
kerep/src/random/xoroshiro/64bitValue/xoroshiro128plusplus.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/* Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
||||
|
||||
To the extent possible under law, the author has dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
|
||||
|
||||
#include "xoroshiro128.h"
|
||||
|
||||
/* This is xoroshiro128++ 1.0, one of our all-purpose, rock-solid,
|
||||
small-state generators. It is extremely (sub-ns) fast and it passes all
|
||||
tests we are aware of, but its state space is large enough only for
|
||||
mild parallelism.
|
||||
|
||||
For generating just floating-poi32 numbers, xoroshiro128+ is even
|
||||
faster (but it has a very mild bias, see notes in the comments).
|
||||
|
||||
The state must be seeded so that it is not everywhere zero. If you have
|
||||
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
|
||||
output to fill s. */
|
||||
|
||||
|
||||
static inline u64 rotl(const u64 x, i32 k) {
|
||||
return (x << k) | (x >> (64 - k));
|
||||
}
|
||||
|
||||
u64 xoroshiro128plusplus_next(void* _state){
|
||||
xoroshiro128_state* state=_state;
|
||||
const u64 s0 = state->s[0];
|
||||
u64 s1 = state->s[1];
|
||||
const u64 result = rotl(s0 + s1, 17) + s0;
|
||||
|
||||
s1 ^= s0;
|
||||
state->s[0] = rotl(s0, 49) ^ s1 ^ (s1 << 21); // a, b
|
||||
state->s[1] = rotl(s1, 28); // c
|
||||
|
||||
return result;
|
||||
}
|
||||
39
kerep/src/random/xoroshiro/64bitValue/xoroshiro128starstar.c
Normal file
39
kerep/src/random/xoroshiro/64bitValue/xoroshiro128starstar.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
||||
|
||||
To the extent possible under law, the author has dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
|
||||
|
||||
#include "xoroshiro128.h"
|
||||
|
||||
/* This is xoroshiro128** 1.0, one of our all-purpose, rock-solid,
|
||||
small-state generators. It is extremely (sub-ns) fast and it passes all
|
||||
tests we are aware of, but its state space is large enough only for
|
||||
mild parallelism.
|
||||
|
||||
For generating just floating-poi32 numbers, xoroshiro128+ is even
|
||||
faster (but it has a very mild bias, see notes in the comments).
|
||||
|
||||
The state must be seeded so that it is not everywhere zero. If you have
|
||||
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
|
||||
output to fill s. */
|
||||
|
||||
|
||||
static inline u64 rotl(const u64 x, i32 k) {
|
||||
return (x << k) | (x >> (64 - k));
|
||||
}
|
||||
|
||||
u64 xoroshiro128starstar_next(void* _state){
|
||||
xoroshiro128_state* state=_state;
|
||||
const u64 s0 = state->s[0];
|
||||
u64 s1 = state->s[1];
|
||||
const u64 result = rotl(s0 * 5, 7) * 9;
|
||||
|
||||
s1 ^= s0;
|
||||
state->s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b
|
||||
state->s[1] = rotl(s1, 37); // c
|
||||
|
||||
return result;
|
||||
}
|
||||
2
kerep/src/random/xoroshiro/xoroshiro.h
Normal file
2
kerep/src/random/xoroshiro/xoroshiro.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#include "32bitValue/xoroshiro64.h"
|
||||
#include "64bitValue/xoroshiro128.h"
|
||||
24
kerep/src/random/xoshiro-xoroshiro.md
Normal file
24
kerep/src/random/xoshiro-xoroshiro.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Xoshiro/Xoroshiro RNG algorithms
|
||||
There are a bunch of versions of xoshiro/xoroshiro algorithms, which are created by [David Blackman and Sebastiano Vigna](https://prng.di.unimi.it/)
|
||||
|
||||
|
||||
```
|
||||
xoroshiro
|
||||
├── 32bitValue
|
||||
| ├── xoroshiro64star.c
|
||||
| └── xoroshiro64starstar.c
|
||||
└── 64bitValue
|
||||
├── xoroshiro128plus.c
|
||||
├── xoroshiro128plusplus.c
|
||||
└── xoroshiro128starstar.c
|
||||
|
||||
xoshiro
|
||||
├── 32bitValue
|
||||
│ ├── xoshiro128plus.c
|
||||
│ ├── xoshiro128plusplus.c
|
||||
│ └── xoshiro128starstar.c
|
||||
└── 64bitValue
|
||||
├── xoshiro256plus.c
|
||||
├── xoshiro256plusplus.c
|
||||
└── xoshiro256starstar.c
|
||||
```
|
||||
40
kerep/src/random/xoshiro/32bitValue/xoshiro128.h
Normal file
40
kerep/src/random/xoshiro/32bitValue/xoshiro128.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../../../base/std.h"
|
||||
#include "../../splitmix64/splitmix64.h"
|
||||
|
||||
|
||||
typedef union {
|
||||
u64 merged[2];
|
||||
u32 s[4];
|
||||
} xoshiro128_state;
|
||||
typedef void* xoshiro128_statePtr;
|
||||
|
||||
xoshiro128_statePtr xoshiro128_init(u64 seed);
|
||||
#define xoshiro128plus_init xoshiro128_init
|
||||
#define xoshiro128plusplus_init xoshiro128_init
|
||||
#define xoshiro128starstar_init xoshiro128_init
|
||||
|
||||
static inline xoshiro128_statePtr xoshiro128_initFromTime(void) { return xoshiro128_init(time(NULL)); }
|
||||
#define xoshiro128plus_initFromTime xoshiro128_initFromTime
|
||||
#define xoshiro128plusplus_initFromTime xoshiro128_initFromTime
|
||||
#define xoshiro128starstar_initFromTime xoshiro128_initFromTime
|
||||
|
||||
u32 xoshiro128plus_next(xoshiro128_statePtr);
|
||||
u32 xoshiro128plusplus_next(xoshiro128_statePtr);
|
||||
u32 xoshiro128starstar_next(xoshiro128_statePtr);
|
||||
|
||||
static inline void xoshiro128_free(xoshiro128_statePtr state) {
|
||||
free(state);
|
||||
}
|
||||
#define xoshiro128plus_free xoshiro128_free
|
||||
#define xoshiro128plusplus_free xoshiro128_free
|
||||
#define xoshiro128starstar_free xoshiro128_free
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
54
kerep/src/random/xoshiro/32bitValue/xoshiro128plus.c
Normal file
54
kerep/src/random/xoshiro/32bitValue/xoshiro128plus.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
||||
|
||||
To the extent possible under law, the author has dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
|
||||
|
||||
#include "xoshiro128.h"
|
||||
|
||||
/* This is xoshiro128+ 1.0, our best and fastest 32-bit generator for 32-bit
|
||||
floating-poi32 numbers. We suggest to use its upper bits for
|
||||
floating-poi32 generation, as it is slightly faster than xoshiro128**.
|
||||
It passes all tests we are aware of except for
|
||||
linearity tests, as the lowest four bits have low linear complexity, so
|
||||
if low linear complexity is not considered an issue (as it is usually
|
||||
the case) it can be used to generate 32-bit outputs, too.
|
||||
|
||||
We suggest to use a sign test to extract a random Boolean value, and
|
||||
right shifts to extract subsets of bits.
|
||||
|
||||
The state must be seeded so that it is not everywhere zero. */
|
||||
|
||||
|
||||
static inline u32 rotl(const u32 x, i32 k) {
|
||||
return (x << k) | (x >> (32 - k));
|
||||
}
|
||||
|
||||
u32 xoshiro128plus_next(void* _state){
|
||||
xoshiro128_state* state=_state;
|
||||
const u32 result = state->s[0] + state->s[3];
|
||||
|
||||
const u32 t = state->s[1] << 9;
|
||||
|
||||
state->s[2] ^= state->s[0];
|
||||
state->s[3] ^= state->s[1];
|
||||
state->s[1] ^= state->s[2];
|
||||
state->s[0] ^= state->s[3];
|
||||
|
||||
state->s[2] ^= t;
|
||||
|
||||
state->s[3] = rotl(state->s[3], 11);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void* xoshiro128_init(u64 seed){
|
||||
xoshiro128_state* state=malloc(sizeof(xoshiro128_state));
|
||||
splitmix64_state* splitmix=splitmix64_init(seed);
|
||||
state->merged[0]=splitmix64_next(splitmix);
|
||||
state->merged[1]=splitmix64_next(splitmix);
|
||||
splitmix64_free(splitmix);
|
||||
return state;
|
||||
}
|
||||
42
kerep/src/random/xoshiro/32bitValue/xoshiro128plusplus.c
Normal file
42
kerep/src/random/xoshiro/32bitValue/xoshiro128plusplus.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/* Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
||||
|
||||
To the extent possible under law, the author has dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
|
||||
|
||||
#include "xoshiro128.h"
|
||||
|
||||
/* This is xoshiro128++ 1.0, one of our 32-bit all-purpose, rock-solid
|
||||
generators. It has excellent speed, a state size (128 bits) that is
|
||||
large enough for mild parallelism, and it passes all tests we are aware
|
||||
of.
|
||||
|
||||
For generating just single-precision (i.e., 32-bit) floating-point
|
||||
numbers, xoshiro128+ is even faster.
|
||||
|
||||
The state must be seeded so that it is not everywhere zero. */
|
||||
|
||||
|
||||
static inline u32 rotl(const u32 x, i32 k) {
|
||||
return (x << k) | (x >> (32 - k));
|
||||
}
|
||||
|
||||
u32 xoshiro128plusplus_next(void* _state){
|
||||
xoshiro128_state* state=_state;
|
||||
const u32 result = rotl(state->s[0] + state->s[3], 7) + state->s[0];
|
||||
|
||||
const u32 t = state->s[1] << 9;
|
||||
|
||||
state->s[2] ^= state->s[0];
|
||||
state->s[3] ^= state->s[1];
|
||||
state->s[1] ^= state->s[2];
|
||||
state->s[0] ^= state->s[3];
|
||||
|
||||
state->s[2] ^= t;
|
||||
|
||||
state->s[3] = rotl(state->s[3], 11);
|
||||
|
||||
return result;
|
||||
}
|
||||
45
kerep/src/random/xoshiro/32bitValue/xoshiro128starstar.c
Normal file
45
kerep/src/random/xoshiro/32bitValue/xoshiro128starstar.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
||||
|
||||
To the extent possible under law, the author has dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
|
||||
|
||||
#include "xoshiro128.h"
|
||||
|
||||
/* This is xoshiro128** 1.1, one of our 32-bit all-purpose, rock-solid
|
||||
generators. It has excellent speed, a state size (128 bits) that is
|
||||
large enough for mild parallelism, and it passes all tests we are aware
|
||||
of.
|
||||
|
||||
Note that version 1.0 had mistakenly state->s[0] instead of state->s[1] as state
|
||||
word passed to the scrambler.
|
||||
|
||||
For generating just single-precision (i.e., 32-bit) floating-point
|
||||
numbers, xoshiro128+ is even faster.
|
||||
|
||||
The state must be seeded so that it is not everywhere zero. */
|
||||
|
||||
|
||||
static inline u32 rotl(const u32 x, i32 k) {
|
||||
return (x << k) | (x >> (32 - k));
|
||||
}
|
||||
|
||||
u32 xoshiro128starstar_next(void* _state){
|
||||
xoshiro128_state* state=_state;
|
||||
const u32 result = rotl(state->s[1] * 5, 7) * 9;
|
||||
|
||||
const u32 t = state->s[1] << 9;
|
||||
|
||||
state->s[2] ^= state->s[0];
|
||||
state->s[3] ^= state->s[1];
|
||||
state->s[1] ^= state->s[2];
|
||||
state->s[0] ^= state->s[3];
|
||||
|
||||
state->s[2] ^= t;
|
||||
|
||||
state->s[3] = rotl(state->s[3], 11);
|
||||
|
||||
return result;
|
||||
}
|
||||
39
kerep/src/random/xoshiro/64bitValue/xoshiro256.h
Normal file
39
kerep/src/random/xoshiro/64bitValue/xoshiro256.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../../../base/std.h"
|
||||
#include "../../splitmix64/splitmix64.h"
|
||||
|
||||
|
||||
typedef union {
|
||||
u64 s[4];
|
||||
} xoshiro256_state;
|
||||
typedef void* xoshiro256_statePtr;
|
||||
|
||||
xoshiro256_statePtr xoshiro256_init(u64 seed);
|
||||
#define xoshiro256plus_init xoshiro256_init
|
||||
#define xoshiro256plusplus_init xoshiro256_init
|
||||
#define xoshiro256starstar_init xoshiro256_init
|
||||
|
||||
static inline xoshiro256_statePtr xoshiro256_initFromTime(void) { return xoshiro256_init(time(NULL)); }
|
||||
#define xoshiro256plus_initFromTime xoshiro256_initFromTime
|
||||
#define xoshiro256plusplus_initFromTime xoshiro256_initFromTime
|
||||
#define xoshiro256starstar_initFromTime xoshiro256_initFromTime
|
||||
|
||||
u64 xoshiro256plus_next(xoshiro256_statePtr);
|
||||
u64 xoshiro256plusplus_next(xoshiro256_statePtr);
|
||||
u64 xoshiro256starstar_next(xoshiro256_statePtr);
|
||||
|
||||
static inline void xoshiro256_free(xoshiro256_statePtr state) {
|
||||
free(state);
|
||||
}
|
||||
#define xoshiro256plus_free xoshiro256_free
|
||||
#define xoshiro256plusplus_free xoshiro256_free
|
||||
#define xoshiro256starstar_free xoshiro256_free
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
58
kerep/src/random/xoshiro/64bitValue/xoshiro256plus.c
Normal file
58
kerep/src/random/xoshiro/64bitValue/xoshiro256plus.c
Normal file
@@ -0,0 +1,58 @@
|
||||
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
||||
|
||||
To the extent possible under law, the author has dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
|
||||
|
||||
#include "xoshiro256.h"
|
||||
|
||||
/* This is xoshiro256+ 1.0, our best and fastest generator for floating-point
|
||||
numbers. We suggest to use its upper bits for floating-point
|
||||
generation, as it is slightly faster than xoshiro256++/xoshiro256**. It
|
||||
passes all tests we are aware of except for the lowest three bits,
|
||||
which might fail linearity tests (and just those), so if low linear
|
||||
complexity is not considered an issue (as it is usually the case) it
|
||||
can be used to generate 64-bit outputs, too.
|
||||
|
||||
We suggest to use a sign test to extract a random Boolean value, and
|
||||
right shifts to extract subsets of bits.
|
||||
|
||||
The state must be seeded so that it is not everywhere zero. If you have
|
||||
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
|
||||
output to fill s. */
|
||||
|
||||
|
||||
static inline u64 rotl(const u64 x, i32 k) {
|
||||
return (x << k) | (x >> (64 - k));
|
||||
}
|
||||
|
||||
u64 xoshiro256plus_next(void* _state){
|
||||
xoshiro256_state* state=_state;
|
||||
const u64 result = state->s[0] + state->s[3];
|
||||
|
||||
const u64 t = state->s[1] << 17;
|
||||
|
||||
state->s[2] ^= state->s[0];
|
||||
state->s[3] ^= state->s[1];
|
||||
state->s[1] ^= state->s[2];
|
||||
state->s[0] ^= state->s[3];
|
||||
|
||||
state->s[2] ^= t;
|
||||
|
||||
state->s[3] = rotl(state->s[3], 45);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void* xoshiro256_init(u64 seed){
|
||||
xoshiro256_state* state=malloc(sizeof(xoshiro256_state));
|
||||
splitmix64_state* splitmix=splitmix64_init(seed);
|
||||
state->s[0]=splitmix64_next(splitmix);
|
||||
state->s[1]=splitmix64_next(splitmix);
|
||||
state->s[2]=splitmix64_next(splitmix);
|
||||
state->s[3]=splitmix64_next(splitmix);
|
||||
splitmix64_free(splitmix);
|
||||
return state;
|
||||
}
|
||||
37
kerep/src/random/xoshiro/64bitValue/xoshiro256plusplus.c
Normal file
37
kerep/src/random/xoshiro/64bitValue/xoshiro256plusplus.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
||||
|
||||
To the extent possible under law, the author has dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
|
||||
|
||||
#include "xoshiro256.h"
|
||||
|
||||
/* This is xoshiro256++ 1.0, one of our all-purpose, rock-solid generators.
|
||||
It has excellent (sub-ns) speed, a state (256 bits) that is large
|
||||
enough for any parallel application, and it passes all tests we are
|
||||
aware of.
|
||||
|
||||
For generating just floating-poi32 numbers, xoshiro256+ is even faster.
|
||||
|
||||
The state must be seeded so that it is not everywhere zero. If you have
|
||||
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
|
||||
output to fill s. */
|
||||
|
||||
static inline u64 rotl(const u64 x, i32 k) {
|
||||
return (x << k) | (x>>(64 - k));
|
||||
}
|
||||
|
||||
u64 xoshiro256plusplus_next(void* _state) {
|
||||
xoshiro256_state* state=_state;
|
||||
const u64 result=rotl(state->s[0] + state->s[3], 23) + state->s[0];
|
||||
const u64 t=state->s[1] << 17;
|
||||
state->s[2] ^= state->s[0];
|
||||
state->s[3] ^= state->s[1];
|
||||
state->s[1] ^= state->s[2];
|
||||
state->s[0] ^= state->s[3];
|
||||
state->s[2] ^= t;
|
||||
state->s[3]=rotl(state->s[3], 45);
|
||||
return result;
|
||||
}
|
||||
42
kerep/src/random/xoshiro/64bitValue/xoshiro256starstar.c
Normal file
42
kerep/src/random/xoshiro/64bitValue/xoshiro256starstar.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
||||
|
||||
To the extent possible under law, the author has dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
|
||||
|
||||
#include "xoshiro256.h"
|
||||
|
||||
/* This is xoshiro256** 1.0, one of our all-purpose, rock-solid
|
||||
generators. It has excellent (sub-ns) speed, a state (256 bits) that is
|
||||
large enough for any parallel application, and it passes all tests we
|
||||
are aware of.
|
||||
|
||||
For generating just floating-poi32 numbers, xoshiro256+ is even faster.
|
||||
|
||||
The state must be seeded so that it is not everywhere zero. If you have
|
||||
a 64-bit seed, we suggest to seed a splitmix64 generator and use its
|
||||
output to fill s. */
|
||||
|
||||
static inline u64 rotl(const u64 x, i32 k) {
|
||||
return (x << k) | (x >> (64 - k));
|
||||
}
|
||||
|
||||
u64 xoshiro256starstar_next(void* _state){
|
||||
xoshiro256_state* state=_state;
|
||||
const u64 result = rotl(state->s[1] * 5, 7) * 9;
|
||||
|
||||
const u64 t = state->s[1] << 17;
|
||||
|
||||
state->s[2] ^= state->s[0];
|
||||
state->s[3] ^= state->s[1];
|
||||
state->s[1] ^= state->s[2];
|
||||
state->s[0] ^= state->s[3];
|
||||
|
||||
state->s[2] ^= t;
|
||||
|
||||
state->s[3] = rotl(state->s[3], 45);
|
||||
|
||||
return result;
|
||||
}
|
||||
2
kerep/src/random/xoshiro/xoshiro.h
Normal file
2
kerep/src/random/xoshiro/xoshiro.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#include "32bitValue/xoshiro128.h"
|
||||
#include "64bitValue/xoshiro256.h"
|
||||
Reference in New Issue
Block a user