diff options
| author | Martin Kagamino Lehoux <martin@lehoux.net> | 2025-08-23 15:31:28 +0200 |
|---|---|---|
| committer | Martin Kagamino Lehoux <martin@lehoux.net> | 2025-08-27 11:45:01 +0200 |
| commit | a44ce5c6f74fb777408b455ae21ca545447c0ade (patch) | |
| tree | cc2bcf4713f4dcb48456be6396e4f7bf6d974733 | |
| parent | 03b645f22bfc7afadc5a8aa6d59edf0eba74a048 (diff) | |
json: parse negative numbers
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | README.md | 18 | ||||
| -rw-r--r-- | src/json.c | 16 | ||||
| -rw-r--r-- | src/vec.c | 2 | ||||
| -rw-r--r-- | tests/test_json.c | 12 |
6 files changed, 35 insertions, 19 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f2f8ee..94d59a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_C_STANDARD 17) file(GLOB SOURCES "src/*.c") file(GLOB TEST_SOURCES "test/*.c") -add_compile_options(-Wall -pedantic -Wextra -march=native) +add_compile_options(-Wall -pedantic -Wextra -mavx2 -mno-avx512f) add_executable(main main.c ${SOURCES}) target_link_libraries(main m) @@ -11,8 +11,8 @@ release: profile: mkdir -p Profile cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -B Profile - cmake --build Release - valgrind --tool=callgrind --dump-instr=yes --callgrind-out-file=callgrind.out ./Release/main 100MB.json 1 + cmake --build Profile + valgrind --tool=callgrind --dump-instr=yes --callgrind-out-file=callgrind.out ./Profile/main 100MB.json 1 kcachegrind callgrind.out test: @@ -6,18 +6,20 @@ - Fix tests in release - Static functions for private? - `valgrind --leak-check=full ./your_program` -- negative numbers - web server, Json parsing, struct codegen -- what is a const char * +- what is a const char \* +- whitechar simd +- assert not in release ## Benchmarks -| version | result | throughput | ram| -|---|---|---|---| -|json.loads|652 ms ± 6.65 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)||| -|v1|336 ms ± 163 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)||| -|no 0 mem alloc|299 ms ± 8 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)||| -|Str_view|272 ms ± 6 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)|330.46 MB/s|1255 MB| +| version | result | throughput | ram | +| -------------- | ------------------------------------------------------------------- | ----------- | ------- | +| json.loads | 652 ms ± 6.65 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) | | | +| v1 | 336 ms ± 163 ms per loop (mean ± std. dev. of 10 runs, 1 loop each) | | | +| no 0 mem alloc | 299 ms ± 8 ms per loop (mean ± std. dev. of 10 runs, 1 loop each) | | | +| Str_view | 272 ms ± 6 ms per loop (mean ± std. dev. of 10 runs, 1 loop each) | 330.46 MB/s | 1255 MB | +| simd | 254 ms ± 6 ms per loop (mean ± std. dev. of 10 runs, 1 loop each) | 353.36 MB/s | 1255 MB | ```c void print_bytes(byte_32 *data) { @@ -121,14 +121,15 @@ parse_result parse_any(Arena *a, byte *src, uptr pos, uptr max_pos); parse_result parse_number(byte *src, uptr start_pos) { parse_result result = {0}; - result.pos = start_pos; + bool is_neg = src[start_pos] == '-'; + result.pos = start_pos + is_neg; i32 integer = 0; while (isdigit(src[result.pos])) { integer = integer * 10 + (src[result.pos] - '0'); result.pos++; } if (src[result.pos] != '.') { - result.value = JSON_integer(integer); + result.value = JSON_integer(is_neg ? -integer : integer); return result; } result.pos++; @@ -139,7 +140,8 @@ parse_result parse_number(byte *src, uptr start_pos) { decimal_place *= 0.1; result.pos++; } - result.value = JSON_float((f32)integer + fractional_part); + result.value = JSON_float(is_neg ? -(f32)integer - fractional_part + : (f32)integer + fractional_part); return result; } @@ -177,7 +179,7 @@ parse_result parse_array(Arena *a, byte *src, uptr start_pos, uptr max_pos) { return result; } -parse_result parse_string(Arena *a, byte *src, uptr start_pos, uptr max_pos) { +parse_result parse_string(byte *src, uptr start_pos, uptr max_pos) { assert_parse(src[start_pos] == '"', "invalid string start", src, start_pos); parse_result result = {0}; result.pos = start_pos + 1; @@ -224,7 +226,7 @@ parse_result parse_object(Arena *a, byte *src, uptr start_pos, uptr max_pos) { return result; } for (;;) { - parse_result key_result = parse_string(a, src, result.pos, max_pos); + parse_result key_result = parse_string(src, result.pos, max_pos); result.pos = absorb_whitespaces(src, key_result.pos); assert_parse(src[result.pos] == ':', "invalid keyval delim", src, result.pos); @@ -249,9 +251,9 @@ parse_result parse_object(Arena *a, byte *src, uptr start_pos, uptr max_pos) { parse_result parse_any(Arena *a, byte *src, uptr pos, uptr max_pos) { pos = absorb_whitespaces(src, pos); - if (isdigit(src[pos])) return parse_number(src, pos); + if (isdigit(src[pos]) || src[pos] == '-') return parse_number(src, pos); if (src[pos] == '[') return parse_array(a, src, pos, max_pos); - if (src[pos] == '"') return parse_string(a, src, pos, max_pos); + if (src[pos] == '"') return parse_string(src, pos, max_pos); if (src[pos] == '{') return parse_object(a, src, pos, max_pos); if (memcmp(src + pos, "true", 4) == 0) { parse_result result = {0}; @@ -5,7 +5,7 @@ #include "../include/vec.h" Vec _Vec_new(Arena *a, size tsize, size cap, size align) { - assert(cap > 0); + assert(cap > 0, "negative cap"); Vec v = {0}; v.tsize = tsize; v.cap = cap; diff --git a/tests/test_json.c b/tests/test_json.c index e050c72..1aec8c5 100644 --- a/tests/test_json.c +++ b/tests/test_json.c @@ -216,3 +216,15 @@ i32 test_json_complex_multiline() { return 0; } + +i32 test_negative_numbers() { + Arena perm = Arena_new(128e3); + JSON doc = JSON_parse_raw(&perm, "[-1, -2.5]"); + + JSON integer = *Vec_get(doc.as.array, JSON, 0); + t_assert(integer.as.integer == -1); + JSON floating = *Vec_get(doc.as.array, JSON, 1); + t_assert(floating.as.floating == -2.5); + + return 0; +} |
