aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2025-08-23 15:31:28 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2025-08-27 11:45:01 +0200
commita44ce5c6f74fb777408b455ae21ca545447c0ade (patch)
treecc2bcf4713f4dcb48456be6396e4f7bf6d974733
parent03b645f22bfc7afadc5a8aa6d59edf0eba74a048 (diff)
json: parse negative numbers
-rw-r--r--CMakeLists.txt2
-rw-r--r--Makefile4
-rw-r--r--README.md18
-rw-r--r--src/json.c16
-rw-r--r--src/vec.c2
-rw-r--r--tests/test_json.c12
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)
diff --git a/Makefile b/Makefile
index f4c5e8f..30f1f1b 100644
--- a/Makefile
+++ b/Makefile
@@ -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:
diff --git a/README.md b/README.md
index d721753..b3d5b22 100644
--- a/README.md
+++ b/README.md
@@ -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) {
diff --git a/src/json.c b/src/json.c
index 99ae01b..a237527 100644
--- a/src/json.c
+++ b/src/json.c
@@ -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};
diff --git a/src/vec.c b/src/vec.c
index a5c2fb4..e64db9b 100644
--- a/src/vec.c
+++ b/src/vec.c
@@ -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;
+}