aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--Makefile5
-rw-r--r--README.md6
-rw-r--r--generate.fish9
-rw-r--r--include/assert.h17
-rw-r--r--include/testing.h10
-rw-r--r--include/types.h4
-rw-r--r--src/json.c9
-rw-r--r--tests/test_json.c55
-rw-r--r--tests/test_string.c16
10 files changed, 75 insertions, 58 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 94d59a8..06cbb74 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.30.5)
project(kagamic VERSION 0.1 LANGUAGES C)
-set(CMAKE_C_STANDARD 17)
+set(CMAKE_C_STANDARD 23)
file(GLOB SOURCES "src/*.c")
file(GLOB TEST_SOURCES "test/*.c")
diff --git a/Makefile b/Makefile
index 30f1f1b..4c508f0 100644
--- a/Makefile
+++ b/Makefile
@@ -22,3 +22,8 @@ test:
format:
clang-format -i src/*.c include/*.h tests/*.c *.c
+
+check:
+ make test
+ clang-format -i --dry-run src/*.c include/*.h tests/*.c *.c --fail-on-incomplete-format
+ ! rg 't_assert\(.*=='
diff --git a/README.md b/README.md
index 9fa35fe..3e9b39b 100644
--- a/README.md
+++ b/README.md
@@ -3,11 +3,13 @@
## TODO
- Vec_get not safe, I made a type mistake. And should be more efficient for loops
-- Fix tests in release
-- Static functions for private?
- `valgrind --leak-check=full ./your_program`
- web server, Json parsing, struct codegen
- assert not in release
+- python based generate
+- test helpers to load json files
+- add test with backspaces weird
+- remove t_assert
## Benchmarks
diff --git a/generate.fish b/generate.fish
index 96f8542..fc84937 100644
--- a/generate.fish
+++ b/generate.fish
@@ -13,12 +13,11 @@ for f in $fs;
for func in $funcs;
set pfunc (echo $func | awk '{match($0, /test_[^(]+/); print substr($0, RSTART, RLENGTH)}');
echo "Found $pfunc in $f";
- echo " test($pfunc);" >> test.c
+ echo " test($pfunc);" >> test.c
end;
end;
echo "
- printf(\"Success: %d, Failures: %d\n\", success, failures);
+ printf(\"Success: %d, Failures: %d\n\", success, failures);
- return failures;
-}
-" >> test.c;
+ return failures;
+}" >> test.c;
diff --git a/include/assert.h b/include/assert.h
index ad9c2fd..aa62bd1 100644
--- a/include/assert.h
+++ b/include/assert.h
@@ -3,12 +3,13 @@
#include <stdio.h>
#include <stdlib.h>
-#define assert(condition, ...) \
- do { \
- if (!(condition)) { \
- fprintf(stderr, "Assertion failed: %s:%d in %s(): ", __FILE__, __LINE__, __func__); \
- fprintf(stderr, __VA_ARGS__); \
- fprintf(stderr, "\n"); \
- abort(); \
- } \
+#define assert(condition, ...) \
+ do { \
+ if (!(condition)) { \
+ fprintf(stderr, "Assertion failed: %s:%d in %s(): ", __FILE__, \
+ __LINE__, __func__); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ abort(); \
+ } \
} while (0)
diff --git a/include/testing.h b/include/testing.h
index 9e0c022..dc070d3 100644
--- a/include/testing.h
+++ b/include/testing.h
@@ -1,4 +1,6 @@
+#pragma once
#include <stdio.h>
+#include <string.h>
#define t_assert(fact) \
if (!(fact)) { \
@@ -22,3 +24,11 @@
#a, b, #b, __FILE__, __LINE__, __func__); \
return 1; \
}
+
+#define t_assert_strequal(a, b) \
+ if ((a.len != b.len) || (a.len && memcmp(a.data, b.data, a.len))) { \
+ fprintf(stderr, \
+ "Assertion failed: %.*s (%s) != %.*s (%s) at %s:%d in %s()\n", (i32)a.len, a.data, \
+ #a, (i32)b.len, b.data, #b, __FILE__, __LINE__, __func__); \
+ return 1; \
+ }
diff --git a/include/types.h b/include/types.h
index da3a093..6df9510 100644
--- a/include/types.h
+++ b/include/types.h
@@ -1,7 +1,7 @@
+#include <immintrin.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
-#include <immintrin.h>
typedef ptrdiff_t size;
typedef char byte;
@@ -9,7 +9,7 @@ typedef uintptr_t uptr;
typedef int32_t i32;
typedef uint64_t u64;
typedef float f32;
-typedef __m256i byte_32;
+typedef __m256i bytex32;
#define sizeof(x) (size)sizeof(x)
#define countof(a) (sizeof(a) / sizeof(*(a)))
diff --git a/src/json.c b/src/json.c
index c299b63..f6dc4e6 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1,5 +1,6 @@
#include <ctype.h>
#include <immintrin.h>
+#include <stdbit.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
@@ -185,15 +186,15 @@ parse_result parse_string(byte *src, uptr start_pos, uptr max_pos) {
result.pos = start_pos + 1;
// SIMD optimization: process 32 bytes at a time using AVX2
- byte_32 quote_mask = _mm256_set1_epi8('"');
+ bytex32 quote_mask = _mm256_set1_epi8('"');
for (; result.pos + 32 <= max_pos; result.pos += 32) {
- byte_32 chunk = _mm256_loadu_si256((byte_32 *)(src + result.pos));
- byte_32 cmp = _mm256_cmpeq_epi8(chunk, quote_mask);
+ bytex32 chunk = _mm256_loadu_si256((bytex32 *)(src + result.pos));
+ bytex32 cmp = _mm256_cmpeq_epi8(chunk, quote_mask);
i32 mask = _mm256_movemask_epi8(cmp);
if (mask != 0) {
- result.pos += __builtin_ctz(mask);
+ result.pos += stdc_trailing_zeros_ui(mask);
if (src[result.pos - 1] != '\\') break;
};
}
diff --git a/tests/test_json.c b/tests/test_json.c
index 53dc6e3..b5ad9af 100644
--- a/tests/test_json.c
+++ b/tests/test_json.c
@@ -8,7 +8,7 @@ i32 test_json_integer() {
JSON json_int = JSON_parse_raw(&perm, "123");
- t_assert(json_int.as.integer == 123);
+ t_assert_equal(json_int.as.integer, 123);
t_assert_equal(Arena_get_used(perm), 0);
return 0;
}
@@ -18,7 +18,7 @@ i32 test_json_int_array() {
JSON json_int_array = JSON_parse_raw(&perm, "[1,2,3]");
- t_assert(json_int_array.type == JSON_ARRAY);
+ t_assert_equal(json_int_array.type, JSON_ARRAY);
t_assert_equal(json_int_array.as.array.len, 3);
int ints[3];
int sum = 0;
@@ -27,10 +27,10 @@ i32 test_json_int_array() {
ints[i] = item->as.integer;
sum += item->as.integer;
}
- t_assert(ints[0] == 1);
- t_assert(ints[1] == 2);
- t_assert(ints[2] == 3);
- t_assert(sum == 6);
+ t_assert_equal(ints[0], 1);
+ t_assert_equal(ints[1], 2);
+ t_assert_equal(ints[2], 3);
+ t_assert_equal(sum, 6);
t_assert_equal(Arena_get_used(perm), 576);
return 0;
@@ -41,7 +41,7 @@ i32 test_json_empty_array() {
JSON json_empty_array = JSON_parse_raw(&perm, "[]");
- t_assert(json_empty_array.as.array.len == 0);
+ t_assert_equal(json_empty_array.as.array.len, 0);
t_assert_equal(Arena_get_used(perm), 0); // TODO: weird
return 0;
@@ -54,10 +54,10 @@ i32 test_json_nested_array() {
JSON sub_array = *Vec_get(doc.as.array, JSON, 0);
JSON val_1 = *Vec_get(sub_array.as.array, JSON, 0);
- t_assert(val_1.as.integer == 1);
+ t_assert_equal(val_1.as.integer, 1);
JSON val_2 = *Vec_get(sub_array.as.array, JSON, 1);
- t_assert(Str_equals(StrView_copy(&perm, val_2.as.string), S("abc")));
- t_assert_equal(Arena_get_used(perm), 1155);
+ t_assert_strequal(val_2.as.string, S("abc"));
+ t_assert_equal(Arena_get_used(perm), 1152);
return 0;
}
@@ -67,8 +67,8 @@ i32 test_json_string() {
JSON js = JSON_parse_raw(&perm, "\"abc\"");
- t_assert(Str_equals(StrView_copy(&perm, js.as.string), S("abc")));
- t_assert_equal(Arena_get_used(perm), 3);
+ t_assert_strequal(js.as.string, S("abc"));
+ t_assert_equal(Arena_get_used(perm), 0);
return 0;
}
@@ -92,8 +92,8 @@ i32 test_json_object() {
t_assert_equal(doc.as.object.len, 1);
t_assert(Str_equals(*Vec_get(doc.as.object.keys, Str, 0), S("key")));
JSON value = *JSONObject_get(doc.as.object, S("key"));
- t_assert(Str_equals(StrView_copy(&perm, value.as.string), S("value")));
- t_assert_equal(Arena_get_used(perm), 677);
+ t_assert_strequal(value.as.string, S("value"));
+ t_assert_equal(Arena_get_used(perm), 672);
return 0;
}
@@ -104,9 +104,9 @@ i32 test_json_boolean() {
JSON doc = JSON_parse_raw(&perm, "{\"a\": true, \"b\": false}");
JSON a = *JSONObject_get(doc.as.object, S("a"));
- t_assert(a.as.boolean == true);
+ t_assert_equal(a.as.boolean, true);
JSON b = *JSONObject_get(doc.as.object, S("b"));
- t_assert(b.as.boolean == false);
+ t_assert_equal(b.as.boolean, false);
t_assert_equal(Arena_get_used(perm), 672);
return 0;
@@ -132,7 +132,7 @@ i32 test_json_null() {
JSON doc = JSON_parse_raw(&perm, "[null]");
t_assert_equal(doc.as.array.len, 1);
JSON first = *Vec_get(doc.as.array, JSON, 0);
- t_assert(first.type == JSON_NULL);
+ t_assert_equal(first.type, JSON_NULL);
t_assert_equal(Arena_get_used(perm), 576);
return 0;
@@ -143,7 +143,7 @@ i32 test_json_long_spaces() {
JSON doc = JSON_parse_raw(
&perm, "{\t \t \t \t \t }");
- t_assert(doc.as.object.len == 0);
+ t_assert_equal(doc.as.object.len, 0);
return 0;
}
@@ -158,10 +158,9 @@ i32 test_json_multiline() {
" \"generator_version\": \"1.0\"\n"
"}");
JSON target_size_mb = *JSONObject_get(doc.as.object, S("target_size_mb"));
- t_assert(target_size_mb.as.integer == 1);
+ t_assert_equal(target_size_mb.as.integer, 1);
JSON generated_at = *JSONObject_get(doc.as.object, S("generated_at"));
- t_assert(Str_equals(StrView_copy(&perm, generated_at.as.string),
- S("2025-07-22T10:36:30.974926")));
+ t_assert_strequal(generated_at.as.string, S("2025-07-22T10:36:30.974926"));
return 0;
}
@@ -172,9 +171,9 @@ i32 test_json_nested_object() {
JSON doc = JSON_parse_raw(&perm, "{\"1\":{\"2\":{}}}");
JSON lvl_1 = *JSONObject_get(doc.as.object, S("1"));
- t_assert(lvl_1.type == JSON_OBJECT);
+ t_assert_equal(lvl_1.type, JSON_OBJECT);
JSON lvl_2 = *JSONObject_get(lvl_1.as.object, S("2"));
- t_assert(lvl_2.type == JSON_OBJECT);
+ t_assert_equal(lvl_2.type, JSON_OBJECT);
return 0;
}
@@ -183,7 +182,7 @@ i32 test_json_array_in_object() {
JSON doc = JSON_parse_raw(&perm, "{\"tags\": [\"TWvZi0\",\"pM0TPv9X\"]}");
JSON tags = *JSONObject_get(doc.as.object, S("tags"));
- t_assert(tags.type == JSON_ARRAY);
+ t_assert_equal(tags.type, JSON_ARRAY);
t_assert_equal(tags.as.array.len, 2);
return 0;
@@ -218,11 +217,11 @@ i32 test_json_complex_multiline() {
" }");
JSON id = *JSONObject_get(doc.as.object, S("id"));
- t_assert(id.as.integer == 819228);
+ t_assert_equal(id.as.integer, 819228);
JSON metadata = *JSONObject_get(doc.as.object, S("metadata"));
JSON preferences = *JSONObject_get(metadata.as.object, S("preferences"));
JSON theme = *JSONObject_get(preferences.as.object, S("theme"));
- t_assert(Str_equals(StrView_copy(&perm, theme.as.string), S("auto")));
+ t_assert_strequal(theme.as.string, S("auto"));
return 0;
}
@@ -232,9 +231,9 @@ i32 test_negative_numbers() {
JSON doc = JSON_parse_raw(&perm, "[-1, -2.5]");
JSON integer = *Vec_get(doc.as.array, JSON, 0);
- t_assert(integer.as.integer == -1);
+ t_assert_equal(integer.as.integer, -1);
JSON floating = *Vec_get(doc.as.array, JSON, 1);
- t_assert(floating.as.floating == -2.5);
+ t_assert_fequal(floating.as.floating, -2.5);
return 0;
}
diff --git a/tests/test_string.c b/tests/test_string.c
index 8b5d0d6..297e294 100644
--- a/tests/test_string.c
+++ b/tests/test_string.c
@@ -4,7 +4,7 @@
#include <stdio.h>
i32 test_string_literal_equality() {
- t_assert(Str_equals(S("Bonjour"), S("Bonjour")));
+ t_assert_strequal(S("Bonjour"), S("Bonjour"));
return 0;
}
@@ -14,28 +14,28 @@ i32 test_string_copy() {
Str cpy = Str_copy(&perm, src.data, src.len);
- t_assert(Str_equals(src, cpy));
+ t_assert_strequal(src, cpy);
t_assert_equal(Arena_get_used(perm), 5);
return 0;
}
i32 test_fast_string() {
- byte_32 quote_mask = _mm256_set1_epi8('"');
+ bytex32 quote_mask = _mm256_set1_epi8('"');
byte *s = malloc(32 * sizeof(byte));
s = "abcdefghijklmnopqrstuvwxyzabcdef";
- byte_32 chunk = _mm256_loadu_si256((byte_32 *)s);
- byte_32 cmp = _mm256_cmpeq_epi8(chunk, quote_mask);
+ bytex32 chunk = _mm256_loadu_si256((bytex32 *)s);
+ bytex32 cmp = _mm256_cmpeq_epi8(chunk, quote_mask);
i32 mask = _mm256_movemask_epi8(cmp);
- t_assert(_mm_popcnt_u32(mask) == 0);
+ t_assert_equal(_mm_popcnt_u32(mask), 0);
s = "abcdefghijklm\"nopqrstuvwxyzabcde";
- chunk = _mm256_loadu_si256((byte_32 *)s);
+ chunk = _mm256_loadu_si256((bytex32 *)s);
cmp = _mm256_cmpeq_epi8(chunk, quote_mask);
mask = _mm256_movemask_epi8(cmp);
- t_assert(_mm_popcnt_u32(mask) == 1);
+ t_assert_equal(_mm_popcnt_u32(mask), 1);
return 0;
}