-
-
Save Xe/1afdd4c7e7c9cfa23d1aa87194ee5190 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Generated by V | |
#define linux (1) | |
#include <pthread.h> | |
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually | |
#include <stdlib.h> | |
#include <signal.h> | |
#include <stdarg.h> // for va_list | |
#include <inttypes.h> // int64_t etc | |
//================================== TYPEDEFS ================================*/ | |
typedef unsigned char byte; | |
typedef unsigned int uint; | |
typedef int64_t i64; | |
typedef int32_t i32; | |
typedef int16_t i16; | |
typedef int8_t i8; | |
typedef uint64_t u64; | |
typedef uint32_t u32; | |
typedef uint16_t u16; | |
typedef uint8_t u8; | |
typedef uint32_t rune; | |
typedef float f32; | |
typedef double f64; | |
typedef unsigned char* byteptr; | |
typedef int* intptr; | |
typedef void* voidptr; | |
typedef struct array array; | |
typedef struct map map; | |
typedef array array_string; | |
typedef array array_int; | |
typedef array array_byte; | |
typedef array array_uint; | |
typedef array array_float; | |
typedef map map_int; | |
typedef map map_string; | |
#ifndef bool | |
typedef int bool; | |
#define true 1 | |
#define false 0 | |
#endif | |
//============================== HELPER C MACROS =============================*/ | |
#define _PUSH(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push(arr, &tmp);} | |
#define _IN(typ, val, arr) array_##typ##_contains(arr, val) | |
#define ALLOC_INIT(type, ...) (type *)memdup((type[]){ __VA_ARGS__ }, sizeof(type)) | |
#define UTF8_CHAR_LEN( byte ) (( 0xE5000000 >> (( byte >> 3 ) & 0x1e )) & 3 ) + 1 | |
//================================== GLOBALS =================================*/ | |
//int V_ZERO = 0; | |
byteptr g_str_buf; | |
int load_so(byteptr); | |
void reload_so(); | |
void init_consts(); | |
i64 total_m = 0; // For counting total RAM allocated | |
int g_test_ok = 1; | |
/*================================== FNS =================================*/ | |
typedef struct array array; | |
typedef array array_int; | |
typedef array array_string; | |
typedef struct string string; | |
typedef struct ustring ustring; | |
typedef array array_byte; | |
typedef struct map map; | |
typedef array array_Entry; | |
typedef struct Entry Entry; | |
typedef struct Entry2 Entry2; | |
typedef struct smap smap; | |
typedef array array_Entry2; | |
typedef struct Option Option; | |
typedef struct StringBuilder StringBuilder; | |
struct array { | |
void* data; | |
int len; | |
int cap; | |
int element_size; | |
}; | |
struct string { | |
byte* str; | |
int len; | |
}; | |
struct ustring { | |
string s; | |
array_int runes; | |
int len; | |
}; | |
struct map { | |
int element_size; | |
array_Entry entries; | |
bool is_sorted; | |
}; | |
struct Entry { | |
string key; | |
void* val; | |
}; | |
struct Entry2 { | |
string key; | |
string val; | |
}; | |
struct smap { | |
array_Entry2 entries; | |
bool is_sorted; | |
}; | |
struct Option { | |
void* data; | |
string error; | |
bool ok; | |
}; | |
struct StringBuilder { | |
array_byte buf; | |
int len; | |
}; | |
string _STR(const char*, ...); | |
string _STR_TMP(const char*, ...); | |
array new_array(int mylen, int cap, int elm_size); | |
array new_array_from_c_array(int len, int cap, int elm_size, void* c_array); | |
array new_array_from_c_array_no_alloc(int len, int cap, int elm_size, void* c_array); | |
array array_repeat(void* val, int nr_repeats, int elm_size); | |
void array_append_array(array* a, array b); | |
void array_sort_with_compare(array* a, void* compare); | |
void array_insert(array* a, int i, void* val); | |
void array_prepend(array* a, void* val); | |
void array_delete(array* a, int idx); | |
void* array__get(array a, int i); | |
void* array_first(array a); | |
void* array_last(array a); | |
array array_left(array s, int n); | |
array array_right(array s, int n); | |
array array_slice(array s, int start, int _end); | |
void array_set(array* a, int idx, void* val); | |
void array__push(array* arr, void* val); | |
void array__push_many(array* arr, void* val, int size); | |
string array_int_str(array_int a); | |
void v_array_int_free(array_int a); | |
string array_string_str(array_string a); | |
void v_free(void* a); | |
string tos_clone(byte* s); | |
string tos2(byte* s); | |
string tos_no_len(byte* s); | |
string string_clone(string a); | |
byte* string_cstr(string s); | |
string string_replace(string s, string rep, string with); | |
int string_to_i(string s); | |
float string_to_float(string s); | |
bool string_eq(string s, string a); | |
bool string_ne(string s, string a); | |
bool string_ge(string s, string a); | |
bool string_le(string s, string a); | |
bool string_lt(string s, string a); | |
bool string_gt(string s, string a); | |
string string_add(string s, string a); | |
array_string string_split(string s, string delim); | |
array_string string_split_single(string s, byte delim); | |
array_string string_split_into_lines(string s); | |
string string_left(string s, int n); | |
string string_right(string s, int n); | |
string string_substr(string s, int start, int end); | |
int string_index(string s, string p); | |
int string_last_index(string s, string p); | |
int string_index_after(string s, string p, int start); | |
bool string_contains(string s, string p); | |
bool string_starts_with(string s, string p); | |
bool string_ends_with(string s, string p); | |
string string_to_lower(string s); | |
string string_to_upper(string s); | |
string string_find_between(string s, string start, string end); | |
bool array_string_contains(array_string ar, string val); | |
bool array_int_contains(array_int ar, int val); | |
void* array_string_to_c(array_string a); | |
bool is_space(byte c); | |
bool byte_is_space(byte c); | |
string string_trim_space(string s); | |
string string_trim(string s, byte c); | |
string string_trim_left(string s, string cutset); | |
string string_trim_right(string s, string cutset); | |
int compare_strings(string* a, string* b); | |
int compare_strings_by_len(string* a, string* b); | |
int compare_lower_strings(string* a, string* b); | |
void array_string_sort(array_string* s); | |
void array_string_sort_ignore_case(array_string* s); | |
void array_string_sort_by_len(array_string* s); | |
ustring string_ustring(string s); | |
ustring string_ustring_tmp(string s); | |
string ustring_substr(ustring u, int start, int end); | |
string ustring_left(ustring u, int pos); | |
string ustring_right(ustring u, int pos); | |
byte string_at(string s, int idx); | |
string ustring_at(ustring u, int idx); | |
void v_ustring_free(ustring u); | |
int abs(int a); | |
bool byte_is_digit(byte c); | |
bool byte_is_letter(byte c); | |
void v_string_free(string s); | |
void v_array_string_free(array_string arr); | |
string string_all_before(string s, string dot); | |
string string_all_before_last(string s, string dot); | |
string string_all_after(string s, string dot); | |
string array_string_join(array_string a, string del); | |
string array_string_join_lines(array_string s); | |
string string_limit(string s, int max); | |
bool byte_is_white(byte c); | |
string repeat_char(byte c, int n); | |
int string_hash(string s); | |
void v_exit(int code); | |
bool isnil(void* v); | |
void on_panic(int (*f)( int /*FFF*/ )); | |
void print_backtrace(); | |
void v_panic(string s); | |
void println(string s); | |
void eprintln(string s); | |
void v_print(string s); | |
byte* v_malloc(int n); | |
byte* v_calloc(int n); | |
int _strlen(byte* s); | |
Option opt_ok(void* data); | |
void* memdup(void* src, int sz); | |
Option v_error(string s); | |
array_int range_int(int start, int end); | |
string double_str(double d); | |
string float_str(float d); | |
string f64_str(f64 d); | |
string f32_str(f32 d); | |
string ptr_str(void* ptr); | |
string int_str(int nn); | |
string u8_str(u8 nn); | |
string i64_str(i64 nn); | |
string bool_str(bool b); | |
string int_hex(int n); | |
string i64_hex(i64 n); | |
bool array_byte_contains(array_byte a, byte val); | |
string byte_str(byte c); | |
int string_is_utf8(string s); | |
string utf32_to_str(u32 code); | |
string utf32_to_str_no_malloc(u32 code, void* buf); | |
int string_utf32_code(string _rune); | |
map new_map(int cap, int elm_size); | |
Entry map_new_entry(map* m, string key, void* val); | |
void map__set(map* m, string key, void* val); | |
int volt_abs(int n); | |
void map_bs(map m, string query, int start, int end, void* out); | |
int compare_map(Entry* a, Entry* b); | |
void map_sort(map* m); | |
bool map_get(map m, string key, void* out); | |
void v_map_print(map m); | |
void v_map_free(map m); | |
string map_string_str(map_string m); | |
smap new_smap(); | |
void smap_set(smap* m, string key, string val); | |
string smap_get(smap m, string key); | |
string smap_bs(smap m, string query, int start, int end); | |
int compare_smap(Entry2* a, Entry2* b); | |
void smap_sort(smap* m); | |
void v_smap_free(smap m); | |
string smap_str(smap m); | |
StringBuilder new_string_builder(int initial_size); | |
void StringBuilder_write(StringBuilder* b, string s); | |
void StringBuilder_writeln(StringBuilder* b, string s); | |
string StringBuilder_str(StringBuilder b); | |
void StringBuilder_cut(StringBuilder b, int n); | |
array new_array(int mylen, int cap, int elm_size) { | |
array arr= (array){ .len = mylen , .cap = cap , .element_size = elm_size , .data = v_malloc ( cap * elm_size ) } ; | |
return arr ; | |
} | |
array new_array_from_c_array(int len, int cap, int elm_size, void* c_array) { | |
array arr= (array){ .len = len , .cap = cap , .element_size = elm_size , .data = v_malloc ( cap * elm_size ) } ; | |
memcpy ( arr .data , c_array , len * elm_size ) ; | |
return arr ; | |
} | |
array new_array_from_c_array_no_alloc(int len, int cap, int elm_size, void* c_array) { | |
array arr= (array){ .len = len , .cap = cap , .element_size = elm_size , .data = c_array } ; | |
return arr ; | |
} | |
array array_repeat(void* val, int nr_repeats, int elm_size) { | |
array arr= (array){ .len = nr_repeats , .cap = nr_repeats , .element_size = elm_size , .data = v_malloc ( nr_repeats * elm_size ) } ; | |
for ( | |
int i= 0 ; i < nr_repeats ; i ++ ) { | |
memcpy ( arr .data + i * elm_size , val , elm_size ) ; | |
} | |
; | |
return arr ; | |
} | |
void array_append_array(array* a, array b) { | |
for ( | |
int i= 0 ; i < b .len ; i ++ ) { | |
void* val= ( *(void**) array__get( b , i) ) ; | |
array__push( a , val ) ; | |
} | |
; | |
} | |
void array_sort_with_compare(array* a, void* compare) { | |
qsort ( a ->data , a ->len , a ->element_size , compare ) ; | |
} | |
void array_insert(array* a, int i, void* val) { | |
if ( i >= a ->len ) { | |
/*if*/ | |
v_panic ( tos2("array.insert: index larger than length") ) ; | |
return ; | |
} | |
; | |
array__push( a , val ) ; | |
int size= a ->element_size ; | |
memmove ( a ->data + (/*lpar*/ i + 1 ) * size , a ->data + i * size , (/*lpar*/ a ->len - i ) * size ) ; | |
array_set( a , i , val ) ; | |
} | |
void array_prepend(array* a, void* val) { | |
array_insert( a , 0 , val ) ; | |
} | |
void array_delete(array* a, int idx) { | |
int size= a ->element_size ; | |
memmove ( a ->data + idx * size , a ->data + (/*lpar*/ idx + 1 ) * size , (/*lpar*/ a ->len - idx ) * size ) ; | |
a ->len -- ; | |
a ->cap -- ; | |
} | |
void* array__get(array a, int i) { | |
if ( i < 0 || i >= a .len ) { | |
/*if*/ | |
v_panic ( _STR("array index out of range: %d/%d", i, a .len) ) ; | |
} | |
; | |
return a .data + i * a .element_size ; | |
} | |
void* array_first(array a) { | |
if ( a .len == 0 ) { | |
/*if*/ | |
v_panic ( tos2("array.first: empty array") ) ; | |
} | |
; | |
return a .data + 0 ; | |
} | |
void* array_last(array a) { | |
if ( a .len == 0 ) { | |
/*if*/ | |
v_panic ( tos2("array.last: empty array") ) ; | |
} | |
; | |
return a .data + (/*lpar*/ a .len - 1 ) * a .element_size ; | |
} | |
array array_left(array s, int n) { | |
if ( n >= s .len ) { | |
/*if*/ | |
return s ; | |
} | |
; | |
return array_slice( s , 0 , n ) ; | |
} | |
array array_right(array s, int n) { | |
if ( n >= s .len ) { | |
/*if*/ | |
return s ; | |
} | |
; | |
return array_slice( s , n , s .len ) ; | |
} | |
array array_slice(array s, int start, int _end) { | |
int end= _end ; | |
if ( start > end ) { | |
/*if*/ | |
v_panic ( _STR("invalid slice index: %d > %d", start, end) ) ; | |
} | |
; | |
if ( end >= s .len ) { | |
/*if*/ | |
end = s .len ; | |
} | |
; | |
int l= end - start ; | |
array res= (array){ .element_size = s .element_size , .data = s .data + start * s .element_size , .len = l , .cap = l } ; | |
return res ; | |
} | |
void array_set(array* a, int idx, void* val) { | |
if ( idx < 0 || idx >= a ->len ) { | |
/*if*/ | |
v_panic ( _STR("array index out of range: %d / %d", idx, a ->len) ) ; | |
} | |
; | |
memcpy ( a ->data + a ->element_size * idx , val , a ->element_size ) ; | |
} | |
void array__push(array* arr, void* val) { | |
if ( arr ->len >= arr ->cap - 1 ) { | |
/*if*/ | |
int cap= (/*lpar*/ arr ->len + 1 ) * 2 ; | |
if ( arr ->cap == 0 ) { | |
/*if*/ | |
arr ->data = v_malloc ( cap * arr ->element_size ) ; | |
} | |
else { | |
/*else if*/ | |
arr ->data = realloc ( arr ->data , cap * arr ->element_size ) ; | |
} | |
; | |
arr ->cap = cap ; | |
} | |
; | |
memcpy ( arr ->data + arr ->element_size * arr ->len , val , arr ->element_size ) ; | |
arr ->len ++ ; | |
} | |
void array__push_many(array* arr, void* val, int size) { | |
if ( arr ->len >= arr ->cap - size ) { | |
/*if*/ | |
int cap= (/*lpar*/ arr ->len + size ) * 2 ; | |
if ( arr ->cap == 0 ) { | |
/*if*/ | |
arr ->data = v_malloc ( cap * arr ->element_size ) ; | |
} | |
else { | |
/*else if*/ | |
arr ->data = realloc ( arr ->data , cap * arr ->element_size ) ; | |
} | |
; | |
arr ->cap = cap ; | |
} | |
; | |
memcpy ( arr ->data + arr ->element_size * arr ->len , val , arr ->element_size * size ) ; | |
arr ->len += size ; | |
} | |
string array_int_str(array_int a) { | |
string res= tos2("[") ; | |
for ( | |
int i= 0 ; i < a .len ; i ++ ) { | |
int val= ( *(int*) array__get( a , i) ) ; | |
res = string_add(res, _STR("%d", val) ) ; | |
if ( i < a .len - 1 ) { | |
/*if*/ | |
res = string_add(res, tos2(", ") ) ; | |
} | |
; | |
} | |
; | |
res = string_add(res, tos2("]") ) ; | |
return res ; | |
} | |
void v_array_int_free(array_int a) { | |
free ( a .data ) ; | |
} | |
string array_string_str(array_string a) { | |
string res= tos2("[") ; | |
for ( | |
int i= 0 ; i < a .len ; i ++ ) { | |
string val= ( *(string*) array__get( a , i) ) ; | |
res = string_add(res, _STR("\"%.*s\"", val.len, val.str) ) ; | |
if ( i < a .len - 1 ) { | |
/*if*/ | |
res = string_add(res, tos2(", ") ) ; | |
} | |
; | |
} | |
; | |
res = string_add(res, tos2("]") ) ; | |
return res ; | |
} | |
void v_free(void* a) { | |
free ( a ) ; | |
} | |
string tos(byte* s, int len) { | |
if ( isnil ( s ) ) { | |
/*if*/ | |
v_panic ( tos2("tos(): nil string") ) ; | |
} | |
; | |
return (string){ .str = s , .len = len } ; | |
} | |
string tos_clone(byte* s) { | |
if ( isnil ( s ) ) { | |
/*if*/ | |
v_panic ( tos2("tos: nil string") ) ; | |
return (string){ .str = 0 , .len = 0 } ; | |
} | |
; | |
int len= strlen ( s ) ; | |
string res= tos ( s , len ) ; | |
return string_clone( res ) ; | |
} | |
string tos2(byte* s) { | |
if ( isnil ( s ) ) { | |
/*if*/ | |
v_panic ( tos2("tos2: nil string") ) ; | |
return (string){ .str = 0 , .len = 0 } ; | |
} | |
; | |
int len= strlen ( s ) ; | |
string res= tos ( s , len ) ; | |
return res ; | |
} | |
string tos_no_len(byte* s) { | |
return tos2 ( s ) ; | |
} | |
string string_clone(string a) { | |
string b= (string){ .len = a .len , .str = v_malloc ( a .len + 1 ) } ; | |
for ( | |
int i= 0 ; i < a .len ; i ++ ) { | |
b .str[ i ]/*rbyte 1*/ = a .str[ i ]/*rbyte 0*/ ; | |
} | |
; | |
b .str[ a .len ]/*rbyte 1*/ = '\0' ; | |
return b ; | |
} | |
byte* string_cstr(string s) { | |
string clone= string_clone( s ) ; | |
return clone .str ; | |
} | |
string string_replace(string s, string rep, string with) { | |
if ( s .len == 0 || rep .len == 0 ) { | |
/*if*/ | |
return tos2("") ; | |
} | |
; | |
if ( ! string_contains( s , rep ) ) { | |
/*if*/ | |
return s ; | |
} | |
; | |
array_int idxs=new_array_from_c_array(0, 0, sizeof(int), (int[]) { }) ; | |
{ | |
} | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
int rep_i= 0 ; | |
int j= i ; | |
while ( rep_i < rep .len && j < s .len && s .str[ j ]/*rbyte 0*/ == rep .str[ rep_i ]/*rbyte 0*/ ) { | |
rep_i ++ ; | |
j ++ ; | |
} | |
; | |
if ( rep_i == rep .len ) { | |
/*if*/ | |
_PUSH(& idxs , ( i ), tmp12, int) ; | |
} | |
; | |
} | |
; | |
if ( idxs .len == 0 ) { | |
/*if*/ | |
return s ; | |
} | |
; | |
int new_len= s .len + idxs .len * (/*lpar*/ with .len - rep .len ) ; | |
byte* b= v_malloc ( new_len + 1 ) ; | |
int idx_pos= 0 ; | |
int cur_idx= ( *(int*) array__get( idxs , idx_pos) ) ; | |
int b_i= 0 ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
if ( i == cur_idx ) { | |
/*if*/ | |
for ( | |
int j= 0 ; j < with .len ; j ++ ) { | |
b [/*ptr*/ b_i ]/*rbyte 1*/ = with .str[ j ]/*rbyte 0*/ ; | |
b_i ++ ; | |
} | |
; | |
i += rep .len - 1 ; | |
idx_pos ++ ; | |
if ( idx_pos < idxs .len ) { | |
/*if*/ | |
cur_idx = ( *(int*) array__get( idxs , idx_pos) ) ; | |
} | |
; | |
} | |
else { | |
/*else if*/ | |
b [/*ptr*/ b_i ]/*rbyte 1*/ = s .str[ i ]/*rbyte 0*/ ; | |
b_i ++ ; | |
} | |
; | |
} | |
; | |
b [/*ptr*/ new_len ]/*rbyte 1*/ = '\0' ; | |
return tos ( b , new_len ) ; | |
} | |
int string_to_i(string s) { | |
return atoi ( s .str ) ; | |
} | |
float string_to_float(string s) { | |
return atof ( s .str ) ; | |
} | |
bool string_eq(string s, string a) { | |
if ( isnil ( s .str ) ) { | |
/*if*/ | |
v_panic ( tos2("string.eq(): nil string") ) ; | |
} | |
; | |
if ( s .len != a .len ) { | |
/*if*/ | |
return 0 ; | |
} | |
; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
if ( s .str[ i ]/*rbyte 0*/ != a .str[ i ]/*rbyte 0*/ ) { | |
/*if*/ | |
return 0 ; | |
} | |
; | |
} | |
; | |
return 1 ; | |
} | |
bool string_ne(string s, string a) { | |
return ! string_eq( s , a ) ; | |
} | |
bool string_ge(string s, string a) { | |
int j= 0 ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
if ( i >= a .len ) { | |
/*if*/ | |
return 1 ; | |
} | |
; | |
if ( (/*casttt*/ (int)( /*77*/ s .str[ i ]/*rbyte 0*/ ) ) < (/*casttt*/ (int)( /*77*/ a .str[ j ]/*rbyte 0*/ ) ) ) { | |
/*if*/ | |
return 0 ; | |
} | |
else if ( (/*casttt*/ (int)( /*77*/ s .str[ i ]/*rbyte 0*/ ) ) > (/*casttt*/ (int)( /*77*/ a .str[ j ]/*rbyte 0*/ ) ) ) { | |
/*if*/ | |
return 1 ; | |
} | |
; | |
j ++ ; | |
} | |
; | |
return 1 ; | |
} | |
bool string_le(string s, string a) { | |
return ! string_ge( s , a ) || string_eq( s , a ) ; | |
} | |
bool string_lt(string s, string a) { | |
return string_le( s , a ) && string_ne( s , a ) ; | |
} | |
bool string_gt(string s, string a) { | |
return string_ge( s , a ) && string_ne( s , a ) ; | |
} | |
string string_add(string s, string a) { | |
int new_len= a .len + s .len ; | |
string res= (string){ .len = new_len , .str = v_malloc ( new_len + 1 ) } ; | |
for ( | |
int j= 0 ; j < s .len ; j ++ ) { | |
res .str[ j ]/*rbyte 1*/ = s .str[ j ]/*rbyte 0*/ ; | |
} | |
; | |
for ( | |
int j= 0 ; j < a .len ; j ++ ) { | |
res .str[ s .len + j ]/*rbyte 1*/ = a .str[ j ]/*rbyte 0*/ ; | |
} | |
; | |
res .str[ new_len ]/*rbyte 1*/ = '\0' ; | |
return res ; | |
} | |
array_string string_split(string s, string delim) { | |
array_string res=new_array_from_c_array(0, 0, sizeof(string), (string[]) { }) ; | |
if ( delim .len == 0 ) { | |
/*if*/ | |
_PUSH(& res , ( s ), tmp32, string) ; | |
return res ; | |
} | |
; | |
if ( delim .len == 1 ) { | |
/*if*/ | |
return string_split_single( s , delim .str[ 0 ]/*rbyte 0*/ ) ; | |
} | |
; | |
int i= 0 ; | |
int start= 0 ; | |
while ( i < s .len ) { | |
bool a= s .str[ i ]/*rbyte 0*/ == delim .str[ 0 ]/*rbyte 0*/ ; | |
int j= 1 ; | |
while ( j < delim .len && a ) { | |
a = a && s .str[ i + j ]/*rbyte 0*/ == delim .str[ j ]/*rbyte 0*/ ; | |
j ++ ; | |
} | |
; | |
bool last= i == s .len - 1 ; | |
if ( a || last ) { | |
/*if*/ | |
if ( last ) { | |
/*if*/ | |
i ++ ; | |
} | |
; | |
string val= string_substr( s , start , i ) ; | |
if ( val .len > 0 ) { | |
/*if*/ | |
if ( string_starts_with( val , delim ) ) { | |
/*if*/ | |
val = string_right( val , delim .len ) ; | |
} | |
; | |
_PUSH(& res , ( string_trim_space( val ) ), tmp39, string) ; | |
} | |
; | |
start = i ; | |
} | |
; | |
i ++ ; | |
} | |
; | |
return res ; | |
} | |
array_string string_split_single(string s, byte delim) { | |
array_string res=new_array_from_c_array(0, 0, sizeof(string), (string[]) { }) ; | |
if ( (/*casttt*/ (int)( /*77*/ delim ) ) == 0 ) { | |
/*if*/ | |
_PUSH(& res , ( s ), tmp41, string) ; | |
return res ; | |
} | |
; | |
int i= 0 ; | |
int start= 0 ; | |
while ( i < s .len ) { | |
bool a= s .str[ i ]/*rbyte 0*/ == delim ; | |
bool b= i == s .len - 1 ; | |
if ( a || b ) { | |
/*if*/ | |
if ( i == s .len - 1 ) { | |
/*if*/ | |
i ++ ; | |
} | |
; | |
string val= string_substr( s , start , i ) ; | |
if ( val .len > 0 ) { | |
/*if*/ | |
_PUSH(& res , ( string_trim_space( val ) ), tmp47, string) ; | |
} | |
; | |
start = i + 1 ; | |
} | |
; | |
i ++ ; | |
} | |
; | |
return res ; | |
} | |
array_string string_split_into_lines(string s) { | |
array_string res=new_array_from_c_array(0, 0, sizeof(string), (string[]) { }) ; | |
if ( s .len == 0 ) { | |
/*if*/ | |
return res ; | |
} | |
; | |
int start= 0 ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
bool last= i == s .len - 1 ; | |
if ( (/*casttt*/ (int)( /*77*/ s .str[ i ]/*rbyte 0*/ ) ) == 10 || last ) { | |
/*if*/ | |
if ( last ) { | |
/*if*/ | |
i ++ ; | |
} | |
; | |
string line= string_substr( s , start , i ) ; | |
_PUSH(& res , ( line ), tmp53, string) ; | |
start = i + 1 ; | |
} | |
; | |
} | |
; | |
return res ; | |
} | |
string string_left(string s, int n) { | |
if ( n >= s .len ) { | |
/*if*/ | |
return s ; | |
} | |
; | |
return string_substr( s , 0 , n ) ; | |
} | |
string string_right(string s, int n) { | |
if ( n >= s .len ) { | |
/*if*/ | |
return tos2("") ; | |
} | |
; | |
return string_substr( s , n , s .len ) ; | |
} | |
string string_substr(string s, int start, int end) { | |
if ( start >= s .len ) { | |
/*if*/ | |
return tos2("") ; | |
} | |
; | |
int len= end - start ; | |
string res= (string){ .str = s .str + start , .len = len } ; | |
return res ; | |
} | |
int string_index(string s, string p) { | |
if ( p .len > s .len ) { | |
/*if*/ | |
return - 1 ; | |
} | |
; | |
int i= 0 ; | |
while ( i < s .len ) { | |
int j= 0 ; | |
int ii= i ; | |
while ( j < p .len && s .str[ ii ]/*rbyte 0*/ == p .str[ j ]/*rbyte 0*/ ) { | |
j ++ ; | |
ii ++ ; | |
} | |
; | |
if ( j == p .len ) { | |
/*if*/ | |
return i ; | |
} | |
; | |
i ++ ; | |
} | |
; | |
return - 1 ; | |
} | |
int string_last_index(string s, string p) { | |
if ( p .len > s .len ) { | |
/*if*/ | |
return - 1 ; | |
} | |
; | |
int i= s .len - p .len ; | |
while ( i >= 0 ) { | |
int j= 0 ; | |
while ( j < p .len && s .str[ i + j ]/*rbyte 0*/ == p .str[ j ]/*rbyte 0*/ ) { | |
j ++ ; | |
} | |
; | |
if ( j == p .len ) { | |
/*if*/ | |
return i ; | |
} | |
; | |
i -- ; | |
} | |
; | |
return - 1 ; | |
} | |
int string_index_after(string s, string p, int start) { | |
if ( p .len > s .len ) { | |
/*if*/ | |
return - 1 ; | |
} | |
; | |
int strt= start ; | |
if ( start < 0 ) { | |
/*if*/ | |
strt = 0 ; | |
} | |
; | |
if ( start >= s .len ) { | |
/*if*/ | |
return - 1 ; | |
} | |
; | |
int i= strt ; | |
while ( i < s .len ) { | |
int j= 0 ; | |
int ii= i ; | |
while ( j < p .len && s .str[ ii ]/*rbyte 0*/ == p .str[ j ]/*rbyte 0*/ ) { | |
j ++ ; | |
ii ++ ; | |
} | |
; | |
if ( j == p .len ) { | |
/*if*/ | |
return i ; | |
} | |
; | |
i ++ ; | |
} | |
; | |
return - 1 ; | |
} | |
bool string_contains(string s, string p) { | |
bool res= string_index( s , p ) > 0 - 1 ; | |
return res ; | |
} | |
bool string_starts_with(string s, string p) { | |
bool res= string_index( s , p ) == 0 ; | |
return res ; | |
} | |
bool string_ends_with(string s, string p) { | |
if ( p .len > s .len ) { | |
/*if*/ | |
return 0 ; | |
} | |
; | |
bool res= string_last_index( s , p ) == s .len - p .len ; | |
return res ; | |
} | |
string string_to_lower(string s) { | |
byte* b= v_malloc ( s .len ) ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
b [/*ptr*/ i ]/*rbyte 1*/ = tolower ( s .str [/*ptr*/ i ]/*rbyte 0*/ ) ; | |
} | |
; | |
return tos ( b , s .len ) ; | |
} | |
string string_to_upper(string s) { | |
byte* b= v_malloc ( s .len ) ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
b [/*ptr*/ i ]/*rbyte 1*/ = toupper ( s .str [/*ptr*/ i ]/*rbyte 0*/ ) ; | |
} | |
; | |
return tos ( b , s .len ) ; | |
} | |
string string_find_between(string s, string start, string end) { | |
int start_pos= string_index( s , start ) ; | |
if ( start_pos == - 1 ) { | |
/*if*/ | |
return tos2("") ; | |
} | |
; | |
string val= string_right( s , start_pos + start .len ) ; | |
int end_pos= string_index( val , end ) ; | |
if ( end_pos == - 1 ) { | |
/*if*/ | |
return val ; | |
} | |
; | |
return string_left( val , end_pos ) ; | |
} | |
bool array_string_contains(array_string ar, string val) { | |
array_string tmp75 = ar; | |
; | |
for (int tmp76 = 0; tmp76 < tmp75 .len; tmp76 ++) { | |
string s = ((string *) tmp75.data)[tmp76]; | |
if (string_eq( s , val ) ) { | |
/*if*/ | |
return 1 ; | |
} | |
; | |
} | |
; | |
return 0 ; | |
} | |
bool array_int_contains(array_int ar, int val) { | |
array_int tmp77 = ar ; | |
; | |
for (int i = 0; i < tmp77 .len; i ++) { | |
int s = ((int *) tmp77 . data)[i]; | |
if ( s == val ) { | |
/*if*/ | |
return 1 ; | |
} | |
; | |
} | |
; | |
return 0 ; | |
} | |
void* array_string_to_c(array_string a) { | |
char ** res = malloc(sizeof(char*) * a.len); | |
for ( | |
int i= 0 ; i < a .len ; i ++ ) { | |
string val= ( *(string*) array__get( a , i) ) ; | |
res[i] = val.str; | |
} | |
; | |
return res; | |
return 0 ; | |
} | |
bool is_space(byte c) { | |
return isspace ( c ) ; | |
} | |
bool byte_is_space(byte c) { | |
return is_space ( c ) ; | |
} | |
string string_trim_space(string s) { | |
if (string_eq( s , tos2("") ) ) { | |
/*if*/ | |
return tos2("") ; | |
} | |
; | |
int i= 0 ; | |
while ( i < s .len && is_space ( s .str[ i ]/*rbyte 0*/ ) ) { | |
i ++ ; | |
} | |
; | |
string res= string_right( s , i ) ; | |
int end= res .len - 1 ; | |
while ( end >= 0 && is_space ( res .str[ end ]/*rbyte 1*/ ) ) { | |
end -- ; | |
} | |
; | |
res = string_left( res , end + 1 ) ; | |
return res ; | |
} | |
string string_trim(string s, byte c) { | |
if (string_eq( s , tos2("") ) ) { | |
/*if*/ | |
return tos2("") ; | |
} | |
; | |
int i= 0 ; | |
while ( i < s .len && c == s .str[ i ]/*rbyte 0*/ ) { | |
i ++ ; | |
} | |
; | |
string res= string_right( s , i ) ; | |
int end= res .len - 1 ; | |
while ( end >= 0 && c == res .str[ end ]/*rbyte 1*/ ) { | |
end -- ; | |
} | |
; | |
res = string_left( res , end + 1 ) ; | |
return res ; | |
} | |
string string_trim_left(string s, string cutset) { | |
int start= string_index( s , cutset ) ; | |
if ( start != 0 ) { | |
/*if*/ | |
return s ; | |
} | |
; | |
while ( start < s .len - 1 && s .str[ start ]/*rbyte 0*/ == cutset .str[ 0 ]/*rbyte 0*/ ) { | |
start ++ ; | |
} | |
; | |
return string_right( s , start ) ; | |
} | |
string string_trim_right(string s, string cutset) { | |
return s ; | |
int pos= string_last_index( s , cutset ) ; | |
if ( pos == - 1 ) { | |
/*if*/ | |
return s ; | |
} | |
; | |
return string_left( s , pos ) ; | |
} | |
int compare_strings(string* a, string* b) { | |
if ( string_le(* a ,* b ) ) { | |
/*if*/ | |
return - 1 ; | |
} | |
; | |
if ( string_ge(* a ,* b ) ) { | |
/*if*/ | |
return 1 ; | |
} | |
; | |
return 0 ; | |
} | |
int compare_strings_by_len(string* a, string* b) { | |
if ( a ->len < b ->len ) { | |
/*if*/ | |
return - 1 ; | |
} | |
; | |
if ( a ->len > b ->len ) { | |
/*if*/ | |
return 1 ; | |
} | |
; | |
return 0 ; | |
} | |
int compare_lower_strings(string* a, string* b) { | |
string aa= string_to_lower(* a ) ; | |
string bb= string_to_lower(* a ) ; | |
return compare_strings (& /*11 EXP:"string*" GOT:"string" */ aa ,& /*11 EXP:"string*" GOT:"string" */ bb ) ; | |
} | |
void array_string_sort(array_string* s) { | |
array_sort_with_compare( s , compare_strings ) ; | |
} | |
void array_string_sort_ignore_case(array_string* s) { | |
array_sort_with_compare( s , compare_lower_strings ) ; | |
} | |
void array_string_sort_by_len(array_string* s) { | |
array_sort_with_compare( s , compare_strings_by_len ) ; | |
} | |
ustring string_ustring(string s) { | |
ustring res= (ustring){ .s = s , .runes = new_array ( 0 , s .len , sizeof( int) ) , .len = 0 } ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
int char_len= 0 ; | |
char_len =UTF8_CHAR_LEN(s.str[i]); | |
_PUSH(& res .runes , ( i ), tmp95, int) ; | |
i += char_len - 1 ; | |
res .len ++ ; | |
} | |
; | |
return res ; | |
} | |
array_int g_ustring_runes; | |
ustring string_ustring_tmp(string s) { | |
ustring res= (ustring){ .s = s , .runes = 0 , .len = 0 } ; | |
res.runes = g_ustring_runes ; | |
res.runes.len = s.len ; | |
int j= 0 ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
int char_len= 0 ; | |
char_len =UTF8_CHAR_LEN(s.str[i]); | |
int tmp100 = i; | |
array_set(&/*q*/ res .runes , j , & tmp100) ; | |
j ++ ; | |
i += char_len - 1 ; | |
res .len ++ ; | |
} | |
; | |
return res ; | |
} | |
string ustring_substr(ustring u, int start, int end) { | |
start = ( *(int*) array__get( u .runes , start) ) ; | |
if ( end >= u .runes .len ) { | |
/*if*/ | |
end = u .s .len ; | |
} | |
else { | |
/*else if*/ | |
end = ( *(int*) array__get( u .runes , end) ) ; | |
} | |
; | |
return string_substr( u .s , start , end ) ; | |
} | |
string ustring_left(ustring u, int pos) { | |
return ustring_substr( u , 0 , pos ) ; | |
} | |
string ustring_right(ustring u, int pos) { | |
return ustring_substr( u , pos , u .len ) ; | |
} | |
byte string_at(string s, int idx) { | |
if ( idx < 0 || idx >= s .len ) { | |
/*if*/ | |
v_panic ( _STR("string index out of range: %d / %d", idx, s .len) ) ; | |
} | |
; | |
return s .str [/*ptr*/ idx ]/*rbyte 0*/ ; | |
} | |
string ustring_at(ustring u, int idx) { | |
return ustring_substr( u , idx , idx + 1 ) ; | |
} | |
void v_ustring_free(ustring u) { | |
v_array_int_free( u .runes ) ; | |
} | |
int abs(int a) { | |
if ( a >= 0 ) { | |
/*if*/ | |
return a ; | |
} | |
; | |
return - a ; | |
} | |
bool byte_is_digit(byte c) { | |
return c >= '0' && c <= '9' ; | |
} | |
bool byte_is_letter(byte c) { | |
return (/*lpar*/ c >= 'a' && c <= 'z' ) || (/*lpar*/ c >= 'A' && c <= 'Z' ) ; | |
} | |
void v_string_free(string s) { | |
free ( s .str ) ; | |
} | |
void v_array_string_free(array_string arr) { | |
array_string tmp105 = arr; | |
; | |
for (int tmp106 = 0; tmp106 < tmp105 .len; tmp106 ++) { | |
string s = ((string *) tmp105.data)[tmp106]; | |
v_string_free( s ) ; | |
} | |
; | |
free ( arr .data ) ; | |
} | |
string string_all_before(string s, string dot) { | |
int pos= string_index( s , dot ) ; | |
if ( pos == - 1 ) { | |
/*if*/ | |
return s ; | |
} | |
; | |
return string_left( s , pos ) ; | |
} | |
string string_all_before_last(string s, string dot) { | |
int pos= string_last_index( s , dot ) ; | |
if ( pos == - 1 ) { | |
/*if*/ | |
return s ; | |
} | |
; | |
return string_left( s , pos ) ; | |
} | |
string string_all_after(string s, string dot) { | |
int pos= string_last_index( s , dot ) ; | |
if ( pos == - 1 ) { | |
/*if*/ | |
return s ; | |
} | |
; | |
return string_right( s , pos + dot .len ) ; | |
} | |
string array_string_join(array_string a, string del) { | |
if ( a .len == 0 ) { | |
/*if*/ | |
return tos2("") ; | |
} | |
; | |
int len= 0 ; | |
array_string tmp111 = a ; | |
; | |
for (int i = 0; i < tmp111 .len; i ++) { | |
string val = ((string *) tmp111 . data)[i]; | |
len += val .len + del .len ; | |
} | |
; | |
len -= del .len ; | |
string res= tos2("") ; | |
res .len = len ; | |
res .str = v_malloc ( res .len + 1 ) ; | |
int idx= 0 ; | |
array_string tmp114 = a ; | |
; | |
for (int i = 0; i < tmp114 .len; i ++) { | |
string val = ((string *) tmp114 . data)[i]; | |
for ( | |
int j= 0 ; j < val .len ; j ++ ) { | |
byte c= val .str[ j ]/*rbyte 0*/ ; | |
res .str [/*ptr*/ idx ]/*rbyte 1*/ = val .str [/*ptr*/ j ]/*rbyte 0*/ ; | |
idx ++ ; | |
} | |
; | |
if ( i != a .len - 1 ) { | |
/*if*/ | |
for ( | |
int k= 0 ; k < del .len ; k ++ ) { | |
res .str [/*ptr*/ idx ]/*rbyte 1*/ = del .str [/*ptr*/ k ]/*rbyte 0*/ ; | |
idx ++ ; | |
} | |
; | |
} | |
; | |
} | |
; | |
res .str [/*ptr*/ res .len ]/*rbyte 1*/ = '\0' ; | |
return res ; | |
} | |
string array_string_join_lines(array_string s) { | |
return array_string_join( s , tos2("\n") ) ; | |
} | |
string string_limit(string s, int max) { | |
ustring u= string_ustring( s ) ; | |
if ( u .len <= max ) { | |
/*if*/ | |
return s ; | |
} | |
; | |
return ustring_substr( u , 0 , max ) ; | |
} | |
bool byte_is_white(byte c) { | |
int i= (/*casttt*/ (int)( /*77*/ c ) ) ; | |
return i == 10 || i == 32 || i == 9 || i == 13 || c == '\r' ; | |
} | |
string repeat_char(byte c, int n) { | |
if ( n <= 0 ) { | |
/*if*/ | |
return tos2("") ; | |
} | |
; | |
byte* arr= v_malloc ( n + 1 ) ; | |
for ( | |
int i= 0 ; i < n ; i ++ ) { | |
arr [/*ptr*/ i ]/*rbyte 1*/ = c ; | |
} | |
; | |
arr [/*ptr*/ n ]/*rbyte 1*/ = '\0' ; | |
return tos ( arr , n ) ; | |
} | |
int string_hash(string s) { | |
int hash= (/*casttt*/ (int)( /*77*/ 0 ) ) ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
hash = hash * (/*casttt*/ (int)( /*77*/ 31 ) ) + (/*casttt*/ (int)( /*77*/ s .str [/*ptr*/ i ]/*rbyte 0*/ ) ) ; | |
} | |
; | |
return hash ; | |
} | |
void v_exit(int code) { | |
exit ( code ) ; | |
} | |
bool isnil(void* v) { | |
return v == 0 ; | |
} | |
void on_panic(int (*f)( int /*FFF*/ )) { | |
} | |
void print_backtrace() { | |
return ; | |
#ifdef mac | |
voidptr buffer [100 ]= {} /* arkek init*/ ; | |
void* nr_ptrs= backtrace ( buffer , 100 ) ; | |
backtrace_symbols_fd ( buffer , nr_ptrs , 1 ) ; | |
#endif | |
; | |
} | |
void v_panic(string s) { | |
println ( _STR("V panic: %.*s", s.len, s.str) ) ; | |
print_backtrace ( ) ; | |
exit ( 1 ) ; | |
} | |
void println(string s) { | |
if ( isnil ( s .str ) ) { | |
/*if*/ | |
v_panic ( tos2("println(NIL)") ) ; | |
} | |
; | |
printf ( "%.*s\n" , s .len , s .str ) ; | |
} | |
void eprintln(string s) { | |
if ( isnil ( s .str ) ) { | |
/*if*/ | |
v_panic ( tos2("eprintln(NIL)") ) ; | |
} | |
; | |
#ifdef mac | |
fprintf ( stderr , "%.*s\n" , s .len , s .str ) ; | |
; | |
#else | |
println ( s ) ; | |
#endif | |
; | |
} | |
void v_print(string s) { | |
printf ( "%.*s" , s .len , s .str ) ; | |
} | |
byte* v_malloc(int n) { | |
if ( n < 0 ) { | |
/*if*/ | |
v_panic ( tos2("malloc(<0)") ) ; | |
} | |
; | |
#ifdef VPLAY | |
if ( n > 10000 ) { | |
/*if*/ | |
v_panic ( tos2("allocating more than 10 KB is not allowed in the playground") ) ; | |
} | |
; | |
#endif | |
#ifdef DEBUG_ALLOC | |
i64 total= (/*casttt*/ (i64)( /*77*/ 0 ) ) ; | |
total_m += n; | |
total = total_m; | |
println ( _STR("\n\n\nmalloc(%d) total=%lld", n, total) ) ; | |
print_backtrace ( ) ; | |
#endif | |
byte* ptr= malloc ( n ) ; | |
if ( isnil ( ptr ) ) { | |
/*if*/ | |
v_panic ( _STR("malloc(%d) failed", n) ) ; | |
} | |
; | |
return ptr ; | |
} | |
byte* v_calloc(int n) { | |
if ( n < 0 ) { | |
/*if*/ | |
v_panic ( tos2("calloc(<0)") ) ; | |
} | |
; | |
return calloc ( sizeof( float) * n , sizeof( float) ) ; | |
} | |
int _strlen(byte* s) { | |
return strlen ( s ) ; | |
} | |
Option opt_ok(void* data) { | |
return (Option){ .data = data , .ok = 1 , .error = tos("", 0) , } ; | |
} | |
void* memdup(void* src, int sz) { | |
byte* mem= v_malloc ( sz ) ; | |
return memcpy ( mem , src , sz ) ; | |
} | |
Option v_error(string s) { | |
return (Option){ .error = s , .data = 0 , .ok = 0 } ; | |
} | |
array_int range_int(int start, int end) { | |
int len= end - start ; | |
int tmp7 = 0; | |
array_int res= array_repeat(&tmp7, len , sizeof(int) ) ; | |
for ( | |
int i= 0 ; i < len ; i ++ ) { | |
int tmp10 = start + i; | |
array_set(&/*q*/ res , i , & tmp10) ; | |
} | |
; | |
return res ; | |
} | |
string double_str(double d) { | |
byte* buf= v_malloc ( sizeof( double) * 5 + 1 ) ; | |
sprintf ( buf , "%f" , d ) ; | |
return tos ( buf , _strlen ( buf ) ) ; | |
} | |
string float_str(float d) { | |
byte* buf= v_malloc ( sizeof( double) * 5 + 1 ) ; | |
sprintf ( buf , "%f" , d ) ; | |
return tos ( buf , _strlen ( buf ) ) ; | |
} | |
string f64_str(f64 d) { | |
byte* buf= v_malloc ( sizeof( double) * 5 + 1 ) ; | |
sprintf ( buf , "%f" , d ) ; | |
return tos ( buf , _strlen ( buf ) ) ; | |
} | |
string f32_str(f32 d) { | |
byte* buf= v_malloc ( sizeof( double) * 5 + 1 ) ; | |
sprintf ( buf , "%f" , d ) ; | |
return tos ( buf , _strlen ( buf ) ) ; | |
} | |
string ptr_str(void* ptr) { | |
byte* buf= v_malloc ( sizeof( double) * 5 + 1 ) ; | |
sprintf ( buf , "%p" , ptr ) ; | |
return tos ( buf , _strlen ( buf ) ) ; | |
} | |
string int_str(int nn) { | |
int n= nn ; | |
if ( n == 0 ) { | |
/*if*/ | |
return tos2("0") ; | |
} | |
; | |
int max= 16 ; | |
byte* buf= v_malloc ( max ) ; | |
int len= 0 ; | |
bool is_neg= 0 ; | |
if ( n < 0 ) { | |
/*if*/ | |
n = - n ; | |
is_neg = 1 ; | |
} | |
; | |
while ( n > 0 ) { | |
int d= n % 10 ; | |
buf [/*ptr*/ max - len - 1 ]/*rbyte 1*/ = d + (/*casttt*/ (int)( /*77*/ '0' ) ) ; | |
len ++ ; | |
n = n / 10 ; | |
} | |
; | |
if ( is_neg ) { | |
/*if*/ | |
buf [/*ptr*/ max - len - 1 ]/*rbyte 1*/ = '-' ; | |
len ++ ; | |
} | |
; | |
return tos ( buf + max - len , len ) ; | |
} | |
string u8_str(u8 nn) { | |
u8 n= nn ; | |
if ( n == (/*casttt*/ (u8)( /*77*/ 0 ) ) ) { | |
/*if*/ | |
return tos2("0") ; | |
} | |
; | |
int max= 5 ; | |
byte* buf= v_malloc ( max ) ; | |
int len= 0 ; | |
bool is_neg= 0 ; | |
if ( n < (/*casttt*/ (u8)( /*77*/ 0 ) ) ) { | |
/*if*/ | |
n = - n ; | |
is_neg = 1 ; | |
} | |
; | |
while ( n > (/*casttt*/ (u8)( /*77*/ 0 ) ) ) { | |
u8 d= n % (/*casttt*/ (u8)( /*77*/ 10 ) ) ; | |
buf [/*ptr*/ max - len - 1 ]/*rbyte 1*/ = d + (/*casttt*/ (u8)( /*77*/ '0' ) ) ; | |
len ++ ; | |
n = n / (/*casttt*/ (u8)( /*77*/ 10 ) ) ; | |
} | |
; | |
if ( is_neg ) { | |
/*if*/ | |
buf [/*ptr*/ max - len - 1 ]/*rbyte 1*/ = '-' ; | |
len ++ ; | |
} | |
; | |
return tos ( buf + max - len , len ) ; | |
} | |
string i64_str(i64 nn) { | |
i64 n= nn ; | |
if ( n == (/*casttt*/ (i64)( /*77*/ 0 ) ) ) { | |
/*if*/ | |
return tos2("0") ; | |
} | |
; | |
int max= 32 ; | |
byte* buf= v_malloc ( max ) ; | |
int len= 0 ; | |
bool is_neg= 0 ; | |
if ( n < (/*casttt*/ (i64)( /*77*/ 0 ) ) ) { | |
/*if*/ | |
n = - n ; | |
is_neg = 1 ; | |
} | |
; | |
while ( n > (/*casttt*/ (i64)( /*77*/ 0 ) ) ) { | |
int d= (/*casttt*/ (int)( /*77*/ n % (/*casttt*/ (i64)( /*77*/ 10 ) ) ) ) ; | |
buf [/*ptr*/ max - len - 1 ]/*rbyte 1*/ = d + (/*casttt*/ (int)( /*77*/ '0' ) ) ; | |
len ++ ; | |
n = n / (/*casttt*/ (i64)( /*77*/ 10 ) ) ; | |
} | |
; | |
if ( is_neg ) { | |
/*if*/ | |
buf [/*ptr*/ max - len - 1 ]/*rbyte 1*/ = '-' ; | |
len ++ ; | |
} | |
; | |
return tos ( buf + max - len , len ) ; | |
} | |
string bool_str(bool b) { | |
if ( b ) { | |
/*if*/ | |
return tos2("true") ; | |
} | |
; | |
return tos2("false") ; | |
} | |
string int_hex(int n) { | |
string s= int_str( n ) ; | |
byte* hex= v_malloc ( s .len + 2 ) ; | |
sprintf ( hex , "0x%x" , n ) ; | |
return tos ( hex , s .len + 2 ) ; | |
} | |
string i64_hex(i64 n) { | |
string s= i64_str( n ) ; | |
byte* hex= v_malloc ( s .len + 2 ) ; | |
sprintf ( hex , "0x%x" , n ) ; | |
return tos ( hex , s .len + 2 ) ; | |
} | |
bool array_byte_contains(array_byte a, byte val) { | |
array_byte tmp28 = a; | |
; | |
for (int tmp29 = 0; tmp29 < tmp28 .len; tmp29 ++) { | |
byte aa = ((byte *) tmp28.data)[tmp29]; | |
if ( aa == val ) { | |
/*if*/ | |
return 1 ; | |
} | |
; | |
} | |
; | |
return 0 ; | |
} | |
string byte_str(byte c) { | |
string str= (string){ .len = 1 , .str = v_malloc ( 2 ) } ; | |
str .str [/*ptr*/ 0 ]/*rbyte 1*/ = c ; | |
str .str [/*ptr*/ 1 ]/*rbyte 1*/ = '\0' ; | |
return str ; | |
} | |
int string_is_utf8(string s) { | |
int faulty_bytes= 0 ; | |
int len= s .len ; | |
int i= 0 ; | |
byte * str = s.str; | |
while (i < len) { | |
if (str[i] <= 0x7F) /* 00..7F */ { | |
i += 1; | |
} | |
else if (str[i] >= 0xC2 && str[i] <= 0xDF) /* C2..DF 80..BF */ { | |
if (i + 1 < len) /* Expect a 2nd byte */ { | |
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) { | |
printf( "After a first byte between C2 and DF, expecting a 2nd byte between 80 and BF"); | |
faulty_bytes = 2; | |
goto end; | |
} | |
} | |
else { | |
printf( "After a first byte between C2 and DF, expecting a 2nd byte."); | |
faulty_bytes = 1; | |
goto end; | |
} | |
i += 2; | |
} | |
else if (str[i] == 0xE0) /* E0 A0..BF 80..BF */ { | |
if (i + 2 < len) /* Expect a 2nd and 3rd byte */ { | |
if (str[i + 1] < 0xA0 || str[i + 1] > 0xBF) { | |
printf( "After a first byte of E0, expecting a 2nd byte between A0 and BF."); | |
faulty_bytes = 2; | |
goto end; | |
} | |
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) { | |
printf( "After a first byte of E0, expecting a 3nd byte between 80 and BF."); | |
faulty_bytes = 3; | |
goto end; | |
} | |
} | |
else { | |
printf( "After a first byte of E0, expecting two following bytes."); | |
faulty_bytes = 1; | |
goto end; | |
} | |
i += 3; | |
} | |
else if (str[i] >= 0xE1 && str[i] <= 0xEC) /* E1..EC 80..BF 80..BF */ { | |
if (i + 2 < len) /* Expect a 2nd and 3rd byte */ { | |
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) { | |
printf( "After a first byte between E1 and EC, expecting the 2nd byte between 80 and BF."); | |
faulty_bytes = 2; | |
goto end; | |
} | |
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) { | |
printf( "After a first byte between E1 and EC, expecting the 3rd byte between 80 and BF."); | |
faulty_bytes = 3; | |
goto end; | |
} | |
} | |
else { | |
printf( "After a first byte between E1 and EC, expecting two following bytes."); | |
faulty_bytes = 1; | |
goto end; | |
} | |
i += 3; | |
} | |
else if (str[i] == 0xED) /* ED 80..9F 80..BF */ { | |
if (i + 2 < len) /* Expect a 2nd and 3rd byte */ { | |
if (str[i + 1] < 0x80 || str[i + 1] > 0x9F) { | |
printf( "After a first byte of ED, expecting 2nd byte between 80 and 9F."); | |
faulty_bytes = 2; | |
goto end; | |
} | |
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) { | |
printf( "After a first byte of ED, expecting 3rd byte between 80 and BF."); | |
faulty_bytes = 3; | |
goto end; | |
} | |
} | |
else { | |
printf( "After a first byte of ED, expecting two following bytes."); | |
faulty_bytes = 1; | |
goto end; | |
} | |
i += 3; | |
} | |
else if (str[i] >= 0xEE && str[i] <= 0xEF) /* EE..EF 80..BF 80..BF */ { | |
if (i + 2 < len) /* Expect a 2nd and 3rd byte */ { | |
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) { | |
printf( "After a first byte between EE and EF, expecting 2nd byte between 80 and BF."); | |
faulty_bytes = 2; | |
goto end; | |
} | |
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) { | |
printf( "After a first byte between EE and EF, expecting 3rd byte between 80 and BF."); | |
faulty_bytes = 3; | |
goto end; | |
} | |
} | |
else { | |
printf( "After a first byte between EE and EF, two following bytes."); | |
faulty_bytes = 1; | |
goto end; | |
} | |
i += 3; | |
} | |
else if (str[i] == 0xF0) /* F0 90..BF 80..BF 80..BF */ { | |
if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */ { | |
if (str[i + 1] < 0x90 || str[i + 1] > 0xBF) { | |
printf( "After a first byte of F0, expecting 2nd byte between 90 and BF."); | |
faulty_bytes = 2; | |
goto end; | |
} | |
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) { | |
printf( "After a first byte of F0, expecting 3rd byte between 80 and BF."); | |
faulty_bytes = 3; | |
goto end; | |
} | |
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF) { | |
printf( "After a first byte of F0, expecting 4th byte between 80 and BF."); | |
faulty_bytes = 4; | |
goto end; | |
} | |
} | |
else { | |
printf( "After a first byte of F0, expecting three following bytes."); | |
faulty_bytes = 1; | |
goto end; | |
} | |
i += 4; | |
} | |
else if (str[i] >= 0xF1 && str[i] <= 0xF3) /* F1..F3 80..BF 80..BF 80..BF */ { | |
if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */ { | |
if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) { | |
printf( "After a first byte of F1, F2, or F3, expecting a 2nd byte between 80 and BF."); | |
faulty_bytes = 2; | |
goto end; | |
} | |
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) { | |
printf( "After a first byte of F1, F2, or F3, expecting a 3rd byte between 80 and BF."); | |
faulty_bytes = 3; | |
goto end; | |
} | |
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF) { | |
printf( "After a first byte of F1, F2, or F3, expecting a 4th byte between 80 and BF."); | |
faulty_bytes = 4; | |
goto end; | |
} | |
} | |
else { | |
printf( "After a first byte of F1, F2, or F3, expecting three following bytes."); | |
faulty_bytes = 1; | |
goto end; | |
} | |
i += 4; | |
} | |
else if (str[i] == 0xF4) /* F4 80..8F 80..BF 80..BF */ { | |
if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */ { | |
if (str[i + 1] < 0x80 || str[i + 1] > 0x8F) { | |
printf( "After a first byte of F4, expecting 2nd byte between 80 and 8F."); | |
faulty_bytes = 2; | |
goto end; | |
} | |
if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) { | |
printf( "After a first byte of F4, expecting 3rd byte between 80 and BF."); | |
faulty_bytes = 3; | |
goto end; | |
} | |
if (str[i + 3] < 0x80 || str[i + 3] > 0xBF) { | |
printf( "After a first byte of F4, expecting 4th byte between 80 and BF."); | |
faulty_bytes = 4; | |
goto end; | |
} | |
} | |
else { | |
printf( "After a first byte of F4, expecting three following bytes."); | |
faulty_bytes = 1; | |
goto end; | |
} | |
i += 4; | |
} | |
else { | |
printf( "i=%d Expecting bytes in the following ranges: 00..7F C2..F4.", | |
i); | |
faulty_bytes = 1; | |
goto end; | |
} | |
} | |
end: ; | |
bool ok= faulty_bytes == 0 ; | |
if ( ok ) { | |
/*if*/ | |
return - 1 ; | |
} | |
; | |
if ( ! ok ) { | |
/*if*/ | |
println ( _STR("utf is bad dalen=%d KEK %.*s sdf", len, s.len, s.str) ) ; | |
} | |
; | |
return i ; | |
} | |
string utf32_to_str(u32 code) { | |
byte* buffer= v_malloc ( 5 ) ; | |
if (code <= 0x7F) { | |
buffer[0] = code; | |
return tos(buffer, 1); | |
} | |
if (code <= 0x7FF) { | |
buffer[0] = 0xC0 | (code >> 6); /* 110xxxxx */ | |
buffer[1] = 0x80 | (code & 0x3F); /* 10xxxxxx */ | |
return tos(buffer, 2); | |
} | |
if (code <= 0xFFFF) { | |
buffer[0] = 0xE0 | (code >> 12); /* 1110xxxx */ | |
buffer[1] = 0x80 | ((code >> 6) & 0x3F); /* 10xxxxxx */ | |
buffer[2] = 0x80 | (code & 0x3F); /* 10xxxxxx */ | |
return tos(buffer, 3); | |
} | |
if (code <= 0x10FFFF) { | |
buffer[0] = 0xF0 | (code >> 18); /* 11110xxx */ | |
buffer[1] = 0x80 | ((code >> 12) & 0x3F); /* 10xxxxxx */ | |
buffer[2] = 0x80 | ((code >> 6) & 0x3F); /* 10xxxxxx */ | |
buffer[3] = 0x80 | (code & 0x3F); /* 10xxxxxx */ | |
return tos(buffer, 4); | |
} | |
return tos2("") ; | |
} | |
string utf32_to_str_no_malloc(u32 code, void* buf) { | |
char* buffer = buf; | |
if (code <= 0x7F) { | |
buffer[0] = code; | |
return tos(buffer, 1); | |
} | |
if (code <= 0x7FF) { | |
buffer[0] = 0xC0 | (code >> 6); /* 110xxxxx */ | |
buffer[1] = 0x80 | (code & 0x3F); /* 10xxxxxx */ | |
return tos(buffer, 2); | |
} | |
if (code <= 0xFFFF) { | |
buffer[0] = 0xE0 | (code >> 12); /* 1110xxxx */ | |
buffer[1] = 0x80 | ((code >> 6) & 0x3F); /* 10xxxxxx */ | |
buffer[2] = 0x80 | (code & 0x3F); /* 10xxxxxx */ | |
return tos(buffer, 3); | |
} | |
if (code <= 0x10FFFF) { | |
buffer[0] = 0xF0 | (code >> 18); /* 11110xxx */ | |
buffer[1] = 0x80 | ((code >> 12) & 0x3F); /* 10xxxxxx */ | |
buffer[2] = 0x80 | ((code >> 6) & 0x3F); /* 10xxxxxx */ | |
buffer[3] = 0x80 | (code & 0x3F); /* 10xxxxxx */ | |
return tos(buffer, 4); | |
} | |
return tos2("") ; | |
} | |
int string_utf32_code(string _rune) { | |
if ( _rune .len == 0 ) { | |
/*if*/ | |
return 0 ; | |
} | |
; | |
if ( _rune .len == 1 ) { | |
/*if*/ | |
return (/*casttt*/ (int)( /*77*/ _rune .str[ 0 ]/*rbyte 0*/ ) ) ; | |
} | |
; | |
byte b= (/*casttt*/ (byte)( /*77*/ (/*casttt*/ (int)( /*77*/ _rune .str[ 0 ]/*rbyte 0*/ ) ) ) ) ; | |
b <<= _rune.len; | |
int res= (/*casttt*/ (int)( /*77*/ b ) ) ; | |
int shift= 6 - _rune .len ; | |
for ( | |
int i= 1 ; i < _rune .len ; i ++ ) { | |
int c= (/*casttt*/ (int)( /*77*/ _rune .str[ i ]/*rbyte 0*/ ) ) ; | |
res <<= shift; | |
res |= c & 0x3f; | |
shift = 6 ; | |
} | |
; | |
return res ; | |
} | |
map new_map(int cap, int elm_size) { | |
map res= (map){ .element_size = elm_size , .entries = new_array(0, 1, sizeof(Entry)) , .is_sorted = 0 } ; | |
return res ; | |
} | |
Entry map_new_entry(map* m, string key, void* val) { | |
Entry new_e= (Entry){ .key = key , .val = v_malloc ( m ->element_size ) } ; | |
memcpy ( new_e .val , val , m ->element_size ) ; | |
return new_e ; | |
} | |
void map__set(map* m, string key, void* val) { | |
Entry e= map_new_entry(& /* ? */* m , key , val ) ; | |
for ( | |
int i= 0 ; i < m ->entries .len ; i ++ ) { | |
Entry entry= ( *(Entry*) array__get( m ->entries , i) ) ; | |
if (string_eq( entry .key , key ) ) { | |
/*if*/ | |
Entry tmp8 = e; | |
array_set(&/*q*/ m ->entries , i , & tmp8) ; | |
return ; | |
} | |
; | |
} | |
; | |
_PUSH(& m ->entries , ( e ), tmp9, Entry) ; | |
m ->is_sorted = 0 ; | |
} | |
int volt_abs(int n) { | |
if ( n < 0 ) { | |
/*if*/ | |
return - n ; | |
} | |
; | |
return n ; | |
} | |
void map_bs(map m, string query, int start, int end, void* out) { | |
int mid= start + (/*lpar*/ (/*lpar*/ end - start ) / 2 ) ; | |
if ( end - start == 0 ) { | |
/*if*/ | |
Entry last= ( *(Entry*) array__get( m .entries , end) ) ; | |
memcpy ( out , last .val , m .element_size ) ; | |
return ; | |
} | |
; | |
if ( end - start == 1 ) { | |
/*if*/ | |
Entry first= ( *(Entry*) array__get( m .entries , start) ) ; | |
memcpy ( out , first .val , m .element_size ) ; | |
return ; | |
} | |
; | |
if ( mid >= m .entries .len ) { | |
/*if*/ | |
return ; | |
} | |
; | |
Entry mid_msg= ( *(Entry*) array__get( m .entries , mid) ) ; | |
if (string_lt( query , mid_msg .key ) ) { | |
/*if*/ | |
map_bs( m , query , start , mid , out ) ; | |
return ; | |
} | |
; | |
map_bs( m , query , mid , end , out ) ; | |
} | |
int compare_map(Entry* a, Entry* b) { | |
if (string_lt( a ->key , b ->key ) ) { | |
/*if*/ | |
return - 1 ; | |
} | |
; | |
if (string_gt( a ->key , b ->key ) ) { | |
/*if*/ | |
return 1 ; | |
} | |
; | |
return 0 ; | |
} | |
void map_sort(map* m) { | |
array_sort_with_compare(& /* ? */ m ->entries , compare_map ) ; | |
m ->is_sorted = 1 ; | |
} | |
bool map_get(map m, string key, void* out) { | |
if ( m .is_sorted ) { | |
/*if*/ | |
map_bs( m , key , 0 , m .entries .len , out ) ; | |
return 1 ; | |
} | |
; | |
for ( | |
int i= 0 ; i < m .entries .len ; i ++ ) { | |
Entry entry= ( *(Entry*) array__get( m .entries , i) ) ; | |
if (string_eq( entry .key , key ) ) { | |
/*if*/ | |
memcpy ( out , entry .val , m .element_size ) ; | |
return 1 ; | |
} | |
; | |
} | |
; | |
return 0 ; | |
} | |
void v_map_print(map m) { | |
println ( tos2("<<<<<<<<") ) ; | |
for ( | |
int i= 0 ; i < m .entries .len ; i ++ ) { | |
} | |
; | |
println ( tos2(">>>>>>>>>>") ) ; | |
} | |
void v_map_free(map m) { | |
} | |
string map_string_str(map_string m) { | |
if ( m .entries .len == 0 ) { | |
/*if*/ | |
return tos2("{}") ; | |
} | |
; | |
string s= tos2("{\n") ; | |
array_Entry tmp26 = m .entries; | |
; | |
for (int tmp27 = 0; tmp27 < tmp26 .len; tmp27 ++) { | |
Entry entry = ((Entry *) tmp26.data)[tmp27]; | |
string tmp28 = tos("", 0); bool tmp29 = map_get( m , entry .key, & tmp28); | |
if (!tmp29) tmp28 = tos("", 0); | |
string val= tmp28 ; | |
s = string_add(s, _STR(" \"%.*s\" => \"%.*s\"\n", entry .key.len, entry .key.str, val.len, val.str) ) ; | |
} | |
; | |
s = string_add(s, tos2("}") ) ; | |
return s ; | |
} | |
smap new_smap() { | |
smap res= (smap){ .entries = new_array(0, 1, sizeof(Entry2)) , .is_sorted = 0 } ; | |
return res ; | |
} | |
void smap_set(smap* m, string key, string val) { | |
Entry2 e= (Entry2){ .key = key , .val = val } ; | |
_PUSH(& m ->entries , ( e ), tmp3, Entry2) ; | |
} | |
string smap_get(smap m, string key) { | |
if ( m .is_sorted ) { | |
/*if*/ | |
return smap_bs( m , key , 0 , m .entries .len ) ; | |
} | |
; | |
for ( | |
int i= 0 ; i < m .entries .len ; i ++ ) { | |
Entry2 entry= ( *(Entry2*) array__get( m .entries , i) ) ; | |
if (string_eq( entry .key , key ) ) { | |
/*if*/ | |
return entry .val ; | |
} | |
; | |
} | |
; | |
return tos2("") ; | |
} | |
string smap_bs(smap m, string query, int start, int end) { | |
int mid= start + (/*lpar*/ (/*lpar*/ end - start ) / 2 ) ; | |
if ( end - start == 0 ) { | |
/*if*/ | |
Entry2 last= ( *(Entry2*) array__get( m .entries , end) ) ; | |
return last .val ; | |
} | |
; | |
if ( end - start == 1 ) { | |
/*if*/ | |
Entry2 first= ( *(Entry2*) array__get( m .entries , start) ) ; | |
return first .val ; | |
} | |
; | |
if ( mid >= m .entries .len ) { | |
/*if*/ | |
return tos2("") ; | |
} | |
; | |
Entry2 mid_msg= ( *(Entry2*) array__get( m .entries , mid) ) ; | |
if (string_lt( query , mid_msg .key ) ) { | |
/*if*/ | |
return smap_bs( m , query , start , mid ) ; | |
} | |
; | |