Add README
This commit is contained in:
parent
97f21e24dc
commit
91aeeecc0f
@ -4,16 +4,16 @@
|
|||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_C_EXTENSIONS OFF)
|
set(CMAKE_C_EXTENSIONS OFF)
|
||||||
set(CMAKE_C_STANDARD 99)
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
|
||||||
add_definitions(-DCMAKE_EXPORT_COMPILE_COMMANDS=ON)
|
add_definitions(-DCMAKE_EXPORT_COMPILE_COMMANDS=ON)
|
||||||
|
|
||||||
if (NOT MSVC)
|
if (NOT MSVC)
|
||||||
set(WARNING_FLAGS_C -Wall -Wextra -Wpedantic -Wvla -Wshadow -Wundef -Wmisleading-indentation -Wnull-dereference -Wswitch-default -Wstrict-overflow=5 -Wconversion -Wno-sign-conversion -Wsign-promo -Wcast-align -Wcast-qual -Wdouble-promotion -Wformat=2 -Winit-self -Wdisabled-optimization -Wno-unused-function)
|
set(WARNING_FLAGS_C -Wall -Wextra -Wpedantic -Wvla -Wshadow -Wundef -Wmisleading-indentation -Wnull-dereference -Wswitch-default -Wstrict-overflow=5 -Wconversion -Wno-sign-conversion -Wcast-align -Wcast-qual -Wdouble-promotion -Wformat=2 -Winit-self -Wdisabled-optimization -Wno-unused-function)
|
||||||
|
|
||||||
set(WARNING_FLAGS_CXX -Wall -Wextra -Wpedantic -Wvla -Wshadow -Wundef -Wmisleading-indentation -Wnull-dereference -Wswitch-default -Wstrict-overflow=5 -Wconversion -Wno-sign-conversion -Wsign-promo -Wcast-align -Wcast-qual -Wdouble-promotion -Wformat=2 -Winit-self -Wdisabled-optimization -Woverloaded-virtual -Wredundant-decls -Wctor-dtor-privacy -Wno-unused-function)
|
set(WARNING_FLAGS_CXX -Wall -Wextra -Wpedantic -Wvla -Wshadow -Wundef -Wmisleading-indentation -Wnull-dereference -Wswitch-default -Wstrict-overflow=5 -Wconversion -Wno-sign-conversion -Wsign-promo -Wcast-align -Wcast-qual -Wdouble-promotion -Wformat=2 -Winit-self -Wdisabled-optimization -Woverloaded-virtual -Wredundant-decls -Wctor-dtor-privacy -Wno-unused-function)
|
||||||
|
|
||||||
set(DBG_FLAGS -fsanitize=undefined,address -g3 -glldb -Og)
|
set(DBG_FLAGS -fsanitize=undefined,address -g3 -Og)
|
||||||
else ()
|
else ()
|
||||||
set(WARNING_FLAGS_C /W4)
|
set(WARNING_FLAGS_C /W4)
|
||||||
set(WARNING_FLAGS_CXX /W4)
|
set(WARNING_FLAGS_CXX /W4)
|
||||||
@ -45,7 +45,7 @@ set(LIBGUF_IMPLS ${CMAKE_CURRENT_SOURCE_DIR}/libguf_impls/guf_alloc_libc_impl.c
|
|||||||
foreach(current_target IN LISTS TARGETS)
|
foreach(current_target IN LISTS TARGETS)
|
||||||
add_executable(${current_target} ${current_target}/${current_target}.c ${LIBGUF_IMPLS})
|
add_executable(${current_target} ${current_target}/${current_target}.c ${LIBGUF_IMPLS})
|
||||||
set_target_properties(${current_target} PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
|
set_target_properties(${current_target} PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
|
||||||
target_include_directories(${current_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/" "${CMAKE_CURRENT_SOURCE_DIR}/libguf/src/")
|
target_include_directories(${current_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/" "${CMAKE_CURRENT_SOURCE_DIR}/libguf/")
|
||||||
|
|
||||||
target_compile_options(${current_target} PRIVATE ${WARNING_FLAGS_C} $<$<CONFIG:Debug>:${DBG_FLAGS}>)
|
target_compile_options(${current_target} PRIVATE ${WARNING_FLAGS_C} $<$<CONFIG:Debug>:${DBG_FLAGS}>)
|
||||||
target_link_options(${current_target} PRIVATE ${WARNING_FLAGS_C} $<$<CONFIG:Debug>:${DBG_FLAGS}>)
|
target_link_options(${current_target} PRIVATE ${WARNING_FLAGS_C} $<$<CONFIG:Debug>:${DBG_FLAGS}>)
|
||||||
|
|||||||
53
README.md
Executable file
53
README.md
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
# Advent of Code 2025
|
||||||
|
C99 solutions to the puzzles of [Advent of Code 2025](https://adventofcode.com/2025) using my [libguf](https://git.tilde.town/fruit/libguf).
|
||||||
|
|
||||||
|
(Previous years: [2024](https://github.com/zeichensystem/advent-of-code-2024), [2023](https://github.com/zeichensystem/advent-of-code-2023))
|
||||||
|
|
||||||
|
As the creator of Advent of Code does not allow/encourage sharing your own puzzle inputs, I only put example puzzle inputs into [input/](input/) publicly, so you can at least run those if you don't have your own puzzle inputs.
|
||||||
|
|
||||||
|
My answers are correct for my puzzle inputs (and for the example inputs), but in my experience it is definitely possible to come up with *incorrect* code which may produce the *correct* answers for your own puzzle input, but which might not work for all other possible/legal puzzle inputs. (I put the answers to my puzzle inputs and to the example inputs as comments at the very top of the source-files for each day.)
|
||||||
|
|
||||||
|
## How to build and run
|
||||||
|
You need at least a C99 compiler and cmake.
|
||||||
|
|
||||||
|
### 1. Configure cmake and generate build systems
|
||||||
|
Navigate to the top level of this repository (the directory where [CMakeLists.txt](CMakeLists.txt) is located) and create your build directories, for instance:
|
||||||
|
|
||||||
|
`mkdir -p build/Release build/Debug`
|
||||||
|
|
||||||
|
Then, run:
|
||||||
|
|
||||||
|
`cmake -DCMAKE_BUILD_TYPE=Release -S . -B build/Release`
|
||||||
|
|
||||||
|
`cmake -DCMAKE_BUILD_TYPE=Debug -S . -B build/Debug`
|
||||||
|
|
||||||
|
to generate the release build system into your build directory `build/Release` (and the debug build system into your build directory `build/Debug`). (If you do not run the commands at the top level of this repository, you have to run them with `-S path-to-this-repo` instead of `-S .` like above.)
|
||||||
|
|
||||||
|
You can also set `-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=` if you want to use a custom output directory for the compiled binaries; by default, they will be put into the `bin/` directory at the root of this repository.
|
||||||
|
|
||||||
|
### 2. Build
|
||||||
|
Run
|
||||||
|
|
||||||
|
`cmake --build build/Release --target day-nn`
|
||||||
|
|
||||||
|
to build the release-mode executable for `day-nn` (or run `cmake --build build/Release` to build the release-mode executables for all days, but this might take a while).
|
||||||
|
|
||||||
|
The resulting executable will be called `day-nn` (or `day-nn_dbg` for debug builds). By default, it will be put into the `bin/` directory at the root of this repository (or into the directory you specified with `-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=` in step 1).
|
||||||
|
|
||||||
|
(For example: Run `cmake --build build/Release --target day-03` to build the release-mode executable which solves Day 3. It will be put into `bin/day-03` by default. Or run `cmake --build build/Debug --target day-03` to build the debug-mode executable `bin/day-03_dbg` instead, assuming you generated the debug build system into 'build/Debug' in step 1.)
|
||||||
|
|
||||||
|
### 3. Run
|
||||||
|
Run `bin/day-nn input_day_nn.txt` to compute and print the solutions (part 1 and part 2) for *day-nn* (with `input_day_nn.txt` being your puzzle input for that day). If you don't have your own puzzle inputs, you can use the example inputs from the [input/](input/) directory.
|
||||||
|
|
||||||
|
```
|
||||||
|
Usage: day-nn [-help] puzzle_input [-v]
|
||||||
|
-v: use verbose output (optional)
|
||||||
|
-help: print this help, ignore the rest, and quit (optional)
|
||||||
|
puzzle_input: your puzzle input file (optional/ignored if -help is used)
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also build and run *day-nn* in one step with `cmake --build build/Release --target run-day-nn`, but this assumes you have saved your puzzle input for *day-nn* as `input/day-nn.txt` within this repository.
|
||||||
|
|
||||||
|
If you don't have your own puzzle inputs but still want to test the executable for *day-nn*, you can build and run with `cmake --build build/Release --target run-day-nn-example` (which uses the puzzle's example input `input/day-nn-example.txt` automatically).
|
||||||
|
|
||||||
|
For example: `cmake --build build/Release --target run-day-02-example` to build and run the release-mode executable for *day-02* with the example input [input/day-02-example.txt](input/day-02-example.txt)
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,67 +0,0 @@
|
|||||||
„Ich weiß nicht“, rief ich ohne Klang „ich weiß ja nicht. Wenn
|
|
||||||
niemand kommt, dann kommt eben niemand. Ich habe niemandem etwas
|
|
||||||
Böses getan, niemand hat mir etwas Böses getan, niemand aber will
|
|
||||||
mir helfen. Lauter niemand. Aber so ist es doch nicht. Nur daß mir
|
|
||||||
niemand hilft —, sonst wäre lauter niemand hübsch. Ich würde ganz
|
|
||||||
gern — warum denn nicht — einen Ausflug mit einer Gesellschaft von
|
|
||||||
lauter Niemand machen. Natürlich ins Gebirge, wohin denn sonst? Wie
|
|
||||||
sich diese Niemand aneinander drängen, diese vielen quer gestreckten
|
|
||||||
und eingehängten Arme, diese vielen Füße, durch winzige Schritte
|
|
||||||
getrennt! Versteht sich, daß alle in Frack sind. Wir gehen so lala,
|
|
||||||
der Wind fährt durch die Lücken, die wir und unsere Gliedmaßen offen
|
|
||||||
lassen. Die Hälse werden im Gebirge frei! Es ist ein Wunder, daß
|
|
||||||
wir nicht singen.“
|
|
||||||
|
|
||||||
Det var i den Tid, jeg gik omkring og sulted i Kristiania, denne forunderlige By,
|
|
||||||
som ingen forlader, før han har fået Mærker af den . . . .
|
|
||||||
Jeg ligger vågen på min Kvist og hører en Klokke nedenunder mig slå seks Slag; det var allerede ganske lyst,
|
|
||||||
og Folk begyndte at færdes op og ned i Trapperne. Nede ved Døren, hvor mit Rum var tapetseret med gamle Numre
|
|
||||||
af »Morgenbladet«, kunde jeg så tydelig se en Bekendtgørelse fra Fyrdirektøren, og lidt tilvenstre derfra et fedt,
|
|
||||||
bugnende Avertissement fra Bager Fabian Olsen om nybagt Brød.
|
|
||||||
|
|
||||||
The quick brown fox jumps over the lazy dog.
|
|
||||||
|
|
||||||
Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen Wolther spillede på xylofon.
|
|
||||||
|
|
||||||
Falsches Üben von Xylophonmusik quält jeden größeren Zwerg.
|
|
||||||
|
|
||||||
Ξεσκεπάζω τὴν ψυχοφθόρα βδελυγμία.
|
|
||||||
|
|
||||||
El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.
|
|
||||||
|
|
||||||
Le cœur déçu mais l'âme plutôt naïve, Louÿs rêva de crapaüter en
|
|
||||||
canoë au delà des îles, près du mälström où brûlent les novæ.
|
|
||||||
|
|
||||||
D'fhuascail Íosa, Úrmhac na hÓighe Beannaithe, pór Éava agus Ádhaimh.
|
|
||||||
|
|
||||||
Árvíztűrő tükörfúrógép.
|
|
||||||
|
|
||||||
Pchnąć w tę łódź jeża lub ośm skrzyń fig.
|
|
||||||
|
|
||||||
Kæmi ný öxi hér ykist þjófum nú bæði víl og ádrepa.
|
|
||||||
|
|
||||||
В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!
|
|
||||||
|
|
||||||
Pijamalı hasta, yağız şoföre çabucak güvendi.
|
|
||||||
|
|
||||||
Albert osti fagotin ja töräytti puhkuvan melodian.
|
|
||||||
|
|
||||||
דג סקרן שט בים מאוכזב ולפתע מצא חברה
|
|
||||||
|
|
||||||
نص حكيم له سر قاطع وذو شأن عظيم مكتوب على ثوب أخضر ومغلف بجلد أزرق
|
|
||||||
|
|
||||||
بر اثر چنین تلقین و شستشوی مغزی جامعی، سطح و پایهٔ ذهن و فهم و نظر بعضی اشخاص واژگونه و معکوس میشود
|
|
||||||
|
|
||||||
키스의 고유조건은 입술끼리 만나야 하고 특별한 기술은 필요치 않다.
|
|
||||||
|
|
||||||
いろはにほへとちりぬるを
|
|
||||||
わかよたれそつねならむ
|
|
||||||
うゐのおくやまけふこえて
|
|
||||||
あさきゆめみしゑひもせす
|
|
||||||
|
|
||||||
イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム
|
|
||||||
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン
|
|
||||||
|
|
||||||
ᚠᛇᚻ᛫ᛒᛦᚦ᛫ᚠᚱᚩᚠᚢᚱ᛫ᚠᛁᚱᚪ᛫ᚷᛖᚻᚹᛦᛚᚳᚢᛗ
|
|
||||||
ᛋᚳᛖᚪᛚ᛫ᚦᛖᚪᚻ᛫ᛗᚪᚾᚾᚪ᛫ᚷᛖᚻᚹᛦᛚᚳ᛫ᛗᛁᚳᛚᚢᚾ᛫ᚻᛦᛏ᛫ᛞᚫᛚᚪᚾ
|
|
||||||
ᚷᛁᚠ᛫ᚻᛖ᛫ᚹᛁᛚᛖ᛫ᚠᚩᚱ᛫ᛞᚱᛁᚻᛏᚾᛖ᛫ᛞᚩᛗᛖᛋ᛫ᚻᛚᛇᛏᚪᚾ᛬
|
|
||||||
@ -1,320 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include "guf_init.h" /* Must be included once (or compiled in a separate .c file and linked) */
|
|
||||||
|
|
||||||
#define GUF_ALLOC_LIBC_IMPL_STATIC
|
|
||||||
#include "guf_alloc_libc.h"
|
|
||||||
|
|
||||||
#include "guf_cstr.h"
|
|
||||||
#include "guf_linalg.h"
|
|
||||||
#include "guf_utils.h"
|
|
||||||
|
|
||||||
#define GUF_T float
|
|
||||||
#define GUF_SORT_IMPL_STATIC
|
|
||||||
#include "guf_sort.h"
|
|
||||||
|
|
||||||
#define GUF_T int
|
|
||||||
#define GUF_SORT_IMPL_STATIC
|
|
||||||
#include "guf_sort.h"
|
|
||||||
|
|
||||||
#define GUF_DBUF_NAME dbuf_int
|
|
||||||
#define GUF_T int
|
|
||||||
#define GUF_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DBUF_IMPL_STATIC
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_DBUF_NAME dbuf_float
|
|
||||||
#define GUF_T float
|
|
||||||
#define GUF_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DBUF_IMPL_STATIC
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_T guf_cstr_heap
|
|
||||||
#define GUF_DBUF_NAME dbuf_heap_cstr
|
|
||||||
#define GUF_T_COPY guf_cstr_heap_copy
|
|
||||||
#define GUF_T_MOVE guf_cstr_heap_move
|
|
||||||
#define GUF_T_FREE guf_cstr_heap_free
|
|
||||||
#define GUF_T_EQ guf_cstr_heap_eq
|
|
||||||
#define GUF_DBUF_IMPL_STATIC
|
|
||||||
// #define GUF_CNT_WITH_ELEM_CTX
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_T guf_cstr_const
|
|
||||||
#define GUF_DBUF_NAME dbuf_const_cstr
|
|
||||||
#define GUF_T_EQ guf_cstr_const_eq
|
|
||||||
#define GUF_DBUF_IMPL_STATIC
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_RAND_IMPL_STATIC
|
|
||||||
// #define GUF_RAND_32_BIT
|
|
||||||
#include "guf_rand.h"
|
|
||||||
|
|
||||||
#include "impls/dict_impl.h"
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
guf_allocator allocator;
|
|
||||||
guf_libc_alloc_ctx allocator_ctx;
|
|
||||||
guf_alloc_tracker_init(&allocator_ctx.tracker, 1, "example_allocator", NULL, NULL);
|
|
||||||
allocator_ctx.zero_init = false;
|
|
||||||
guf_libc_allocator_init(&allocator, &allocator_ctx);
|
|
||||||
|
|
||||||
printf("libguf example: " GUF_PLATFORM_STRING "\n");
|
|
||||||
guf_platform_assert_endianness();
|
|
||||||
guf_platform_assert_native_word_bits();
|
|
||||||
|
|
||||||
guf_allocator zero_init_allocator;
|
|
||||||
guf_libc_alloc_ctx zero_init_allocator_ctx;
|
|
||||||
guf_alloc_tracker_init(&zero_init_allocator_ctx.tracker, 2, "example_zero_init_allocator", stdout, stderr);
|
|
||||||
zero_init_allocator_ctx.zero_init = true;
|
|
||||||
guf_libc_allocator_init(&zero_init_allocator, &zero_init_allocator_ctx);
|
|
||||||
|
|
||||||
dict_cstr_int ht;
|
|
||||||
dict_cstr_int_init(&ht, &zero_init_allocator);
|
|
||||||
|
|
||||||
dict_cstr_int_insert_val_arg(&ht, "Hello", 42, GUF_CPY_VALUE, GUF_CPY_VALUE);
|
|
||||||
dict_cstr_int_insert_val_arg(&ht, "World", 64, GUF_CPY_VALUE, GUF_CPY_VALUE);
|
|
||||||
|
|
||||||
int kv_iter = 0;
|
|
||||||
GUF_CNT_FOREACH(&ht, dict_cstr_int, kv_it) {
|
|
||||||
printf("%d: %s -> %d\n", kv_iter++, kv_it.ptr->key, kv_it.ptr->val);
|
|
||||||
}
|
|
||||||
|
|
||||||
guf_cstr_const key = "World";
|
|
||||||
int *res = dict_cstr_int_at_val_arg(&ht, "World");
|
|
||||||
if (res) {
|
|
||||||
printf("%s: %d\n", key, *res);
|
|
||||||
} else {
|
|
||||||
printf("key '%s' not found\n", key);
|
|
||||||
}
|
|
||||||
|
|
||||||
GUF_ASSERT(dict_cstr_int_at_val_arg(&ht, "World"));
|
|
||||||
GUF_ASSERT(dict_cstr_int_at_val_arg(&ht, "Hello"));
|
|
||||||
GUF_ASSERT(dict_cstr_int_at_val_arg(&ht, "hello") == NULL);
|
|
||||||
GUF_ASSERT(dict_cstr_int_at_val_arg(&ht, "") == NULL);
|
|
||||||
|
|
||||||
GUF_ASSERT(dict_cstr_int_contains_val_arg(&ht, "World"));
|
|
||||||
GUF_ASSERT(dict_cstr_int_contains_val_arg(&ht, "Hello"));
|
|
||||||
|
|
||||||
const int ht_needle_val = 64;
|
|
||||||
const dict_cstr_int_iter ht_it = dict_cstr_int_find_val(&ht, dict_cstr_int_begin(&ht), dict_cstr_int_end(&ht), &ht_needle_val);
|
|
||||||
|
|
||||||
if (!dict_cstr_int_iter_is_end(&ht, ht_it)) {
|
|
||||||
printf("found value %d (key %s)\n", ht_needle_val, ht_it.ptr->key);
|
|
||||||
}
|
|
||||||
|
|
||||||
dict_cstr_int_free(&ht, NULL);
|
|
||||||
|
|
||||||
|
|
||||||
GUF_CNT_LIFETIME_BLOCK(dbuf_float, floats, {
|
|
||||||
floats = dbuf_float_new(&allocator);
|
|
||||||
|
|
||||||
for (int i = 0; i <= 16; ++i) {
|
|
||||||
dbuf_float_push_val(&floats, i % 2 ? (float)i * -2.f : (float)i * 2.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// float *tmp = test_allocator.alloc(floats.size * sizeof(float), &test_allocator_ctx);
|
|
||||||
// float *res = float_arr_merge_sort(floats.data, tmp, floats.size, GUF_SORT_ASCENDING, NULL);
|
|
||||||
// test_allocator.free(tmp, floats.size * sizeof(float), &test_allocator_ctx);
|
|
||||||
// GUF_ASSERT_RELEASE(res == floats.data);
|
|
||||||
|
|
||||||
float_arr_qsort(floats.data, floats.size, GUF_SORT_ASCENDING, NULL);
|
|
||||||
GUF_ASSERT_RELEASE(float_arr_is_sorted(floats.data, floats.size, GUF_SORT_ASCENDING, NULL));
|
|
||||||
|
|
||||||
GUF_CNT_FOREACH(&floats, dbuf_float, it) {
|
|
||||||
printf("float: %f\n", (double)*it.ptr);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
dbuf_heap_cstr strings = dbuf_heap_cstr_new(&allocator);
|
|
||||||
dbuf_heap_cstr_push_val_cpy(&strings, "Foo 1");
|
|
||||||
dbuf_heap_cstr_push_val_cpy(&strings, "Bar 2");
|
|
||||||
char *move_me = guf_cstr_dup("Baz 3");
|
|
||||||
dbuf_heap_cstr_push(&strings, &move_me, GUF_CPY_MOVE);
|
|
||||||
GUF_ASSERT_RELEASE(move_me == NULL);
|
|
||||||
|
|
||||||
dbuf_heap_cstr_push_val_cpy(&strings, "Boz 4");
|
|
||||||
|
|
||||||
char *findme = "Baz 3";
|
|
||||||
dbuf_heap_cstr_iter beg = dbuf_heap_cstr_begin(&strings);
|
|
||||||
dbuf_heap_cstr_iter end = dbuf_heap_cstr_end(&strings);
|
|
||||||
dbuf_heap_cstr_iter fnd_it = dbuf_heap_cstr_find(&strings, beg, end, &findme);
|
|
||||||
if (!dbuf_heap_cstr_iter_is_end(&strings, fnd_it)) {
|
|
||||||
printf("%s found in range [%td, %td) at idx %td\n", findme, dbuf_heap_cstr_iter_to_idx(&strings, beg), dbuf_heap_cstr_iter_to_idx(&strings, end), dbuf_heap_cstr_iter_to_idx(&strings, fnd_it));
|
|
||||||
} else {
|
|
||||||
printf("%s not found in range [%td, %td) at idx %td\n", findme, dbuf_heap_cstr_iter_to_idx(&strings, beg), dbuf_heap_cstr_iter_to_idx(&strings, end), dbuf_heap_cstr_iter_to_idx(&strings, fnd_it));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dbuf_heap_cstr_contains_val(&strings, "Baz 3")) {
|
|
||||||
printf("contains\n");
|
|
||||||
} else {
|
|
||||||
printf("does not contain\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
GUF_CNT_FOREACH(&strings, dbuf_heap_cstr, it) {
|
|
||||||
printf("%s\n", *it.ptr);
|
|
||||||
}
|
|
||||||
dbuf_heap_cstr_free(&strings, NULL);
|
|
||||||
|
|
||||||
dbuf_const_cstr const_strings = dbuf_const_cstr_new(&allocator);
|
|
||||||
dbuf_const_cstr_push_val(&const_strings, "Const 1");
|
|
||||||
dbuf_const_cstr_push_val(&const_strings, "Const 2");
|
|
||||||
const char *foo = "Const 3";
|
|
||||||
dbuf_const_cstr_push(&const_strings, &foo, GUF_CPY_VALUE);
|
|
||||||
|
|
||||||
dbuf_const_cstr_iter found_it = dbuf_const_cstr_find(&const_strings, dbuf_const_cstr_begin(&const_strings), dbuf_const_cstr_end(&const_strings), &foo);
|
|
||||||
if (found_it.ptr != dbuf_const_cstr_end(&const_strings).ptr) {
|
|
||||||
*found_it.ptr = "Found!";
|
|
||||||
}
|
|
||||||
|
|
||||||
GUF_CNT_FOREACH(&const_strings, dbuf_const_cstr, it) {
|
|
||||||
printf("%s\n", *it.ptr);
|
|
||||||
}
|
|
||||||
dbuf_const_cstr_free(&const_strings, NULL);
|
|
||||||
|
|
||||||
dbuf_int integers = dbuf_int_new(&allocator);
|
|
||||||
dbuf_int_push_val(&integers, 420);
|
|
||||||
dbuf_int_push_val(&integers, 520);
|
|
||||||
dbuf_int_push_val(&integers, 620);
|
|
||||||
dbuf_int_push_val(&integers, 720);
|
|
||||||
dbuf_int_push_val(&integers, 820);
|
|
||||||
|
|
||||||
guf_err err;
|
|
||||||
dbuf_int_try_at(&integers, 16, &err);
|
|
||||||
if (err) {
|
|
||||||
printf("%s %s\n", guf_err_to_str(err), GUF_ERR_MSG_EMPTY());
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
GUF_DBUF_FOREACH(integers, int, elem) {
|
|
||||||
printf("elem %d: %d\n", i, *elem);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
GUF_CNT_FOREACH(&integers, dbuf_int, it) {
|
|
||||||
printf("it-elem: %d", *it.ptr);
|
|
||||||
if (dbuf_int_iter_next(&integers, it, 1).ptr != dbuf_int_end(&integers).ptr) {
|
|
||||||
printf(", it-next: %d", *dbuf_int_iter_next(&integers, it, 1).ptr);
|
|
||||||
}
|
|
||||||
if (dbuf_int_iter_next(&integers, it, -1).ptr != dbuf_int_end(&integers).ptr) {
|
|
||||||
printf(", it-prev: %d", *dbuf_int_iter_next(&integers, it, -1).ptr);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (dbuf_int_iter it = dbuf_int_begin(&integers); it.ptr != dbuf_int_end(&integers).ptr; it = dbuf_int_iter_next(&integers, it, 2)) {
|
|
||||||
printf("every other: %d\n", *it.ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (dbuf_int_iter it = dbuf_int_rbegin(&integers); it.ptr != dbuf_int_rend(&integers).ptr; it = dbuf_int_iter_next(&integers, it, 1)) {
|
|
||||||
printf("reverse: %d\n", *it.ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (dbuf_int_iter it = dbuf_int_rbegin(&integers); it.ptr != dbuf_int_rend(&integers).ptr; it = dbuf_int_iter_next(&integers, it, 2)) {
|
|
||||||
printf("every other reverse: %d (idx %td)\n", *it.ptr, dbuf_int_iter_to_idx(&integers, it));
|
|
||||||
}
|
|
||||||
|
|
||||||
dbuf_int_free(&integers, NULL);
|
|
||||||
printf("\n");
|
|
||||||
guf_randstate rng;
|
|
||||||
guf_randstate_init(&rng, (guf_rand_seed_t)time(NULL));
|
|
||||||
int heads = 0, tails = 0;
|
|
||||||
int throws = 10;
|
|
||||||
for (i = 0; i < throws; ++i) {
|
|
||||||
bool is_head = guf_rand_flip(&rng);
|
|
||||||
if (is_head) {
|
|
||||||
puts("head");
|
|
||||||
++heads;
|
|
||||||
} else {
|
|
||||||
puts("tail");
|
|
||||||
++tails;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("n: %d\nheads: %d\ntails: %d\n", throws, heads, tails);
|
|
||||||
|
|
||||||
int result[256];
|
|
||||||
memset(result, 0, sizeof result);
|
|
||||||
for (int n = 0; n < 32000; ++n) {
|
|
||||||
float r = roundf(guf_rand_normal_sample_one_f32(&rng, 100, 15));
|
|
||||||
r = guf_clamp_f32(r, 0, 255);
|
|
||||||
result[(int)r] += 1;
|
|
||||||
}
|
|
||||||
for (size_t n = 60; n <= 140; ++n) {
|
|
||||||
printf("%zu:\t", n);
|
|
||||||
for (int j = 0; j < result[n] / 8; ++j) {
|
|
||||||
putc('#', stdout);
|
|
||||||
}
|
|
||||||
puts("");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (float angle = 0; angle <= 8.f * GUF_PI_F32; angle += 0.001f) {
|
|
||||||
guf_quaternion rotq = guf_quaternion_from_axis_angle(angle, guf_vec3_normalised((guf_vec3){-2324234.3f, 1.4f, -1.3f}));
|
|
||||||
guf_mat4x4 rotmat, rotmat_inv;
|
|
||||||
guf_mat4x4_init_from_quaternion(&rotmat, rotq);
|
|
||||||
GUF_ASSERT_RELEASE(guf_mat4x4_inverted(&rotmat, &rotmat_inv))
|
|
||||||
|
|
||||||
guf_mat4x4_set_trans(&rotmat, (guf_vec3){42.1234f, -512.2f, 3.1415926f});
|
|
||||||
GUF_ASSERT_RELEASE(guf_mat4x4_inverted(&rotmat, &rotmat_inv));
|
|
||||||
|
|
||||||
GUF_ASSERT_RELEASE(guf_mat4x4_inverted(&rotmat_inv, &rotmat));
|
|
||||||
GUF_ASSERT_RELEASE(guf_mat4x4_inverted(&rotmat, &rotmat_inv));
|
|
||||||
}
|
|
||||||
|
|
||||||
guf_quaternion q = guf_quaternion_from_axis_angle(GUF_PI_F32 / 8.f, guf_vec3_normalised((guf_vec3){0.3f, 10.2f, -25.f}));
|
|
||||||
|
|
||||||
guf_mat4x4 mat;
|
|
||||||
guf_mat4x4_init_from_quaternion(&mat, q);
|
|
||||||
guf_mat4x4_set_trans(&mat, (guf_vec3){42.1234f, -512.2f, 3.1415926f});
|
|
||||||
|
|
||||||
mat.data[2][0] *= 100000.4f;
|
|
||||||
|
|
||||||
const guf_mat4x4 mat_cpy = mat;
|
|
||||||
|
|
||||||
printf("Matrix:\n");
|
|
||||||
guf_mat4x4_print_with_precision(&mat, stdout, 8);
|
|
||||||
|
|
||||||
guf_mat4x4 mat_inv;
|
|
||||||
bool invertible = guf_mat4x4_inverted(&mat, &mat_inv);
|
|
||||||
if (!invertible) {
|
|
||||||
printf("Not invertible\n");
|
|
||||||
} else {
|
|
||||||
printf("Inverse:\n");
|
|
||||||
guf_mat4x4_print_with_precision(&mat_inv, stdout, 8);
|
|
||||||
GUF_ASSERT_RELEASE(guf_mat4x4_inverted(&mat_inv, &mat));
|
|
||||||
GUF_ASSERT_RELEASE(guf_mat4x4_nearly_equal(&mat, &mat_cpy, 1e-4f, 1e-5f));
|
|
||||||
}
|
|
||||||
|
|
||||||
mat = (guf_mat4x4) {.data = {
|
|
||||||
{1, 1.3f, 1, 1},
|
|
||||||
{2, 2.6f, 2, 2},
|
|
||||||
{0, 0, 2, 4},
|
|
||||||
{0, 0, 0, 1}
|
|
||||||
}};
|
|
||||||
printf("Matrix 2:\n");
|
|
||||||
guf_mat4x4_print_with_precision(&mat, stdout, 8);
|
|
||||||
invertible = guf_mat4x4_inverted(&mat, &mat_inv);
|
|
||||||
if (!invertible) {
|
|
||||||
printf("Not invertible\n");
|
|
||||||
} else {
|
|
||||||
printf("Inverse:\n");
|
|
||||||
guf_mat4x4_print_with_precision(&mat_inv, stdout, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool leak = false;
|
|
||||||
if (guf_alloc_tracker_found_leak(&allocator_ctx.tracker)) {
|
|
||||||
printf("Found memory leak:\n");
|
|
||||||
guf_alloc_tracker_print(&allocator_ctx.tracker, stderr);
|
|
||||||
leak = true;
|
|
||||||
}
|
|
||||||
if (guf_alloc_tracker_found_leak(&zero_init_allocator_ctx.tracker)) {
|
|
||||||
printf("Found memory leak:\n");
|
|
||||||
guf_alloc_tracker_print(&zero_init_allocator_ctx.tracker, stderr);
|
|
||||||
leak = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return leak ? EXIT_FAILURE: EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#define GUF_ALLOC_LIBC_IMPL
|
|
||||||
#include "guf_alloc_libc.h"
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#define GUF_ALLOC_TRACKER_IMPL
|
|
||||||
#include "guf_alloc_tracker.h"
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#define GUF_MATH_CKDINT_IMPL
|
|
||||||
#include "guf_math_ckdint.h"
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
#include "dbuf_impl.h"
|
|
||||||
|
|
||||||
#define GUF_DBUF_NAME dbuf_int
|
|
||||||
#define GUF_T int
|
|
||||||
#define GUF_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DBUF_IMPL
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_DBUF_NAME dbuf_i32
|
|
||||||
#define GUF_T int32_t
|
|
||||||
#define GUF_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DBUF_IMPL
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_DBUF_NAME dbuf_char
|
|
||||||
#define GUF_T char
|
|
||||||
#define GUF_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DBUF_IMPL
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_DBUF_NAME dbuf_float
|
|
||||||
#define GUF_T float
|
|
||||||
#define GUF_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DBUF_IMPL
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_T guf_cstr_heap
|
|
||||||
#define GUF_DBUF_NAME dbuf_heap_cstr
|
|
||||||
#define GUF_T_COPY guf_cstr_heap_copy
|
|
||||||
#define GUF_T_MOVE guf_cstr_heap_move
|
|
||||||
#define GUF_T_FREE guf_cstr_heap_free
|
|
||||||
#define GUF_T_EQ guf_cstr_heap_eq
|
|
||||||
#define GUF_DBUF_IMPL
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_T guf_cstr_const
|
|
||||||
#define GUF_DBUF_NAME dbuf_const_cstr
|
|
||||||
#define GUF_T_EQ guf_cstr_const_eq
|
|
||||||
#define GUF_DBUF_IMPL
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_T guf_str_view
|
|
||||||
#define GUF_DBUF_NAME dbuf_str_view
|
|
||||||
#define GUF_T_EQ guf_str_view_equal
|
|
||||||
#define GUF_DBUF_IMPL
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_T guf_str
|
|
||||||
#define GUF_DBUF_NAME dbuf_str
|
|
||||||
#define GUF_T_COPY guf_str_copy
|
|
||||||
#define GUF_T_MOVE guf_str_move
|
|
||||||
#define GUF_T_FREE guf_str_free
|
|
||||||
#define GUF_T_EQ guf_str_equal
|
|
||||||
#define GUF_DBUF_IMPL
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
#ifndef GUF_DBUF_IMPL_H
|
|
||||||
#define GUF_DBUF_IMPL_H
|
|
||||||
|
|
||||||
#include "guf_cstr.h"
|
|
||||||
#include "guf_str.h"
|
|
||||||
|
|
||||||
#define GUF_DBUF_NAME dbuf_int
|
|
||||||
#define GUF_T int
|
|
||||||
#define GUF_T_IS_INTEGRAL_TYPE
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_DBUF_NAME dbuf_i32
|
|
||||||
#define GUF_T int32_t
|
|
||||||
#define GUF_T_IS_INTEGRAL_TYPE
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_DBUF_NAME dbuf_char
|
|
||||||
#define GUF_T char
|
|
||||||
#define GUF_T_IS_INTEGRAL_TYPE
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_DBUF_NAME dbuf_float
|
|
||||||
#define GUF_T float
|
|
||||||
#define GUF_T_IS_INTEGRAL_TYPE
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_T guf_cstr_heap
|
|
||||||
#define GUF_DBUF_NAME dbuf_heap_cstr
|
|
||||||
#define GUF_T_COPY guf_cstr_heap_copy
|
|
||||||
#define GUF_T_MOVE guf_cstr_heap_move
|
|
||||||
#define GUF_T_FREE guf_cstr_heap_free
|
|
||||||
#define GUF_T_EQ guf_cstr_heap_eq
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_T guf_cstr_const
|
|
||||||
#define GUF_DBUF_NAME dbuf_const_cstr
|
|
||||||
#define GUF_T_EQ guf_cstr_const_eq
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_T guf_str_view
|
|
||||||
#define GUF_DBUF_NAME dbuf_str_view
|
|
||||||
#define GUF_T_EQ guf_str_view_equal
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#define GUF_T guf_str
|
|
||||||
#define GUF_DBUF_NAME dbuf_str
|
|
||||||
#define GUF_T_COPY guf_str_copy
|
|
||||||
#define GUF_T_MOVE guf_str_move
|
|
||||||
#define GUF_T_FREE guf_str_free
|
|
||||||
#define GUF_T_EQ guf_str_equal
|
|
||||||
#include "guf_dbuf.h"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
#include "dict_impl.h"
|
|
||||||
|
|
||||||
#define GUF_DICT_KEY_T guf_cstr_const
|
|
||||||
#define GUF_DICT_KEY_T_EQ guf_cstr_const_eq
|
|
||||||
#define GUF_DICT_KEY_HASH guf_cstr_const_hash
|
|
||||||
#define GUF_DICT_VAL_T int
|
|
||||||
#define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DICT_NAME dict_cstr_int
|
|
||||||
#define GUF_DICT_IMPL
|
|
||||||
#include "guf_dict.h"
|
|
||||||
|
|
||||||
#define GUF_DICT_KEY_T guf_str_view
|
|
||||||
#define GUF_DICT_KEY_HASH guf_str_view_hash
|
|
||||||
#define GUF_DICT_KEY_T_EQ guf_str_view_equal
|
|
||||||
#define GUF_DICT_VAL_T int32_t
|
|
||||||
#define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DICT_NAME dict_sv_i32
|
|
||||||
#define GUF_DICT_IMPL
|
|
||||||
// #define GUF_DICT_64_BIT_IDX
|
|
||||||
// #define GUF_DICT_PROBE_LINEAR
|
|
||||||
// #define GUF_DICT_32_BIT_HASH
|
|
||||||
#include "guf_dict.h"
|
|
||||||
|
|
||||||
#define GUF_DICT_KEY_T guf_str
|
|
||||||
#define GUF_DICT_KEY_HASH guf_str_hash
|
|
||||||
#define GUF_DICT_KEY_T_EQ guf_str_equal
|
|
||||||
#define GUF_DICT_KEY_T_CMP guf_str_cmp
|
|
||||||
#define GUF_DICT_KEY_T_COPY guf_str_copy
|
|
||||||
#define GUF_DICT_KEY_T_MOVE guf_str_move
|
|
||||||
#define GUF_DICT_KEY_T_FREE guf_str_free
|
|
||||||
#define GUF_DICT_VAL_T int32_t
|
|
||||||
#define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DICT_NAME dict_str_i32
|
|
||||||
#define GUF_DICT_IMPL
|
|
||||||
// #define GUF_DICT_64_BIT_IDX
|
|
||||||
// #define GUF_DICT_PROBE_LINEAR
|
|
||||||
// #define GUF_DICT_32_BIT_HASH
|
|
||||||
#include "guf_dict.h"
|
|
||||||
|
|
||||||
#define GUF_DICT_KEY_T int32_t
|
|
||||||
#define GUF_DICT_KEY_HASH int32_hash
|
|
||||||
#define GUF_DICT_KEY_T_EQ int32_eq
|
|
||||||
#define GUF_DICT_VAL_T bool
|
|
||||||
#define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DICT_NAME dict_i32_bool
|
|
||||||
#define GUF_DICT_IMPL
|
|
||||||
#include "guf_dict.h"
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
#ifndef GUF_DICT_IMPL_H
|
|
||||||
#define GUF_DICT_IMPL_H
|
|
||||||
|
|
||||||
#include "guf_common.h"
|
|
||||||
#include "guf_cstr.h"
|
|
||||||
#include "guf_str.h"
|
|
||||||
|
|
||||||
#include "guf_hash.h"
|
|
||||||
|
|
||||||
#define GUF_DICT_KEY_T guf_cstr_const
|
|
||||||
#define GUF_DICT_KEY_HASH guf_cstr_const_hash
|
|
||||||
#define GUF_DICT_KEY_T_EQ guf_cstr_const_eq
|
|
||||||
#define GUF_DICT_VAL_T int
|
|
||||||
#define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DICT_NAME dict_cstr_int
|
|
||||||
#include "guf_dict.h"
|
|
||||||
|
|
||||||
#define GUF_DICT_KEY_T guf_str_view
|
|
||||||
#define GUF_DICT_KEY_HASH guf_str_view_hash
|
|
||||||
#define GUF_DICT_KEY_T_EQ guf_str_view_equal
|
|
||||||
#define GUF_DICT_VAL_T int32_t
|
|
||||||
#define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DICT_NAME dict_sv_i32
|
|
||||||
// #define GUF_DICT_64_BIT_IDX
|
|
||||||
// #define GUF_DICT_PROBE_LINEAR
|
|
||||||
// #define GUF_DICT_32_BIT_HASH
|
|
||||||
#include "guf_dict.h"
|
|
||||||
|
|
||||||
#define GUF_DICT_KEY_T guf_str
|
|
||||||
#define GUF_DICT_KEY_HASH guf_str_hash
|
|
||||||
#define GUF_DICT_KEY_T_EQ guf_str_equal
|
|
||||||
#define GUF_DICT_KEY_T_CMP guf_str_cmp
|
|
||||||
#define GUF_DICT_KEY_T_COPY guf_str_copy
|
|
||||||
#define GUF_DICT_KEY_T_MOVE guf_str_move
|
|
||||||
#define GUF_DICT_KEY_T_FREE guf_str_free
|
|
||||||
#define GUF_DICT_VAL_T int32_t
|
|
||||||
#define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DICT_NAME dict_str_i32
|
|
||||||
// #define GUF_DICT_64_BIT_IDX
|
|
||||||
// #define GUF_DICT_PROBE_LINEAR
|
|
||||||
// #define GUF_DICT_32_BIT_HASH
|
|
||||||
#include "guf_dict.h"
|
|
||||||
|
|
||||||
static inline guf_hash_size_t int32_hash(const int32_t *a)
|
|
||||||
{
|
|
||||||
return guf_hash(a, sizeof(int32_t), GUF_HASH_INIT); // TODO: byte order...
|
|
||||||
}
|
|
||||||
static inline bool int32_eq(const int32_t *a, const int32_t *b)
|
|
||||||
{
|
|
||||||
return *a == *b;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GUF_DICT_KEY_T int32_t
|
|
||||||
#define GUF_DICT_KEY_HASH int32_hash
|
|
||||||
#define GUF_DICT_KEY_T_EQ int32_eq
|
|
||||||
#define GUF_DICT_VAL_T bool
|
|
||||||
#define GUF_DICT_VAL_T_IS_INTEGRAL_TYPE
|
|
||||||
#define GUF_DICT_NAME dict_i32_bool
|
|
||||||
#include "guf_dict.h"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1 +0,0 @@
|
|||||||
#include "guf_init.h"
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#define GUF_LINALG_IMPL
|
|
||||||
#include "guf_linalg.h"
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#define GUF_RAND_IMPL
|
|
||||||
#include "guf_rand.h"
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
#include "sort_impl.h"
|
|
||||||
|
|
||||||
#define GUF_T float
|
|
||||||
#define GUF_SORT_IMPL
|
|
||||||
#include "guf_sort.h"
|
|
||||||
|
|
||||||
#define GUF_T int32_t
|
|
||||||
#define GUF_SORT_IMPL
|
|
||||||
#include "guf_sort.h"
|
|
||||||
|
|
||||||
#define GUF_T int8_t
|
|
||||||
#define GUF_SORT_IMPL
|
|
||||||
#include "guf_sort.h"
|
|
||||||
|
|
||||||
#define GUF_T guf_cstr_heap
|
|
||||||
#define GUF_SORT_IMPL
|
|
||||||
#include "guf_sort.h"
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
#ifndef GUF_SORT_IMPL_H
|
|
||||||
#define GUF_SORT_IMPL_H
|
|
||||||
|
|
||||||
#include "guf_cstr.h"
|
|
||||||
|
|
||||||
#define GUF_T float
|
|
||||||
#include "guf_sort.h"
|
|
||||||
|
|
||||||
#define GUF_T int32_t
|
|
||||||
#include "guf_sort.h"
|
|
||||||
|
|
||||||
#define GUF_T int8_t
|
|
||||||
#include "guf_sort.h"
|
|
||||||
|
|
||||||
#define GUF_T guf_cstr_heap
|
|
||||||
#include "guf_sort.h"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#define GUF_STR_IMPL
|
|
||||||
#include "guf_str.h"
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "test_dbuf.hpp"
|
|
||||||
#include "test_dict.hpp"
|
|
||||||
#include "test_utf8.hpp"
|
|
||||||
#include "test_str.hpp"
|
|
||||||
#include "test_ckdint.hpp"
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include "guf_assert.h"
|
|
||||||
#include "guf_math.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<std::unique_ptr<Test>> g_tests {};
|
|
||||||
|
|
||||||
static void init_tests()
|
|
||||||
{
|
|
||||||
g_tests.push_back(std::make_unique<DbufIntTest>("DbufIntTest"));
|
|
||||||
g_tests.push_back(std::make_unique<DbufCstringTest>("DbufCstringTest"));
|
|
||||||
g_tests.push_back(std::make_unique<DbufStrTest>("DbufStrTest"));
|
|
||||||
|
|
||||||
g_tests.push_back(std::make_unique<DictSvToIntTest>("DictSvToIntTest"));
|
|
||||||
g_tests.push_back(std::make_unique<UTF8Test>("UTF8Test"));
|
|
||||||
g_tests.push_back(std::make_unique<StrTest>("StrTest"));
|
|
||||||
g_tests.push_back(std::make_unique<CkdIntTest>("CkdIntTest"));
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
init_tests();
|
|
||||||
|
|
||||||
std::cout << "Running " << g_tests.size() << " tests...\n";
|
|
||||||
|
|
||||||
// std::cout << "max cap 1:" << dict_sv_i32_max_capacity() << "\n";
|
|
||||||
// std::cout << "max cap 2:" << dict_cstr_int_max_capacity() << "\n";
|
|
||||||
|
|
||||||
size_t num_passed = 0;
|
|
||||||
for (auto &test : g_tests) {
|
|
||||||
Test *tst = test.get();
|
|
||||||
GUF_ASSERT_RELEASE(tst);
|
|
||||||
tst->before_run();
|
|
||||||
tst->run();
|
|
||||||
tst->after_run();
|
|
||||||
std::cout << "- " << *tst << "\n";
|
|
||||||
if (tst->passed) {
|
|
||||||
++num_passed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool passed_all = (num_passed == g_tests.size());
|
|
||||||
GUF_ASSERT_RELEASE(num_passed <= g_tests.size());
|
|
||||||
|
|
||||||
if (passed_all) {
|
|
||||||
std::cout << "-> SUCCESS: Passed all (" << num_passed << "/" << g_tests.size() << ") tests.\n";
|
|
||||||
} else {
|
|
||||||
std::cout << "-> FAILURE: Failed " << (g_tests.size() - num_passed) << "/" << g_tests.size() << " tests.\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return passed_all ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
@ -1,108 +0,0 @@
|
|||||||
#ifndef GUF_TEST_HPP
|
|
||||||
#define GUF_TEST_HPP
|
|
||||||
|
|
||||||
#include <stack>
|
|
||||||
#include <string>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <iostream>
|
|
||||||
#include <chrono>
|
|
||||||
#include <iomanip>
|
|
||||||
extern "C" {
|
|
||||||
#include "guf_common.h"
|
|
||||||
#include "guf_assert.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#define TEST_CHECK(COND) (check((COND), GUF_STRINGIFY(COND), __LINE__, __FILE__))
|
|
||||||
|
|
||||||
struct Test
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::chrono::steady_clock::time_point time_start, time_end;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::stack<std::string> check_name_stack;
|
|
||||||
std::string full_check_name = "";
|
|
||||||
|
|
||||||
void push_check_name(const std::string& check_name)
|
|
||||||
{
|
|
||||||
check_name_stack.push(check_name);
|
|
||||||
full_check_name = full_check_name + "::" + check_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pop_check_name()
|
|
||||||
{
|
|
||||||
const size_t sep_idx = full_check_name.rfind("::");
|
|
||||||
GUF_ASSERT_RELEASE(sep_idx != std::string::npos);
|
|
||||||
full_check_name = full_check_name.substr(0, sep_idx);
|
|
||||||
check_name_stack.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool check(bool cond, std::string_view msg, size_t line, std::string_view fname)
|
|
||||||
{
|
|
||||||
if (!cond) {
|
|
||||||
std::cerr << name << full_check_name << ": ";
|
|
||||||
std::cerr << "FAILED CHECK (" << msg << ") on line " << line << " in file " << fname << "\n"; \
|
|
||||||
++num_failed_checks;
|
|
||||||
} else {
|
|
||||||
++num_passed_checks;
|
|
||||||
}
|
|
||||||
return cond;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
const std::string name {};
|
|
||||||
std::chrono::duration<float, std::milli> runtime_ms {0};
|
|
||||||
bool passed {false}, done {false};
|
|
||||||
size_t num_failed_checks {0}, num_passed_checks {0};
|
|
||||||
|
|
||||||
Test(const std::string& nm) : name{nm} {}
|
|
||||||
virtual ~Test() = default;
|
|
||||||
|
|
||||||
size_t total_checks() const
|
|
||||||
{
|
|
||||||
return num_passed_checks + num_failed_checks;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void run() = 0;
|
|
||||||
|
|
||||||
void before_run()
|
|
||||||
{
|
|
||||||
time_start = std::chrono::steady_clock::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
void after_run()
|
|
||||||
{
|
|
||||||
done = true;
|
|
||||||
passed = (num_failed_checks == 0);
|
|
||||||
|
|
||||||
time_end = std::chrono::steady_clock::now();
|
|
||||||
runtime_ms = std::chrono::duration_cast<decltype(runtime_ms)>(time_end - time_start);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream &os, const Test& tst)
|
|
||||||
{
|
|
||||||
std::ios_base::fmtflags os_flags = os.flags();
|
|
||||||
std::streamsize os_precision = os.precision();
|
|
||||||
|
|
||||||
os << tst.name << ": " << (tst.passed ? "PASS" : "FAIL");
|
|
||||||
os << std::fixed << std::setprecision(2);
|
|
||||||
os << " (" << tst.num_passed_checks << "/" << tst.total_checks() << ") in " << tst.runtime_ms.count() << " ms";
|
|
||||||
|
|
||||||
os.precision(os_precision);
|
|
||||||
os.flags(os_flags);
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct std::hash<std::unique_ptr<Test>> {
|
|
||||||
std::size_t operator()(const std::unique_ptr<Test>& test) const
|
|
||||||
{
|
|
||||||
if (test.get() == nullptr) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return std::hash<std::string>()(test.get()->name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,361 +0,0 @@
|
|||||||
#include "test_ckdint.hpp"
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include "guf_math_ckdint.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
CkdIntTest:
|
|
||||||
*/
|
|
||||||
|
|
||||||
void CkdIntTest::run()
|
|
||||||
{
|
|
||||||
push_check_name("test_ckd");
|
|
||||||
test_ckd();
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
push_check_name("test_ckd_uint");
|
|
||||||
test_ckd_uint();
|
|
||||||
pop_check_name();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CkdIntTest::test_ckd()
|
|
||||||
{
|
|
||||||
for (int32_t a = INT8_MIN; a <= INT8_MAX; ++a) {
|
|
||||||
for (int32_t b = INT8_MIN; b <= INT8_MAX; ++b) {
|
|
||||||
const int32_t add_res = a + b;
|
|
||||||
const guf_math_ckd_result ckd_add = guf_ckd_add_i8((int8_t)a, (int8_t)b);
|
|
||||||
TEST_CHECK(ckd_add == guf_ckd_add_i8((int8_t)b, (int8_t)a));
|
|
||||||
TEST_CHECK(ckd_add == guf_ckd_add_least_i8((int_least8_t)a, (int_least8_t)b));
|
|
||||||
if (add_res > INT8_MAX) {
|
|
||||||
TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
int8_t saturated, saturated2;
|
|
||||||
TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(saturated == INT8_MAX);
|
|
||||||
TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(saturated == saturated2);
|
|
||||||
|
|
||||||
int8_t wrapped, wrapped2;
|
|
||||||
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MIN + (add_res % (INT8_MAX + 1)));
|
|
||||||
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(wrapped == wrapped2);
|
|
||||||
}
|
|
||||||
else if (add_res < INT8_MIN) {
|
|
||||||
TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
int8_t saturated, saturated2;
|
|
||||||
TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(saturated == INT8_MIN);
|
|
||||||
TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(saturated == saturated2);
|
|
||||||
|
|
||||||
int8_t wrapped, wrapped2;
|
|
||||||
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MAX - (-add_res % (-INT8_MIN + 1)));
|
|
||||||
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(wrapped == wrapped2);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
TEST_CHECK(ckd_add == GUF_MATH_CKD_SUCCESS);
|
|
||||||
int8_t saturated, saturated2;
|
|
||||||
TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(saturated) == add_res);
|
|
||||||
TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(saturated == saturated2);
|
|
||||||
|
|
||||||
int8_t wrapped, wrapped2;
|
|
||||||
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(wrapped) == add_res);
|
|
||||||
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(wrapped == wrapped2);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int32_t sub_res = a - b;
|
|
||||||
const guf_math_ckd_result ckd_sub = guf_ckd_sub_i8((int8_t)a, (int8_t)b);
|
|
||||||
TEST_CHECK(ckd_sub == guf_ckd_sub_least_i8((int_least8_t)a, (int_least8_t)b));
|
|
||||||
if (sub_res > INT8_MAX) {
|
|
||||||
TEST_CHECK(ckd_sub == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
int8_t saturated;
|
|
||||||
TEST_CHECK(guf_saturating_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(saturated == INT8_MAX);
|
|
||||||
int8_t wrapped;
|
|
||||||
TEST_CHECK(guf_wrapping_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MIN + (sub_res % (INT8_MAX + 1)));
|
|
||||||
} else if (sub_res < INT8_MIN) {
|
|
||||||
TEST_CHECK(ckd_sub == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
int8_t saturated;
|
|
||||||
TEST_CHECK(guf_saturating_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(saturated == INT8_MIN);
|
|
||||||
int8_t wrapped;
|
|
||||||
TEST_CHECK(guf_wrapping_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MAX - (-sub_res % (-INT8_MIN + 1)));
|
|
||||||
} else {
|
|
||||||
TEST_CHECK(ckd_sub == GUF_MATH_CKD_SUCCESS);
|
|
||||||
int8_t saturated;
|
|
||||||
TEST_CHECK(guf_saturating_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(saturated) == sub_res);
|
|
||||||
int8_t wrapped;
|
|
||||||
TEST_CHECK(guf_wrapping_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(wrapped) == sub_res);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int32_t mul_res = a * b;
|
|
||||||
const guf_math_ckd_result ckd_mul = guf_ckd_mul_i8((int8_t)a, (int8_t)b);
|
|
||||||
TEST_CHECK(ckd_mul == guf_ckd_mul_least_i8((int_least8_t)a, (int_least8_t)b));
|
|
||||||
TEST_CHECK(ckd_mul == guf_ckd_mul_i8((int8_t)b, (int8_t)a));
|
|
||||||
if (mul_res > INT8_MAX) {
|
|
||||||
TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
int8_t saturated, saturated2;
|
|
||||||
TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(saturated == INT8_MAX);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(saturated == saturated2);
|
|
||||||
|
|
||||||
int8_t wrapped, wrapped2;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(wrapped == wrapped2);
|
|
||||||
// TODO: check wrapped
|
|
||||||
} else if (mul_res < INT8_MIN) {
|
|
||||||
TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
int8_t saturated, saturated2;
|
|
||||||
TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(saturated == INT8_MIN);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(saturated == saturated2);
|
|
||||||
|
|
||||||
int8_t wrapped, wrapped2;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(wrapped == wrapped2);
|
|
||||||
// TODO: check wrapped
|
|
||||||
} else {
|
|
||||||
TEST_CHECK(ckd_mul == GUF_MATH_CKD_SUCCESS);
|
|
||||||
int8_t saturated, saturated2;
|
|
||||||
TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(saturated) == mul_res);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(saturated == saturated2);
|
|
||||||
|
|
||||||
int8_t wrapped, wrapped2;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(wrapped) == mul_res);
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(wrapped == wrapped2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int8_t mul_i8_res = -1;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i8(42, 5, &mul_i8_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(mul_i8_res == -46);
|
|
||||||
mul_i8_res = -1;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i8(5, 42, &mul_i8_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(mul_i8_res == -46);
|
|
||||||
|
|
||||||
int16_t mul_i16_res = -1245;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i16(32767, 2, &mul_i16_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(mul_i16_res == -2);
|
|
||||||
mul_i16_res = -1245;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i16(-32767, 2, &mul_i16_res) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(mul_i16_res == 2);
|
|
||||||
/*
|
|
||||||
// https://play.rust-lang.org/?version=stable&mode=debug&edition=2024
|
|
||||||
|
|
||||||
use std::num::Wrapping;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let a = Wrapping(-314159265_i32);
|
|
||||||
let b = Wrapping(4096_i32);
|
|
||||||
println!("{}", a * b);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
int32_t mul_i32_res = -12345;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i32(INT32_MAX, 2, &mul_i32_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(mul_i32_res == -2);
|
|
||||||
mul_i32_res = -12345;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i32(2, INT32_MAX, &mul_i32_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(mul_i32_res == -2);
|
|
||||||
|
|
||||||
mul_i32_res = -12345;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i32(INT32_MAX, -2, &mul_i32_res) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(mul_i32_res == 2);
|
|
||||||
mul_i32_res = -12345;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i32(-2, INT32_MAX, &mul_i32_res) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(mul_i32_res == 2);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i32(42002718, 314159265, &mul_i32_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(mul_i32_res == -972735522);
|
|
||||||
mul_i32_res = -12345;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_i32(314159265, 42002718, &mul_i32_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(mul_i32_res == -972735522);
|
|
||||||
|
|
||||||
mul_i32_res = 12345;
|
|
||||||
guf_wrapping_mul_i32(42002718, 314159265, &mul_i32_res);
|
|
||||||
TEST_CHECK(mul_i32_res == -972735522);
|
|
||||||
|
|
||||||
mul_i32_res = 12345;
|
|
||||||
guf_wrapping_mul_i32(-42002718, 314159265, &mul_i32_res);
|
|
||||||
TEST_CHECK(mul_i32_res == 972735522);
|
|
||||||
|
|
||||||
mul_i32_res = 12345;
|
|
||||||
guf_wrapping_mul_i32(-88888888, 99999999, &mul_i32_res);
|
|
||||||
TEST_CHECK(mul_i32_res == 1374494264);
|
|
||||||
|
|
||||||
mul_i32_res = 12345;
|
|
||||||
guf_wrapping_mul_i32(INT32_MIN, -1, &mul_i32_res);
|
|
||||||
TEST_CHECK(mul_i32_res == INT32_MIN);
|
|
||||||
|
|
||||||
mul_i32_res = 12345;
|
|
||||||
guf_wrapping_mul_i32(-2147483648, 2147483640, &mul_i32_res);
|
|
||||||
TEST_CHECK(mul_i32_res == 0);
|
|
||||||
|
|
||||||
mul_i32_res = 12345;
|
|
||||||
guf_wrapping_mul_i32(-2048, -314159265, &mul_i32_res);
|
|
||||||
TEST_CHECK(mul_i32_res == -846919680);
|
|
||||||
|
|
||||||
mul_i32_res = 12345;
|
|
||||||
guf_wrapping_mul_i32(4096, -314159265, &mul_i32_res);
|
|
||||||
TEST_CHECK(mul_i32_res == 1693839360);
|
|
||||||
|
|
||||||
|
|
||||||
int_least32_t mul_i32least_res = -12345;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_least_i32(INT32_MAX, 2, &mul_i32least_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(mul_i32least_res == -2);
|
|
||||||
mul_i32least_res = -12345;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_least_i32(2, INT32_MAX, &mul_i32least_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(mul_i32least_res == -2);
|
|
||||||
|
|
||||||
mul_i32least_res = -12345;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_least_i32(INT32_MAX, -2, &mul_i32least_res) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(mul_i32least_res == 2);
|
|
||||||
mul_i32least_res = -12345;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_least_i32(-2, INT32_MAX, &mul_i32least_res) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(mul_i32least_res == 2);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_wrapping_mul_least_i32(42002718, 314159265, &mul_i32least_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(mul_i32least_res == -972735522);
|
|
||||||
mul_i32least_res = -12345;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_least_i32(314159265, 42002718, &mul_i32least_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(mul_i32least_res == -972735522);
|
|
||||||
|
|
||||||
mul_i32least_res = 12345;
|
|
||||||
guf_wrapping_mul_least_i32(42002718, 314159265, &mul_i32least_res);
|
|
||||||
TEST_CHECK(mul_i32least_res == -972735522);
|
|
||||||
|
|
||||||
mul_i32least_res = 12345;
|
|
||||||
guf_wrapping_mul_least_i32(-42002718, 314159265, &mul_i32least_res);
|
|
||||||
TEST_CHECK(mul_i32least_res == 972735522);
|
|
||||||
|
|
||||||
mul_i32least_res = 12345;
|
|
||||||
guf_wrapping_mul_least_i32(-88888888, 99999999, &mul_i32least_res);
|
|
||||||
TEST_CHECK(mul_i32least_res == 1374494264);
|
|
||||||
|
|
||||||
mul_i32least_res = 12345;
|
|
||||||
guf_wrapping_mul_least_i32(INT32_MIN, -1, &mul_i32least_res);
|
|
||||||
TEST_CHECK(mul_i32least_res == INT32_MIN);
|
|
||||||
|
|
||||||
mul_i32least_res = 12345;
|
|
||||||
guf_wrapping_mul_least_i32(-2147483648, 2147483640, &mul_i32least_res);
|
|
||||||
TEST_CHECK(mul_i32least_res == 0);
|
|
||||||
|
|
||||||
mul_i32least_res = 12345;
|
|
||||||
guf_wrapping_mul_least_i32(-2048, -314159265, &mul_i32least_res);
|
|
||||||
TEST_CHECK(mul_i32least_res == -846919680);
|
|
||||||
|
|
||||||
mul_i32least_res = 12345;
|
|
||||||
guf_wrapping_mul_least_i32(4096, -314159265, &mul_i32least_res);
|
|
||||||
TEST_CHECK(mul_i32least_res == 1693839360);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ptrdiff_t ptrdiff_res = -1234;
|
|
||||||
TEST_CHECK(guf_saturating_add_ptrdiff_t(PTRDIFF_MAX, 1, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(ptrdiff_res == PTRDIFF_MAX);
|
|
||||||
ptrdiff_res = -1234;
|
|
||||||
TEST_CHECK(guf_saturating_add_ptrdiff_t(PTRDIFF_MIN, -1, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(ptrdiff_res == PTRDIFF_MIN);
|
|
||||||
|
|
||||||
ptrdiff_res = -1234;
|
|
||||||
TEST_CHECK(guf_saturating_mul_ptrdiff_t(PTRDIFF_MAX, 2, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(ptrdiff_res == PTRDIFF_MAX);
|
|
||||||
ptrdiff_res = -1234;
|
|
||||||
TEST_CHECK(guf_saturating_mul_ptrdiff_t(PTRDIFF_MIN, 2, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(ptrdiff_res == PTRDIFF_MIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CkdIntTest::test_ckd_uint()
|
|
||||||
{
|
|
||||||
for (int32_t a = 0; a <= UINT8_MAX; ++a) {
|
|
||||||
for (int32_t b = 0; b <= UINT8_MAX; ++b) {
|
|
||||||
const int32_t add_res = a + b;
|
|
||||||
const guf_math_ckd_result ckd_add = guf_ckd_add_u8((uint8_t)a, (uint8_t)b);
|
|
||||||
GUF_ASSERT(ckd_add == guf_ckd_add_least_u8((uint_least8_t)a, (uint_least8_t)b));
|
|
||||||
if (add_res > UINT8_MAX) {
|
|
||||||
TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
uint8_t saturated;
|
|
||||||
TEST_CHECK(guf_saturating_add_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(saturated == UINT8_MAX);
|
|
||||||
uint8_t wrapped;
|
|
||||||
TEST_CHECK(guf_wrapping_add_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(wrapped) == 0 + (add_res % (UINT8_MAX + 1)));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
TEST_CHECK(ckd_add == GUF_MATH_CKD_SUCCESS);
|
|
||||||
uint8_t saturated;
|
|
||||||
TEST_CHECK(guf_saturating_add_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(saturated) == add_res);
|
|
||||||
uint8_t wrapped;
|
|
||||||
TEST_CHECK(guf_wrapping_add_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(wrapped) == add_res);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int32_t sub_res = a - b;
|
|
||||||
const guf_math_ckd_result ckd_sub = guf_ckd_sub_u8((uint8_t)a, (uint8_t)b);
|
|
||||||
GUF_ASSERT(ckd_sub == guf_ckd_sub_least_u8((uint_least8_t)a, (uint_least8_t)b));
|
|
||||||
if (sub_res < 0) {
|
|
||||||
TEST_CHECK(ckd_sub == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
uint8_t saturated;
|
|
||||||
TEST_CHECK(guf_saturating_sub_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(saturated == 0);
|
|
||||||
uint8_t wrapped;
|
|
||||||
TEST_CHECK(guf_wrapping_sub_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_NEG);
|
|
||||||
TEST_CHECK(wrapped == static_cast<uint8_t>(static_cast<uint8_t>(a) - static_cast<uint8_t>(b)));
|
|
||||||
} else {
|
|
||||||
TEST_CHECK(ckd_sub == GUF_MATH_CKD_SUCCESS);
|
|
||||||
uint8_t saturated;
|
|
||||||
TEST_CHECK(guf_saturating_sub_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(saturated) == sub_res);
|
|
||||||
uint8_t wrapped;
|
|
||||||
TEST_CHECK(guf_wrapping_sub_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(wrapped) == sub_res);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int32_t mul_res = a * b;
|
|
||||||
const guf_math_ckd_result ckd_mul = guf_ckd_mul_u8((uint8_t)a, (uint8_t)b);
|
|
||||||
GUF_ASSERT(ckd_mul == guf_ckd_mul_least_u8((uint_least8_t)a, (uint_least8_t)b));
|
|
||||||
if (mul_res > UINT8_MAX) {
|
|
||||||
TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
uint8_t saturated;
|
|
||||||
TEST_CHECK(guf_saturating_mul_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(saturated == UINT8_MAX);
|
|
||||||
uint8_t wrapped;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_POS);
|
|
||||||
TEST_CHECK(wrapped == static_cast<uint8_t>(static_cast<uint8_t>(a) * static_cast<uint8_t>(b)));
|
|
||||||
} else {
|
|
||||||
TEST_CHECK(ckd_mul == GUF_MATH_CKD_SUCCESS);
|
|
||||||
uint8_t saturated;
|
|
||||||
TEST_CHECK(guf_saturating_mul_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(saturated) == mul_res);
|
|
||||||
uint8_t wrapped;
|
|
||||||
TEST_CHECK(guf_wrapping_mul_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_SUCCESS);
|
|
||||||
TEST_CHECK(static_cast<int32_t>(wrapped) == mul_res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "test.hpp"
|
|
||||||
|
|
||||||
struct CkdIntTest : public Test
|
|
||||||
{
|
|
||||||
CkdIntTest(const std::string& nm) : Test(nm) {};
|
|
||||||
void run() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void test_ckd();
|
|
||||||
void test_ckd_uint();
|
|
||||||
};
|
|
||||||
@ -1,685 +0,0 @@
|
|||||||
#include "test_dbuf.hpp"
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include "guf_alloc_libc.h"
|
|
||||||
#include "impls/dbuf_impl.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
DbufIntTest
|
|
||||||
*/
|
|
||||||
|
|
||||||
void DbufIntTest::run()
|
|
||||||
{
|
|
||||||
if (done) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// allocator_ctx.tracker.log = fopen("alloc_log.txt", "w");
|
|
||||||
// allocator_ctx.tracker.err_log = fopen("alloc_err_log.txt", "w");
|
|
||||||
|
|
||||||
dbuf_int dbuf {};
|
|
||||||
dbuf_int_init(&dbuf, 0, &allocator);
|
|
||||||
|
|
||||||
push_check_name("test_push");
|
|
||||||
|
|
||||||
test_push(&dbuf, 256);
|
|
||||||
test_push(&dbuf, 128);
|
|
||||||
test_push(&dbuf, 17);
|
|
||||||
TEST_CHECK(dbuf.size == (256 + 128 + 17));
|
|
||||||
|
|
||||||
dbuf_int_free(&dbuf, NULL);
|
|
||||||
TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 0 && dbuf.data == NULL);
|
|
||||||
|
|
||||||
dbuf_int_init(&dbuf, 24, &allocator);
|
|
||||||
TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 24 && dbuf.data);
|
|
||||||
|
|
||||||
test_push(&dbuf, 365);
|
|
||||||
test_push(&dbuf, 4);
|
|
||||||
test_push(&dbuf, 25);
|
|
||||||
test_push(&dbuf, 64);
|
|
||||||
TEST_CHECK(dbuf.size == (365 + 4 + 25 + 64));
|
|
||||||
|
|
||||||
dbuf_int_free(&dbuf, NULL);
|
|
||||||
TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 0 && dbuf.data == NULL);
|
|
||||||
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
push_check_name("insert_remove");
|
|
||||||
|
|
||||||
for (int n = 0; n <= 128; ++n) {
|
|
||||||
test_insert_remove(n);
|
|
||||||
}
|
|
||||||
test_insert_remove(400);
|
|
||||||
test_insert_remove(401);
|
|
||||||
test_insert_remove(512);
|
|
||||||
test_insert_remove(513);
|
|
||||||
test_insert_remove(601);
|
|
||||||
test_insert_remove(2048);
|
|
||||||
test_insert_remove(2049);
|
|
||||||
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
TEST_CHECK(!guf_alloc_tracker_found_leak(&allocator_ctx.tracker));
|
|
||||||
// guf_alloc_tracker_print(&allocator_ctx.tracker, stdout);
|
|
||||||
// puts("");
|
|
||||||
// fclose(allocator_ctx.tracker.log);
|
|
||||||
// fclose(allocator_ctx.tracker.err_log);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int> DbufIntTest::dbuf_to_vec(dbuf_int *dbuf)
|
|
||||||
{
|
|
||||||
std::vector<int> vec;
|
|
||||||
GUF_CNT_FOREACH(dbuf, dbuf_int, it) {
|
|
||||||
vec.push_back(*it.ptr);
|
|
||||||
}
|
|
||||||
return vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DbufIntTest::test_push(dbuf_int *dbuf, int n)
|
|
||||||
{
|
|
||||||
std::vector<int> vec = dbuf_to_vec(dbuf);
|
|
||||||
|
|
||||||
TEST_CHECK(std::ssize(vec) == dbuf->size);
|
|
||||||
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
dbuf_int_push_val(dbuf, i);
|
|
||||||
vec.push_back(i);
|
|
||||||
TEST_CHECK(*dbuf_int_back(dbuf) == vec.back());
|
|
||||||
}
|
|
||||||
|
|
||||||
ptrdiff_t i = 0;
|
|
||||||
GUF_CNT_FOREACH(dbuf, dbuf_int, it) {
|
|
||||||
TEST_CHECK(*it.ptr == vec.at(i++));
|
|
||||||
}
|
|
||||||
TEST_CHECK(i == dbuf->size);
|
|
||||||
|
|
||||||
i = dbuf->size - 1;
|
|
||||||
GUF_CNT_FOREACH_REVERSE(dbuf, dbuf_int, rit) {
|
|
||||||
TEST_CHECK(*rit.ptr == vec.at(i--));
|
|
||||||
}
|
|
||||||
TEST_CHECK(i == -1);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void DbufIntTest::test_insert_remove(int n)
|
|
||||||
{
|
|
||||||
dbuf_int dbuf = {};
|
|
||||||
dbuf_int_init(&dbuf, 0, &allocator);
|
|
||||||
std::vector<int> vec = dbuf_to_vec(&dbuf);
|
|
||||||
|
|
||||||
guf_err err = GUF_ERR_NONE;
|
|
||||||
dbuf_int_try_erase(&dbuf, 0, &err);
|
|
||||||
TEST_CHECK(err == GUF_ERR_IDX_RANGE);
|
|
||||||
|
|
||||||
err = GUF_ERR_NONE;
|
|
||||||
dbuf_int_try_erase(&dbuf, 12, &err);
|
|
||||||
TEST_CHECK(err == GUF_ERR_IDX_RANGE);
|
|
||||||
|
|
||||||
err = GUF_ERR_NONE;
|
|
||||||
dbuf_int_try_front(&dbuf, &err);
|
|
||||||
TEST_CHECK(err == GUF_ERR_IDX_RANGE);
|
|
||||||
|
|
||||||
err = GUF_ERR_NONE;
|
|
||||||
dbuf_int_try_back(&dbuf, &err);
|
|
||||||
TEST_CHECK(err == GUF_ERR_IDX_RANGE);
|
|
||||||
|
|
||||||
err = GUF_ERR_NONE;
|
|
||||||
dbuf_int_try_at(&dbuf, 0, &err);
|
|
||||||
TEST_CHECK(err == GUF_ERR_IDX_RANGE);
|
|
||||||
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
dbuf_int_insert_val(&dbuf, i, i);
|
|
||||||
dbuf_int_insert_val(&dbuf, i * 2, 0);
|
|
||||||
dbuf_int_insert_val(&dbuf, i * 4, dbuf.size);
|
|
||||||
|
|
||||||
vec.insert(vec.begin() + i, i);
|
|
||||||
vec.insert(vec.begin(), i * 2);
|
|
||||||
vec.insert(vec.end(), i * 4);
|
|
||||||
}
|
|
||||||
TEST_CHECK(std::ssize(vec) == dbuf.size);
|
|
||||||
|
|
||||||
// Iterate
|
|
||||||
dbuf_int_iter it_dbuf = dbuf_int_begin(&dbuf);
|
|
||||||
std::vector<int>::const_iterator it_vec = vec.begin();
|
|
||||||
while (!dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec != vec.end()) {
|
|
||||||
TEST_CHECK(*it_dbuf.ptr == *it_vec);
|
|
||||||
it_dbuf = dbuf_int_iter_next(&dbuf, it_dbuf, 1);
|
|
||||||
std::advance(it_vec, 1);
|
|
||||||
}
|
|
||||||
TEST_CHECK(dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec == vec.end());
|
|
||||||
|
|
||||||
// Step iterate.
|
|
||||||
it_dbuf = dbuf_int_begin(&dbuf);
|
|
||||||
it_vec = vec.begin();
|
|
||||||
while (!dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec != vec.end()) {
|
|
||||||
TEST_CHECK(*it_dbuf.ptr == *it_vec);
|
|
||||||
it_dbuf = dbuf_int_iter_next(&dbuf, it_dbuf, 7);
|
|
||||||
|
|
||||||
if (dbuf_int_iter_is_end(&dbuf, it_dbuf)) {
|
|
||||||
it_vec = vec.end();
|
|
||||||
} else {
|
|
||||||
std::advance(it_vec, 7);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST_CHECK(dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec == vec.end());
|
|
||||||
|
|
||||||
// Reverse iterate.
|
|
||||||
dbuf_int_iter rit_dbuf = dbuf_int_rbegin(&dbuf);
|
|
||||||
std::vector<int>::const_reverse_iterator rit_vec = vec.crbegin();
|
|
||||||
while (!dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec != vec.crend()) {
|
|
||||||
TEST_CHECK(*rit_dbuf.ptr == *rit_vec);
|
|
||||||
rit_dbuf = dbuf_int_iter_next(&dbuf, rit_dbuf, 1);
|
|
||||||
std::advance(rit_vec, 1);
|
|
||||||
}
|
|
||||||
TEST_CHECK(dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec == vec.rend());
|
|
||||||
|
|
||||||
// Reverse iterate step.
|
|
||||||
rit_dbuf = dbuf_int_rbegin(&dbuf);
|
|
||||||
rit_vec = vec.crbegin();
|
|
||||||
while (!dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec != vec.crend()) {
|
|
||||||
TEST_CHECK(*rit_dbuf.ptr == *rit_vec);
|
|
||||||
rit_dbuf = dbuf_int_iter_next(&dbuf, rit_dbuf, 4);
|
|
||||||
if (dbuf_int_iter_is_end(&dbuf, rit_dbuf)) {
|
|
||||||
rit_vec = vec.rend();
|
|
||||||
} else {
|
|
||||||
std::advance(rit_vec, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST_CHECK(dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec == vec.rend());
|
|
||||||
|
|
||||||
TEST_CHECK(dbuf.size == std::ssize(vec));
|
|
||||||
|
|
||||||
for (ptrdiff_t i = 0; i < dbuf.size; i += 8) {
|
|
||||||
dbuf_int_erase(&dbuf, i);
|
|
||||||
dbuf_int_erase(&dbuf, 0);
|
|
||||||
dbuf_int_pop(&dbuf);
|
|
||||||
|
|
||||||
vec.erase(vec.begin() + i);
|
|
||||||
vec.erase(vec.begin() + 0);
|
|
||||||
vec.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CHECK(dbuf.size == std::ssize(vec));
|
|
||||||
|
|
||||||
for (ptrdiff_t i = 0; i < dbuf.size; i += 8) {
|
|
||||||
TEST_CHECK(*dbuf_int_at(&dbuf, i) == vec.at(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
const ptrdiff_t size = dbuf.size;
|
|
||||||
for (ptrdiff_t i = 0; i < size; ++i) {
|
|
||||||
int a = dbuf_int_pop_move(&dbuf);
|
|
||||||
int b = vec.back();
|
|
||||||
TEST_CHECK(a == b);
|
|
||||||
vec.pop_back();
|
|
||||||
}
|
|
||||||
TEST_CHECK(dbuf.size == 0 && vec.size() == 0);
|
|
||||||
|
|
||||||
dbuf_int_free(&dbuf, NULL);
|
|
||||||
TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 0 && !dbuf.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
DbufCstringTest
|
|
||||||
*/
|
|
||||||
|
|
||||||
void DbufCstringTest::run()
|
|
||||||
{
|
|
||||||
if (done) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// allocator_ctx.tracker.log = fopen("alloc_log.txt", "w");
|
|
||||||
// allocator_ctx.tracker.err_log = fopen("alloc_err_log.txt", "w");
|
|
||||||
|
|
||||||
push_check_name("push_insert_erase");
|
|
||||||
|
|
||||||
for (int i = 1; i <= 32; ++i) {
|
|
||||||
test_push_insert_erase(i);
|
|
||||||
test_push_insert_erase(i, i - 1);
|
|
||||||
test_push_insert_erase(i, i + 1);
|
|
||||||
test_push_insert_erase(i, i);
|
|
||||||
test_push_insert_erase(i, i / 2);
|
|
||||||
}
|
|
||||||
test_push_insert_erase(2048);
|
|
||||||
test_push_insert_erase(2048, 11);
|
|
||||||
|
|
||||||
dbuf_heap_cstr str_dbuf = {};
|
|
||||||
dbuf_heap_cstr_init(&str_dbuf, 0, &allocator);
|
|
||||||
std::vector<std::string> str_vec {};
|
|
||||||
|
|
||||||
for (int i = 0; i < 512; ++i) {
|
|
||||||
char buf[128];
|
|
||||||
memset(buf, '\0', GUF_ARR_SIZE(buf));
|
|
||||||
snprintf(buf, GUF_ARR_SIZE(buf), "This is a pretty guf string (number %d)", i);
|
|
||||||
guf_cstr_heap str = buf;
|
|
||||||
dbuf_heap_cstr_push(&str_dbuf, &str, GUF_CPY_DEEP);
|
|
||||||
str_vec.push_back(std::string{buf});
|
|
||||||
}
|
|
||||||
for (int i = 0; i < str_dbuf.size + 16; ++i) {
|
|
||||||
test_iter(str_vec, &str_dbuf, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
dbuf_heap_cstr_free(&str_dbuf, NULL);
|
|
||||||
TEST_CHECK(str_dbuf.size == 0 && str_dbuf.capacity == 0 && !str_dbuf.data);
|
|
||||||
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
push_check_name("find");
|
|
||||||
test_find();
|
|
||||||
test_find(3);
|
|
||||||
test_find(42);
|
|
||||||
test_find(129);
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
TEST_CHECK(!guf_alloc_tracker_found_leak(&allocator_ctx.tracker));
|
|
||||||
// guf_alloc_tracker_print(&allocator_ctx.tracker, stdout);
|
|
||||||
// puts("");
|
|
||||||
// fclose(allocator_ctx.tracker.log);
|
|
||||||
// fclose(allocator_ctx.tracker.err_log);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DbufCstringTest::test_iter(std::vector<std::string>& str_vec, dbuf_heap_cstr *str_dbuf, int step)
|
|
||||||
{
|
|
||||||
GUF_ASSERT_RELEASE(str_dbuf);
|
|
||||||
if (step <= 0) {
|
|
||||||
step = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptrdiff_t i = 0;
|
|
||||||
GUF_CNT_FOREACH(str_dbuf, dbuf_heap_cstr, it) {
|
|
||||||
char *str = *it.ptr;
|
|
||||||
TEST_CHECK(str_vec.at(i) == str);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
TEST_CHECK(i == str_dbuf->size);
|
|
||||||
|
|
||||||
i = str_dbuf->size - 1;
|
|
||||||
GUF_CNT_FOREACH_REVERSE(str_dbuf, dbuf_heap_cstr, rit) {
|
|
||||||
char *str = *rit.ptr;
|
|
||||||
TEST_CHECK(str_vec.at(i) == str);
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
TEST_CHECK(i == -1);
|
|
||||||
|
|
||||||
dbuf_heap_cstr_iter it_dbuf = dbuf_heap_cstr_begin(str_dbuf);
|
|
||||||
std::vector<std::string>::iterator it_vec = str_vec.begin();
|
|
||||||
while (!dbuf_heap_cstr_iter_is_end(str_dbuf, it_dbuf)) {
|
|
||||||
TEST_CHECK(it_vec != str_vec.end());
|
|
||||||
TEST_CHECK(*it_vec == *it_dbuf.ptr);
|
|
||||||
it_dbuf = dbuf_heap_cstr_iter_next(str_dbuf, it_dbuf, step);
|
|
||||||
if (!dbuf_heap_cstr_iter_is_end(str_dbuf, it_dbuf)) {
|
|
||||||
std::advance(it_vec, step);
|
|
||||||
} else {
|
|
||||||
it_vec = str_vec.end();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST_CHECK(dbuf_heap_cstr_iter_is_end(str_dbuf, it_dbuf) && it_vec == str_vec.end());
|
|
||||||
|
|
||||||
dbuf_heap_cstr_iter rit_dbuf = dbuf_heap_cstr_rbegin(str_dbuf);
|
|
||||||
std::vector<std::string>::reverse_iterator rit_vec = str_vec.rbegin();
|
|
||||||
while (!dbuf_heap_cstr_iter_is_end(str_dbuf, rit_dbuf)) {
|
|
||||||
TEST_CHECK(rit_vec != str_vec.rend());
|
|
||||||
TEST_CHECK(*rit_vec == *rit_dbuf.ptr);
|
|
||||||
rit_dbuf = dbuf_heap_cstr_iter_next(str_dbuf, rit_dbuf, step);
|
|
||||||
if (!dbuf_heap_cstr_iter_is_end(str_dbuf, rit_dbuf)) {
|
|
||||||
std::advance(rit_vec, step);
|
|
||||||
} else {
|
|
||||||
rit_vec = str_vec.rend();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST_CHECK(dbuf_heap_cstr_iter_is_end(str_dbuf, rit_dbuf) && rit_vec == str_vec.rend());
|
|
||||||
|
|
||||||
for (i = 0; i < str_dbuf->size; ++i) {
|
|
||||||
char *str = *dbuf_heap_cstr_at(str_dbuf, i);
|
|
||||||
TEST_CHECK(str_vec.at(i) == str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DbufCstringTest::test_push_insert_erase(int n, ptrdiff_t start_cap)
|
|
||||||
{
|
|
||||||
std::vector<std::string> str_vec;
|
|
||||||
dbuf_heap_cstr str_dbuf {};
|
|
||||||
dbuf_heap_cstr_init(&str_dbuf, start_cap, &allocator);
|
|
||||||
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
constexpr int BUF_SZ = 128;
|
|
||||||
char buf[BUF_SZ];
|
|
||||||
memset(buf, '\0', BUF_SZ);
|
|
||||||
snprintf(buf, BUF_SZ, "This is string number %d", i);
|
|
||||||
guf_cstr_heap str = buf;
|
|
||||||
|
|
||||||
dbuf_heap_cstr_push(&str_dbuf, &str, GUF_CPY_DEEP);
|
|
||||||
dbuf_heap_cstr_push_val_cpy(&str_dbuf, str);
|
|
||||||
char *heap_buf = strdup("Move me plz");
|
|
||||||
dbuf_heap_cstr_push(&str_dbuf, &heap_buf, GUF_CPY_MOVE);
|
|
||||||
TEST_CHECK(heap_buf == NULL);
|
|
||||||
|
|
||||||
TEST_CHECK(strncmp(*dbuf_heap_cstr_back(&str_dbuf), "Move me plz", BUF_SZ) == 0);
|
|
||||||
TEST_CHECK(strncmp(*dbuf_heap_cstr_at(&str_dbuf, str_dbuf.size - 2), buf, BUF_SZ) == 0);
|
|
||||||
TEST_CHECK(strncmp(*dbuf_heap_cstr_at(&str_dbuf, str_dbuf.size - 3), buf, BUF_SZ) == 0);
|
|
||||||
|
|
||||||
str_vec.push_back(std::string{buf});
|
|
||||||
str_vec.push_back(std::string{buf});
|
|
||||||
str_vec.emplace_back("Move me plz");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CHECK(str_dbuf.size == std::ssize(str_vec));
|
|
||||||
TEST_CHECK(str_dbuf.size == 3 * n);
|
|
||||||
|
|
||||||
for (int i = 1; i <= 8; ++i) {
|
|
||||||
test_iter(str_vec, &str_dbuf, i);
|
|
||||||
}
|
|
||||||
test_iter(str_vec, &str_dbuf, (int)str_dbuf.size);
|
|
||||||
test_iter(str_vec, &str_dbuf, (int)str_dbuf.size - 1);
|
|
||||||
test_iter(str_vec, &str_dbuf, (int)str_dbuf.size + 1);
|
|
||||||
|
|
||||||
for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) {
|
|
||||||
TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert front.
|
|
||||||
for (ptrdiff_t i = 0; i < 16; ++i) {
|
|
||||||
char str[] = "front";
|
|
||||||
dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, 0);
|
|
||||||
str_vec.insert(str_vec.begin(), std::string{str});
|
|
||||||
}
|
|
||||||
TEST_CHECK(std::ssize(str_vec) == str_dbuf.size);
|
|
||||||
for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) {
|
|
||||||
TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i));
|
|
||||||
}
|
|
||||||
// Insert back.
|
|
||||||
for (ptrdiff_t i = 0; i < 16; ++i) {
|
|
||||||
char str[] = "front";
|
|
||||||
dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, str_dbuf.size);
|
|
||||||
str_vec.insert(str_vec.end(), std::string{str});
|
|
||||||
}
|
|
||||||
TEST_CHECK(std::ssize(str_vec) == str_dbuf.size);
|
|
||||||
for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) {
|
|
||||||
TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert at i.
|
|
||||||
char str[] = "guf";
|
|
||||||
dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, str_dbuf.size / 2);
|
|
||||||
str_vec.insert(str_vec.begin() + str_vec.size() / 2, str);
|
|
||||||
dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, str_dbuf.size / 4);
|
|
||||||
str_vec.insert(str_vec.begin() + str_vec.size() / 4, str);
|
|
||||||
dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, 1);
|
|
||||||
str_vec.insert(str_vec.begin() + 1, str);
|
|
||||||
dbuf_heap_cstr_insert_val_cpy(&str_dbuf, str, str_dbuf.size - 1);
|
|
||||||
str_vec.insert(str_vec.begin() + (str_vec.size() - 1), str);
|
|
||||||
|
|
||||||
for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) {
|
|
||||||
TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
guf_err err = GUF_ERR_NONE;
|
|
||||||
dbuf_heap_cstr_try_insert_val_cpy(&str_dbuf, str, str_dbuf.size + 1, &err);
|
|
||||||
TEST_CHECK(err == GUF_ERR_IDX_RANGE);
|
|
||||||
|
|
||||||
err = GUF_ERR_NONE;
|
|
||||||
dbuf_heap_cstr_try_insert_val_cpy(&str_dbuf, str, -1, &err);
|
|
||||||
TEST_CHECK(err == GUF_ERR_IDX_RANGE);
|
|
||||||
|
|
||||||
err = GUF_ERR_NONE;
|
|
||||||
dbuf_heap_cstr_try_insert_val_cpy(&str_dbuf, str, str_dbuf.size + 2, &err);
|
|
||||||
TEST_CHECK(err == GUF_ERR_IDX_RANGE);
|
|
||||||
|
|
||||||
TEST_CHECK(std::ssize(str_vec) == str_dbuf.size);
|
|
||||||
for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) {
|
|
||||||
TEST_CHECK(str_vec.at(i) == *dbuf_heap_cstr_at(&str_dbuf, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (str_dbuf.size) {
|
|
||||||
dbuf_heap_cstr_erase(&str_dbuf, str_dbuf.size - 1);
|
|
||||||
str_vec.erase(str_vec.end() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ptrdiff_t to_rem = 8;
|
|
||||||
while (str_dbuf.size && to_rem--) {
|
|
||||||
dbuf_heap_cstr_erase(&str_dbuf, 0);
|
|
||||||
str_vec.erase(str_vec.begin());
|
|
||||||
TEST_CHECK(std::ssize(str_vec) == str_dbuf.size);
|
|
||||||
if (str_dbuf.size) {
|
|
||||||
dbuf_heap_cstr_pop(&str_dbuf);
|
|
||||||
str_vec.pop_back();
|
|
||||||
TEST_CHECK(std::ssize(str_vec) == str_dbuf.size);
|
|
||||||
}
|
|
||||||
if (str_dbuf.size) {
|
|
||||||
dbuf_heap_cstr_erase(&str_dbuf, str_dbuf.size / 2);
|
|
||||||
str_vec.erase(str_vec.begin() + (str_vec.size() / 2));
|
|
||||||
TEST_CHECK(std::ssize(str_vec) == str_dbuf.size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dbuf_heap_cstr_free(&str_dbuf, NULL);
|
|
||||||
TEST_CHECK(str_dbuf.size == 0 && str_dbuf.capacity == 0 && !str_dbuf.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DbufCstringTest::test_find(int n)
|
|
||||||
{
|
|
||||||
if (n < 2) {
|
|
||||||
n = 2;
|
|
||||||
}
|
|
||||||
std::vector<std::string> str_vec {};
|
|
||||||
|
|
||||||
dbuf_heap_cstr str_dbuf = {};
|
|
||||||
dbuf_heap_cstr_init(&str_dbuf, 0, &allocator);
|
|
||||||
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
constexpr int BUF_SZ = 128;
|
|
||||||
char buf[BUF_SZ];
|
|
||||||
memset(buf, '\0', BUF_SZ);
|
|
||||||
snprintf(buf, BUF_SZ, "String number %d", i);
|
|
||||||
|
|
||||||
dbuf_heap_cstr_push_val_cpy(&str_dbuf, buf);
|
|
||||||
str_vec.push_back(buf);
|
|
||||||
}
|
|
||||||
char *move_me = strdup("Moved string");
|
|
||||||
dbuf_heap_cstr_push(&str_dbuf, &move_me, GUF_CPY_MOVE);
|
|
||||||
GUF_ASSERT_RELEASE(move_me == NULL);
|
|
||||||
str_vec.emplace_back("Moved string");
|
|
||||||
|
|
||||||
TEST_CHECK(std::ssize(str_vec) == str_dbuf.size);
|
|
||||||
|
|
||||||
for (ptrdiff_t i = 0; i < str_dbuf.size; ++i) {
|
|
||||||
char *needle = *dbuf_heap_cstr_at(&str_dbuf, i);
|
|
||||||
TEST_CHECK(str_vec.at(i) == needle);
|
|
||||||
|
|
||||||
TEST_CHECK(dbuf_heap_cstr_contains_val(&str_dbuf, needle));
|
|
||||||
|
|
||||||
dbuf_heap_cstr_iter fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), dbuf_heap_cstr_end(&str_dbuf), needle);
|
|
||||||
TEST_CHECK(!dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it));
|
|
||||||
TEST_CHECK(std::find(str_vec.cbegin(), str_vec.cend(), needle) != str_vec.end());
|
|
||||||
|
|
||||||
dbuf_heap_cstr_iter begin = dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), i);
|
|
||||||
dbuf_heap_cstr_iter end = dbuf_heap_cstr_end(&str_dbuf);
|
|
||||||
fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, begin, end, needle);
|
|
||||||
TEST_CHECK(!dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it));
|
|
||||||
TEST_CHECK(std::find(str_vec.cbegin() + i, str_vec.cend(), needle) != str_vec.end());
|
|
||||||
|
|
||||||
begin = dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), i + 1);
|
|
||||||
end = dbuf_heap_cstr_end(&str_dbuf);
|
|
||||||
fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, begin, end, needle);
|
|
||||||
TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it));
|
|
||||||
TEST_CHECK(std::find(str_vec.cbegin() + i + 1, str_vec.cend(), needle) == str_vec.end());
|
|
||||||
|
|
||||||
// Reverse.
|
|
||||||
fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_rbegin(&str_dbuf), dbuf_heap_cstr_rend(&str_dbuf), needle);
|
|
||||||
TEST_CHECK(!dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it));
|
|
||||||
TEST_CHECK(std::find(str_vec.crbegin(), str_vec.crend(), needle) != str_vec.rend());
|
|
||||||
}
|
|
||||||
|
|
||||||
char needle[] = "Definitely not inside";
|
|
||||||
dbuf_heap_cstr_iter fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), dbuf_heap_cstr_end(&str_dbuf), needle);
|
|
||||||
TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it));
|
|
||||||
TEST_CHECK(std::find(str_vec.cbegin(), str_vec.cend(), needle) == str_vec.end());
|
|
||||||
|
|
||||||
fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_rbegin(&str_dbuf), dbuf_heap_cstr_rend(&str_dbuf), needle);
|
|
||||||
TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it));
|
|
||||||
TEST_CHECK(std::find(str_vec.crbegin(), str_vec.crend(), needle) == str_vec.rend());
|
|
||||||
|
|
||||||
char *needle2 = *dbuf_heap_cstr_at(&str_dbuf, 0);
|
|
||||||
fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), 1), dbuf_heap_cstr_end(&str_dbuf), needle2);
|
|
||||||
TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it));
|
|
||||||
TEST_CHECK(std::find(str_vec.cbegin() + 1, str_vec.cend(), needle2) == str_vec.end());
|
|
||||||
|
|
||||||
needle2 = *dbuf_heap_cstr_back(&str_dbuf);
|
|
||||||
fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), 1), dbuf_heap_cstr_iter_next(&str_dbuf, dbuf_heap_cstr_end(&str_dbuf), -1), needle2);
|
|
||||||
TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it));
|
|
||||||
TEST_CHECK(std::find(str_vec.begin(), str_vec.end() - 1, needle2) == (str_vec.end() - 1));
|
|
||||||
|
|
||||||
needle2 = *dbuf_heap_cstr_at(&str_dbuf, 0);
|
|
||||||
fnd_it = dbuf_heap_cstr_find_val(&str_dbuf, dbuf_heap_cstr_begin(&str_dbuf), dbuf_heap_cstr_begin(&str_dbuf), needle2);
|
|
||||||
TEST_CHECK(dbuf_heap_cstr_iter_is_end(&str_dbuf, fnd_it));
|
|
||||||
TEST_CHECK(std::find(str_vec.cbegin(), str_vec.cbegin(), needle2) == str_vec.cbegin());
|
|
||||||
|
|
||||||
dbuf_heap_cstr_free(&str_dbuf, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
DbufStrTest:
|
|
||||||
*/
|
|
||||||
|
|
||||||
void DbufStrTest::run()
|
|
||||||
{
|
|
||||||
test_push_insert_erase(16);
|
|
||||||
test_push_insert_erase(16, 1);
|
|
||||||
test_push_insert_erase(16, 15);
|
|
||||||
test_push_insert_erase(16, 16);
|
|
||||||
test_push_insert_erase(16, 97);
|
|
||||||
test_push_insert_erase(16, 256);
|
|
||||||
|
|
||||||
test_push_insert_erase(500);
|
|
||||||
test_push_insert_erase(500, 1);
|
|
||||||
test_push_insert_erase(500, 499);
|
|
||||||
test_push_insert_erase(500, 500);
|
|
||||||
test_push_insert_erase(500, 97);
|
|
||||||
test_push_insert_erase(500, 256);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DbufStrTest::test_push_insert_erase(size_t n, ptrdiff_t start_cap)
|
|
||||||
{
|
|
||||||
dbuf_str strings = start_cap < 0 ? dbuf_str_new(&allocator) : dbuf_str_new_with_capacity(start_cap, &allocator);
|
|
||||||
std::vector<std::string> strings_cpp {};
|
|
||||||
|
|
||||||
guf_libc_alloc_ctx str_allocator_ctx = {
|
|
||||||
.tracker = guf_alloc_tracker_new(42, "test_push_insert_erase: local str allocator", NULL, NULL),
|
|
||||||
.zero_init = false
|
|
||||||
};
|
|
||||||
guf_allocator str_allocator = guf_libc_allocator_new(&str_allocator_ctx);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
|
||||||
std::string str;
|
|
||||||
for (size_t c = 0; c < 512 + GUF_STR_SSO_BUF_CAP; ++c) {
|
|
||||||
str += (char)(c % 10 + '0');
|
|
||||||
}
|
|
||||||
const guf_str_view sv_long = guf_str_view{.str = str.data(), .len = (ptrdiff_t)str.size()};
|
|
||||||
const guf_str_view sv_short = guf_str_view{.str = str.data(), .len = (ptrdiff_t)GUF_STR_SSO_BUF_CAP - 1};
|
|
||||||
|
|
||||||
guf_str long_str = GUF_STR_UNINITIALISED_CPP, short_str = GUF_STR_UNINITIALISED_CPP;
|
|
||||||
guf_str_init(&long_str, sv_long, &str_allocator);
|
|
||||||
guf_str_init(&short_str, sv_short, &str_allocator);
|
|
||||||
|
|
||||||
TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 1 + (i*3));
|
|
||||||
|
|
||||||
// Move
|
|
||||||
guf_err err;
|
|
||||||
dbuf_str_try_push(&strings, &long_str, GUF_CPY_MOVE, &err);
|
|
||||||
TEST_CHECK(err == GUF_ERR_NONE);
|
|
||||||
dbuf_str_try_push(&strings, &short_str, GUF_CPY_MOVE, &err);
|
|
||||||
TEST_CHECK(err == GUF_ERR_NONE);
|
|
||||||
|
|
||||||
strings_cpp.push_back(str.substr(0, str.size()));
|
|
||||||
strings_cpp.push_back(str.substr(0, GUF_STR_SSO_BUF_CAP - 1));
|
|
||||||
|
|
||||||
TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 1 + (i*3));
|
|
||||||
|
|
||||||
TEST_CHECK(guf_str_is_uninit(&long_str));
|
|
||||||
TEST_CHECK(guf_str_is_uninit(&short_str));
|
|
||||||
|
|
||||||
// Deep-copy
|
|
||||||
guf_str_init(&long_str, sv_long, &str_allocator);
|
|
||||||
guf_str_init(&short_str, sv_short, &str_allocator);
|
|
||||||
|
|
||||||
TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 2 + (i*3));
|
|
||||||
|
|
||||||
dbuf_str_try_push(&strings, &long_str, GUF_CPY_DEEP, &err);
|
|
||||||
TEST_CHECK(err == GUF_ERR_NONE);
|
|
||||||
dbuf_str_try_push(&strings, &short_str, GUF_CPY_DEEP, &err);
|
|
||||||
TEST_CHECK(err == GUF_ERR_NONE);
|
|
||||||
|
|
||||||
strings_cpp.push_back(str.substr(0, str.size()));
|
|
||||||
strings_cpp.push_back(str.substr(0, GUF_STR_SSO_BUF_CAP - 1));
|
|
||||||
|
|
||||||
TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 3 + (i*3));
|
|
||||||
|
|
||||||
TEST_CHECK(guf_str_is_valid(&long_str) && guf_str_is_valid(&short_str));
|
|
||||||
TEST_CHECK(guf_str_view_equal_val_arg(guf_str_view_from_str(&long_str), sv_long));
|
|
||||||
TEST_CHECK(guf_str_view_equal_val_arg(guf_str_view_from_str(&short_str), sv_short));
|
|
||||||
|
|
||||||
guf_str_free(&long_str, NULL);
|
|
||||||
guf_str_free(&short_str, NULL);
|
|
||||||
|
|
||||||
TEST_CHECK(str_allocator_ctx.tracker.free_count == 1 + (i*1));
|
|
||||||
TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 3 + (i*3));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CHECK(str_allocator_ctx.tracker.free_count == n);
|
|
||||||
TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 3 * n);
|
|
||||||
|
|
||||||
TEST_CHECK(strings.size == 4 * (ptrdiff_t)n);
|
|
||||||
TEST_CHECK(strings.size == std::ssize(strings_cpp));
|
|
||||||
|
|
||||||
std::string str;
|
|
||||||
for (size_t c = 0; c < 512 + GUF_STR_SSO_BUF_CAP; ++c) {
|
|
||||||
str += (char)(c % 10 + '0');
|
|
||||||
}
|
|
||||||
const guf_str_view sv_long = guf_str_view{.str = str.data(), .len = (ptrdiff_t)str.size()};
|
|
||||||
const guf_str_view sv_short = guf_str_view{.str = str.data(), .len = (ptrdiff_t)GUF_STR_SSO_BUF_CAP - 1};
|
|
||||||
size_t i = 0;
|
|
||||||
GUF_CNT_FOREACH(&strings, dbuf_str, it) {
|
|
||||||
if (TEST_CHECK(it.ptr)) {
|
|
||||||
const guf_str *s = it.ptr;
|
|
||||||
TEST_CHECK(guf_str_view_equal_val_arg(guf_str_view_from_str(s), i % 2 == 0 ? sv_long : sv_short));
|
|
||||||
const guf_str_view sv_cpp = guf_str_view {.str = strings_cpp.at(i).data(), .len = (ptrdiff_t)strings_cpp.at(i).size()};
|
|
||||||
TEST_CHECK(guf_str_view_equal_val_arg(guf_str_view_from_str(s), sv_cpp));
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
GUF_CNT_FOREACH(&strings, dbuf_str, it) {
|
|
||||||
if (TEST_CHECK(it.ptr)) {
|
|
||||||
guf_str *s = it.ptr;
|
|
||||||
TEST_CHECK(guf_str_append(s, GUF_CSTR_LIT_TO_VIEW_CPP("<END>")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::vector<guf_str_view> delims = {guf_str_view{.str = "<END>", .len = 5}};
|
|
||||||
i = 0;
|
|
||||||
GUF_CNT_FOREACH(&strings, dbuf_str, it) {
|
|
||||||
if (TEST_CHECK(it.ptr)) {
|
|
||||||
const guf_str *s = it.ptr;
|
|
||||||
guf_str_tok_state tk_state = guf_str_tok_state_new(guf_str_view_from_str(s), delims.data(), std::ssize(delims), GUF_STR_TOK_DELIM_OPT_MATCH_LONGEST);
|
|
||||||
size_t tok_n = 0;
|
|
||||||
while (guf_str_tok_next(&tk_state, true)) {
|
|
||||||
TEST_CHECK(guf_str_view_equal_val_arg(tk_state.cur_tok , i % 2 == 0 ? sv_long : sv_short));
|
|
||||||
TEST_CHECK(guf_str_view_equal_val_arg(tk_state.cur_delim, guf_str_view{.str = "<END>", .len = 5}));
|
|
||||||
++tok_n;
|
|
||||||
}
|
|
||||||
TEST_CHECK(tok_n == 1);
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
dbuf_str_free(&strings, NULL);
|
|
||||||
TEST_CHECK(!guf_alloc_tracker_found_leak(&str_allocator_ctx.tracker));
|
|
||||||
}
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <vector>
|
|
||||||
#include "test.hpp"
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include "guf_alloc_libc.h"
|
|
||||||
#include "impls/dbuf_impl.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DbufIntTest : public Test
|
|
||||||
{
|
|
||||||
DbufIntTest(const std::string& nm) : Test(nm)
|
|
||||||
{
|
|
||||||
allocator_ctx.zero_init = false;
|
|
||||||
guf_alloc_tracker_init(&allocator_ctx.tracker, 1, "DbufIntTest_allocator", NULL, NULL);
|
|
||||||
guf_libc_allocator_init(&allocator, &allocator_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void run() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
guf_allocator allocator;
|
|
||||||
guf_libc_alloc_ctx allocator_ctx;
|
|
||||||
|
|
||||||
std::vector<int> dbuf_to_vec(dbuf_int *dbuf);
|
|
||||||
void test_push(dbuf_int *dbuf, int n);
|
|
||||||
void test_insert_remove(int n);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct DbufCstringTest : public Test
|
|
||||||
{
|
|
||||||
DbufCstringTest(std::string nm) : Test(nm)
|
|
||||||
{
|
|
||||||
allocator_ctx.zero_init = false;
|
|
||||||
guf_alloc_tracker_init(&allocator_ctx.tracker, 2, "DbufCstringTest_allocator", NULL, NULL);
|
|
||||||
guf_libc_allocator_init(&allocator, &allocator_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void run() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
guf_allocator allocator;
|
|
||||||
guf_libc_alloc_ctx allocator_ctx;
|
|
||||||
|
|
||||||
void test_iter(std::vector<std::string>& str_vec, dbuf_heap_cstr *str_dbuf, int step = 1);
|
|
||||||
void test_push_insert_erase(int n, ptrdiff_t start_cap = 0);
|
|
||||||
void test_find(int n = 32);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct DbufStrTest : public Test
|
|
||||||
{
|
|
||||||
DbufStrTest(std::string nm) : Test(nm)
|
|
||||||
{
|
|
||||||
allocator_ctx.zero_init = false;
|
|
||||||
guf_alloc_tracker_init(&allocator_ctx.tracker, 3, "DbufStrTest_allocator", NULL, NULL);
|
|
||||||
guf_libc_allocator_init(&allocator, &allocator_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void run() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
guf_allocator allocator;
|
|
||||||
guf_libc_alloc_ctx allocator_ctx;
|
|
||||||
|
|
||||||
void test_push_insert_erase(size_t n, ptrdiff_t start_cap = 0);
|
|
||||||
};
|
|
||||||
@ -1,431 +0,0 @@
|
|||||||
#include "test_dict.hpp"
|
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <cstring>
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include "guf_alloc_libc.h"
|
|
||||||
#include "guf_str.h"
|
|
||||||
#include "impls/dict_impl.h"
|
|
||||||
#include "impls/dbuf_impl.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
DictSvToIntTest:
|
|
||||||
*/
|
|
||||||
|
|
||||||
void DictSvToIntTest::run()
|
|
||||||
{
|
|
||||||
if (done) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
push_check_name("insert_lookup(\"utf8-test.txt\")");
|
|
||||||
if (TEST_CHECK(load_file(TEST_DATA_DIR "/utf8-test.txt"))) {
|
|
||||||
insert_lookup();
|
|
||||||
for (ptrdiff_t i = 0; i <= 64; ++i) {
|
|
||||||
insert_lookup(i);
|
|
||||||
}
|
|
||||||
insert_lookup(512);
|
|
||||||
insert_lookup(1997);
|
|
||||||
insert_lookup(1999);
|
|
||||||
}
|
|
||||||
free_file();
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
push_check_name("insert_lookup(\"bartleby.txt\")");
|
|
||||||
if (TEST_CHECK(load_file(TEST_DATA_DIR "/bartleby.txt"))) {
|
|
||||||
insert_lookup();
|
|
||||||
insert_lookup(201);
|
|
||||||
}
|
|
||||||
free_file();
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
//guf_alloc_tracker_print(&allocator_ctx.tracker, NULL);
|
|
||||||
TEST_CHECK(!guf_alloc_tracker_found_leak(&allocator_ctx.tracker));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DictSvToIntTest::insert_lookup(std::optional<ptrdiff_t> inital_dict_cap)
|
|
||||||
{
|
|
||||||
std::unordered_map<std::string_view, int32_t> word_cnt_map {};
|
|
||||||
dict_sv_i32 word_cnt_dict {};
|
|
||||||
dict_str_i32 word_cnt_dict_str {};
|
|
||||||
|
|
||||||
if (inital_dict_cap) {
|
|
||||||
dict_sv_i32_init_with_capacity(&word_cnt_dict, &allocator, inital_dict_cap.value());
|
|
||||||
dict_str_i32_init_with_capacity(&word_cnt_dict_str, &allocator, inital_dict_cap.value());
|
|
||||||
} else {
|
|
||||||
dict_sv_i32_init(&word_cnt_dict, &allocator);
|
|
||||||
dict_str_i32_init(&word_cnt_dict_str, &allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
dbuf_str_view delims = dbuf_str_view_new(&allocator);
|
|
||||||
for (size_t i = 0; i < GUF_ARR_SIZE(GUF_UTF8_WHITESPACE); ++i) {
|
|
||||||
guf_str_view d = {.str = GUF_UTF8_WHITESPACE[i], .len = (ptrdiff_t)strlen(GUF_UTF8_WHITESPACE[i])};
|
|
||||||
dbuf_str_view_push_val(&delims, d);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < GUF_ARR_SIZE(GUF_UTF8_COMMON_PUNCT); ++i) {
|
|
||||||
guf_str_view d = {.str = GUF_UTF8_COMMON_PUNCT[i], .len = (ptrdiff_t)strlen(GUF_UTF8_COMMON_PUNCT[i])};
|
|
||||||
dbuf_str_view_push_val(&delims, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
guf_str_tok_state tok_state = guf_str_tok_state_new(guf_str_view{.str = text_buf.data, .len = text_buf.size}, delims.data, delims.size, GUF_STR_TOK_DELIM_OPT_MATCH_LONGEST);
|
|
||||||
while (guf_str_tok_next(&tok_state, true)) {
|
|
||||||
guf_str_view tok = tok_state.cur_tok;
|
|
||||||
// if (tok.len <= 0) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
std::string_view sv(tok.str , tok.len);
|
|
||||||
//std::cout << sv << std::string_view(tok_state.cur_delim.str, tok_state.cur_delim.len);
|
|
||||||
TEST_CHECK(dict_sv_i32_contains(&word_cnt_dict, &tok) == word_cnt_map.contains(sv));
|
|
||||||
if (!dict_sv_i32_contains(&word_cnt_dict, &tok)) {
|
|
||||||
dict_sv_i32_insert_val_arg(&word_cnt_dict, tok, 1, GUF_CPY_VALUE, GUF_CPY_VALUE);
|
|
||||||
word_cnt_map.insert({sv, 1});
|
|
||||||
if (TEST_CHECK(!dict_str_i32_contains_val_arg(&word_cnt_dict_str, guf_str_new_readonly(tok)))) {
|
|
||||||
dict_str_i32_insert_val_arg(&word_cnt_dict_str, guf_str_new(tok, &allocator), 1, GUF_CPY_MOVE, GUF_CPY_VALUE);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int32_t *cnt = dict_sv_i32_at_val_arg(&word_cnt_dict, tok);
|
|
||||||
if (TEST_CHECK(cnt)) {
|
|
||||||
*cnt += 1;
|
|
||||||
}
|
|
||||||
int32_t *cnt_2 = dict_str_i32_at_val_arg(&word_cnt_dict_str, guf_str_new_readonly(tok));
|
|
||||||
if (TEST_CHECK(cnt_2)) {
|
|
||||||
*cnt_2 += 1;
|
|
||||||
}
|
|
||||||
// else {
|
|
||||||
// std::cout << "tok: " << std::string_view{tok.str, (size_t)tok.len} << "\n";
|
|
||||||
// }
|
|
||||||
word_cnt_map.at(sv) += 1;
|
|
||||||
}
|
|
||||||
// printf("tok_len: %td ", tok.len);
|
|
||||||
// printf("'%.*s'\n", (int)tok.len, tok.str);
|
|
||||||
TEST_CHECK(dict_sv_i32_debug_valid_size(&word_cnt_dict));
|
|
||||||
TEST_CHECK(dict_str_i32_debug_valid_size(&word_cnt_dict_str));
|
|
||||||
|
|
||||||
}
|
|
||||||
dbuf_str_view_free(&delims, NULL);
|
|
||||||
|
|
||||||
TEST_CHECK(dict_sv_i32_size(&word_cnt_dict) == std::ssize(word_cnt_map));
|
|
||||||
TEST_CHECK(dict_sv_i32_debug_valid_size(&word_cnt_dict));
|
|
||||||
|
|
||||||
TEST_CHECK(dict_str_i32_size(&word_cnt_dict_str) == std::ssize(word_cnt_map));
|
|
||||||
TEST_CHECK(dict_str_i32_debug_valid_size(&word_cnt_dict_str));
|
|
||||||
|
|
||||||
for (const auto & [word, cnt] : word_cnt_map ) {
|
|
||||||
guf_str_view sv = {.str = word.data(), .len = (ptrdiff_t)word.size()};
|
|
||||||
int32_t *res = dict_sv_i32_at(&word_cnt_dict, &sv);
|
|
||||||
int32_t *res2 = dict_str_i32_at_val_arg(&word_cnt_dict_str, guf_str_new_readonly(sv));
|
|
||||||
TEST_CHECK(res && *res == cnt);
|
|
||||||
TEST_CHECK(res2 && *res2 == cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
ptrdiff_t i = 0;
|
|
||||||
GUF_CNT_FOREACH(&word_cnt_dict, dict_sv_i32, kv_it) {
|
|
||||||
const dict_sv_i32_kv *kv = kv_it.ptr;
|
|
||||||
if (TEST_CHECK(kv)) {
|
|
||||||
const int32_t cnt = kv->val;
|
|
||||||
const std::string_view sv(kv->key.str, kv->key.len);
|
|
||||||
if (TEST_CHECK(word_cnt_map.contains(sv))) {
|
|
||||||
TEST_CHECK(word_cnt_map.at(sv) == cnt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
TEST_CHECK(i == dict_sv_i32_size(&word_cnt_dict));
|
|
||||||
TEST_CHECK(i == std::ssize(word_cnt_map));
|
|
||||||
TEST_CHECK(dict_sv_i32_debug_valid_size(&word_cnt_dict));
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
GUF_CNT_FOREACH(&word_cnt_dict_str, dict_str_i32, kv_it) {
|
|
||||||
const dict_str_i32_kv *kv = kv_it.ptr;
|
|
||||||
if (TEST_CHECK(kv)) {
|
|
||||||
const int32_t cnt = kv->val;
|
|
||||||
const std::string_view sv(guf_str_const_cstr(&kv->key), guf_str_len(&kv->key));
|
|
||||||
// std::cout << sv << "\n";
|
|
||||||
|
|
||||||
if (TEST_CHECK(word_cnt_map.contains(sv))) {
|
|
||||||
TEST_CHECK(word_cnt_map.at(sv) == cnt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
TEST_CHECK(i == dict_str_i32_size(&word_cnt_dict_str));
|
|
||||||
TEST_CHECK(i == std::ssize(word_cnt_map));
|
|
||||||
TEST_CHECK(dict_str_i32_debug_valid_size(&word_cnt_dict_str));
|
|
||||||
|
|
||||||
// std::cout << "load fac: " << dict_sv_i32_load_factor(&word_cnt_dict) << ", cap: " << word_cnt_dict.kv_indices_cap << " elem cap: " << word_cnt_dict.kv_elems.capacity << "\n";
|
|
||||||
// std::cout << "size: " << dict_sv_i32_size(&word_cnt_dict) << ", max probelen: " << word_cnt_dict.max_probelen << "\n";
|
|
||||||
// std::cout << "mem usage: " << dict_sv_i32_memory_usage(&word_cnt_dict) << "\n";
|
|
||||||
|
|
||||||
// Erase tests:
|
|
||||||
const double load_fac_before_erase = dict_sv_i32_load_factor(&word_cnt_dict);
|
|
||||||
const ptrdiff_t size_before_erase = dict_sv_i32_size(&word_cnt_dict);
|
|
||||||
ptrdiff_t num_del = 0;
|
|
||||||
while (dict_sv_i32_size(&word_cnt_dict) > size_before_erase / 2) {
|
|
||||||
dict_sv_i32_kv *kv = NULL;
|
|
||||||
if (num_del % 2) {
|
|
||||||
dict_sv_i32_iter it = dict_sv_i32_begin(&word_cnt_dict);
|
|
||||||
GUF_ASSERT_RELEASE(!dict_sv_i32_iter_is_end(&word_cnt_dict, it));
|
|
||||||
kv = it.ptr;
|
|
||||||
} else {
|
|
||||||
dict_sv_i32_iter rit = dict_sv_i32_rbegin(&word_cnt_dict);
|
|
||||||
GUF_ASSERT_RELEASE(!dict_sv_i32_iter_is_end(&word_cnt_dict, rit));
|
|
||||||
kv = rit.ptr;
|
|
||||||
}
|
|
||||||
GUF_ASSERT_RELEASE(kv);
|
|
||||||
|
|
||||||
const guf_str_view key = kv->key;
|
|
||||||
|
|
||||||
const bool del_success = dict_sv_i32_erase(&word_cnt_dict, &key);
|
|
||||||
TEST_CHECK(del_success);
|
|
||||||
TEST_CHECK(!dict_sv_i32_contains(&word_cnt_dict, &key));
|
|
||||||
|
|
||||||
std::string_view sv(key.str, (size_t)key.len);
|
|
||||||
if (TEST_CHECK(word_cnt_map.contains(sv))) {
|
|
||||||
word_cnt_map.erase(sv);
|
|
||||||
}
|
|
||||||
TEST_CHECK(!word_cnt_map.contains(sv));
|
|
||||||
|
|
||||||
if (del_success) {
|
|
||||||
++num_del;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST_CHECK(dict_sv_i32_size(&word_cnt_dict) >= 0);
|
|
||||||
TEST_CHECK(size_before_erase - num_del == dict_sv_i32_size(&word_cnt_dict));
|
|
||||||
TEST_CHECK(std::ssize(word_cnt_map) == dict_sv_i32_size(&word_cnt_dict));
|
|
||||||
|
|
||||||
if (dict_sv_i32_size(&word_cnt_dict) != 0) {
|
|
||||||
TEST_CHECK(load_fac_before_erase == dict_sv_i32_load_factor(&word_cnt_dict));
|
|
||||||
} else {
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dict_sv_i32_size(&word_cnt_dict) >= 4) {
|
|
||||||
dict_sv_i32_kv_dbuf_iter it = dict_sv_i32_begin(&word_cnt_dict);
|
|
||||||
it = dict_sv_i32_iter_next(&word_cnt_dict, it, 1);
|
|
||||||
GUF_ASSERT_RELEASE(!dict_sv_i32_iter_is_end(&word_cnt_dict, it));
|
|
||||||
|
|
||||||
guf_str_view key = it.ptr->key;
|
|
||||||
|
|
||||||
bool del_success = dict_sv_i32_erase(&word_cnt_dict, &key);
|
|
||||||
TEST_CHECK(del_success);
|
|
||||||
TEST_CHECK(!dict_sv_i32_contains(&word_cnt_dict, &key));
|
|
||||||
|
|
||||||
std::string_view sv(key.str, (size_t)key.len);
|
|
||||||
if (TEST_CHECK(word_cnt_map.contains(sv))) {
|
|
||||||
word_cnt_map.erase(sv);
|
|
||||||
}
|
|
||||||
|
|
||||||
it = dict_sv_i32_rbegin(&word_cnt_dict);
|
|
||||||
it = dict_sv_i32_iter_next(&word_cnt_dict, it, 1);
|
|
||||||
GUF_ASSERT_RELEASE(!dict_sv_i32_iter_is_end(&word_cnt_dict, it));
|
|
||||||
key = it.ptr->key;
|
|
||||||
|
|
||||||
del_success = dict_sv_i32_erase(&word_cnt_dict, &key);
|
|
||||||
TEST_CHECK(del_success);
|
|
||||||
TEST_CHECK(!dict_sv_i32_contains(&word_cnt_dict, &key));
|
|
||||||
|
|
||||||
sv = std::string_view(key.str, (size_t)key.len);
|
|
||||||
if (TEST_CHECK(word_cnt_map.contains(sv))) {
|
|
||||||
word_cnt_map.erase(sv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST_CHECK(std::ssize(word_cnt_map) == dict_sv_i32_size(&word_cnt_dict));
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
GUF_CNT_FOREACH(&word_cnt_dict, dict_sv_i32, kv_it) {
|
|
||||||
const dict_sv_i32_kv *kv = kv_it.ptr;
|
|
||||||
if (TEST_CHECK(kv)) {
|
|
||||||
const int32_t cnt = kv->val;
|
|
||||||
const std::string_view sv(kv->key.str, (size_t)kv->key.len);
|
|
||||||
if (TEST_CHECK(word_cnt_map.contains(sv))) {
|
|
||||||
TEST_CHECK(word_cnt_map.at(sv) == cnt);
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST_CHECK(i == word_cnt_dict.kv_elems.size);
|
|
||||||
TEST_CHECK(i == std::ssize(word_cnt_map));
|
|
||||||
|
|
||||||
while (dict_sv_i32_size(&word_cnt_dict) > 0) {
|
|
||||||
const dict_sv_i32_iter beg = dict_sv_i32_begin(&word_cnt_dict);
|
|
||||||
if (TEST_CHECK(!dict_sv_i32_iter_is_end(&word_cnt_dict, beg))) {
|
|
||||||
const guf_str_view key = beg.ptr->key;
|
|
||||||
if (TEST_CHECK(dict_sv_i32_contains(&word_cnt_dict, &key))) {
|
|
||||||
const bool del_success = dict_sv_i32_erase(&word_cnt_dict, &key);
|
|
||||||
TEST_CHECK(del_success);
|
|
||||||
TEST_CHECK(!dict_sv_i32_contains(&word_cnt_dict, &key));
|
|
||||||
}
|
|
||||||
const std::string_view sv(key.str, (size_t)key.len);
|
|
||||||
if (TEST_CHECK(word_cnt_map.contains(sv))) {
|
|
||||||
word_cnt_map.erase(sv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST_CHECK(dict_sv_i32_size(&word_cnt_dict) == 0 && word_cnt_map.size() == 0);
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == 0);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == 0);
|
|
||||||
|
|
||||||
dict_sv_i32_insert_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Hej"), (size_t)64, GUF_CPY_VALUE, GUF_CPY_VALUE);
|
|
||||||
dict_sv_i32_insert_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("verden!"), (size_t)128, GUF_CPY_VALUE, GUF_CPY_VALUE);
|
|
||||||
dict_sv_i32_insert_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Flødeskum"), (size_t)256, GUF_CPY_VALUE, GUF_CPY_VALUE);
|
|
||||||
dict_sv_i32_insert_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("med"), (size_t)512, GUF_CPY_VALUE, GUF_CPY_VALUE);
|
|
||||||
dict_sv_i32_insert_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Faxe Kondi."), (size_t)1024, GUF_CPY_VALUE, GUF_CPY_VALUE);
|
|
||||||
|
|
||||||
TEST_CHECK(dict_sv_i32_size(&word_cnt_dict) == 5);
|
|
||||||
|
|
||||||
int32_t *val = dict_sv_i32_at_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Hej"));
|
|
||||||
TEST_CHECK(val && *val == 64);
|
|
||||||
val = dict_sv_i32_at_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Flødeskum"));
|
|
||||||
TEST_CHECK(val && *val == 256);
|
|
||||||
val = dict_sv_i32_at_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Faxe Kondi."));
|
|
||||||
TEST_CHECK(val && *val == 1024);
|
|
||||||
val = dict_sv_i32_at_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("verden!"));
|
|
||||||
TEST_CHECK(val && *val == 128);
|
|
||||||
val = dict_sv_i32_at_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("med"));
|
|
||||||
TEST_CHECK(val && *val == 512);
|
|
||||||
|
|
||||||
TEST_CHECK(word_cnt_dict.kv_elems.size == 5);
|
|
||||||
|
|
||||||
TEST_CHECK(word_cnt_dict.kv_elems.data[0].val == 64 && std::strcmp(word_cnt_dict.kv_elems.data[0].key.str, "Hej") == 0);
|
|
||||||
TEST_CHECK(word_cnt_dict.kv_elems.data[1].val == 128 && std::strcmp(word_cnt_dict.kv_elems.data[1].key.str, "verden!") == 0);
|
|
||||||
TEST_CHECK(word_cnt_dict.kv_elems.data[2].val == 256 && std::strcmp(word_cnt_dict.kv_elems.data[2].key.str, "Flødeskum") == 0);
|
|
||||||
TEST_CHECK(word_cnt_dict.kv_elems.data[3].val == 512 && std::strcmp(word_cnt_dict.kv_elems.data[3].key.str, "med") == 0);
|
|
||||||
TEST_CHECK(word_cnt_dict.kv_elems.data[4].val == 1024 && std::strcmp(word_cnt_dict.kv_elems.data[4].key.str, "Faxe Kondi.") == 0);
|
|
||||||
|
|
||||||
const double load_fac_beg = dict_sv_i32_load_factor(&word_cnt_dict);
|
|
||||||
const ptrdiff_t cap_begin = word_cnt_dict.kv_indices_cap;
|
|
||||||
ptrdiff_t del = 0;
|
|
||||||
|
|
||||||
TEST_CHECK(dict_sv_i32_erase_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Hej")));
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == ++del);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == load_fac_beg);
|
|
||||||
for (ptrdiff_t n = 0; n < cap_begin + 128; ++n) {
|
|
||||||
dict_sv_i32_insert_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Hej"), 64, GUF_CPY_VALUE, GUF_CPY_VALUE);
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == --del);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == load_fac_beg);
|
|
||||||
|
|
||||||
TEST_CHECK(dict_sv_i32_erase_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Hej")));
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == ++del);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == load_fac_beg);
|
|
||||||
}
|
|
||||||
TEST_CHECK(word_cnt_dict.kv_indices_cap == cap_begin);
|
|
||||||
|
|
||||||
|
|
||||||
TEST_CHECK(dict_sv_i32_erase_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Faxe Kondi.")));
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == ++del);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == load_fac_beg);
|
|
||||||
for (ptrdiff_t n = 0; n < 256; ++n) {
|
|
||||||
dict_sv_i32_insert_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Faxe Kondi."), 128, GUF_CPY_VALUE, GUF_CPY_VALUE);
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == --del);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == load_fac_beg);
|
|
||||||
|
|
||||||
TEST_CHECK(dict_sv_i32_erase_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Faxe Kondi.")));
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == ++del);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == load_fac_beg);
|
|
||||||
}
|
|
||||||
TEST_CHECK(word_cnt_dict.kv_indices_cap == cap_begin);
|
|
||||||
|
|
||||||
TEST_CHECK(dict_sv_i32_erase_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("med")));
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == ++del);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == load_fac_beg);
|
|
||||||
for (ptrdiff_t n = 0; n < 512 + cap_begin; ++n) {
|
|
||||||
dict_sv_i32_insert_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("med"), 256, GUF_CPY_VALUE, GUF_CPY_VALUE);
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == --del);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == load_fac_beg);
|
|
||||||
|
|
||||||
TEST_CHECK(dict_sv_i32_erase_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("med")));
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == ++del);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == load_fac_beg);
|
|
||||||
}
|
|
||||||
TEST_CHECK(word_cnt_dict.kv_indices_cap == cap_begin);
|
|
||||||
|
|
||||||
TEST_CHECK(dict_sv_i32_erase_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Flødeskum")));
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == ++del);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == load_fac_beg);
|
|
||||||
for (ptrdiff_t n = 0; n < 71; ++n) {
|
|
||||||
dict_sv_i32_insert_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Flødeskum"), 512, GUF_CPY_VALUE, GUF_CPY_VALUE);
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == --del);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == load_fac_beg);
|
|
||||||
|
|
||||||
TEST_CHECK(dict_sv_i32_erase_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("Flødeskum")));
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == ++del);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == load_fac_beg);
|
|
||||||
}
|
|
||||||
TEST_CHECK(word_cnt_dict.kv_indices_cap == cap_begin);
|
|
||||||
|
|
||||||
TEST_CHECK(dict_sv_i32_erase_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("verden!")));
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == 0);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == 0);
|
|
||||||
for (ptrdiff_t n = 0; n < 201; ++n) {
|
|
||||||
dict_sv_i32_insert_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("verden!"), 128, GUF_CPY_VALUE, GUF_CPY_VALUE);
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == 0);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) > 0);
|
|
||||||
|
|
||||||
TEST_CHECK(dict_sv_i32_erase_val_arg(&word_cnt_dict, GUF_CSTR_TO_VIEW_CPP("verden!")));
|
|
||||||
TEST_CHECK(word_cnt_dict.num_tombstones == 0);
|
|
||||||
TEST_CHECK(dict_sv_i32_load_factor(&word_cnt_dict) == 0);
|
|
||||||
}
|
|
||||||
TEST_CHECK(word_cnt_dict.kv_indices_cap == cap_begin);
|
|
||||||
|
|
||||||
TEST_CHECK(word_cnt_dict.kv_elems.size == 0);
|
|
||||||
TEST_CHECK(dict_sv_i32_size(&word_cnt_dict) == 0);
|
|
||||||
|
|
||||||
|
|
||||||
std::string str;
|
|
||||||
for (size_t c = 0; c < GUF_STR_SSO_BUF_CAP * 4; ++c) {
|
|
||||||
str += c % 2 ? "AAA" : "aaa";
|
|
||||||
}
|
|
||||||
|
|
||||||
guf_str str_cpy = guf_str_new(guf_str_view{.str = str.data(), .len = (ptrdiff_t)str.size()}, &allocator);
|
|
||||||
dict_str_i32_insert_val_arg(&word_cnt_dict_str, str_cpy, 42, GUF_CPY_DEEP, GUF_CPY_VALUE);
|
|
||||||
int32_t *foo = dict_str_i32_at_val_arg(&word_cnt_dict_str, guf_str_new_readonly(guf_str_view_from_str(&str_cpy)));
|
|
||||||
if (TEST_CHECK(foo)) {
|
|
||||||
TEST_CHECK(*foo == 42);
|
|
||||||
}
|
|
||||||
guf_str_append(&str_cpy, GUF_CSTR_LIT_TO_VIEW_CPP("Foobar"));
|
|
||||||
int32_t *foo2 = dict_str_i32_at_val_arg(&word_cnt_dict_str, guf_str_new_readonly(guf_str_view{.str = str.data(), .len = (ptrdiff_t)str.size()}));
|
|
||||||
if (TEST_CHECK(foo2)) {
|
|
||||||
TEST_CHECK(*foo2 == 42);
|
|
||||||
}
|
|
||||||
|
|
||||||
guf_str_free(&str_cpy, NULL);
|
|
||||||
|
|
||||||
dict_sv_i32_free(&word_cnt_dict, NULL);
|
|
||||||
dict_str_i32_free(&word_cnt_dict_str, NULL);
|
|
||||||
|
|
||||||
bool dbuf_null = !word_cnt_dict.kv_elems.data && !word_cnt_dict.kv_elems.allocator && !word_cnt_dict.kv_elems.capacity && !word_cnt_dict.kv_elems.size;
|
|
||||||
TEST_CHECK(dbuf_null && !word_cnt_dict.kv_indices && !word_cnt_dict.kv_indices_cap && !word_cnt_dict.max_probelen && !word_cnt_dict.num_tombstones);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DictSvToIntTest::load_file(const char *fname)
|
|
||||||
{
|
|
||||||
FILE *in_file {nullptr};
|
|
||||||
if (!in_file) {
|
|
||||||
in_file = fopen(fname, "r");
|
|
||||||
}
|
|
||||||
|
|
||||||
GUF_ASSERT_RELEASE(in_file);
|
|
||||||
|
|
||||||
dbuf_char_init(&text_buf, 128, &allocator);
|
|
||||||
|
|
||||||
int c = EOF;
|
|
||||||
while ((c = fgetc(in_file)) != EOF) {
|
|
||||||
dbuf_char_push_val(&text_buf, (char)c);
|
|
||||||
text_vec.push_back((char)c);
|
|
||||||
}
|
|
||||||
fclose(in_file);
|
|
||||||
|
|
||||||
// dbuf_char_insert_val(&text_buf, '\xC0', 1);
|
|
||||||
// text_vec.insert(text_vec.cbegin() + 1, '\xC0');
|
|
||||||
|
|
||||||
return TEST_CHECK(std::ssize(text_vec) == text_buf.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DictSvToIntTest::free_file()
|
|
||||||
{
|
|
||||||
dbuf_char_free(&text_buf, NULL);
|
|
||||||
text_buf = {};
|
|
||||||
text_vec.clear();
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <vector>
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
#include "test.hpp"
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include "impls/dbuf_impl.h"
|
|
||||||
#include "guf_alloc_libc.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DictSvToIntTest : public Test
|
|
||||||
{
|
|
||||||
DictSvToIntTest(const std::string& nm) : Test(nm)
|
|
||||||
{
|
|
||||||
allocator_ctx.zero_init = false;
|
|
||||||
guf_alloc_tracker_init(&allocator_ctx.tracker, 3, "DictSvToIntTest_allocator", NULL, NULL);
|
|
||||||
guf_libc_allocator_init(&allocator, &allocator_ctx);
|
|
||||||
};
|
|
||||||
|
|
||||||
void run() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
guf_allocator allocator;
|
|
||||||
guf_libc_alloc_ctx allocator_ctx;
|
|
||||||
|
|
||||||
dbuf_char text_buf {};
|
|
||||||
std::vector<char> text_vec {};
|
|
||||||
|
|
||||||
bool load_file(const char *fname);
|
|
||||||
void free_file();
|
|
||||||
|
|
||||||
void insert_lookup(std::optional<ptrdiff_t> inital_dict_cap = {});
|
|
||||||
};
|
|
||||||
@ -1,379 +0,0 @@
|
|||||||
#include "test_str.hpp"
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include "guf_alloc_libc.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
StrTest:
|
|
||||||
*/
|
|
||||||
|
|
||||||
void StrTest::run()
|
|
||||||
{
|
|
||||||
if (done) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<std::string> words = {
|
|
||||||
"",
|
|
||||||
"\0",
|
|
||||||
"Hello",
|
|
||||||
"Othell\0o",
|
|
||||||
"f\0\0",
|
|
||||||
"\0",
|
|
||||||
"0",
|
|
||||||
"a",
|
|
||||||
"ab",
|
|
||||||
"🌈 waow a rainboge!",
|
|
||||||
"orange cat(1) :3",
|
|
||||||
"xes yag",
|
|
||||||
"Hello, world! This is a pretty darn long string I'd say...",
|
|
||||||
"I want to eat crayons. I crave crayons because they are tasty, and everybody telling me crayons are not edible must be either lying or dumb. I like trains. 42 is a number. 3.14159265... is not a rational number, and it is called pi. I ate some pie (it was a crayon pie).",
|
|
||||||
std::string(32, 'a'),
|
|
||||||
std::string(64, 'b'),
|
|
||||||
std::string(1024, 'a'),
|
|
||||||
std::string(2048, 'a'),
|
|
||||||
std::string(4096, 'a'),
|
|
||||||
std::string(5001, 'a'),
|
|
||||||
std::string(7121, 'a'),
|
|
||||||
std::string(2000, 'a'),
|
|
||||||
std::string(GUF_STR_SSO_BUF_CAP, 'a'),
|
|
||||||
std::string(GUF_STR_SSO_BUF_CAP - 1, 'a'),
|
|
||||||
std::string(GUF_STR_SSO_BUF_CAP + 1, 'a'),
|
|
||||||
std::string(GUF_STR_SSO_BUF_CAP - 2, 'a'),
|
|
||||||
std::string(GUF_STR_SSO_BUF_CAP + 2, 'a'),
|
|
||||||
std::string(GUF_STR_SSO_BUF_CAP - 3, 'a'),
|
|
||||||
std::string(GUF_STR_SSO_BUF_CAP + 3, 'a'),
|
|
||||||
std::string(GUF_STR_SSO_BUF_CAP * 2, 'a'),
|
|
||||||
std::string(GUF_STR_SSO_BUF_CAP * 3, 'a'),
|
|
||||||
std::string(GUF_STR_SSO_BUF_CAP * 4, 'a'),
|
|
||||||
std::string(GUF_STR_SSO_BUF_CAP * 5, 'a'),
|
|
||||||
std::string(GUF_STR_SSO_BUF_CAP * 6, 'a'),
|
|
||||||
std::string(GUF_STR_SSO_BUF_CAP * 7, 'a'),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
push_check_name("init_empy");
|
|
||||||
test_init_empty();
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
push_check_name("append_char");
|
|
||||||
for (const auto& word : words) {
|
|
||||||
test_init_free(word);
|
|
||||||
test_append_char(word);
|
|
||||||
test_append_char(word, true);
|
|
||||||
}
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
push_check_name("append_str");
|
|
||||||
for (size_t i = 0; i < words.size(); ++i) {
|
|
||||||
const auto& w1 = words.at(i);
|
|
||||||
append_str(w1, w1);
|
|
||||||
append_str(w1, w1);
|
|
||||||
for (size_t j = i + 1; j < words.size(); ++j) {
|
|
||||||
const auto& w2 = words.at(j);
|
|
||||||
append_str(w1, w2);
|
|
||||||
append_str(w2, w1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
push_check_name("test_popsplit");
|
|
||||||
std::vector<std::string_view> split = test_popsplit("1997-04-01", "-");
|
|
||||||
if (TEST_CHECK(split.size() == 3)) {
|
|
||||||
TEST_CHECK(split.at(0) == "1997" && split.at(1) == "04" && split.at(2) == "01");
|
|
||||||
}
|
|
||||||
split = test_popsplit("1997-04-01-", "-");
|
|
||||||
if (TEST_CHECK(split.size() == 3)) {
|
|
||||||
TEST_CHECK(split.at(0) == "1997" && split.at(1) == "04" && split.at(2) == "01");
|
|
||||||
}
|
|
||||||
|
|
||||||
split = test_popsplit("2025/05/08", "/");
|
|
||||||
if (TEST_CHECK(split.size() == 3)) {
|
|
||||||
TEST_CHECK(split.at(0) == "2025" && split.at(1) == "05" && split.at(2) == "08");
|
|
||||||
}
|
|
||||||
split = test_popsplit("2025/05/08/", "/");
|
|
||||||
if (TEST_CHECK(split.size() == 3)) {
|
|
||||||
TEST_CHECK(split.at(0) == "2025" && split.at(1) == "05" && split.at(2) == "08");
|
|
||||||
}
|
|
||||||
split = test_popsplit("2025/05/08//", "/");
|
|
||||||
if (TEST_CHECK(split.size() == 4)) {
|
|
||||||
TEST_CHECK(split.at(0) == "2025" && split.at(1) == "05" && split.at(2) == "08" && split.at(3) == "");
|
|
||||||
}
|
|
||||||
|
|
||||||
split = test_popsplit("/2025/05/08", "/");
|
|
||||||
if (TEST_CHECK(split.size() == 4)) {
|
|
||||||
TEST_CHECK(split.at(0) == "" && split.at(1) == "2025" && split.at(2) == "05" && split.at(3) == "08");
|
|
||||||
}
|
|
||||||
split = test_popsplit("//2025/05/08", "/");
|
|
||||||
if (TEST_CHECK(split.size() == 5)) {
|
|
||||||
TEST_CHECK(split.at(0) == "" && split.at(1) == "" && split.at(2) == "2025" && split.at(3) == "05" && split.at(4) == "08");
|
|
||||||
}
|
|
||||||
|
|
||||||
split = test_popsplit("I eat formidable crayons, oof, for real", "foo");
|
|
||||||
if (TEST_CHECK(split.size() == 1)) {
|
|
||||||
TEST_CHECK(split.at(0) == "I eat formidable crayons, oof, for real");
|
|
||||||
}
|
|
||||||
|
|
||||||
split = test_popsplit("Hej <<", "<<");
|
|
||||||
if (TEST_CHECK(split.size() == 1)) {
|
|
||||||
TEST_CHECK(split.at(0) == "Hej ");
|
|
||||||
}
|
|
||||||
split = test_popsplit("Hej << verden", "<<");
|
|
||||||
if (TEST_CHECK(split.size() == 2)) {
|
|
||||||
TEST_CHECK(split.at(0) == "Hej " && split.at(1) == " verden");
|
|
||||||
}
|
|
||||||
split = test_popsplit("<< Hej << verden", "<<");
|
|
||||||
if (TEST_CHECK(split.size() == 3)) {
|
|
||||||
TEST_CHECK(split.at(0) == "" && split.at(1) == " Hej " && split.at(2) == " verden");
|
|
||||||
}
|
|
||||||
split = test_popsplit("<< Hej << verden <<< foo<>", "<<");
|
|
||||||
if (TEST_CHECK(split.size() == 4)) {
|
|
||||||
TEST_CHECK(split.at(0) == "" && split.at(1) == " Hej " && split.at(2) == " verden " && split.at(3) == "< foo<>");
|
|
||||||
}
|
|
||||||
|
|
||||||
split = test_popsplit("I eat tofu", "");
|
|
||||||
if (TEST_CHECK(split.size() == 1)) {
|
|
||||||
TEST_CHECK(split.at(0) == "I eat tofu");
|
|
||||||
}
|
|
||||||
|
|
||||||
split = test_popsplit("At 3 a.m. during FULL-moon FULL-STOP Next to the public-library's -STOP sign FULL-STOP", "FULL-STOP");
|
|
||||||
if (TEST_CHECK(split.size() == 2)) {
|
|
||||||
TEST_CHECK(split.at(0) == "At 3 a.m. during FULL-moon " && split.at(1) == " Next to the public-library's -STOP sign ");
|
|
||||||
}
|
|
||||||
split = test_popsplit("At 3 a.m. during FULL-moon FULL-STOP Next to the public-library's -STOP sign FULL-STOPI like trains, FULL-STO", "FULL-STOP");
|
|
||||||
if (TEST_CHECK(split.size() == 3)) {
|
|
||||||
TEST_CHECK(split.at(0) == "At 3 a.m. during FULL-moon " && split.at(1) == " Next to the public-library's -STOP sign " && split.at(2) == "I like trains, FULL-STO");
|
|
||||||
}
|
|
||||||
split = test_popsplit("At 3 a.m. during FULL-moon FULL-STOP Next to the public-library's -STOP sign FULL-STOPI like trains, FULL-STO Poo", "FULL-STOP");
|
|
||||||
if (TEST_CHECK(split.size() == 3)) {
|
|
||||||
TEST_CHECK(split.at(0) == "At 3 a.m. during FULL-moon " && split.at(1) == " Next to the public-library's -STOP sign " && split.at(2) == "I like trains, FULL-STO Poo");
|
|
||||||
}
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
push_check_name("get_toks");
|
|
||||||
std::vector<std::string_view> tok_words = {"hello", "world", "cat", "vertex", "normal", "pizza", "running", "mouse", "playing", "adjacent"};
|
|
||||||
std::vector<std::string_view> delims = {",", " ", "\n", "\t", "\r"};
|
|
||||||
|
|
||||||
for (int is_trailing = 0; is_trailing < 2; ++is_trailing) {
|
|
||||||
for (ptrdiff_t num_words = 1; num_words < std::ssize(tok_words); ++num_words) {
|
|
||||||
std::string str = "";
|
|
||||||
for (ptrdiff_t j = 0; j < num_words; ++j) {
|
|
||||||
str += tok_words.at(j);
|
|
||||||
if (j < num_words - 1 || is_trailing) {
|
|
||||||
str += ", ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::vector<std::string_view> toks = get_toks(std::string_view{str}, delims, false, GUF_STR_TOK_DELIM_OPT_MATCH_LONGEST);
|
|
||||||
if (TEST_CHECK(std::ssize(toks) == num_words)) {
|
|
||||||
for (ptrdiff_t i = 0; i < num_words; ++i) {
|
|
||||||
TEST_CHECK(toks.at(i) == tok_words.at(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string_view tok_str = "<stats>age: 28, occupation: NULL, crayons_eaten: 256 </stats>";
|
|
||||||
delims = {"<stats>", "</stats>", ":", ",", " ", "\t", "<stats", "<", ">", "</"};
|
|
||||||
auto tok_result = get_toks(tok_str, delims, true, GUF_STR_TOK_DELIM_OPT_MATCH_LONGEST);
|
|
||||||
TEST_CHECK(tok_result.size() == 19);
|
|
||||||
TEST_CHECK(tok_result.at(18) == "</stats>" && tok_result.at(0) == "<stats>" && tok_result.at(1) == "age" && tok_result.at(2) == ":" && tok_result.at(3) == " " && tok_result.at(4) == "28");
|
|
||||||
|
|
||||||
tok_result = get_toks(tok_str, delims, false, GUF_STR_TOK_DELIM_OPT_MATCH_LONGEST);
|
|
||||||
TEST_CHECK(tok_result.size() == 6);
|
|
||||||
TEST_CHECK(tok_result.at(0) == "age" && tok_result.at(1) == "28" && tok_result.at(2) == "occupation" && tok_result.at(3) == "NULL" &&
|
|
||||||
tok_result.at(4) == "crayons_eaten" && tok_result.at(5) == "256");
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
// guf_alloc_tracker_print(&allocator_ctx.tracker, NULL);
|
|
||||||
TEST_CHECK(!guf_alloc_tracker_found_leak(&allocator_ctx.tracker));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void StrTest::test_init_free(std::string str)
|
|
||||||
{
|
|
||||||
guf_str s0;
|
|
||||||
guf_str_init(&s0, GUF_CSTR_TO_VIEW_CPP(str.c_str()), &allocator);
|
|
||||||
guf_str s1 = guf_str_new(GUF_CSTR_TO_VIEW_CPP(str.c_str()), &allocator);
|
|
||||||
guf_str s2;
|
|
||||||
guf_str_init_from_cstr(&s2, str.c_str(), &allocator);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_str_equal(&s0, &s1));
|
|
||||||
TEST_CHECK(guf_str_equal(&s0, &s2));
|
|
||||||
TEST_CHECK(guf_str_equal(&s1, &s2));
|
|
||||||
|
|
||||||
TEST_CHECK((ptrdiff_t)str.size() == guf_str_len(&s0));
|
|
||||||
TEST_CHECK(str == guf_str_const_cstr(&s0));
|
|
||||||
TEST_CHECK(str == guf_str_cstr(&s0));
|
|
||||||
|
|
||||||
TEST_CHECK((ptrdiff_t)str.size() == guf_str_len(&s1));
|
|
||||||
TEST_CHECK(str == guf_str_const_cstr(&s1));
|
|
||||||
TEST_CHECK(str == guf_str_cstr(&s1));
|
|
||||||
|
|
||||||
TEST_CHECK((ptrdiff_t)str.size() == guf_str_len(&s2));
|
|
||||||
TEST_CHECK(str == guf_str_const_cstr(&s2));
|
|
||||||
TEST_CHECK(str == guf_str_cstr(&s2));
|
|
||||||
|
|
||||||
guf_str_free(&s0, NULL);
|
|
||||||
guf_str_free(&s1, NULL);
|
|
||||||
guf_str_free(&s2, NULL);
|
|
||||||
TEST_CHECK(guf_str_is_uninit(&s0));
|
|
||||||
TEST_CHECK(guf_str_is_uninit(&s1));
|
|
||||||
TEST_CHECK(guf_str_is_uninit(&s2));
|
|
||||||
}
|
|
||||||
|
|
||||||
void StrTest::test_init_empty()
|
|
||||||
{
|
|
||||||
std::string str = "";
|
|
||||||
guf_str s = GUF_STR_UNINITIALISED_CPP;
|
|
||||||
guf_str_init_empty(&s, &allocator);
|
|
||||||
TEST_CHECK(guf_str_len(&s) == 0);
|
|
||||||
TEST_CHECK(str == guf_str_const_cstr(&s));
|
|
||||||
|
|
||||||
guf_str_append_char(&s, 'a', 1024);
|
|
||||||
str.append(1024, 'a');
|
|
||||||
TEST_CHECK(guf_str_len(&s) == (ptrdiff_t)str.size());
|
|
||||||
TEST_CHECK(guf_str_const_cstr(&s) == str);
|
|
||||||
|
|
||||||
guf_str_append_char(&s, 'b', 24);
|
|
||||||
str.append(24, 'b');
|
|
||||||
TEST_CHECK(guf_str_len(&s) == (ptrdiff_t)str.size());
|
|
||||||
TEST_CHECK(guf_str_const_cstr(&s) == str);
|
|
||||||
|
|
||||||
guf_str_append_char(&s, 'c', 255);
|
|
||||||
str.append(255, 'c');
|
|
||||||
TEST_CHECK(guf_str_len(&s) == (ptrdiff_t)str.size());
|
|
||||||
TEST_CHECK(guf_str_const_cstr(&s) == str);
|
|
||||||
|
|
||||||
*guf_str_at(&s, 0) = '<';
|
|
||||||
str.at(0) = '<';
|
|
||||||
TEST_CHECK(guf_str_len(&s) == (ptrdiff_t)str.size());
|
|
||||||
TEST_CHECK(guf_str_const_cstr(&s) == str);
|
|
||||||
|
|
||||||
*guf_str_at(&s, guf_str_len(&s) - 1) = '>';
|
|
||||||
str.at(str.size() - 1) = '>';
|
|
||||||
TEST_CHECK(guf_str_len(&s) == (ptrdiff_t)str.size());
|
|
||||||
TEST_CHECK(guf_str_const_cstr(&s) == str);
|
|
||||||
|
|
||||||
guf_err err = GUF_ERR_NONE;
|
|
||||||
TEST_CHECK(NULL == guf_str_try_at(&s, guf_str_len(&s), &err));
|
|
||||||
TEST_CHECK(err != GUF_ERR_NONE && err == GUF_ERR_IDX_RANGE);
|
|
||||||
err = GUF_ERR_NONE;
|
|
||||||
TEST_CHECK(NULL == guf_str_try_at(&s, -1, &err));
|
|
||||||
TEST_CHECK(err != GUF_ERR_NONE && err == GUF_ERR_IDX_RANGE);
|
|
||||||
|
|
||||||
guf_str_free(&s, NULL);
|
|
||||||
TEST_CHECK(guf_str_is_uninit(&s));
|
|
||||||
}
|
|
||||||
|
|
||||||
void StrTest::test_append_char(std::string str, bool include_null)
|
|
||||||
{
|
|
||||||
guf_str s0 = guf_str_new(guf_str_view{.str = str.c_str(), .len = (ptrdiff_t)str.size()}, &allocator);
|
|
||||||
|
|
||||||
TEST_CHECK((ptrdiff_t)str.size() == guf_str_len(&s0));
|
|
||||||
TEST_CHECK((str == std::string_view{guf_str_const_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
|
||||||
|
|
||||||
for (int i = include_null ? 0 : 1; i < 128; ++i) {
|
|
||||||
char ch = (char)i;
|
|
||||||
guf_str_append_one_char(&s0, ch);
|
|
||||||
str.append(1, ch);
|
|
||||||
TEST_CHECK(guf_str_len(&s0) == (ptrdiff_t)str.size());
|
|
||||||
TEST_CHECK((str == std::string_view{guf_str_const_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = include_null ? 0 : 1; i < 128; ++i) {
|
|
||||||
char ch = (char)i;
|
|
||||||
guf_str_append_char(&s0, ch, i);
|
|
||||||
str.append(i, ch);
|
|
||||||
TEST_CHECK(guf_str_len(&s0) == (ptrdiff_t)str.size());
|
|
||||||
TEST_CHECK((str == std::string_view{guf_str_const_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
|
||||||
guf_str_append_char(&s0, ch, i * 16);
|
|
||||||
str.append(i * 16, ch);
|
|
||||||
TEST_CHECK(guf_str_len(&s0) == (ptrdiff_t)str.size());
|
|
||||||
TEST_CHECK((str == std::string_view{guf_str_const_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
|
||||||
}
|
|
||||||
|
|
||||||
guf_str_free(&s0, NULL);
|
|
||||||
TEST_CHECK(guf_str_is_uninit(&s0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void StrTest::append_str(const std::string& a, const std::string& b)
|
|
||||||
{
|
|
||||||
std::string str0 = a;
|
|
||||||
guf_str s0 = guf_str_new(guf_str_view{.str = str0.c_str(), .len = (ptrdiff_t)str0.size()}, &allocator);
|
|
||||||
TEST_CHECK(guf_str_len(&s0) == (ptrdiff_t)str0.size());
|
|
||||||
TEST_CHECK((str0 == std::string_view{guf_str_const_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
|
||||||
TEST_CHECK((str0 == std::string_view{guf_str_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
|
||||||
|
|
||||||
for (int i = 0; i <= 64; ++i) {
|
|
||||||
str0.append(b);
|
|
||||||
guf_str_append(&s0, guf_str_view{.str = b.c_str(), .len = (ptrdiff_t)b.size()});
|
|
||||||
TEST_CHECK(guf_str_len(&s0) == (ptrdiff_t)str0.size());
|
|
||||||
TEST_CHECK((str0 == std::string_view{guf_str_const_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
|
||||||
TEST_CHECK((str0 == std::string_view{guf_str_cstr(&s0), (size_t)guf_str_len(&s0)}));
|
|
||||||
}
|
|
||||||
|
|
||||||
guf_str_free(&s0, NULL);
|
|
||||||
TEST_CHECK(guf_str_is_uninit(&s0));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string_view> StrTest::test_popsplit(std::string_view str, std::string_view delim)
|
|
||||||
{
|
|
||||||
std::vector<std::string_view> result = {};
|
|
||||||
|
|
||||||
if (delim.size() > 0) { // NOTE: str.find with an empty delimiter returns 0, not std::string::npos
|
|
||||||
std::string_view src_cpp = str;
|
|
||||||
for (size_t idx = src_cpp.find(delim, 0); src_cpp.size() > 0; idx = src_cpp.find(delim, 0)) {
|
|
||||||
result.push_back(src_cpp.substr(0, idx));
|
|
||||||
if (idx == std::string::npos) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
src_cpp = src_cpp.substr(idx + delim.size());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.push_back(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const guf_str_view delim_sv = guf_str_view{.str = delim.data(), .len = (ptrdiff_t)delim.size()};
|
|
||||||
guf_str_view src = guf_str_view{.str = str.data(), .len = (ptrdiff_t)str.size()};
|
|
||||||
size_t n = 0;
|
|
||||||
do {
|
|
||||||
const guf_str_view popped = guf_str_view_pop_split(&src, delim_sv);
|
|
||||||
TEST_CHECK(n < result.size());
|
|
||||||
TEST_CHECK(std::string_view(popped.str, (size_t)popped.len) == result.at(n));
|
|
||||||
const guf_str_view res = {.str = result.at(n).data(), .len = (ptrdiff_t)result.at(n).size()};
|
|
||||||
TEST_CHECK(guf_str_view_equal(&popped, &res));
|
|
||||||
TEST_CHECK(guf_str_view_equal_val_arg(popped, res));
|
|
||||||
// std::cout << "guf: " << std::string_view{popped.str, (size_t)popped.len} << "\n";
|
|
||||||
// std::cout << "cpp: " << std::string_view{res.str, (size_t)res.len} << "\n";
|
|
||||||
++n;
|
|
||||||
} while (src.len > 0);
|
|
||||||
TEST_CHECK(n == result.size());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string_view> StrTest::get_toks(std::string_view sv_in, const std::vector<std::string_view>& delims_in, bool preserve_delims, guf_str_tok_delim_opt opt)
|
|
||||||
{
|
|
||||||
const guf_str_view sv = guf_str_view{.str = sv_in.data(), .len = (ptrdiff_t)sv_in.size()};
|
|
||||||
std::vector<guf_str_view> delims;
|
|
||||||
for (const auto delim : delims_in) {
|
|
||||||
delims.push_back(guf_str_view{.str = delim.data(), .len = (ptrdiff_t)delim.size()});
|
|
||||||
}
|
|
||||||
guf_str_tok_state tok_state = guf_str_tok_state_new(sv, delims.data(), std::ssize(delims), opt);
|
|
||||||
|
|
||||||
std::vector<std::string_view> toks_out;
|
|
||||||
while (guf_str_tok_next(&tok_state, preserve_delims)) {
|
|
||||||
if (tok_state.cur_tok.len > 0) {
|
|
||||||
toks_out.push_back( std::string_view{tok_state.cur_tok.str, (size_t)tok_state.cur_tok.len});
|
|
||||||
}
|
|
||||||
if (preserve_delims && tok_state.cur_delim.len > 0) {
|
|
||||||
toks_out.push_back( std::string_view{tok_state.cur_delim.str, (size_t)tok_state.cur_delim.len});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST_CHECK(tok_state.done);
|
|
||||||
const ptrdiff_t num_toks = preserve_delims ? tok_state.num_delims_read + tok_state.num_toks_read : tok_state.num_toks_read;
|
|
||||||
TEST_CHECK(num_toks == std::ssize(toks_out));
|
|
||||||
return toks_out;
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include "test.hpp"
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include "guf_str.h"
|
|
||||||
#include "guf_alloc_libc.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
struct StrTest : public Test
|
|
||||||
{
|
|
||||||
StrTest(const std::string& nm) : Test(nm)
|
|
||||||
{
|
|
||||||
allocator_ctx.zero_init = false;
|
|
||||||
guf_alloc_tracker_init(&allocator_ctx.tracker, 4, "StrTest_allocator", NULL, NULL);
|
|
||||||
guf_libc_allocator_init(&allocator, &allocator_ctx);
|
|
||||||
};
|
|
||||||
|
|
||||||
void run() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
guf_allocator allocator;
|
|
||||||
guf_libc_alloc_ctx allocator_ctx;
|
|
||||||
|
|
||||||
void test_init_free(std::string str);
|
|
||||||
void test_init_empty();
|
|
||||||
void test_append_char(std::string str, bool include_null = false);
|
|
||||||
void append_str(const std::string& a, const std::string& b);
|
|
||||||
std::vector<std::string_view> test_popsplit(std::string_view str, std::string_view delim);
|
|
||||||
std::vector<std::string_view> get_toks(std::string_view sv_in, const std::vector<std::string_view>& delims_in, bool preserve_delims = false, guf_str_tok_delim_opt opt = GUF_STR_TOK_DELIM_OPT_MATCH_LONGEST);
|
|
||||||
};
|
|
||||||
@ -1,387 +0,0 @@
|
|||||||
#include "test_utf8.hpp"
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include "guf_alloc_libc.h"
|
|
||||||
#include "guf_str.h"
|
|
||||||
#include "impls/dict_impl.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
UTF8Test:
|
|
||||||
*/
|
|
||||||
|
|
||||||
void UTF8Test::run()
|
|
||||||
{
|
|
||||||
if (done) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
push_check_name("read_utf8_chars");
|
|
||||||
ptrdiff_t valid = 0, invalid = 0;
|
|
||||||
read_utf8_chars(TEST_DATA_DIR "/" "utf8-test.txt", &valid, &invalid);
|
|
||||||
TEST_CHECK(valid == 2635 && invalid == 0);
|
|
||||||
read_utf8_chars(TEST_DATA_DIR "/" "bartleby.txt", &valid, &invalid);
|
|
||||||
TEST_CHECK(valid > 16000 && invalid == 0);
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
push_check_name("count_words");
|
|
||||||
dbuf_str_view delims = dbuf_str_view_new(&allocator);
|
|
||||||
for (size_t i = 0; i < GUF_ARR_SIZE(GUF_UTF8_WHITESPACE); ++i) {
|
|
||||||
guf_str_view d = {.str = GUF_UTF8_WHITESPACE[i], .len = (ptrdiff_t)strlen(GUF_UTF8_WHITESPACE[i])};
|
|
||||||
dbuf_str_view_push_val(&delims, d);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < GUF_ARR_SIZE(GUF_UTF8_COMMON_PUNCT); ++i) {
|
|
||||||
guf_str_view d = {.str = GUF_UTF8_COMMON_PUNCT[i], .len = (ptrdiff_t)strlen(GUF_UTF8_COMMON_PUNCT[i])};
|
|
||||||
dbuf_str_view_push_val(&delims, d);
|
|
||||||
}
|
|
||||||
int words = count_words(TEST_DATA_DIR "/" "utf8-test.txt", &delims);
|
|
||||||
TEST_CHECK(words == 422);
|
|
||||||
int words_with_delims = count_words_with_delims(TEST_DATA_DIR "/" "utf8-test.txt", &delims);
|
|
||||||
TEST_CHECK(words_with_delims == 950);
|
|
||||||
|
|
||||||
int words2 = count_words(TEST_DATA_DIR "/" "bartleby.txt", &delims);
|
|
||||||
TEST_CHECK(words2 > 2048);
|
|
||||||
|
|
||||||
dbuf_str_view_free(&delims, NULL);
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
push_check_name("encode_decode");
|
|
||||||
encode_decode();
|
|
||||||
encode_decode_file(TEST_DATA_DIR "/" "utf8-test.txt");
|
|
||||||
encode_decode_file(TEST_DATA_DIR "/" "bartleby.txt");
|
|
||||||
pop_check_name();
|
|
||||||
|
|
||||||
//guf_alloc_tracker_print(&allocator_ctx.tracker, NULL);
|
|
||||||
TEST_CHECK(!guf_alloc_tracker_found_leak(&allocator_ctx.tracker));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool UTF8Test::load_text(const char *fname)
|
|
||||||
{
|
|
||||||
FILE *in_file {nullptr};
|
|
||||||
if (!in_file) {
|
|
||||||
in_file = fopen(fname, "r");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!in_file) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
dbuf_char_init(&text_buf, 128, &allocator);
|
|
||||||
|
|
||||||
int c = EOF;
|
|
||||||
while ((c = fgetc(in_file)) != EOF) {
|
|
||||||
dbuf_char_push_val(&text_buf, (char)c);
|
|
||||||
text_vec.push_back((char)c);
|
|
||||||
}
|
|
||||||
fclose(in_file);
|
|
||||||
|
|
||||||
return TEST_CHECK(std::ssize(text_vec) == text_buf.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UTF8Test::free_text()
|
|
||||||
{
|
|
||||||
dbuf_char_free(&text_buf, NULL);
|
|
||||||
text_vec.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void UTF8Test::read_utf8_chars(const char *fname, ptrdiff_t *n_valid, ptrdiff_t *n_invalid)
|
|
||||||
{
|
|
||||||
GUF_ASSERT_RELEASE(load_text(fname));
|
|
||||||
|
|
||||||
ptrdiff_t valid_chars = 0, invalid_chars = 0, bytes = 0;
|
|
||||||
guf_str_view input_str = {.str = text_buf.data, .len = text_buf.size};
|
|
||||||
guf_utf8_char ch = {};
|
|
||||||
for (guf_utf8_stat stat = guf_utf8_char_next(&ch, &input_str); stat != GUF_UTF8_READ_DONE; stat = guf_utf8_char_next(&ch, &input_str)) {
|
|
||||||
if (stat == GUF_UTF8_READ_VALID) {
|
|
||||||
++valid_chars;
|
|
||||||
// printf("%s", ch.bytes);
|
|
||||||
} else {
|
|
||||||
++invalid_chars;
|
|
||||||
// printf("::INVALID_UTF8_CHAR::");
|
|
||||||
}
|
|
||||||
bytes += guf_utf8_char_num_bytes(&ch);
|
|
||||||
}
|
|
||||||
TEST_CHECK(input_str.len == 0 && input_str.str == NULL);
|
|
||||||
TEST_CHECK(bytes == text_buf.size);
|
|
||||||
|
|
||||||
// printf("\nread %td bytes\n", bytes);
|
|
||||||
// printf("read %td valid and %td invalid utf-8 characters\n", valid_chars, invalid_chars);
|
|
||||||
|
|
||||||
free_text();
|
|
||||||
|
|
||||||
if (n_valid)
|
|
||||||
*n_valid = valid_chars;
|
|
||||||
if (n_invalid)
|
|
||||||
*n_invalid = invalid_chars;
|
|
||||||
}
|
|
||||||
|
|
||||||
int UTF8Test::count_words(const char *fname, const dbuf_str_view *delims)
|
|
||||||
{
|
|
||||||
GUF_ASSERT_RELEASE(load_text(fname));
|
|
||||||
|
|
||||||
int num_words = 0;
|
|
||||||
|
|
||||||
guf_str_tok_state tok_state = guf_str_tok_state_new(guf_str_view{.str = text_buf.data, .len = text_buf.size}, delims->data, delims->size, GUF_STR_TOK_DELIM_OPT_MATCH_LONGEST);
|
|
||||||
while (guf_str_tok_next(&tok_state, false)) {
|
|
||||||
TEST_CHECK(tok_state.cur_tok.len > 0);
|
|
||||||
++num_words;
|
|
||||||
}
|
|
||||||
|
|
||||||
free_text();
|
|
||||||
return num_words;
|
|
||||||
}
|
|
||||||
|
|
||||||
int UTF8Test::count_words_with_delims(const char *fname, const dbuf_str_view *delims)
|
|
||||||
{
|
|
||||||
GUF_ASSERT_RELEASE(load_text(fname));
|
|
||||||
|
|
||||||
int num_words = 0, num_delims = 0;
|
|
||||||
guf_str_tok_state tok_state = guf_str_tok_state_new(guf_str_view{.str = text_buf.data, .len = text_buf.size}, delims->data, delims->size, GUF_STR_TOK_DELIM_OPT_MATCH_LONGEST);
|
|
||||||
while (guf_str_tok_next(&tok_state, true)) {
|
|
||||||
if (tok_state.cur_tok.len) {
|
|
||||||
++num_words;
|
|
||||||
// printf("'%.*s'\n", (int)tok_state.cur_tok.len, tok_state.cur_tok.str);
|
|
||||||
}
|
|
||||||
if (tok_state.cur_delim.len) {
|
|
||||||
++num_delims;
|
|
||||||
// if (tok_state.cur_delim.str[0] == '\n')
|
|
||||||
// printf("'\\n'\n");
|
|
||||||
// else
|
|
||||||
// printf("'%.*s'\n", (int)tok_state.cur_delim.len, tok_state.cur_delim.str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free_text();
|
|
||||||
return num_words + num_delims;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UTF8Test::encode_decode_file(const char *fname)
|
|
||||||
{
|
|
||||||
GUF_ASSERT_RELEASE(load_text(fname));
|
|
||||||
|
|
||||||
dbuf_i32 cp_buf = dbuf_i32_new(&allocator);
|
|
||||||
|
|
||||||
ptrdiff_t valid_chars = 0, invalid_chars = 0;
|
|
||||||
guf_str_view input_str = {.str = text_buf.data, .len = text_buf.size};
|
|
||||||
guf_utf8_char ch = {};
|
|
||||||
for (guf_utf8_stat stat = guf_utf8_char_next(&ch, &input_str); stat != GUF_UTF8_READ_DONE; stat = guf_utf8_char_next(&ch, &input_str)) {
|
|
||||||
if (stat == GUF_UTF8_READ_VALID) {
|
|
||||||
++valid_chars;
|
|
||||||
const int32_t codepoint = guf_utf8_decode(&ch);
|
|
||||||
TEST_CHECK(codepoint >= 0);
|
|
||||||
dbuf_i32_push_val(&cp_buf, codepoint);
|
|
||||||
} else {
|
|
||||||
++invalid_chars;
|
|
||||||
const int32_t codepoint = guf_utf8_decode(&ch);
|
|
||||||
TEST_CHECK(codepoint < 0);
|
|
||||||
dbuf_i32_push_val(&cp_buf, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST_CHECK(cp_buf.size == valid_chars + invalid_chars);
|
|
||||||
|
|
||||||
guf_str_view in_str = {.str = text_buf.data, .len = text_buf.size};
|
|
||||||
GUF_CNT_FOREACH(&cp_buf, dbuf_i32, it) {
|
|
||||||
GUF_ASSERT_RELEASE(it.ptr);
|
|
||||||
const int32_t codepoint = *it.ptr;
|
|
||||||
guf_utf8_char utf8_ch = {};
|
|
||||||
const guf_utf8_stat stat = guf_utf8_char_next(&utf8_ch, &in_str);
|
|
||||||
if (codepoint >= 0) {
|
|
||||||
TEST_CHECK(stat == GUF_UTF8_READ_VALID);
|
|
||||||
guf_utf8_char encoded_ch = {};
|
|
||||||
TEST_CHECK(guf_utf8_encode(&encoded_ch, codepoint));
|
|
||||||
TEST_CHECK(guf_utf8_equal(&encoded_ch, &utf8_ch));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
guf_utf8_char utf8_ch = {};
|
|
||||||
const guf_utf8_stat stat = guf_utf8_char_next(&utf8_ch, &in_str);
|
|
||||||
TEST_CHECK(stat == GUF_UTF8_READ_DONE);
|
|
||||||
|
|
||||||
dbuf_i32_free(&cp_buf, NULL);
|
|
||||||
|
|
||||||
free_text();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UTF8Test::encode_decode()
|
|
||||||
{
|
|
||||||
guf_utf8_char utf8 = {0};
|
|
||||||
|
|
||||||
// 1 byte characters.
|
|
||||||
for (uint8_t ascii = 0; ascii <= 0x7F; ++ascii) {
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, ascii));
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 1);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == ascii);
|
|
||||||
TEST_CHECK(utf8.bytes[1] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == ascii);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2 byte characters:
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00E6)); // "æ" (Latin Small Letter Ae)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\xA6');
|
|
||||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00E6);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00E5)); // "å" (Latin Small Letter A with Ring Above)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\xA5');
|
|
||||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00E5);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00F8)); // "ø" (Latin Small Letter O with Stroke)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\xB8');
|
|
||||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00F8);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00E4)); // "ä" (Latin Small Letter A with Diaeresis)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\xA4');
|
|
||||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00E4);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00F6)); // "ö" (Latin Small Letter O with Diaeresis)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\xB6');
|
|
||||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00F6);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00D6)); // "Ö" (Latin Capital Letter O with Diaeresis)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\x96');
|
|
||||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00D6);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00FC)); // "ü" (Latin Small Letter U with Diaeresis)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xC3' && utf8.bytes[1] == '\xBC');
|
|
||||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00FC);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x00B5)); // "µ" (Micro Sign)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xC2' && utf8.bytes[1] == '\xB5');
|
|
||||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x00B5);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x030A)); // "◌̊" (Combining Ring Above)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 2);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xCC' && utf8.bytes[1] == '\x8A');
|
|
||||||
TEST_CHECK(utf8.bytes[2] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x030A);
|
|
||||||
|
|
||||||
// 3 byte characters:
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x7121)); // "無" (Nothingness; CJK Unified Ideograph-7121)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 3);
|
|
||||||
TEST_CHECK(!guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xE7' && utf8.bytes[1] == '\x84' && utf8.bytes[2] == '\xA1');
|
|
||||||
TEST_CHECK(utf8.bytes[3] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x7121);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x201E)); // "„" (Double Low-9 Quotation Mark)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 3);
|
|
||||||
TEST_CHECK(!guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xE2' && utf8.bytes[1] == '\x80' && utf8.bytes[2] == '\x9E');
|
|
||||||
TEST_CHECK(utf8.bytes[3] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x201E);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x20AC)); // "€" (Euro Sign)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 3);
|
|
||||||
TEST_CHECK(!guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xE2' && utf8.bytes[1] == '\x82' && utf8.bytes[2] == '\xAC');
|
|
||||||
TEST_CHECK(utf8.bytes[3] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x20AC);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0xFC51)); // "ﱑ" (Arabic Ligature Heh with Jeem Isolated Form)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 3);
|
|
||||||
TEST_CHECK(!guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xEF' && utf8.bytes[1] == '\xB1' && utf8.bytes[2] == '\x91');
|
|
||||||
TEST_CHECK(utf8.bytes[3] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0xFC51);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x1AA3)); // "᪣" (Tai Tham Sign Keow)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 3);
|
|
||||||
TEST_CHECK(!guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xE1' && utf8.bytes[1] == '\xAA' && utf8.bytes[2] == '\xA3');
|
|
||||||
TEST_CHECK(utf8.bytes[3] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x1AA3);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT)); // "<22>" (Replacement Character)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 3);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xEF' && utf8.bytes[1] == '\xBF' && utf8.bytes[2] == '\xBD');
|
|
||||||
TEST_CHECK(utf8.bytes[3] == '\0');
|
|
||||||
TEST_CHECK(guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT);
|
|
||||||
|
|
||||||
// 4 byte characters:
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x1F308)); // "🌈" (Rainbow)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 4);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xF0' && utf8.bytes[1] == '\x9F' && utf8.bytes[2] == '\x8C' && utf8.bytes[3] == '\x88');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x1F308);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x130B8)); // "𓂸" (Egyptian Hieroglyph D052)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 4);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xF0' && utf8.bytes[1] == '\x93' && utf8.bytes[2] == '\x82' && utf8.bytes[3] == '\xB8');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x130B8);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x1F97A)); // "🥺" (Face with Pleading Eyes)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 4);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xF0' && utf8.bytes[1] == '\x9F' && utf8.bytes[2] == '\xA5' && utf8.bytes[3] == '\xBA');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x1F97A);
|
|
||||||
|
|
||||||
TEST_CHECK(guf_utf8_encode(&utf8, 0x1F980)); // "🦀" (Crab)
|
|
||||||
TEST_CHECK(guf_utf8_char_num_bytes(&utf8) == 4);
|
|
||||||
TEST_CHECK(utf8.bytes[0] == '\xF0' && utf8.bytes[1] == '\x9F' && utf8.bytes[2] == '\xA6' && utf8.bytes[3] == '\x80');
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == 0x1F980);
|
|
||||||
|
|
||||||
// Invalid characters:
|
|
||||||
utf8 = {.bytes = {'\xC0', '\x80', 0, 0}};
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) < 0);
|
|
||||||
|
|
||||||
utf8 = {.bytes = {'\xC0', 0, 0, 0}};
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) < 0);
|
|
||||||
|
|
||||||
utf8 = {.bytes = {'\x80', 0, 0, 0}};
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) < 0);
|
|
||||||
|
|
||||||
// "The definition of UTF-8 prohibits encoding character numbers between U+D800 and U+DFFF" (surrogate pairs).
|
|
||||||
TEST_CHECK(!guf_utf8_encode(&utf8, 0xD800));
|
|
||||||
TEST_CHECK(guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT);
|
|
||||||
|
|
||||||
TEST_CHECK(!guf_utf8_encode(&utf8, 0xDFFF));
|
|
||||||
TEST_CHECK(guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT);
|
|
||||||
|
|
||||||
TEST_CHECK(!guf_utf8_encode(&utf8, 0xDA00));
|
|
||||||
TEST_CHECK(guf_utf8_equal(&utf8, &GUF_UTF8_REPLACEMENT_CHAR));
|
|
||||||
TEST_CHECK(guf_utf8_decode(&utf8) == GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT);
|
|
||||||
|
|
||||||
char buf[] = {'\x2F', '\xC0', '\xAE', '\x2E', '\x2F'};
|
|
||||||
guf_str_view input_str = {.str = buf, .len = GUF_ARR_SIZE(buf)};
|
|
||||||
guf_utf8_char ch = {};
|
|
||||||
int valid_chars = 0, invalid_chars = 0;
|
|
||||||
for (guf_utf8_stat stat = guf_utf8_char_next(&ch, &input_str); stat != GUF_UTF8_READ_DONE; stat = guf_utf8_char_next(&ch, &input_str)) {
|
|
||||||
if (stat == GUF_UTF8_READ_VALID) {
|
|
||||||
++valid_chars;
|
|
||||||
} else {
|
|
||||||
++invalid_chars;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST_CHECK(invalid_chars == 2 && valid_chars == 3);
|
|
||||||
|
|
||||||
char buf2[] = {'\xE0', '\x80', 'a', 'b', 'c'}; // 1 invalid 3-byte-character, 2 valid 1-byte-characters
|
|
||||||
input_str = {.str = buf2, .len = GUF_ARR_SIZE(buf2)};
|
|
||||||
ch = {};
|
|
||||||
valid_chars = invalid_chars = 0;
|
|
||||||
for (guf_utf8_stat stat = guf_utf8_char_next(&ch, &input_str); stat != GUF_UTF8_READ_DONE; stat = guf_utf8_char_next(&ch, &input_str)) {
|
|
||||||
if (stat == GUF_UTF8_READ_VALID) {
|
|
||||||
// printf("%s", ch.bytes);
|
|
||||||
++valid_chars;
|
|
||||||
} else {
|
|
||||||
// printf("%s", GUF_UTF8_REPLACEMENT_CHAR.bytes);
|
|
||||||
++invalid_chars;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST_CHECK(invalid_chars == 1 && valid_chars == 2);
|
|
||||||
}
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <vector>
|
|
||||||
#include "test.hpp"
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include "impls/dbuf_impl.h"
|
|
||||||
#include "guf_alloc_libc.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
struct UTF8Test : public Test
|
|
||||||
{
|
|
||||||
UTF8Test(const std::string& nm) : Test(nm)
|
|
||||||
{
|
|
||||||
allocator_ctx.zero_init = false;
|
|
||||||
guf_alloc_tracker_init(&allocator_ctx.tracker, 5, "UTF8Test_allocator", NULL, NULL);
|
|
||||||
guf_libc_allocator_init(&allocator, &allocator_ctx);
|
|
||||||
};
|
|
||||||
|
|
||||||
void run() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
guf_allocator allocator;
|
|
||||||
guf_libc_alloc_ctx allocator_ctx;
|
|
||||||
|
|
||||||
dbuf_char text_buf {};
|
|
||||||
std::vector<char> text_vec;
|
|
||||||
|
|
||||||
bool load_text(const char *fname);
|
|
||||||
void free_text();
|
|
||||||
|
|
||||||
void read_utf8_chars(const char *fname, ptrdiff_t *n_valid, ptrdiff_t *n_invalid);
|
|
||||||
int count_words(const char *fname, const dbuf_str_view *delims);
|
|
||||||
int count_words_with_delims(const char *fname, const dbuf_str_view *delims);
|
|
||||||
void encode_decode_file(const char *fname);
|
|
||||||
void encode_decode();
|
|
||||||
};
|
|
||||||
Loading…
x
Reference in New Issue
Block a user