kerep sources

This commit is contained in:
2023-07-12 13:53:20 +03:00
parent 683395983c
commit 44ee9e210f
88 changed files with 3051 additions and 98 deletions

2
kerep/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
obj/
libkerep.*

41
kerep/build.sh Normal file
View File

@@ -0,0 +1,41 @@
#!/bin/bash
set -eo pipefail
CMP="gcc"
WARN="-std=c11 -Wall -Wno-discarded-qualifiers -Wno-unused-parameter"
ARGS="-O2 -flto -fpic -fdata-sections -ffunction-sections"
SRC="$(find src -name '*.c')"
OS=$(../detect_os.sh)
ARCH=$(../detect_arch.sh)
OUTFILE="bin/libkerep-$OS-$ARCH.a"
rm -rf obj
mkdir obj
mkdir -p bin
echo "----------------[kerep]-----------------"
compiler_call="$CMP $WARN $ARGS -c"
echo "$compiler_call"
OBJECTS=
for srcfile in $SRC
do
echo " $srcfile"
object="obj/$(basename $srcfile).o"
OBJECTS="$OBJECTS
$object"
command="$compiler_call $srcfile -o $object"
if ! $($command); then
exit 1
fi
done
command="ar rcs $OUTFILE $OBJECTS"
echo "$command"
if $($command)
then
echo "static lib $OUTFILE created"
rm -r obj
else
exit 1
fi

View 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)

View 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

View 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

View 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=&el; \
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

View 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.

View 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

View 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);
}

View 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));
}

View 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
````

View 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;
}

View 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
View 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));
}

View 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

View File

@@ -0,0 +1,3 @@
#include "path.h"
#include "dir.h"
#include "file.h"

View 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

View 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);
}

View 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

View 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;
// }

View 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

View 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
}

View 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

View 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("}");
}

View 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

View 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)});
}

View 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
View 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
View 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
View File

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

217
kerep/src/base/cptr.c Normal file
View 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
View File

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

13
kerep/src/base/endian.c Normal file
View 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
View File

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

59
kerep/src/base/errors.c Normal file
View 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
View File

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

41
kerep/src/base/optime.h Normal file
View File

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

139
kerep/src/base/std.h Normal file
View 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

View File

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

View File

@@ -0,0 +1,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)

View File

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

View File

@@ -0,0 +1,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);
}

View File

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

View File

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

View File

@@ -0,0 +1,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);
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,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);
}

View File

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

View 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
View 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
View 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

View 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

View 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

View 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
View 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);
}

View 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

View 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

View 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);
}

View 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

View 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

View 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;
}

View 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;
}

View 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

View 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;
}

View 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;
}

View 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;
}

View File

@@ -0,0 +1,2 @@
#include "32bitValue/xoroshiro64.h"
#include "64bitValue/xoroshiro128.h"

View 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
```

View 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

View 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;
}

View 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;
}

View 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;
}

View 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

View 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;
}

View 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;
}

View 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;
}

View File

@@ -0,0 +1,2 @@
#include "32bitValue/xoshiro128.h"
#include "64bitValue/xoshiro256.h"