I wrote a little bit of tests. But that is it, I have to hurry up for another cool university thing. Look what our supervisor said about this: Е"Если вам это не удобно, то я вас поздравляю, вы неудачник". You don't need to be genius to know that this shit is real

This commit is contained in:
Андреев Григорий 2026-01-27 02:55:58 +03:00
parent 78fd9f0816
commit 26a2badb94
4 changed files with 331 additions and 35 deletions

View File

@ -317,9 +317,10 @@ char digit_to_small_hex(U32 d){
return d >= 10 ? (char)('a' + d - 10) : (char)('0' + d);
}
static_assert(0b11000000 == 0xC0 && 0b10000000 == 0x80 && 0b00111111 == 0x3F, "asdasda");
static_assert(0b11000000 == 0xC0 && 0b10000000 == 0x80 && 0b00111111 == 0x3F &&
0b11100000 == 0xE0 && 0b11110000 == 0xF0, "asdasda");
/* Some bytes (encoding codepoint U) will be appended to str. Utf-8 works only with codepoints below (1u << 24) */
/* Some bytes (encoding codepoint U) will be appended to str. Utf-8 works only with codepoints below (1u << 21) */
void VecU8_encode_as_utf8(VecU8* str, U32 U){
if (U < (1u << 7)) {
VecU8_append(str, (U8)U);
@ -327,14 +328,14 @@ void VecU8_encode_as_utf8(VecU8* str, U32 U){
VecU8_append_span(str, (SpanU8){(U8[]){
0xC0 | (U8)(U >> 6), 0x80 | (U8)(U & 0x3F)
}, 2});
} else if (U < (1u << 17)) {
} else if (U < (1u << 16)) {
VecU8_append_span(str, (SpanU8){(U8[]){
0xC0 | (U8)(U >> 12), 0x80 | (U8)((U >> 6) & 0x3F), (U8)(U & 0x3F)
0xE0 | (U8)(U >> 12), 0x80 | (U8)((U >> 6) & 0x3F), (U8)(U & 0x3F)
}, 3});
} else {
/* U < (1u << 24) */
/* U < (1u << 21) */
VecU8_append_span(str, (SpanU8){(U8[]){
0xC0 | (U8)(U >> 18), 0x80 | (U8)((U >> 12) & 0x3F), 0x80 | (U8)((U >> 6) & 0x3F), (U8)(U & 0x3F)
0xF0 | (U8)(U >> 18), 0x80 | (U8)((U >> 12) & 0x3F), 0x80 | (U8)((U >> 6) & 0x3F), (U8)(U & 0x3F)
}, 4});
}
}

View File

@ -44,8 +44,8 @@ void SpanU8_parsing_skip_entire_line(SpanU8* rem){
}
}
bool SpanU8_parsing_is_char_ahead(SpanU8* rem, char ch){
return rem->len > 0 ? rem->data[0] == (U8)ch : false;
bool SpanU8_parsing_is_char_ahead(SpanU8 rem, char ch){
return rem.len > 0 ? rem.data[0] == (U8)ch : false;
}
/* Time to learn how to read integers */
@ -82,14 +82,6 @@ int SpanU8_read_U64(SpanU8* rem_ret, U64* res_ret){
return 0;
}
U64 SpanU64_expect_read_U64(SpanU8* rem){
U64 x;
int code = SpanU8_read_U64(rem, &x);
if (code)
abortf("Failed to read U64. Syntax error\n");
return x;
}
/* Returns positive on error, 0 on success, rem_ret is untouched on error */
int SpanU8_read_S64(SpanU8* rem_ret, S64* ret){
SpanU8 rem = *rem_ret;
@ -144,6 +136,26 @@ int SpanU8_read_S64(SpanU8* rem_ret, S64* ret){
return 0;
}
/* Helper function. Btw, floating point numbers suck */
float SpanU8_read_float_h_pow10(S64 p){
assert(-50 <= p && p <= 50);
float twopowers[6] = {10.f};
U32 ap = (U32)labs(p);
for (int i = 0; i + 1 < 6; i++) {
twopowers[i + 1] = twopowers[i] * twopowers[i];
}
float rc = 1.f;
for (int i = 0; i < 6; i++) {
if (ap & 1) {
rc *= twopowers[i];
}
ap >>= 1;
}
if (p < 0) {
rc = 1.f / rc;
}
return rc;
}
/* returns positive int on error, 0 on success, rem_ret is untouched on error */
int SpanU8_read_float(SpanU8* rem_ret, float* res_ret){
@ -178,17 +190,18 @@ int SpanU8_read_float(SpanU8* rem_ret, float* res_ret){
saw_digit = true;
} else if (ch == 'e' || ch == 'E') {
SpanU8_parsing_skip_char(&rem);
if (SpanU8_parsing_is_char_ahead(&rem, '+'))
if (SpanU8_parsing_is_char_ahead(rem, '+'))
SpanU8_parsing_skip_char(&rem);
S64 exp;
int ret = SpanU8_read_S64(&rem, &exp);
if (ret)
return ret;
if (exp > 1000 || exp < -999) {
if (res == 0.f)
break;
if (exp > 50 || exp < -50) {
return 2;
}
/* If compiler won't perform pow optimization here, I will throw my chair out of the window */
res = res * powf(10.f, (float)exp);
res *= SpanU8_read_float_h_pow10(exp);
break;
} else {
break;
@ -210,14 +223,6 @@ int SpanU8_read_float(SpanU8* rem_ret, float* res_ret){
return 0;
}
float SpanU8_expect_read_float(SpanU8* rem){
float x;
int code = SpanU8_read_float(rem, &x);
if (code)
abortf("Failed to read float. Syntax error\n");
return x;
}
void SpanU8_parsing_skip_spaces(SpanU8* rem){
while (rem->len) {
U8 ch = *rem->data;

View File

@ -12,10 +12,10 @@ void json_encoding_append_utf16(VecU8* res, U8 codepoint){
}
/* Str is being encoded as JSON string literal */
void json_encoding_append_string(VecU8* res, const VecU8* str){
void json_encoding_append_string(VecU8* res, SpanU8 str){
VecU8_append(res, '"');
for (size_t i = 0; i < str->len; i++) {
U8 ch = str->buf[i];
for (size_t i = 0; i < str.len; i++) {
U8 ch = str.data[i];
if (ch == '\t') {
VecU8_append_span(res, cstr("\\t"));
} else if (ch == '\n') {
@ -48,7 +48,7 @@ void json_encoding_append_to_str(const Json* obj, VecU8* res){
} else if (obj->variant == Json_float) {
VecU8_append_vec(res, VecU8_format("%f", obj->float_num));
} else if (obj->variant == Json_str) {
json_encoding_append_string(res, &obj->str);
json_encoding_append_string(res, VecU8_to_span(&obj->str));
} else if (obj->variant == Json_arr) {
VecU8_append(res, '[');
const VecJson* arr = &obj->arr;
@ -66,7 +66,7 @@ void json_encoding_append_to_str(const Json* obj, VecU8* res){
if (was) {
VecU8_append_span(res, cstr(", "));
}
json_encoding_append_string(res, &it->key);
json_encoding_append_string(res, VecU8_to_span(&it->key));
VecU8_append_span(res, cstr(": "));
json_encoding_append_to_str(&it->value, res);
was = true;
@ -191,7 +191,7 @@ OptionJson json_decoding_h_no_spaces(SpanU8* rem, U32 depth_rem){
bool none_code = SpanU8_parsing_try_read_prefix(rem, cstr("none"));
if (none_code)
return Some_Json(Json_None);
if (SpanU8_parsing_is_char_ahead(rem, '\"')) {
if (SpanU8_parsing_is_char_ahead(*rem, '\"')) {
VecU8 str;
int str_code = json_decoding_parse_string(rem, &str);
if (str_code) {

View File

@ -1,6 +1,296 @@
#include "../core/json_encoded.h"
#include <assert.h>
/* It should be noted, that if a nd b point to parts of different strings, then this function is UB */
bool SpanU8_equal(SpanU8 a, SpanU8 b){
return a.data == b.data && a.len == b.len;
}
bool vec_matches_cstr(VecU8 a, const char* b){
bool ans = SpanU8_cont_equal(VecU8_to_span(&a), SpanU8_from_cstr(b));
VecU8_drop(a);
return ans;
}
void tt1(){
SpanU8 str = cstr("ABC=");
SpanU8 rem = str;
bool c = SpanU8_parsing_try_read_prefix(&rem, cstr("ABC"));
check(c);
check(rem.data == str.data + 3);
check(rem.len == 1);
}
void tt2(){
SpanU8 str = cstr("ABC==");
SpanU8 rem = str;
bool c = SpanU8_parsing_try_read_prefix(&rem, cstr("ABD"));
check(!c);
check(SpanU8_equal(rem, str));
}
void tt3(){
SpanU8 str = (SpanU8){.data = (U8*)"ABC", .len = 2};
SpanU8 rem = str;
bool c = SpanU8_parsing_try_read_prefix(&rem, cstr("ABC"));
check(!c);
check(SpanU8_equal(rem, str));
}
void tt4(){
SpanU8 str = cstr("ABC");
SpanU8 rem = str;
SpanU8_parsing_skip_char(&rem);
check(SpanU8_equal(rem, (SpanU8){str.data + 1, str.len - 1}));
}
void tt5(){
SpanU8 str = cstr("AB");
SpanU8 rem = str;
bool c = SpanU8_parsing_try_read_char(&rem, 'A');
check(c && SpanU8_equal(rem, (SpanU8){str.data + 1, str.len - 1}));
}
void tt6(){
SpanU8 str = cstr("ABC");
SpanU8 rem = str;
bool c = SpanU8_parsing_try_read_char(&rem, 'B');
check(!c && SpanU8_equal(rem, str));
}
void tt7(){
SpanU8 str = (SpanU8){.data = (U8*)"AB", .len = 0};
SpanU8 rem = str;
bool c = SpanU8_parsing_try_read_char(&rem, 'A');
check(!c && SpanU8_equal(rem, str));
}
void tt8(){
SpanU8 str = cstr("abcd\n\n");
SpanU8 rem = str;
SpanU8_parsing_skip_entire_line(&rem);
check(SpanU8_equal(rem, (SpanU8){str.data + 5, str.len - 5}));
}
void tt9(){
SpanU8 str = cstr("abcdef");
SpanU8 rem = str;
SpanU8_parsing_skip_entire_line(&rem);
check(SpanU8_equal(rem, (SpanU8){str.data + 6, 0}));
}
void tt10(){
SpanU8 str = cstr("\nab\n\n");
SpanU8 rem = str;
SpanU8_parsing_skip_entire_line(&rem);
check(SpanU8_equal(rem, (SpanU8){str.data + 1, str.len - 1}));
}
void tt11(){
SpanU8 str = cstr("ABC");
check(SpanU8_parsing_is_char_ahead(str, 'A'));
check(!SpanU8_parsing_is_char_ahead(str, 'B'));
str.len = 0;
check(!SpanU8_parsing_is_char_ahead(str, 'A'));
}
void test_u64_reading_with_good_inp(SpanU8 str, U64 right_val, U64 leftovers){
SpanU8 rem = str;
U64 val;
int c = SpanU8_read_U64(&rem, &val);
check(c == 0);
check(rem.data == str.data + str.len - leftovers && rem.len == leftovers);
check(val == right_val);
}
void tt12(){
test_u64_reading_with_good_inp(cstr("18446744073709551615--"), 18446744073709551615ul, 2);
test_u64_reading_with_good_inp(cstr("69+"), 69, 1);
test_u64_reading_with_good_inp(cstr("0"), 0, 0);
}
void test_u64_reading_with_ill_formed_inp(SpanU8 str){
SpanU8 rem = str;
U64 val;
int c = SpanU8_read_U64(&rem, &val);
check(c > 0);
check(SpanU8_equal(str, rem));
}
void tt13(){
test_u64_reading_with_ill_formed_inp(cstr("18446744073709551616"));
test_u64_reading_with_ill_formed_inp(cstr("01"));
test_u64_reading_with_ill_formed_inp(cstr("-123"));
}
void test_s64_reading_with_ill_formed_inp(SpanU8 str){
SpanU8 rem = str;
S64 val;
int c = SpanU8_read_S64(&rem, &val);
check(c > 0);
check(SpanU8_equal(str, rem));
}
void tt14(){
test_s64_reading_with_ill_formed_inp(cstr("9223372036854775808"));
test_s64_reading_with_ill_formed_inp(cstr("92233720368547758000"));
test_s64_reading_with_ill_formed_inp(cstr("+9223372036854775808"));
test_s64_reading_with_ill_formed_inp(cstr("-9223372036854775809"));
test_s64_reading_with_ill_formed_inp(cstr("-92233720368547758000"));
test_s64_reading_with_ill_formed_inp(cstr("-09"));
test_s64_reading_with_ill_formed_inp(cstr("09"));
test_s64_reading_with_ill_formed_inp(cstr("00"));
test_s64_reading_with_ill_formed_inp(cstr("-00"));
test_s64_reading_with_ill_formed_inp(cstr("+"));
test_s64_reading_with_ill_formed_inp(cstr("-"));
test_s64_reading_with_ill_formed_inp(cstr("+123"));
}
void test_s64_reading_with_good_inp(SpanU8 str, S64 right_val, U64 leftovers){
SpanU8 rem = str;
S64 val;
int c = SpanU8_read_S64(&rem, &val);
check(c == 0);
check(rem.data == str.data + str.len - leftovers && rem.len == leftovers);
check(val == right_val);
}
void tt15(){
test_s64_reading_with_good_inp(cstr("9223372036854775807--"), 9223372036854775807l, 2);
test_s64_reading_with_good_inp(cstr("9223372036854775807"), 9223372036854775807l, 0);
test_s64_reading_with_good_inp(cstr("9223372036854775805"), 9223372036854775805l, 0);
test_s64_reading_with_good_inp(cstr("-9223372036854775808++"), -9223372036854775807l-1, 2);
test_s64_reading_with_good_inp(cstr("-9223372036854775808"), -9223372036854775807l-1, 0);
test_s64_reading_with_good_inp(cstr("413-"), 413, 1);
test_s64_reading_with_good_inp(cstr("0-"), 0, 1);
}
void test_float_reading_with_good_inp(SpanU8 str, float right_val, float eps, U64 lo){
SpanU8 rem = str;
float val;
int c = SpanU8_read_float(&rem, &val);
check(c == 0);
check(rem.data == str.data + str.len - lo && rem.len == lo);
check((right_val >= +1e60 && val >= +1e60) || (right_val <= -1e60 && val <= -1e60) || fabsf(right_val - val) < eps);
}
void tt16(){
test_float_reading_with_good_inp(cstr("1022.312"), 1022.312f, 0.00001f, 0);
test_float_reading_with_good_inp(cstr("1022.1"), 1022.1f, 0.00001f, 0);
test_float_reading_with_good_inp(cstr("0.0000"), 0.f, 0.00001f, 0);
test_float_reading_with_good_inp(cstr("0.0e100"), 0.f, 0.00001f, 0);
test_float_reading_with_good_inp(cstr("1.2e3"), 1200.f, 0.00001f, 0);
test_float_reading_with_good_inp(cstr("101"), 101.f, 0.00001f, 0);
test_float_reading_with_good_inp(cstr("-123"), -123.f, 0.00001f, 0);
test_float_reading_with_good_inp(cstr("-123e-3"), -0.123f, 0.00001f, 0);
test_float_reading_with_good_inp(cstr("98e-3"), 0.098f, 0.00001f, 0);
test_float_reading_with_good_inp(cstr("1e50"), 1.e50f, 0.00001f, 0);
test_float_reading_with_good_inp(cstr("1e-50"), 1.e-50f, 0.00001f, 0);
test_float_reading_with_good_inp(cstr("-1e-50"), -1e-50f, 0.00001f, 0);
test_float_reading_with_good_inp(cstr("-1e50"), -1e50f, 0.00001f, 0);
test_float_reading_with_good_inp(cstr("-15e+4"), -150000, 0.00001f, 0);
}
void test_float_reading_with_ill_formed_inp(SpanU8 str){
SpanU8 rem = str;
float val;
int c = SpanU8_read_float(&rem, &val);
check(c > 0);
check(SpanU8_equal(str, rem));
}
void tt17(){
test_float_reading_with_ill_formed_inp(cstr("+123"));
test_float_reading_with_ill_formed_inp(cstr("1e51"));
test_float_reading_with_ill_formed_inp(cstr("1e9223372036854775807"));
test_float_reading_with_ill_formed_inp(cstr("1e9223372036854775808"));
test_float_reading_with_ill_formed_inp(cstr("1e-51"));
test_float_reading_with_ill_formed_inp(cstr("1e-9223372036854775808"));
test_float_reading_with_ill_formed_inp(cstr("1e-9223372036854775809"));
}
void tt18(){
SpanU8 str = cstr(" 1");
SpanU8 rem = str;
SpanU8_parsing_skip_spaces(&rem);
check(SpanU8_equal(rem, (SpanU8){str.data + 3, str.len - 3}));
}
void tt19(){
SpanU8 str = cstr("\t\r\n ");
SpanU8 rem = str;
SpanU8_parsing_skip_spaces(&rem);
check(SpanU8_equal(rem, (SpanU8){str.data + 4, 0}));
}
void tt20(){
SpanU8 str = cstr("1213");
SpanU8 rem = str;
SpanU8_parsing_skip_spaces(&rem);
check(SpanU8_equal(rem, str));
}
void tt21(){
check(is_hex_char('0'));
check(is_hex_char('9'));
check(is_hex_char('A'));
check(is_hex_char('F'));
check(is_hex_char('a'));
check(is_hex_char('f'));
check(!is_hex_char('_') && !is_hex_char('*') && !is_hex_char('~') && !is_hex_char('-') && !is_hex_char('(')
&& !is_hex_char('/') && !is_hex_char(':') && !is_hex_char('G') && !is_hex_char('g') && !is_hex_char('['));
check(char_to_hex_digit('a') == 10 && char_to_hex_digit('A') == 10 && char_to_hex_digit('9') == 9);
SpanU8 str = cstr("E=");
SpanU8 rem = str;
U32 d;
bool c = SpanU8_parsing_try_read_hex_digit(&rem, &d);
check(c);
check(rem.data == str.data + 1 && rem.len == 1);
check(d == 0xE);
check(!SpanU8_parsing_try_read_hex_digit(&rem, &d));
check(rem.data == str.data + 1 && rem.len == 1);
rem.len = 0;
check(!SpanU8_parsing_try_read_hex_digit(&rem, &d));
check(rem.data == str.data + 1 && rem.len == 0);
}
/* Json kicks in */
void tt22(){
VecU8 buf = VecU8_new();
json_encoding_append_utf16(&buf, 17);
check(SpanU8_cont_equal(VecU8_to_span(&buf), cstr("\\u0011")));
json_encoding_append_utf16(&buf, 7);
check(vec_matches_cstr(buf, "\\u0011\\u0007"));
}
void tt23(){
VecU8 buf = VecU8_new();
json_encoding_append_string(&buf, cstr(""));
check(vec_matches_cstr(buf, "\"\""));
}
void tt24(){
VecU8 buf = VecU8_new();
json_encoding_append_string(&buf, cstr("\"\n\t\r\\ AB"));
check(vec_matches_cstr(buf, "\"" "\\\"\\n\\t\\r\\\\ AB" "\""));
}
void tt25(){
Json x = Json_from_VecJson(VecJson_new());
VecU8 my_ans = json_encode(&x);
Json_drop(x);
check(vec_matches_cstr(my_ans, "[]"));
}
int main(){
tt1(); tt2(); tt3(); tt4(); tt5(); tt6(); tt7(); tt8(); tt9(); tt10(); tt11(); tt12(); tt13(); tt14(); tt15();
tt16(); tt17(); tt18(); tt19();
tt20(); tt21(); tt22(); tt23(); tt24(); tt25()
return 0;
}