├── .gitattributes ├── .github └── workflows │ ├── c-cpp.yml │ └── codeql-analysis.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── all.sh ├── ctl ├── ctl.h ├── deq.h ├── lst.h ├── pqu.h ├── que.h ├── set.h ├── stk.h ├── str.h ├── ust.h └── vec.h ├── examples ├── 6502.c ├── astar.c ├── json.c ├── postfix.c └── snow.c ├── gen_images.sh ├── images ├── compile.log.png ├── deq.log.png ├── lst.log.png ├── pqu.log.png ├── set.log.png ├── tankguy.png ├── ust.log.png └── vec.log.png └── tests ├── func ├── digi.hh ├── test_c11.c ├── test_container_composing.cc ├── test_deq.cc ├── test_lst.cc ├── test_pqu.cc ├── test_que.cc ├── test_set.cc ├── test_std_headers.c ├── test_stk.cc ├── test_str.cc ├── test_ust.cc ├── test_vec.cc └── test_vec_capacity.cc ├── perf ├── deq │ ├── perf_deq_iterate.c │ ├── perf_deq_pop_back.c │ ├── perf_deq_pop_front.c │ ├── perf_deq_push_back.c │ ├── perf_deq_push_front.c │ ├── perf_deq_sort.c │ ├── perf_deque_iterate.cc │ ├── perf_deque_pop_back.cc │ ├── perf_deque_pop_front.cc │ ├── perf_deque_push_back.cc │ ├── perf_deque_push_front.cc │ └── perf_deque_sort.cc ├── lst │ ├── perf_list_iterate.cc │ ├── perf_list_pop_back.cc │ ├── perf_list_pop_front.cc │ ├── perf_list_push_back.cc │ ├── perf_list_push_front.cc │ ├── perf_list_sort.cc │ ├── perf_lst_iterate.c │ ├── perf_lst_pop_back.c │ ├── perf_lst_pop_front.c │ ├── perf_lst_push_back.c │ ├── perf_lst_push_front.c │ └── perf_lst_sort.c ├── perf_compile_c11.c ├── perf_compile_cc.cc ├── perf_plot.py ├── perf_plot_bar.py ├── pqu │ ├── perf_pqu_pop.c │ ├── perf_pqu_push.c │ ├── perf_priority_queue_pop.cc │ └── perf_priority_queue_push.cc ├── set │ ├── perf_set_erase.c │ ├── perf_set_erase.cc │ ├── perf_set_insert.c │ ├── perf_set_insert.cc │ ├── perf_set_iterate.c │ └── perf_set_iterate.cc ├── ust │ ├── perf_unordered_set_erase.cc │ ├── perf_unordered_set_insert.cc │ ├── perf_unordered_set_iterate.cc │ ├── perf_ust_erase.c │ ├── perf_ust_insert.c │ └── perf_ust_iterate.c └── vec │ ├── perf_vec_iterate.c │ ├── perf_vec_pop_back.c │ ├── perf_vec_push_back.c │ ├── perf_vec_sort.c │ ├── perf_vector_iterate.cc │ ├── perf_vector_pop_back.cc │ ├── perf_vector_push_back.cc │ └── perf_vector_sort.cc └── test.h /.gitattributes: -------------------------------------------------------------------------------- 1 | *.c linguist-language=C 2 | *.cc linguist-language=C 3 | *.h linguist-language=C 4 | -------------------------------------------------------------------------------- /.github/workflows/c-cpp.yml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: 4 | push: 5 | branches: [ master, staging ] 6 | 7 | pull_request: 8 | branches: [ master, staging ] 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - name: LIST CPU 19 | run: 20 | lscpu 21 | 22 | - name: O0 23 | run: 24 | make -j9 LONG=1 O0=1 SANITIZE=1 25 | 26 | - name: O1 27 | run: 28 | make -j9 LONG=1 O1=1 SANITIZE=1 29 | 30 | - name: O2 31 | run: 32 | make -j9 LONG=1 O2=1 SANITIZE=1 33 | 34 | - name: O3 35 | run: 36 | make -j9 LONG=1 O3=1 SANITIZE=1 37 | 38 | - name: Og 39 | run: 40 | make -j9 LONG=1 Og=1 SANITIZE=1 41 | 42 | - name: Os 43 | run: 44 | make -j9 LONG=1 Os=1 SANITIZE=1 45 | 46 | - name: Ofast 47 | run: 48 | make -j9 LONG=1 Ofast=1 49 | 50 | - name: O0 (SANITIZE=0) 51 | run: 52 | make -j9 LONG=1 O0=1 SANITIZE=0 53 | 54 | - name: O1 (SANITIZE=0) 55 | run: 56 | make -j9 LONG=1 O1=1 SANITIZE=0 57 | 58 | - name: O2 (SANITIZE=0) 59 | run: 60 | make -j9 LONG=1 O2=1 SANITIZE=0 61 | 62 | - name: O3 (SANITIZE=0) 63 | run: 64 | make -j9 LONG=1 O3=1 SANITIZE=0 65 | 66 | - name: Og (SANITIZE=0) 67 | run: 68 | make -j9 LONG=1 Og=1 SANITIZE=0 69 | 70 | - name: Os (SANITIZE=0) 71 | run: 72 | make -j9 LONG=1 Os=1 SANITIZE=0 73 | 74 | - name: Ofast (SANITIZE=0) 75 | run: 76 | make -j9 LONG=1 Ofast=1 SANITIZE=0 77 | 78 | - name: c99 79 | run: 80 | make -j9 CC=gcc\ -std=c99 81 | 82 | - name: c11 83 | run: 84 | make -j9 CC=gcc\ -std=c11 85 | 86 | - name: examples 87 | run: 88 | make examples 89 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master, staging ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master, staging ] 20 | schedule: 21 | - cron: '29 6 * * 6' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | language: [ 'cpp' ] 32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 33 | # Learn more: 34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v2 39 | 40 | # Initializes the CodeQL tools for scanning. 41 | - name: Initialize CodeQL 42 | uses: github/codeql-action/init@v1 43 | with: 44 | languages: ${{ matrix.language }} 45 | # If you wish to specify custom queries, you can do so here or in a config file. 46 | # By default, queries listed here will override any specified in a config file. 47 | # Prefix the list here with "+" to use these queries and those in the config file. 48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 49 | 50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 51 | # If this step fails, then you should remove it and run the build manually (see below) 52 | - name: Autobuild 53 | uses: github/codeql-action/autobuild@v1 54 | 55 | # ℹ️ Command-line programs to run using the OS shell. 56 | # 📚 https://git.io/JvXDl 57 | 58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 59 | # and modify them (or add more) to build your code if your project 60 | # uses a compiled language 61 | 62 | #- run: | 63 | # make bootstrap 64 | # make release 65 | 66 | - name: Perform CodeQL Analysis 67 | uses: github/codeql-action/analyze@v1 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | test 2 | a.out 3 | *.asm 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Gustav Louw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc -std=c11 2 | CXX = g++ -std=c++17 3 | 4 | LONG = 0 5 | SANITIZE = 0 6 | SRAND = 1 7 | 8 | O0 = 0 9 | O1 = 0 10 | O2 = 0 11 | O3 = 0 12 | Og = 0 13 | Ofast = 0 14 | Os = 0 15 | 16 | CFLAGS = -Ictl 17 | CFLAGS += -Wall -Wextra -Wpedantic -Wfatal-errors -Wshadow 18 | CFLAGS += -march=native 19 | CFLAGS += -g 20 | 21 | ifeq (1, $(LONG)) 22 | CFLAGS += -Werror 23 | CFLAGS += -DLONG 24 | endif 25 | 26 | ifeq (1, $(SANITIZE)) 27 | CFLAGS += -fsanitize=address -fsanitize=undefined 28 | endif 29 | 30 | ifeq (1, $(Og)) 31 | CFLAGS += -Og 32 | endif 33 | 34 | ifeq (1, $(O0)) 35 | CFLAGS += -O0 36 | endif 37 | 38 | ifeq (1, $(O1)) 39 | CFLAGS += -O1 40 | endif 41 | 42 | ifeq (1, $(O2)) 43 | CFLAGS += -O2 44 | endif 45 | 46 | ifeq (1, $(O3)) 47 | CFLAGS += -O3 48 | endif 49 | 50 | ifeq (1, $(Ofast)) 51 | CFLAGS += -Ofast 52 | endif 53 | 54 | ifeq (1, $(Os)) 55 | CFLAGS += -Os 56 | endif 57 | 58 | ifeq (1, $(SRAND)) 59 | CFLAGS += -DSRAND 60 | endif 61 | 62 | TESTS = \ 63 | tests/func/test_std_headers \ 64 | tests/func/test_c11 \ 65 | tests/func/test_container_composing \ 66 | tests/func/test_deq \ 67 | tests/func/test_lst \ 68 | tests/func/test_str \ 69 | tests/func/test_pqu \ 70 | tests/func/test_que \ 71 | tests/func/test_set \ 72 | tests/func/test_ust \ 73 | tests/func/test_stk \ 74 | tests/func/test_vec_capacity \ 75 | tests/func/test_vec 76 | 77 | EXAMPLES = \ 78 | examples/astar \ 79 | examples/postfix \ 80 | examples/json \ 81 | examples/snow \ 82 | examples/6502 83 | 84 | all: $(TESTS) 85 | $(foreach bin,$(TESTS),./$(bin) &&) exit 0 86 | @$(CC) --version 87 | @$(CXX) --version 88 | @rm -f $(TESTS) 89 | 90 | examples: $(EXAMPLES) 91 | 92 | clean: 93 | @rm -f $(TESTS) 94 | @rm -f $(EXAMPLES) 95 | 96 | str: 97 | $(call expand,$@) 98 | lst: 99 | $(call expand,$@,-DT=int -DP) 100 | vec: 101 | $(call expand,$@,-DT=int -DP) 102 | deq: 103 | $(call expand,$@,-DT=int -DP) 104 | stk: 105 | $(call expand,$@,-DT=int -DP) 106 | que: 107 | $(call expand,$@,-DT=int -DP) 108 | pqu: 109 | $(call expand,$@,-DT=int -DP) 110 | set: 111 | $(call expand,$@,-DT=int -DP) 112 | ust: 113 | $(call expand,$@,-DT=int -DP) 114 | 115 | examples/astar: ALWAYS; $(CC) $(CFLAGS) $@.c -o $@ 116 | examples/postfix: ALWAYS; $(CC) $(CFLAGS) $@.c -o $@ 117 | examples/json: ALWAYS; $(CC) $(CFLAGS) $@.c -o $@ 118 | examples/snow: ALWAYS; $(CC) $(CFLAGS) $@.c -o $@ 119 | examples/6502: ALWAYS; $(CC) $(CFLAGS) $@.c -o $@ 120 | tests/func/test_std_headers: ALWAYS; $(CC) $(CFLAGS) $@.c -o $@ 121 | tests/func/test_c11: ALWAYS; $(CC) $(CFLAGS) $@.c -o $@ 122 | tests/func/test_container_composing: ALWAYS; $(CXX) $(CFLAGS) $@.cc -o $@ 123 | tests/func/test_deq: ALWAYS; $(CXX) $(CFLAGS) $@.cc -o $@ 124 | tests/func/test_lst: ALWAYS; $(CXX) $(CFLAGS) $@.cc -o $@ 125 | tests/func/test_pqu: ALWAYS; $(CXX) $(CFLAGS) $@.cc -o $@ 126 | tests/func/test_que: ALWAYS; $(CXX) $(CFLAGS) $@.cc -o $@ 127 | tests/func/test_set: ALWAYS; $(CXX) $(CFLAGS) $@.cc -o $@ 128 | tests/func/test_ust: ALWAYS; $(CXX) $(CFLAGS) $@.cc -o $@ 129 | tests/func/test_stk: ALWAYS; $(CXX) $(CFLAGS) $@.cc -o $@ 130 | tests/func/test_str: ALWAYS; $(CXX) $(CFLAGS) $@.cc -o $@ 131 | tests/func/test_vec_capacity: ALWAYS; $(CXX) $(CFLAGS) $@.cc -o $@ 132 | tests/func/test_vec: ALWAYS; $(CXX) $(CFLAGS) $@.cc -o $@ 133 | 134 | define expand 135 | @$(CC) $(CFLAGS) ctl/$(1).h -E $(2) | clang-format -style=webkit 136 | endef 137 | 138 | ALWAYS: 139 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C TEMPLATE LIBRARY (CTL) 2 | 3 | CTL is a fast compiling, type safe, header only, template-like library for ISO C99/C11. 4 | 5 | ## Motivation 6 | 7 | CTL aims to improve ISO C99/C11 developer productivity by implementing the following 8 | STL containers in ISO C99/C11: 9 | 10 | ``` 11 | deq.h = std::deque 12 | lst.h = std::list 13 | pqu.h = std::priority_queue 14 | que.h = std::queue 15 | set.h = std::set 16 | stk.h = std::stack 17 | str.h = std::string 18 | ust.h = std::unordered_set 19 | vec.h = std::vector 20 | ``` 21 | 22 | ## Use 23 | 24 | Configure a CTL container with a built-in or typedef type `T`. 25 | 26 | ```C 27 | #include 28 | 29 | #define P 30 | #define T int 31 | #include 32 | 33 | int compare(int* a, int* b) { return *b < *a; } 34 | 35 | int main(void) 36 | { 37 | vec_int a = vec_int_init(); 38 | vec_int_push_back(&a, 9); 39 | vec_int_push_back(&a, 1); 40 | vec_int_push_back(&a, 8); 41 | vec_int_push_back(&a, 3); 42 | vec_int_push_back(&a, 4); 43 | vec_int_sort(&a, compare); 44 | foreach(vec_int, &a, it) 45 | printf("%d\n", *it.ref); 46 | vec_int_free(&a); 47 | } 48 | ``` 49 | 50 | Definition `P` states type `T` is Plain Old Data (POD). 51 | 52 | To compile, include the `ctl` directory: 53 | 54 | ```shell 55 | gcc main.c -I ctl 56 | ``` 57 | 58 | For a much more thorough getting started guide, 59 | see the wiki: https://github.com/glouw/ctl/wiki 60 | 61 | ## Memory Ownership 62 | 63 | Types with memory ownership require definition `P` be omitted, and require 64 | function declarations for the C++ equivalent of the destructor and copy constructor, 65 | prior to the inclusion of the container: 66 | 67 | ```C 68 | typedef struct { ... } type; 69 | void type_free(type*); 70 | type type_copy(type*); 71 | #define T type 72 | #include 73 | ``` 74 | 75 | Forgetting a declaration will print a human-readable error message: 76 | 77 | ```shell 78 | tests/test_c11.c:11:11: error: type_free undeclared (first use in this function) 79 | 11 | #define T type 80 | ``` 81 | 82 | ## Performance 83 | 84 | CTL performance is presented in solid colors, and STL in dotted colors, 85 | for template type `T` as type `int` for all measurements. 86 | 87 | ![](images/vec.log.png) 88 | ![](images/lst.log.png) 89 | ![](images/deq.log.png) 90 | ![](images/set.log.png) 91 | ![](images/ust.log.png) 92 | ![](images/pqu.log.png) 93 | ![](images/compile.log.png) 94 | 95 | Omitted from these performance measurements are `que.h`, `stk.h`, and `str.h`, 96 | as their performance characteristics can be inferred from `deq.h`, and `vec.h`, 97 | respectively. 98 | 99 | Note, CTL strings do not support short strings. 100 | 101 | ## Running Tests 102 | 103 | To run all functional tests, run: 104 | 105 | ```shell 106 | make 107 | ``` 108 | 109 | To compile examples, run: 110 | 111 | ```shell 112 | make examples 113 | ``` 114 | 115 | To generate performance graphs, run: 116 | 117 | ```shell 118 | sh gen_images.sh 119 | # Graphing requires python3 and the Plotly family of libraries via pip. 120 | pip install plotly 121 | pip install psutil 122 | pip install kaleido 123 | ``` 124 | 125 | To do all of the above in one step, run: 126 | 127 | ```shell 128 | ./all.sh 129 | ``` 130 | 131 | For maintaining CTL, a container templated to type `int` can be 132 | outputted to `stdout` by running make on the container name, eg: 133 | 134 | ```shell 135 | make deq 136 | make lst 137 | make pqu 138 | make que 139 | make set 140 | make stk 141 | make str 142 | make ust 143 | make vec 144 | ``` 145 | 146 | ## Other 147 | 148 | STL `std::map` will not be implemented in CTL because maps only provide slight 149 | syntactic improvements over sets. 150 | 151 | STL variants of multi-sets and multi-maps will not be implemented because 152 | similar behaviour can be implemented as an amalgamation of a `set` and `lst`. 153 | 154 | ## Base Implementation Details 155 | 156 | ``` 157 | vec.h: realloc 158 | str.h: vec.h 159 | deq.h: realloc (paged) 160 | que.h: deq.h 161 | stk.h: deq.h 162 | pqu.h: vec.h 163 | lst.h: doubly linked list 164 | set.h: red black tree 165 | ust.h: hashed forward linked lists 166 | 167 | vec str deq lst set pqu que stk ust 168 | +-------------------------------------------------------------+ 169 | empty x x x x x x x x x 170 | each x x x x x x 171 | equal x x x x x x x x x 172 | swap x x x x x x x x x 173 | bucket x 174 | bucket_size x 175 | load_factor x 176 | rehash x 177 | insert x x x x x x 178 | init x x x x x x x x x 179 | free x x x x x x x x x 180 | step x x x x x x 181 | range x x x x x x 182 | find x x x x x x 183 | count x x x 184 | lower_bound x 185 | upper_bound x 186 | erase x x x x x x 187 | copy x x x x x x 188 | begin x x x x x x 189 | end x x x x x x 190 | intersection x 191 | union x 192 | difference x 193 | symmetric_difference x 194 | top x x 195 | push x x x 196 | pop x x x 197 | at x x x 198 | front x x x x x 199 | back x x x x x 200 | set x x x 201 | pop_back x x x x 202 | pop_front x x 203 | clear x x x x x 204 | reserve x x 205 | push_back x x x x 206 | push_front x x 207 | transfer x 208 | disconnect x 209 | connect x 210 | resize x x x x 211 | assign x x x x 212 | reverse x 213 | shrink_to_fit x x 214 | data x x 215 | erase_node x 216 | sort x x x x 217 | remove_if x x x x x 218 | splice x 219 | merge x 220 | unique x 221 | append x 222 | insert_str x 223 | replace x x 224 | c_str x 225 | find x 226 | rfind x 227 | find_first_of x 228 | find_last_of x 229 | find_first_not_of x 230 | find_last_not_of x 231 | substr x 232 | compare x 233 | key_compare x 234 | ``` 235 | 236 | ## Acknowledgements 237 | 238 | Thank you https://github.com/kully for the Plotly code, and thank you for the general review and manual testing. 239 | 240 | Thank you `smlckz` for the `foreach` cleanup. 241 | 242 | Thank you https://github.com/wwwVladislav for the addition of set lower_bound and upper_bound. 243 | -------------------------------------------------------------------------------- /all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make -j16 4 | make examples 5 | sh gen_images.sh 6 | -------------------------------------------------------------------------------- /ctl/ctl.h: -------------------------------------------------------------------------------- 1 | #ifndef __CTL_H__ 2 | #define __CTL_H__ 3 | 4 | #include 5 | #include 6 | 7 | #define CAT(a, b) a##b 8 | 9 | #define PASTE(a, b) CAT(a, b) 10 | 11 | #define JOIN(prefix, name) PASTE(prefix, PASTE(_, name)) 12 | 13 | #define SWAP(TYPE, a, b) { TYPE temp = *(a); *(a) = *(b); *(b) = temp; } 14 | 15 | #define foreach(a, b, c) for(JOIN(a, it) c = JOIN(JOIN(a, it), each) (b); !c.done; c.step(&c)) 16 | 17 | #define len(a) (sizeof(a) / sizeof(*(a))) 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /ctl/deq.h: -------------------------------------------------------------------------------- 1 | // 2 | // Double Ended Queue 3 | // 4 | 5 | #ifndef T 6 | #error "Template type T undefined for " 7 | #endif 8 | 9 | #include 10 | 11 | #define A JOIN(deq, T) 12 | #define B JOIN(A, bucket) 13 | #define Z JOIN(A, it) 14 | 15 | #define DEQ_BUCKET_SIZE (512) 16 | 17 | typedef struct B 18 | { 19 | T value[DEQ_BUCKET_SIZE]; 20 | int16_t a; 21 | int16_t b; 22 | } 23 | B; 24 | 25 | typedef struct A 26 | { 27 | void (*free)(T*); 28 | T (*copy)(T*); 29 | B** pages; 30 | size_t mark_a; 31 | size_t mark_b; 32 | size_t capacity; 33 | size_t size; 34 | } 35 | A; 36 | 37 | typedef struct Z 38 | { 39 | void (*step)(struct Z*); 40 | A* container; 41 | T* ref; 42 | size_t index; 43 | size_t index_next; 44 | size_t index_last; 45 | int done; 46 | } 47 | Z; 48 | 49 | static inline B** 50 | JOIN(A, first)(A* self) 51 | { 52 | return &self->pages[self->mark_a]; 53 | } 54 | 55 | static inline B** 56 | JOIN(A, last)(A* self) 57 | { 58 | return &self->pages[self->mark_b - 1]; 59 | } 60 | 61 | static inline T* 62 | JOIN(A, at)(A* self, size_t index) 63 | { 64 | if(self->size == 0) 65 | return NULL; 66 | else 67 | { 68 | B* first = *JOIN(A, first)(self); 69 | size_t actual = index + first->a; 70 | size_t q = actual / DEQ_BUCKET_SIZE; 71 | size_t r = actual % DEQ_BUCKET_SIZE; 72 | B* page = self->pages[self->mark_a + q]; 73 | return &page->value[r]; 74 | } 75 | } 76 | 77 | static inline T* 78 | JOIN(A, front)(A* self) 79 | { 80 | return JOIN(A, at)(self, 0); 81 | } 82 | 83 | static inline T* 84 | JOIN(A, back)(A* self) 85 | { 86 | return JOIN(A, at)(self, self->size - 1); 87 | } 88 | 89 | static inline T* 90 | JOIN(A, begin)(A* self) 91 | { 92 | return JOIN(A, front)(self); 93 | } 94 | 95 | static inline T* 96 | JOIN(A, end)(A* self) 97 | { 98 | return JOIN(A, back)(self) + 1; 99 | } 100 | 101 | static inline void 102 | JOIN(Z, step)(Z* self) 103 | { 104 | self->index = self->index_next; 105 | if(self->index == self->index_last) 106 | self->done = 1; 107 | else 108 | { 109 | self->ref = JOIN(A, at)(self->container, self->index); 110 | self->index_next += 1; 111 | } 112 | } 113 | 114 | static inline Z 115 | JOIN(Z, range)(A* container, T* begin, T* end) 116 | { 117 | static Z zero; 118 | Z self = zero; 119 | if(begin && end) 120 | { 121 | self.container = container; 122 | self.step = JOIN(Z, step); 123 | self.index = begin - JOIN(A, begin)(container); 124 | self.index_next = self.index + 1; 125 | self.index_last = container->size - (JOIN(A, end)(container) - end); 126 | self.ref = JOIN(A, at)(container, self.index); 127 | } 128 | else 129 | self.done = 1; 130 | return self; 131 | } 132 | 133 | static inline int 134 | JOIN(A, empty)(A* self) 135 | { 136 | return self->size == 0; 137 | } 138 | 139 | static inline Z 140 | JOIN(Z, each)(A* a) 141 | { 142 | return JOIN(A, empty)(a) 143 | ? JOIN(Z, range)(a, NULL, NULL) 144 | : JOIN(Z, range)(a, JOIN(A, begin)(a), JOIN(A, end)(a)); 145 | } 146 | 147 | static inline T 148 | JOIN(A, implicit_copy)(T* self) 149 | { 150 | return *self; 151 | } 152 | 153 | static inline int 154 | JOIN(A, equal)(A* self, A* other, int _equal(T*, T*)) 155 | { 156 | if(self->size != other->size) 157 | return 0; 158 | Z a = JOIN(Z, each)(self); 159 | Z b = JOIN(Z, each)(other); 160 | while(!a.done && !b.done) 161 | { 162 | if(!_equal(a.ref, b.ref)) 163 | return 0; 164 | a.step(&a); 165 | b.step(&b); 166 | } 167 | return 1; 168 | } 169 | 170 | static inline void 171 | JOIN(A, swap)(A* self, A* other) 172 | { 173 | A temp = *self; 174 | *self = *other; 175 | *other = temp; 176 | } 177 | 178 | static inline A 179 | JOIN(A, init)(void) 180 | { 181 | static A zero; 182 | A self = zero; 183 | #ifdef P 184 | #undef P 185 | self.copy = JOIN(A, implicit_copy); 186 | #else 187 | self.free = JOIN(T, free); 188 | self.copy = JOIN(T, copy); 189 | #endif 190 | return self; 191 | } 192 | 193 | static inline B* 194 | JOIN(B, init)(size_t cut) 195 | { 196 | B* self = (B*) malloc(sizeof(B)); 197 | self->a = self->b = cut; 198 | return self; 199 | } 200 | 201 | static inline void 202 | JOIN(A, set)(A* self, size_t index, T value) 203 | { 204 | T* ref = JOIN(A, at)(self, index); 205 | if(self->free) 206 | self->free(ref); 207 | *ref = value; 208 | } 209 | 210 | static inline void 211 | JOIN(A, alloc)(A* self, size_t capacity, size_t shift_from) 212 | { 213 | self->capacity = capacity; 214 | self->pages = (B**) realloc(self->pages, capacity * sizeof(B*)); 215 | size_t shift = (self->capacity - shift_from) / 2; 216 | size_t i = self->mark_b; 217 | while(i != 0) 218 | { 219 | i -= 1; 220 | self->pages[i + shift] = self->pages[i]; 221 | } 222 | self->mark_a += shift; 223 | self->mark_b += shift; 224 | } 225 | 226 | static inline void 227 | JOIN(A, push_front)(A* self, T value) 228 | { 229 | if(JOIN(A, empty)(self)) 230 | { 231 | self->mark_a = 0; 232 | self->mark_b = 1; 233 | JOIN(A, alloc)(self, 1, 0); 234 | *JOIN(A, last)(self) = JOIN(B, init)(DEQ_BUCKET_SIZE); 235 | } 236 | else 237 | { 238 | B* page = *JOIN(A, first)(self); 239 | if(page->a == 0) 240 | { 241 | if(self->mark_a == 0) 242 | JOIN(A, alloc)(self, 2 * self->capacity, self->mark_a); 243 | self->mark_a -= 1; 244 | *JOIN(A, first)(self) = JOIN(B, init)(DEQ_BUCKET_SIZE); 245 | } 246 | } 247 | B* page = *JOIN(A, first)(self); 248 | page->a -= 1; 249 | self->size += 1; 250 | page->value[page->a] = value; 251 | } 252 | 253 | static inline void 254 | JOIN(A, pop_front)(A* self) 255 | { 256 | B* page = *JOIN(A, first)(self); 257 | if(self->free) 258 | { 259 | T* ref = &page->value[page->a]; 260 | self->free(ref); 261 | } 262 | page->a += 1; 263 | self->size -= 1; 264 | if(page->a == page->b) 265 | { 266 | free(page); 267 | self->mark_a += 1; 268 | } 269 | } 270 | 271 | static inline void 272 | JOIN(A, push_back)(A* self, T value) 273 | { 274 | if(JOIN(A, empty)(self)) 275 | { 276 | self->mark_a = 0; 277 | self->mark_b = 1; 278 | JOIN(A, alloc)(self, 1, 0); 279 | *JOIN(A, last)(self) = JOIN(B, init)(0); 280 | } 281 | else 282 | { 283 | B* page = *JOIN(A, last)(self); 284 | if(page->b == DEQ_BUCKET_SIZE) 285 | { 286 | if(self->mark_b == self->capacity) 287 | JOIN(A, alloc)(self, 2 * self->capacity, self->mark_b); 288 | self->mark_b += 1; 289 | *JOIN(A, last)(self) = JOIN(B, init)(0); 290 | } 291 | } 292 | B* page = *JOIN(A, last)(self); 293 | page->value[page->b] = value; 294 | page->b += 1; 295 | self->size += 1; 296 | } 297 | 298 | static inline void 299 | JOIN(A, pop_back)(A* self) 300 | { 301 | B* page = *JOIN(A, last)(self); 302 | page->b -= 1; 303 | self->size -= 1; 304 | if(self->free) 305 | { 306 | T* ref = &page->value[page->b]; 307 | self->free(ref); 308 | } 309 | if(page->b == page->a) 310 | { 311 | free(page); 312 | self->mark_b -= 1; 313 | } 314 | } 315 | 316 | static inline void 317 | JOIN(A, erase)(A* self, size_t index) 318 | { 319 | static T zero; 320 | JOIN(A, set)(self, index, zero); 321 | void (*saved)(T*) = self->free; 322 | self->free = NULL; 323 | if(index < self->size / 2) 324 | { 325 | for(size_t i = index; i > 0; i--) 326 | *JOIN(A, at)(self, i) = *JOIN(A, at)(self, i - 1); 327 | JOIN(A, pop_front)(self); 328 | } 329 | else 330 | { 331 | for(size_t i = index; i < self->size - 1; i++) 332 | *JOIN(A, at)(self, i) = *JOIN(A, at)(self, i + 1); 333 | JOIN(A, pop_back)(self); 334 | } 335 | self->free = saved; 336 | } 337 | 338 | static inline void 339 | JOIN(A, insert)(A* self, size_t index, T value) 340 | { 341 | if(self->size > 0) 342 | { 343 | void (*saved)(T*) = self->free; 344 | self->free = NULL; 345 | if(index < self->size / 2) 346 | { 347 | JOIN(A, push_front)(self, *JOIN(A, at)(self, 0)); 348 | for(size_t i = 0; i < index; i++) 349 | *JOIN(A, at)(self, i) = *JOIN(A, at)(self, i + 1); 350 | } 351 | else 352 | { 353 | JOIN(A, push_back)(self, *JOIN(A, at)(self, self->size - 1)); 354 | for(size_t i = self->size - 1; i > index; i--) 355 | *JOIN(A, at)(self, i) = *JOIN(A, at)(self, i - 1); 356 | } 357 | *JOIN(A, at)(self, index) = value; 358 | self->free = saved; 359 | } 360 | else 361 | JOIN(A, push_back)(self, value); 362 | } 363 | 364 | static inline void 365 | JOIN(A, resize)(A* self, size_t size, T value) 366 | { 367 | if(size != self->size) 368 | { 369 | while(size != self->size) 370 | if(size < self->size) 371 | JOIN(A, pop_back)(self); 372 | else 373 | JOIN(A, push_back)(self, self->copy(&value)); 374 | } 375 | if(self->free) 376 | self->free(&value); 377 | } 378 | 379 | static inline void 380 | JOIN(A, assign)(A* self, size_t size, T value) 381 | { 382 | JOIN(A, resize)(self, size, self->copy(&value)); 383 | for(size_t i = 0; i < size; i++) 384 | JOIN(A, set)(self, i, self->copy(&value)); 385 | if(self->free) 386 | self->free(&value); 387 | } 388 | 389 | static inline void 390 | JOIN(A, clear)(A* self) 391 | { 392 | while(!JOIN(A, empty)(self)) 393 | JOIN(A, pop_back)(self); 394 | } 395 | 396 | static inline void 397 | JOIN(A, free)(A* self) 398 | { 399 | JOIN(A, clear)(self); 400 | free(self->pages); 401 | *self = JOIN(A, init)(); 402 | } 403 | 404 | static inline A 405 | JOIN(A, copy)(A* self) 406 | { 407 | A other = JOIN(A, init)(); 408 | while(other.size < self->size) 409 | { 410 | T* value = JOIN(A, at)(self, other.size); 411 | JOIN(A, push_back)(&other, other.copy(value)); 412 | } 413 | return other; 414 | } 415 | 416 | static inline void 417 | JOIN(A, ranged_sort)(A* self, int64_t a, int64_t b, int _compare(T*, T*)) 418 | { 419 | if(a >= b) 420 | return; 421 | int64_t mid = (a + b) / 2; 422 | SWAP(T, JOIN(A, at)(self, a), JOIN(A, at)(self, mid)); 423 | int64_t z = a; 424 | for(int64_t i = a + 1; i <= b; i++) 425 | if(_compare(JOIN(A, at)(self, a), JOIN(A, at)(self, i))) 426 | { 427 | z += 1; 428 | SWAP(T, JOIN(A, at)(self, z), JOIN(A, at)(self, i)); 429 | } 430 | SWAP(T, JOIN(A, at)(self, a), JOIN(A, at)(self, z)); 431 | JOIN(A, ranged_sort)(self, a, z - 1, _compare); 432 | JOIN(A, ranged_sort)(self, z + 1, b, _compare); 433 | } 434 | 435 | static inline void 436 | JOIN(A, sort)(A* self, int _compare(T*, T*)) 437 | { 438 | JOIN(A, ranged_sort)(self, 0, self->size - 1, _compare); 439 | } 440 | 441 | static inline size_t 442 | JOIN(A, remove_if)(A* self, int _match(T*)) 443 | { 444 | size_t erases = 0; 445 | foreach(A, self, it) 446 | if(_match(it.ref)) 447 | { 448 | JOIN(A, erase)(self, it.index); 449 | it.index_next = it.index; 450 | it.index_last -= 1; 451 | erases += 1; 452 | } 453 | return erases; 454 | } 455 | 456 | static inline T* 457 | JOIN(A, find)(A* self, T key, int _equal(T*, T*)) 458 | { 459 | foreach(A, self, it) 460 | if(_equal(it.ref, &key)) 461 | return it.ref; 462 | return NULL; 463 | } 464 | 465 | #undef T 466 | #undef A 467 | #undef B 468 | #undef Z 469 | 470 | #undef DEQ_BUCKET_SIZE 471 | -------------------------------------------------------------------------------- /ctl/lst.h: -------------------------------------------------------------------------------- 1 | // 2 | // Doubly Linked List 3 | // 4 | 5 | #ifndef T 6 | #error "Template type T undefined for " 7 | #endif 8 | 9 | #include 10 | 11 | #define A JOIN(lst, T) 12 | #define B JOIN(A, node) 13 | #define Z JOIN(A, it) 14 | 15 | typedef struct B 16 | { 17 | struct B* prev; 18 | struct B* next; 19 | T value; 20 | } 21 | B; 22 | 23 | typedef struct A 24 | { 25 | void (*free)(T*); 26 | T (*copy)(T*); 27 | B* head; 28 | B* tail; 29 | size_t size; 30 | } 31 | A; 32 | 33 | typedef struct Z 34 | { 35 | void (*step)(struct Z*); 36 | T* ref; 37 | B* begin; 38 | B* node; 39 | B* next; 40 | B* end; 41 | int done; 42 | } 43 | Z; 44 | 45 | static inline T* 46 | JOIN(A, front)(A* self) 47 | { 48 | return &self->head->value; 49 | } 50 | 51 | static inline T* 52 | JOIN(A, back)(A* self) 53 | { 54 | return &self->tail->value; 55 | } 56 | 57 | static inline B* 58 | JOIN(A, begin)(A* self) 59 | { 60 | return self->head; 61 | } 62 | 63 | static inline B* 64 | JOIN(A, end)(A* self) 65 | { 66 | (void) self; 67 | return NULL; 68 | } 69 | 70 | static inline void 71 | JOIN(Z, step)(Z* self) 72 | { 73 | if(self->next == self->end) 74 | self->done = 1; 75 | else 76 | { 77 | self->node = self->next; 78 | self->ref = &self->node->value; 79 | self->next = self->node->next; 80 | } 81 | } 82 | 83 | static inline Z 84 | JOIN(Z, range)(A* container, B* begin, B* end) 85 | { 86 | (void) container; 87 | static Z zero; 88 | Z self = zero; 89 | if(begin) 90 | { 91 | self.step = JOIN(Z, step); 92 | self.begin = begin; 93 | self.end = end; 94 | self.next = begin->next; 95 | self.node = begin; 96 | self.ref = &begin->value; 97 | } 98 | else 99 | self.done = 1; 100 | return self; 101 | } 102 | 103 | static inline int 104 | JOIN(A, empty)(A* self) 105 | { 106 | return self->size == 0; 107 | } 108 | 109 | static inline Z 110 | JOIN(Z, each)(A* a) 111 | { 112 | return JOIN(A, empty)(a) 113 | ? JOIN(Z, range)(a, NULL, NULL) 114 | : JOIN(Z, range)(a, JOIN(A, begin)(a), JOIN(A, end)(a)); 115 | } 116 | 117 | static inline T 118 | JOIN(A, implicit_copy)(T* self) 119 | { 120 | return *self; 121 | } 122 | 123 | static inline int 124 | JOIN(A, equal)(A* self, A* other, int _equal(T*, T*)) 125 | { 126 | if(self->size != other->size) 127 | return 0; 128 | Z a = JOIN(Z, each)(self); 129 | Z b = JOIN(Z, each)(other); 130 | while(!a.done && !b.done) 131 | { 132 | if(!_equal(a.ref, b.ref)) 133 | return 0; 134 | a.step(&a); 135 | b.step(&b); 136 | } 137 | return 1; 138 | } 139 | 140 | static inline void 141 | JOIN(A, swap)(A* self, A* other) 142 | { 143 | A temp = *self; 144 | *self = *other; 145 | *other = temp; 146 | } 147 | 148 | static inline A 149 | JOIN(A, init)(void) 150 | { 151 | static A zero; 152 | A self = zero; 153 | #ifdef P 154 | #undef P 155 | self.copy = JOIN(A, implicit_copy); 156 | #else 157 | self.free = JOIN(T, free); 158 | self.copy = JOIN(T, copy); 159 | #endif 160 | return self; 161 | } 162 | 163 | static inline B* 164 | JOIN(B, init)(T value) 165 | { 166 | B* self = (B*) malloc(sizeof(B)); 167 | self->prev = self->next = NULL; 168 | self->value = value; 169 | return self; 170 | } 171 | 172 | static inline void 173 | JOIN(A, disconnect)(A* self, B* node) 174 | { 175 | if(node == self->tail) self->tail = self->tail->prev; 176 | if(node == self->head) self->head = self->head->next; 177 | if(node->prev) node->prev->next = node->next; 178 | if(node->next) node->next->prev = node->prev; 179 | node->prev = node->next = NULL; 180 | self->size -= 1; 181 | } 182 | 183 | static inline void 184 | JOIN(A, connect)(A* self, B* position, B* node, int before) 185 | { 186 | if(JOIN(A, empty)(self)) 187 | self->head = self->tail = node; 188 | else 189 | if(before) 190 | { 191 | node->next = position; 192 | node->prev = position->prev; 193 | if(position->prev) 194 | position->prev->next = node; 195 | position->prev = node; 196 | if(position == self->head) 197 | self->head = node; 198 | } 199 | else 200 | { 201 | node->prev = position; 202 | node->next = position->next; 203 | if(position->next) 204 | position->next->prev = node; 205 | position->next = node; 206 | if(position == self->tail) 207 | self->tail = node; 208 | } 209 | self->size += 1; 210 | } 211 | 212 | static inline void 213 | JOIN(A, push_back)(A* self, T value) 214 | { 215 | B* node = JOIN(B, init)(value); 216 | JOIN(A, connect)(self, self->tail, node, 0); 217 | } 218 | 219 | static inline void 220 | JOIN(A, push_front)(A* self, T value) 221 | { 222 | B* node = JOIN(B, init)(value); 223 | JOIN(A, connect)(self, self->head, node, 1); 224 | } 225 | 226 | static inline void 227 | JOIN(A, transfer)(A* self, A* other, B* position, B* node, int before) 228 | { 229 | JOIN(A, disconnect)(other, node); 230 | JOIN(A, connect)(self, position, node, before); 231 | } 232 | 233 | static inline void 234 | JOIN(A, erase)(A* self, B* node) 235 | { 236 | JOIN(A, disconnect)(self, node); 237 | if(self->free) 238 | self->free(&node->value); 239 | free(node); 240 | } 241 | 242 | static inline void 243 | JOIN(A, pop_back)(A* self) 244 | { 245 | JOIN(A, erase)(self, self->tail); 246 | } 247 | 248 | static inline void 249 | JOIN(A, pop_front)(A* self) 250 | { 251 | JOIN(A, erase)(self, self->head); 252 | } 253 | 254 | static inline void 255 | JOIN(A, insert)(A* self, B* position, T value) 256 | { 257 | B* node = JOIN(B, init)(value); 258 | JOIN(A, connect)(self, position, node, 1); 259 | } 260 | 261 | static inline void 262 | JOIN(A, clear)(A* self) 263 | { 264 | while(!JOIN(A, empty)(self)) 265 | JOIN(A, pop_back)(self); 266 | } 267 | 268 | static inline void 269 | JOIN(A, free)(A* self) 270 | { 271 | JOIN(A, clear)(self); 272 | *self = JOIN(A, init)(); 273 | } 274 | 275 | static inline void 276 | JOIN(A, resize)(A* self, size_t size, T value) 277 | { 278 | if(size != self->size) 279 | for(size_t i = 0; size != self->size; i++) 280 | (size < self->size) 281 | ? JOIN(A, pop_back)(self) 282 | : JOIN(A, push_back)(self, self->copy(&value)); 283 | if(self->free) 284 | self->free(&value); 285 | } 286 | 287 | static inline A 288 | JOIN(A, copy)(A* self) 289 | { 290 | A other = JOIN(A, init)(); 291 | for(B* node = self->head; node; node = node->next) 292 | JOIN(A, push_back)(&other, self->copy(&node->value)); 293 | return other; 294 | } 295 | 296 | static inline void 297 | JOIN(A, assign)(A* self, size_t size, T value) 298 | { 299 | JOIN(A, resize)(self, size, self->copy(&value)); 300 | size_t i = 0; 301 | foreach(A, self, it) 302 | { 303 | if(self->free) 304 | self->free(it.ref); 305 | *it.ref = self->copy(&value); 306 | i += 1; 307 | } 308 | if(self->free) 309 | self->free(&value); 310 | } 311 | 312 | static inline void 313 | JOIN(A, reverse)(A* self) 314 | { 315 | foreach(A, self, it) 316 | { 317 | B* next = it.node->next; 318 | B* prev = it.node->prev; 319 | it.node->prev = next; 320 | it.node->next = prev; 321 | } 322 | B* tail = self->tail; 323 | B* head = self->head; 324 | self->tail = head; 325 | self->head = tail; 326 | } 327 | 328 | static inline size_t 329 | JOIN(A, remove_if)(A* self, int _equal(T*)) 330 | { 331 | size_t erases = 0; 332 | foreach(A, self, it) 333 | if(_equal(it.ref)) 334 | { 335 | JOIN(A, erase)(self, it.node); 336 | erases += 1; 337 | } 338 | return erases; 339 | } 340 | 341 | static inline void 342 | JOIN(A, splice)(A* self, B* position, A* other) 343 | { 344 | if(self->size == 0 && position == NULL) 345 | JOIN(A, swap)(self, other); 346 | else 347 | foreach(A, other, it) 348 | JOIN(A, transfer)(self, other, position, it.node, 1); 349 | } 350 | 351 | static inline void 352 | JOIN(A, merge)(A* self, A* other, int _compare(T*, T*)) 353 | { 354 | if(JOIN(A, empty)(self)) 355 | JOIN(A, swap)(self, other); 356 | else 357 | { 358 | for(B* node = self->head; node; node = node->next) 359 | while(!JOIN(A, empty)(other) && _compare(&node->value, &other->head->value)) 360 | JOIN(A, transfer)(self, other, node, other->head, 1); 361 | // Remainder. 362 | while(!JOIN(A, empty)(other)) 363 | JOIN(A, transfer)(self, other, self->tail, other->head, 0); 364 | } 365 | } 366 | 367 | static inline void 368 | JOIN(A, sort)(A* self, int _compare(T*, T*)) 369 | { 370 | if(self->size > 1) 371 | { 372 | A carry = JOIN(A, init)(); 373 | A temp[64]; 374 | for(size_t i = 0; i < len(temp); i++) 375 | temp[i] = JOIN(A, init)(); 376 | A* fill = temp; 377 | A* counter = NULL; 378 | do 379 | { 380 | JOIN(A, transfer)(&carry, self, carry.head, self->head, 1); 381 | for(counter = temp; counter != fill && !JOIN(A, empty)(counter); counter++) 382 | { 383 | JOIN(A, merge)(counter, &carry, _compare); 384 | JOIN(A, swap)(&carry, counter); 385 | } 386 | JOIN(A, swap)(&carry, counter); 387 | if(counter == fill) 388 | fill++; 389 | } 390 | while(!JOIN(A, empty)(self)); 391 | for(counter = temp + 1; counter != fill; counter++) 392 | JOIN(A, merge)(counter, counter - 1, _compare); 393 | JOIN(A, swap)(self, fill - 1); 394 | } 395 | } 396 | 397 | static inline void 398 | JOIN(A, unique)(A* self, int _equal(T*, T*)) 399 | { 400 | foreach(A, self, it) 401 | if(it.next && _equal(it.ref, &it.next->value)) 402 | JOIN(A, erase)(self, it.node); 403 | } 404 | 405 | static inline B* 406 | JOIN(A, find)(A* self, T key, int _equal(T*, T*)) 407 | { 408 | foreach(A, self, it) 409 | if(_equal(it.ref, &key)) 410 | return it.node; 411 | return NULL; 412 | } 413 | 414 | #undef T 415 | #undef A 416 | #undef B 417 | #undef Z 418 | -------------------------------------------------------------------------------- /ctl/pqu.h: -------------------------------------------------------------------------------- 1 | // 2 | // Priority Queue 3 | // 4 | 5 | #ifndef T 6 | #error "Template type T undefined for " 7 | #endif 8 | 9 | #define front top 10 | #define at __AT 11 | #define back __BACK 12 | #define begin __BEGIN 13 | #define end __END 14 | #define set __SET 15 | #define pop_back __POP_BACK 16 | #define wipe __WIPE 17 | #define clear __CLEAR 18 | #define fit __FIT 19 | #define reserve __RESERVE 20 | #define push_back __PUSH_BACK 21 | #define resize __RESIZE 22 | #define assign __ASSIGN 23 | #define shrink_to_fit __SHRINK_TO_FIT 24 | #define data __DATA 25 | #define insert __INSERT 26 | #define erase __ERASE 27 | #define sort __SORT 28 | #define step __STEP 29 | #define range __RANGE 30 | #define each __EACH 31 | #define remove_if __REMOVE_IF 32 | 33 | #define vec pqu 34 | #define HOLD 35 | #define COMPARE 36 | #define init __INIT 37 | #include 38 | #undef init 39 | #undef vec 40 | 41 | #define A JOIN(pqu, T) 42 | 43 | static inline A 44 | JOIN(A, init)(int _compare(T*, T*)) 45 | { 46 | A self = JOIN(A, __INIT)(); 47 | self.compare = _compare; 48 | return self; 49 | } 50 | 51 | static inline void 52 | JOIN(A, up)(A* self, size_t n) 53 | { 54 | if(n > 0) 55 | { 56 | size_t p = (n - 1) / 2; 57 | T* x = &self->value[n]; 58 | T* y = &self->value[p]; 59 | if(self->compare(x, y)) 60 | { 61 | SWAP(T, x, y); 62 | JOIN(A, up)(self, p); 63 | } 64 | } 65 | } 66 | 67 | static inline void 68 | JOIN(A, down)(A* self, size_t n) 69 | { 70 | size_t min = 2; 71 | if(self->size < min) 72 | return; 73 | else 74 | if(self->size == min) 75 | { 76 | T* a = &self->value[0]; 77 | T* b = &self->value[1]; 78 | if(!self->compare(a, b)) 79 | SWAP(T, a, b); 80 | } 81 | else 82 | { 83 | size_t l = 2 * n + 1; 84 | size_t r = 2 * n + 2; 85 | if(r < self->size) 86 | { 87 | size_t index = self->compare(&self->value[r], &self->value[l]) ? r : l; 88 | T* x = &self->value[index]; 89 | T* y = &self->value[n]; 90 | if(self->compare(x, y)) 91 | { 92 | SWAP(T, x, y); 93 | JOIN(A, down)(self, index); 94 | } 95 | } 96 | } 97 | } 98 | 99 | static inline void 100 | JOIN(A, push)(A* self, T value) 101 | { 102 | JOIN(A, push_back)(self, value); 103 | JOIN(A, up)(self, self->size - 1); 104 | } 105 | 106 | static inline void 107 | JOIN(A, pop)(A* self) 108 | { 109 | SWAP(T, JOIN(A, front)(self), JOIN(A, back)(self)); 110 | JOIN(A, pop_back)(self); 111 | JOIN(A, down)(self, 0); 112 | } 113 | 114 | #undef front 115 | #undef at 116 | #undef back 117 | #undef begin 118 | #undef end 119 | #undef set 120 | #undef pop_back 121 | #undef wipe 122 | #undef clear 123 | #undef fit 124 | #undef reserve 125 | #undef push_back 126 | #undef resize 127 | #undef assign 128 | #undef shrink_to_fit_fit 129 | #undef data 130 | #undef insert 131 | #undef erase 132 | #undef sort 133 | #undef step 134 | #undef range 135 | #undef each 136 | #undef remove_if 137 | 138 | #undef T // See HOLD. 139 | #undef A 140 | -------------------------------------------------------------------------------- /ctl/que.h: -------------------------------------------------------------------------------- 1 | // 2 | // Queue 3 | // 4 | 5 | #ifndef T 6 | #error "Template type T undefined for " 7 | #endif 8 | 9 | #define push_back push 10 | #define pop_front pop 11 | #define at __AT 12 | #define begin __BEGIN 13 | #define end __END 14 | #define push_front __PUSH_FRONT 15 | #define pop_back __PUSH_BACK 16 | #define erase __ERASE 17 | #define insert __INSERT 18 | #define resize __RESIZE 19 | #define assign __ASSIGN 20 | #define clear __CLEAR 21 | #define ranged_sort __RANGED_SORT 22 | #define sort __SORT 23 | #define range __RANGE 24 | #define each __each 25 | #define step __STEP 26 | #define remove_if __REMOVE_IF 27 | 28 | #define deq que 29 | #include 30 | #undef deq 31 | 32 | #undef push_back 33 | #undef pop_front 34 | #undef at 35 | #undef begin 36 | #undef end 37 | #undef push_front 38 | #undef pop_back 39 | #undef erase 40 | #undef insert 41 | #undef resize 42 | #undef assign 43 | #undef clear 44 | #undef ranged_sort 45 | #undef sort 46 | #undef range 47 | #undef each 48 | #undef step 49 | #undef remove_if 50 | -------------------------------------------------------------------------------- /ctl/stk.h: -------------------------------------------------------------------------------- 1 | // 2 | // Stack 3 | // 4 | 5 | #ifndef T 6 | #error "Template type T undefined for " 7 | #endif 8 | 9 | #define push_back push 10 | #define pop_back pop 11 | #define back top 12 | #define at __AT 13 | #define front __FRONT 14 | #define begin __BEGIN 15 | #define end __END 16 | #define push_front __PUSH_FRONT 17 | #define pop_front __POP_FRONT 18 | #define erase __ERASE 19 | #define insert __INSERT 20 | #define resize __RESIZE 21 | #define assign __ASSIGN 22 | #define clear __CLEAR 23 | #define ranged_sort __RANGED_SORT 24 | #define sort __SORT 25 | #define range __RANGE 26 | #define each __EACH 27 | #define step __STEP 28 | #define remove_if __REMOVE_IF 29 | 30 | #define deq stk 31 | #include 32 | #undef deq 33 | 34 | #undef push_back 35 | #undef pop_back 36 | #undef back 37 | #undef at 38 | #undef front 39 | #undef begin 40 | #undef end 41 | #undef push_front 42 | #undef pop_front 43 | #undef erase 44 | #undef insert 45 | #undef resize 46 | #undef assign 47 | #undef clear 48 | #undef ranged_sort 49 | #undef sort 50 | #undef range 51 | #undef each 52 | #undef step 53 | #undef remove_if 54 | -------------------------------------------------------------------------------- /ctl/str.h: -------------------------------------------------------------------------------- 1 | // 2 | // String 3 | // 4 | 5 | #ifndef __STR__H__ 6 | #define __STR__H__ 7 | 8 | #ifdef T 9 | #error "Template type T defined for " 10 | #endif 11 | 12 | #define vec_char str 13 | #define P 14 | #define T char 15 | #define str_init str___INIT 16 | #define str_equal str___EQUAL 17 | #define str_find str___FIND 18 | #define str_copy str___COPY 19 | #include 20 | #undef str_init 21 | #undef str_copy 22 | #undef str_equal 23 | #undef str_find 24 | #undef vec_char 25 | 26 | #include 27 | #include 28 | 29 | static inline str 30 | str_init(const char* c_str) 31 | { 32 | str self = str___INIT(); 33 | size_t len = strlen(c_str); 34 | size_t min = 15; 35 | str_reserve(&self, len < min ? min : len); 36 | for(const char* s = c_str; *s; s++) 37 | str_push_back(&self, *s); 38 | return self; 39 | } 40 | 41 | static inline void 42 | str_append(str* self, const char* s) 43 | { 44 | size_t start = self->size; 45 | size_t len = strlen(s); 46 | str_resize(self, self->size + len, '\0'); 47 | for(size_t i = 0; i < len; i++) 48 | self->value[start + i] = s[i]; 49 | } 50 | 51 | static inline str 52 | str_copy(str* s) 53 | { 54 | str other = str_init(""); 55 | str_append(&other, s->value); 56 | return other; 57 | } 58 | 59 | static inline void 60 | str_insert_str(str* self, size_t index, const char* s) 61 | { 62 | size_t start = self->size; 63 | size_t len = strlen(s); 64 | str_resize(self, self->size + len, '\0'); 65 | self->size = start; 66 | while(len != 0) 67 | { 68 | len -= 1; 69 | str_insert(self, index, s[len]); 70 | } 71 | } 72 | 73 | static inline void 74 | str_replace(str* self, size_t index, size_t size, const char* s) 75 | { 76 | size_t end = index + size; 77 | if(end >= self->size) 78 | end = self->size; 79 | for(size_t i = index; i < end; i++) 80 | str_erase(self, index); 81 | str_insert_str(self, index, s); 82 | } 83 | 84 | static inline char* 85 | str_c_str(str* self) 86 | { 87 | return str_data(self); 88 | } 89 | 90 | static inline size_t 91 | str_find(str* self, const char* s) 92 | { 93 | char* c_str = self->value; 94 | char* found = strstr(c_str, s); 95 | if(found) 96 | return found - c_str; 97 | return SIZE_MAX; 98 | } 99 | 100 | static inline int 101 | str_count(str* self, char c) 102 | { 103 | size_t count = 0; 104 | for(size_t i = 0; i < self->size; i++) 105 | if(self->value[i] == c) 106 | count += 1; 107 | return count; 108 | } 109 | 110 | static inline size_t 111 | str_rfind(str* self, const char* s) 112 | { 113 | char* c_str = self->value; 114 | for(size_t i = self->size; i != SIZE_MAX; i--) 115 | { 116 | char* found = strstr(&c_str[i], s); 117 | if(found) 118 | return found - c_str; 119 | } 120 | return SIZE_MAX; 121 | } 122 | 123 | static inline size_t 124 | str_find_first_of(str* self, const char* s) 125 | { 126 | for(size_t i = 0; i < self->size; i++) 127 | for(const char* p = s; *p; p++) 128 | if(self->value[i] == *p) 129 | return i; 130 | return SIZE_MAX; 131 | } 132 | 133 | static inline size_t 134 | str_find_last_of(str* self, const char* s) 135 | { 136 | for(size_t i = self->size; i != SIZE_MAX; i--) 137 | for(const char* p = s; *p; p++) 138 | if(self->value[i] == *p) 139 | return i; 140 | return SIZE_MAX; 141 | } 142 | 143 | static inline size_t 144 | str_find_first_not_of(str* self, const char* s) 145 | { 146 | for(size_t i = 0; i < self->size; i++) 147 | { 148 | size_t count = 0; 149 | for(const char* p = s; *p; p++) 150 | if(self->value[i] == *p) 151 | count += 1; 152 | if(count == 0) 153 | return i; 154 | } 155 | return SIZE_MAX; 156 | } 157 | 158 | static inline size_t 159 | str_find_last_not_of(str* self, const char* s) 160 | { 161 | for(size_t i = self->size - 1; i != SIZE_MAX; i--) 162 | { 163 | size_t count = 0; 164 | for(const char* p = s; *p; p++) 165 | if(self->value[i] == *p) 166 | count += 1; 167 | if(count == 0) 168 | return i; 169 | } 170 | return SIZE_MAX; 171 | } 172 | 173 | static inline str 174 | str_substr(str* self, size_t index, size_t size) 175 | { 176 | str substr = str_init(""); 177 | str_resize(&substr, size, '\0'); 178 | for(size_t i = 0; i < size; i++) 179 | substr.value[i] = self->value[index + i]; 180 | return substr; 181 | } 182 | 183 | static inline int 184 | str_compare(str* self, const char* s) 185 | { 186 | return strcmp(self->value, s); 187 | } 188 | 189 | static inline int 190 | str_key_compare(str* self, str* s) 191 | { 192 | return strcmp(self->value, s->value); 193 | } 194 | 195 | #endif 196 | -------------------------------------------------------------------------------- /ctl/ust.h: -------------------------------------------------------------------------------- 1 | // 2 | // Unordered Set 3 | // 4 | 5 | #ifndef T 6 | #error "Template type T undefined for " 7 | #endif 8 | 9 | #include 10 | 11 | #define A JOIN(ust, T) 12 | #define B JOIN(A, node) 13 | #define Z JOIN(A, it) 14 | 15 | typedef struct B 16 | { 17 | T key; 18 | struct B* next; 19 | } 20 | B; 21 | 22 | typedef struct A 23 | { 24 | void (*free)(T*); 25 | T (*copy)(T*); 26 | size_t (*hash)(T*); 27 | int (*equal)(T*, T*); 28 | B** bucket; 29 | size_t size; 30 | size_t bucket_count; 31 | } 32 | A; 33 | 34 | typedef struct Z 35 | { 36 | void (*step)(struct Z*); 37 | B* end; 38 | B* node; 39 | T* ref; 40 | B* next; 41 | A* container; 42 | size_t index; 43 | int done; 44 | } 45 | Z; 46 | 47 | static inline B* 48 | JOIN(A, begin)(A* self) 49 | { 50 | for(size_t i = 0; i < self->bucket_count; i++) 51 | { 52 | B* node = self->bucket[i]; 53 | if(node) 54 | return node; 55 | } 56 | return NULL; 57 | } 58 | 59 | static inline B* 60 | JOIN(A, end)(A* self) 61 | { 62 | (void) self; 63 | return NULL; 64 | } 65 | 66 | static inline size_t 67 | JOIN(Z, index)(A* self, T value) 68 | { 69 | return self->hash(&value) % self->bucket_count; 70 | } 71 | 72 | static inline void 73 | JOIN(Z, update)(Z* self) 74 | { 75 | self->node = self->next; 76 | self->ref = &self->node->key; 77 | self->next = self->node->next; 78 | } 79 | 80 | static inline int 81 | JOIN(Z, scan)(Z* self) 82 | { 83 | for(size_t i = self->index + 1; i < self->container->bucket_count; i++) 84 | { 85 | self->next = self->container->bucket[i]; 86 | if(self->next) 87 | { 88 | self->index = i; 89 | JOIN(Z, update)(self); 90 | return 1; 91 | } 92 | } 93 | return 0; 94 | } 95 | 96 | static inline void 97 | JOIN(Z, step)(Z* self) 98 | { 99 | if(self->next == JOIN(A, end)(self->container)) 100 | { 101 | if(!JOIN(Z, scan)(self)) 102 | self->done = 1; 103 | } 104 | else 105 | JOIN(Z, update)(self); 106 | } 107 | 108 | static inline Z 109 | JOIN(Z, range)(A* container, B* begin, B* end) 110 | { 111 | static Z zero; 112 | Z self = zero; 113 | if(begin) 114 | { 115 | self.step = JOIN(Z, step); 116 | self.node = begin; 117 | self.ref = &self.node->key; 118 | self.next = self.node->next; 119 | self.end = end; 120 | self.container = container; 121 | self.index = JOIN(Z, index)(container, *self.ref); 122 | } 123 | else 124 | self.done = 1; 125 | return self; 126 | } 127 | 128 | static inline B** 129 | JOIN(A, bucket)(A* self, T value) 130 | { 131 | size_t index = JOIN(Z, index)(self, value); 132 | return &self->bucket[index]; 133 | } 134 | 135 | static inline int 136 | JOIN(A, empty)(A* self) 137 | { 138 | return self->size == 0; 139 | } 140 | 141 | static inline Z 142 | JOIN(Z, each)(A* a) 143 | { 144 | return JOIN(A, empty)(a) 145 | ? JOIN(Z, range)(a, NULL, NULL) 146 | : JOIN(Z, range)(a, JOIN(A, begin)(a), JOIN(A, end)(a)); 147 | } 148 | 149 | static inline T 150 | JOIN(A, implicit_copy)(T* self) 151 | { 152 | return *self; 153 | } 154 | 155 | static inline B* 156 | JOIN(A, find)(A* self, T value) 157 | { 158 | if(!JOIN(A, empty)(self)) 159 | { 160 | B** bucket = JOIN(A, bucket)(self, value); 161 | for(B* n = *bucket; n; n = n->next) 162 | if(self->equal(&value, &n->key)) 163 | return n; 164 | } 165 | return NULL; 166 | } 167 | 168 | static inline int 169 | JOIN(A, equal)(A* a, A* b) 170 | { 171 | size_t count_a = 0; 172 | size_t count_b = 0; 173 | foreach(A, a, it) if(JOIN(A, find)(b, *it.ref)) count_a += 1; 174 | foreach(A, b, it) if(JOIN(A, find)(a, *it.ref)) count_b += 1; 175 | return count_a == count_b; 176 | } 177 | 178 | static inline void 179 | JOIN(A, swap)(A* self, A* other) 180 | { 181 | A temp = *self; 182 | *self = *other; 183 | *other = temp; 184 | } 185 | 186 | static inline size_t 187 | JOIN(A, closest_prime)(size_t number) 188 | { 189 | static uint32_t primes[] = { 190 | 2, 3, 5, 7, 11, 191 | 13, 17, 19, 23, 29, 31, 192 | 37, 41, 43, 47, 53, 59, 193 | 61, 67, 71, 73, 79, 83, 194 | 89, 97, 103, 109, 113, 127, 195 | 137, 139, 149, 157, 167, 179, 196 | 193, 199, 211, 227, 241, 257, 197 | 277, 293, 313, 337, 359, 383, 198 | 409, 439, 467, 503, 541, 577, 199 | 619, 661, 709, 761, 823, 887, 200 | 953, 1031, 1109, 1193, 1289, 1381, 201 | 1493, 1613, 1741, 1879, 2029, 2179, 202 | 2357, 2549, 2753, 2971, 3209, 3469, 203 | 3739, 4027, 4349, 4703, 5087, 5503, 204 | 5953, 6427, 6949, 7517, 8123, 8783, 205 | 9497, 10273, 11113, 12011, 12983, 14033, 206 | 15173, 16411, 17749, 19183, 20753, 22447, 207 | 24281, 26267, 28411, 30727, 33223, 35933, 208 | 38873, 42043, 45481, 49201, 53201, 57557, 209 | 62233, 67307, 72817, 78779, 85229, 92203, 210 | 99733, 107897, 116731, 126271, 136607, 147793, 211 | 159871, 172933, 187091, 202409, 218971, 236897, 212 | 256279, 277261, 299951, 324503, 351061, 379787, 213 | 410857, 444487, 480881, 520241, 562841, 608903, 214 | 658753, 712697, 771049, 834181, 902483, 976369, 215 | 1056323, 1142821, 1236397, 1337629, 1447153, 1565659, 216 | 1693859, 1832561, 1982627, 2144977, 2320627, 2510653, 217 | 2716249, 2938679, 3179303, 3439651, 3721303, 4026031, 218 | 4355707, 4712381, 5098259, 5515729, 5967347, 6456007, 219 | 6984629, 7556579, 8175383, 8844859, 9569143, 10352717, 220 | 11200489, 12117689, 13109983, 14183539, 15345007, 16601593, 221 | 17961079, 19431899, 21023161, 22744717, 24607243, 26622317, 222 | 28802401, 31160981, 33712729, 36473443, 39460231, 42691603, 223 | 46187573, 49969847, 54061849, 58488943, 63278561, 68460391, 224 | 74066549, 80131819, 86693767, 93793069, 101473717, 109783337, 225 | 118773397, 128499677, 139022417, 150406843, 162723577, 176048909, 226 | 190465427, 206062531, 222936881, 241193053, 260944219, 282312799, 227 | 305431229, 330442829, 357502601, 386778277, 418451333, 452718089, 228 | 489790921, 529899637, 573292817, 620239453, 671030513, 725980837, 229 | 785430967, 849749479, 919334987, 994618837, 1076067617, 1164186217, 230 | 1259520799, 1362662261, 1474249943, 1594975441, 1725587117, 231 | }; 232 | size_t min = primes[0]; 233 | if(number < min) 234 | return min; 235 | size_t size = len(primes); 236 | for(size_t i = 0; i < size - 1; i++) 237 | { 238 | size_t a = primes[i + 0]; 239 | size_t b = primes[i + 1]; 240 | if(number >= a && number <= b) 241 | return number == a ? a : b; 242 | } 243 | return primes[size - 1]; 244 | } 245 | 246 | static inline B* 247 | JOIN(B, init)(T value) 248 | { 249 | B* n = (B*) malloc(sizeof(B)); 250 | n->key = value; 251 | n->next = NULL; 252 | return n; 253 | } 254 | 255 | static inline void 256 | JOIN(B, push)(A* self, B** bucket, B* n) 257 | { 258 | n->next = *bucket; 259 | self->size += 1; 260 | *bucket = n; 261 | } 262 | 263 | static inline size_t 264 | JOIN(A, bucket_size)(A* self, size_t index) 265 | { 266 | size_t size = 0; 267 | for(B* n = self->bucket[index]; n; n = n->next) 268 | size += 1; 269 | return size; 270 | } 271 | 272 | static inline float 273 | JOIN(A, load_factor)(A* self) 274 | { 275 | return (float) self->size / (float) self->bucket_count; 276 | } 277 | 278 | static inline A 279 | JOIN(A, init)(size_t _hash(T*), int _equal(T*, T*)) 280 | { 281 | static A zero; 282 | A self = zero; 283 | self.hash = _hash; 284 | self.equal = _equal; 285 | #ifdef P 286 | #undef P 287 | self.copy = JOIN(A, implicit_copy); 288 | #else 289 | self.free = JOIN(T, free); 290 | self.copy = JOIN(T, copy); 291 | #endif 292 | return self; 293 | } 294 | 295 | static inline void 296 | JOIN(A, rehash)(A* self, size_t desired_count); 297 | 298 | static inline void 299 | JOIN(A, reserve)(A* self, size_t desired_count) 300 | { 301 | if(self->size > 0) 302 | JOIN(A, rehash)(self, desired_count); 303 | else 304 | { 305 | size_t bucket_count = JOIN(A, closest_prime)(desired_count); 306 | B** temp = (B**) calloc(bucket_count, sizeof(B*)); 307 | for(size_t i = 0; i < self->bucket_count; i++) 308 | temp[i] = self->bucket[i]; 309 | free(self->bucket); 310 | self->bucket = temp; 311 | self->bucket_count = bucket_count; 312 | } 313 | } 314 | 315 | static inline void 316 | JOIN(A, rehash)(A* self, size_t desired_count) 317 | { 318 | if(desired_count <= self->size) 319 | desired_count = self->size + 1; 320 | size_t expected = JOIN(A, closest_prime)(desired_count); 321 | if(expected != self->bucket_count) 322 | { 323 | A rehashed = JOIN(A, init)(self->hash, self->equal); 324 | JOIN(A, reserve)(&rehashed, desired_count); 325 | foreach(A, self, it) 326 | { 327 | B** bucket = JOIN(A, bucket)(&rehashed, it.node->key); 328 | JOIN(B, push)(&rehashed, bucket, it.node); 329 | } 330 | free(self->bucket); 331 | *self = rehashed; 332 | } 333 | } 334 | 335 | static inline void 336 | JOIN(A, free_node)(A* self, B* n) 337 | { 338 | if(self->free) 339 | self->free(&n->key); 340 | free(n); 341 | self->size -= 1; 342 | } 343 | 344 | static inline void 345 | JOIN(A, clear)(A* self) 346 | { 347 | foreach(A, self, it) 348 | JOIN(A, free_node)(self, it.node); 349 | for(size_t i = 0; i < self->bucket_count; i++) 350 | self->bucket[i] = NULL; 351 | } 352 | 353 | static inline void 354 | JOIN(A, free)(A* self) 355 | { 356 | JOIN(A, clear)(self); 357 | free(self->bucket); 358 | } 359 | 360 | static inline void 361 | JOIN(A, insert)(A* self, T value) 362 | { 363 | if(JOIN(A, empty)(self)) 364 | JOIN(A, rehash)(self, 12); 365 | if(JOIN(A, find)(self, value)) 366 | { 367 | if(self->free) 368 | self->free(&value); 369 | } 370 | else 371 | { 372 | B** bucket = JOIN(A, bucket)(self, value); 373 | JOIN(B, push)(self, bucket, JOIN(B, init)(value)); 374 | if(self->size > self->bucket_count) 375 | JOIN(A, rehash)(self, 2 * self->bucket_count); 376 | } 377 | } 378 | 379 | static inline size_t 380 | JOIN(A, count)(A* self, T value) 381 | { 382 | return JOIN(A, find)(self, value) ? 1 : 0; 383 | } 384 | 385 | static inline void 386 | JOIN(A, linked_erase)(A* self, B** bucket, B* n, B* prev, B* next) 387 | { 388 | JOIN(A, free_node)(self, n); 389 | if(prev) 390 | prev->next = next; 391 | else 392 | *bucket = next; 393 | } 394 | 395 | static inline void 396 | JOIN(A, erase)(A* self, T value) 397 | { 398 | if(!JOIN(A, empty)(self)) 399 | { 400 | B** bucket = JOIN(A, bucket)(self, value); 401 | B* prev = NULL; 402 | B* n = *bucket; 403 | while(n) 404 | { 405 | B* next = n->next; 406 | if(self->equal(&n->key, &value)) 407 | { 408 | JOIN(A, linked_erase)(self, bucket, n, prev, next); 409 | break; 410 | } 411 | else 412 | prev = n; 413 | n = next; 414 | } 415 | } 416 | } 417 | 418 | static inline size_t 419 | JOIN(A, remove_if)(A* self, int _match(T*)) 420 | { 421 | size_t erases = 0; 422 | for(size_t i = 0; i < self->bucket_count; i++) 423 | { 424 | B** bucket = &self->bucket[i]; 425 | B* prev = NULL; 426 | B* n = *bucket; 427 | while(n) 428 | { 429 | B* next = n->next; 430 | if(_match(&n->key)) 431 | { 432 | JOIN(A, linked_erase)(self, bucket, n, prev, next); 433 | erases += 1; 434 | } 435 | else 436 | prev = n; 437 | n = next; 438 | } 439 | } 440 | return erases; 441 | } 442 | 443 | static inline A 444 | JOIN(A, copy)(A* self) 445 | { 446 | A other = JOIN(A, init)(self->hash, self->equal); 447 | foreach(A, self, it) 448 | JOIN(A, insert)(&other, self->copy(it.ref)); 449 | return other; 450 | } 451 | 452 | #undef T 453 | #undef A 454 | #undef B 455 | #undef Z 456 | -------------------------------------------------------------------------------- /ctl/vec.h: -------------------------------------------------------------------------------- 1 | // 2 | // Vector 3 | // 4 | 5 | #ifndef T 6 | #error "Template type T undefined for " 7 | #endif 8 | 9 | #include 10 | 11 | #define A JOIN(vec, T) 12 | #define Z JOIN(A, it) 13 | 14 | #define MUST_ALIGN_16(T) (sizeof(T) == sizeof(char)) 15 | 16 | typedef struct A 17 | { 18 | T* value; 19 | void (*free)(T*); 20 | #ifdef COMPARE 21 | int (*compare)(T*, T*); 22 | #endif 23 | T (*copy)(T*); 24 | size_t size; 25 | size_t capacity; 26 | } 27 | A; 28 | 29 | typedef struct Z 30 | { 31 | void (*step)(struct Z*); 32 | T* ref; 33 | T* begin; 34 | T* end; 35 | T* next; 36 | int done; 37 | } 38 | Z; 39 | 40 | static inline T* 41 | JOIN(A, at)(A* self, size_t index) 42 | { 43 | return &self->value[index]; 44 | } 45 | 46 | static inline T* 47 | JOIN(A, front)(A* self) 48 | { 49 | return JOIN(A, at)(self, 0); 50 | } 51 | 52 | static inline T* 53 | JOIN(A, back)(A* self) 54 | { 55 | return JOIN(A, at)(self, self->size - 1); 56 | } 57 | 58 | static inline T* 59 | JOIN(A, begin)(A* self) 60 | { 61 | return JOIN(A, front)(self); 62 | } 63 | 64 | static inline T* 65 | JOIN(A, end)(A* self) 66 | { 67 | return JOIN(A, back)(self) + 1; 68 | } 69 | 70 | static inline void 71 | JOIN(Z, step)(Z* self) 72 | { 73 | if(self->next >= self->end) 74 | self->done = 1; 75 | else 76 | { 77 | self->ref = self->next; 78 | self->next += 1; 79 | } 80 | } 81 | 82 | static inline Z 83 | JOIN(Z, range)(A* container, T* begin, T* end) 84 | { 85 | (void) container; 86 | static Z zero; 87 | Z self = zero; 88 | if(begin && end) 89 | { 90 | self.step = JOIN(Z, step); 91 | self.begin = begin; 92 | self.end = end; 93 | self.next = begin + 1; 94 | self.ref = begin; 95 | } 96 | else 97 | self.done = 1; 98 | return self; 99 | } 100 | 101 | static inline int 102 | JOIN(A, empty)(A* self) 103 | { 104 | return self->size == 0; 105 | } 106 | 107 | static inline Z 108 | JOIN(Z, each)(A* a) 109 | { 110 | return JOIN(A, empty)(a) 111 | ? JOIN(Z, range)(a, NULL, NULL) 112 | : JOIN(Z, range)(a, JOIN(A, begin)(a), JOIN(A, end)(a)); 113 | } 114 | 115 | static inline T 116 | JOIN(A, implicit_copy)(T* self) 117 | { 118 | return *self; 119 | } 120 | 121 | static inline int 122 | JOIN(A, equal)(A* self, A* other, int _equal(T*, T*)) 123 | { 124 | if(self->size != other->size) 125 | return 0; 126 | Z a = JOIN(Z, each)(self); 127 | Z b = JOIN(Z, each)(other); 128 | while(!a.done && !b.done) 129 | { 130 | if(!_equal(a.ref, b.ref)) 131 | return 0; 132 | a.step(&a); 133 | b.step(&b); 134 | } 135 | return 1; 136 | } 137 | 138 | static inline void 139 | JOIN(A, swap)(A* self, A* other) 140 | { 141 | A temp = *self; 142 | *self = *other; 143 | *other = temp; 144 | } 145 | 146 | static inline A 147 | JOIN(A, init)(void) 148 | { 149 | static A zero; 150 | A self = zero; 151 | #ifdef P 152 | #undef P 153 | self.copy = JOIN(A, implicit_copy); 154 | #else 155 | self.free = JOIN(T, free); 156 | self.copy = JOIN(T, copy); 157 | #endif 158 | return self; 159 | } 160 | 161 | static inline void 162 | JOIN(A, set)(A* self, size_t index, T value) 163 | { 164 | T* ref = JOIN(A, at)(self, index); 165 | if(self->free) 166 | self->free(ref); 167 | *ref = value; 168 | } 169 | 170 | static inline void 171 | JOIN(A, pop_back)(A* self) 172 | { 173 | static T zero; 174 | self->size -= 1; 175 | JOIN(A, set)(self, self->size, zero); 176 | } 177 | 178 | static inline void 179 | JOIN(A, wipe)(A* self, size_t n) 180 | { 181 | while(n != 0) 182 | { 183 | JOIN(A, pop_back)(self); 184 | n -= 1; 185 | } 186 | } 187 | 188 | static inline void 189 | JOIN(A, clear)(A* self) 190 | { 191 | if(self->size > 0) 192 | JOIN(A, wipe)(self, self->size); 193 | } 194 | 195 | static inline void 196 | JOIN(A, free)(A* self) 197 | { 198 | JOIN(A, clear)(self); 199 | free(self->value); 200 | *self = JOIN(A, init)(); 201 | } 202 | 203 | static inline void 204 | JOIN(A, fit)(A* self, size_t capacity) 205 | { 206 | static T zero; 207 | size_t overall = capacity; 208 | if(MUST_ALIGN_16(T)) 209 | overall += 1; 210 | self->value = (T*) realloc(self->value, overall * sizeof(T)); 211 | if(MUST_ALIGN_16(T)) 212 | for(size_t i = self->capacity; i < overall; i++) 213 | self->value[i] = zero; 214 | self->capacity = capacity; 215 | } 216 | 217 | static inline void 218 | JOIN(A, reserve)(A* self, const size_t capacity) 219 | { 220 | if(capacity != self->capacity) 221 | { 222 | size_t actual = 0; 223 | if(MUST_ALIGN_16(T)) 224 | { 225 | if(capacity <= self->size) 226 | actual = self->size; 227 | else 228 | if(capacity > self->size && capacity < self->capacity) 229 | actual = capacity; 230 | else 231 | { 232 | actual = 2 * self->capacity; 233 | if(capacity > actual) 234 | actual = capacity; 235 | } 236 | } 237 | else 238 | if(capacity > self->capacity) 239 | actual = capacity; 240 | if(actual > 0) 241 | JOIN(A, fit)(self, actual); 242 | } 243 | } 244 | 245 | static inline void 246 | JOIN(A, push_back)(A* self, T value) 247 | { 248 | if(self->size == self->capacity) 249 | JOIN(A, reserve)(self, self->capacity == 0 ? 1 : 2 * self->capacity); 250 | *JOIN(A, at)(self, self->size) = value; 251 | self->size += 1; 252 | } 253 | 254 | static inline void 255 | JOIN(A, resize)(A* self, size_t size, T value) 256 | { 257 | if(size < self->size) 258 | { 259 | int64_t less = self->size - size; 260 | if(less > 0) 261 | JOIN(A, wipe)(self, less); 262 | } 263 | else 264 | { 265 | if(size > self->capacity) 266 | { 267 | size_t capacity = 2 * self->size; 268 | if(size > capacity) 269 | capacity = size; 270 | JOIN(A, reserve)(self, capacity); 271 | } 272 | for(size_t i = 0; self->size < size; i++) 273 | JOIN(A, push_back)(self, self->copy(&value)); 274 | } 275 | if(self->free) 276 | self->free(&value); 277 | } 278 | 279 | static inline void 280 | JOIN(A, assign)(A* self, size_t size, T value) 281 | { 282 | JOIN(A, resize)(self, size, self->copy(&value)); 283 | for(size_t i = 0; i < size; i++) 284 | JOIN(A, set)(self, i, self->copy(&value)); 285 | if(self->free) 286 | self->free(&value); 287 | } 288 | 289 | static inline void 290 | JOIN(A, shrink_to_fit)(A* self) 291 | { 292 | JOIN(A, fit)(self, self->size); 293 | } 294 | 295 | static inline T* 296 | JOIN(A, data)(A* self) 297 | { 298 | return JOIN(A, front)(self); 299 | } 300 | 301 | static inline void 302 | JOIN(A, insert)(A* self, size_t index, T value) 303 | { 304 | if(self->size > 0) 305 | { 306 | JOIN(A, push_back)(self, *JOIN(A, back)(self)); 307 | for(size_t i = self->size - 2; i > index; i--) 308 | self->value[i] = self->value[i - 1]; 309 | self->value[index] = value; 310 | } 311 | else 312 | JOIN(A, push_back)(self, value); 313 | } 314 | 315 | static inline void 316 | JOIN(A, erase)(A* self, size_t index) 317 | { 318 | static T zero; 319 | JOIN(A, set)(self, index, zero); 320 | for(size_t i = index; i < self->size - 1; i++) 321 | { 322 | self->value[i] = self->value[i + 1]; 323 | self->value[i + 1] = zero; 324 | } 325 | self->size -= 1; 326 | } 327 | 328 | static inline void 329 | JOIN(A, ranged_sort)(A* self, int64_t a, int64_t b, int _compare(T*, T*)) 330 | { 331 | if(a >= b) 332 | return; 333 | int64_t mid = (a + b) / 2; 334 | SWAP(T, &self->value[a], &self->value[mid]); 335 | int64_t z = a; 336 | for(int64_t i = a + 1; i <= b; i++) 337 | if(_compare(&self->value[a], &self->value[i])) 338 | { 339 | z += 1; 340 | SWAP(T, &self->value[z], &self->value[i]); 341 | } 342 | SWAP(T, &self->value[a], &self->value[z]); 343 | JOIN(A, ranged_sort)(self, a, z - 1, _compare); 344 | JOIN(A, ranged_sort)(self, z + 1, b, _compare); 345 | } 346 | 347 | static inline void 348 | JOIN(A, sort)(A* self, int _compare(T*, T*)) 349 | { 350 | JOIN(A, ranged_sort)(self, 0, self->size - 1, _compare); 351 | } 352 | 353 | static inline A 354 | JOIN(A, copy)(A* self) 355 | { 356 | A other = JOIN(A, init)(); 357 | #ifdef COMPARE 358 | other.compare = self->compare; 359 | #endif 360 | JOIN(A, reserve)(&other, self->size); 361 | while(other.size < self->size) 362 | JOIN(A, push_back)(&other, other.copy(&self->value[other.size])); 363 | return other; 364 | } 365 | 366 | static inline size_t 367 | JOIN(A, remove_if)(A* self, int _match(T*)) 368 | { 369 | size_t erases = 0; 370 | foreach(A, self, it) 371 | { 372 | if(_match(it.ref)) 373 | { 374 | size_t index = it.ref - JOIN(A, begin)(self); 375 | JOIN(A, erase)(self, index); 376 | it.end = JOIN(A, end)(self); 377 | it.next = it.ref; 378 | erases += 1; 379 | } 380 | } 381 | return erases; 382 | } 383 | 384 | static inline T* 385 | JOIN(A, find)(A* self, T key, int _equal(T*, T*)) 386 | { 387 | foreach(A, self, it) 388 | if(_equal(it.ref, &key)) 389 | return it.ref; 390 | return NULL; 391 | } 392 | 393 | #ifdef COMPARE 394 | #undef COMPARE 395 | #endif 396 | 397 | #undef A 398 | #undef Z 399 | #undef MUST_ALIGN_16 400 | 401 | // Hold preserves `T` if other containers 402 | // (eg. `pqu.h`) wish to extend `vec.h`. 403 | #ifdef HOLD 404 | #undef HOLD 405 | #else 406 | #undef T 407 | #endif 408 | -------------------------------------------------------------------------------- /examples/astar.c: -------------------------------------------------------------------------------- 1 | // 2 | // -- An A* pathfinder inspired by the excellent tutorial at Red Blob Games -- 3 | // 4 | // See: 5 | // https://www.redblobgames.com/pathfinding/a-star/introduction.html 6 | 7 | #include 8 | #include 9 | 10 | typedef struct 11 | { 12 | int x; 13 | int y; 14 | int priorty; 15 | int width; 16 | } 17 | point; 18 | 19 | point 20 | point_init(int x, int y, int width) 21 | { 22 | return (point) { x, y, 0, width }; 23 | } 24 | 25 | int 26 | point_compare_priority(point* a, point* b) 27 | { 28 | return a->priorty < b->priorty; 29 | } 30 | 31 | int 32 | point_equal(point* a, point* b) 33 | { 34 | return a->x == b->x && a->y == b->y; 35 | } 36 | 37 | point 38 | point_from(str* maze, const char* c, int width) 39 | { 40 | int index = str_find(maze, c); 41 | return point_init(index % width, index / width, width); 42 | } 43 | 44 | int 45 | point_index(point* p) 46 | { 47 | return p->x + p->width * p->y; 48 | } 49 | 50 | int 51 | point_key_compare(point* a, point* b) 52 | { 53 | int i = point_index(a); 54 | int j = point_index(b); 55 | return (i == j) ? 0 : (i < j) ? -1 : 1; 56 | } 57 | 58 | typedef struct 59 | { 60 | point p; 61 | int i; 62 | } 63 | pi; 64 | 65 | typedef struct 66 | { 67 | point a; 68 | point b; 69 | } 70 | pp; 71 | 72 | int 73 | pp_key_compare(pp* a, pp* b) 74 | { 75 | return point_key_compare(&a->a, &b->a); 76 | } 77 | 78 | int 79 | pi_key_compare(pi* a, pi* b) 80 | { 81 | return point_key_compare(&a->p, &b->p); 82 | } 83 | 84 | #define P 85 | #define T point 86 | #include 87 | 88 | #define P 89 | #define T point 90 | #include 91 | 92 | #define P 93 | #define T pi 94 | #include 95 | 96 | #define P 97 | #define T pp 98 | #include 99 | 100 | deq_point 101 | astar(str* maze, int width) 102 | { 103 | point start = point_from(maze, "@", width); 104 | point goal = point_from(maze, "!", width); 105 | pqu_point front = pqu_point_init(point_compare_priority); 106 | pqu_point_push(&front, start); 107 | set_pp from = set_pp_init(pp_key_compare); 108 | set_pi costs = set_pi_init(pi_key_compare); 109 | set_pi_insert(&costs, (pi) {start, 0}); 110 | while(!pqu_point_empty(&front)) 111 | { 112 | point current = *pqu_point_top(&front); 113 | pqu_point_pop(&front); 114 | if(point_equal(¤t, &goal)) 115 | break; 116 | point deltas[] = { 117 | { -1, +1, 0, width }, { 0, +1, 0, width }, { 1, +1, 0, width }, 118 | { -1, 0, 0, width }, /* ~ ~ ~ ~ ~ ~ ~ */ { 1, 0, 0, width }, 119 | { -1, -1, 0, width }, { 0, -1, 0, width }, { 1, -1, 0, width }, 120 | }; 121 | for(size_t i = 0; i < len(deltas); i++) 122 | { 123 | point delta = deltas[i]; 124 | point next = point_init(current.x + delta.x, current.y + delta.y, width); 125 | int new_cost = set_pi_find(&costs, (pi) {.p = current})->key.i; 126 | if(maze->value[point_index(&next)] != '#') 127 | { 128 | set_pi_node* cost = set_pi_find(&costs, (pi) {.p = next}); 129 | if(cost == set_pi_end(&costs) 130 | || new_cost < cost->key.i) 131 | { 132 | set_pi_insert(&costs, (pi) {next, new_cost}); 133 | next.priorty = new_cost + abs(goal.x - next.x) + abs(goal.y - next.y); 134 | pqu_point_push(&front, next); 135 | set_pp_insert(&from, (pp) { next, current }); 136 | } 137 | } 138 | } 139 | } 140 | point current = goal; 141 | deq_point path = deq_point_init(); 142 | while(!point_equal(¤t, &start)) 143 | { 144 | deq_point_push_front(&path, current); 145 | current = set_pp_find(&from, (pp) {.a = current})->key.b; 146 | } 147 | deq_point_push_front(&path, start); 148 | pqu_point_free(&front); 149 | set_pp_free(&from); 150 | set_pi_free(&costs); 151 | return path; 152 | } 153 | 154 | int 155 | main(void) 156 | { 157 | str maze = str_init( 158 | "#########################################################################\n" 159 | "# # # # # # #\n" 160 | "# # ######### # ##### ######### ##### ##### ##### # ! #\n" 161 | "# # # # # # # # # #\n" 162 | "######### # ######### ######### ##### # # # ######### #\n" 163 | "# # # # # # # # # # #\n" 164 | "# # ############# # # ######### ##### # ######### # #\n" 165 | "# # # # # # # # # #\n" 166 | "# ############# ##### ##### # ##### ######### # ##### #\n" 167 | "# # # # # # # # # #\n" 168 | "# ##### ##### # ##### # ######### # # # #############\n" 169 | "# # # # # # # # # # # #\n" 170 | "############# # # # ######### # ##### # ##### ##### #\n" 171 | "# # # # # # # # # #\n" 172 | "# ##### # ######### ##### # ##### ##### ############# #\n" 173 | "# # # # # # # # # #\n" 174 | "# # ######### # ##### ######### # # ############# # #\n" 175 | "# # # # # # # # # # #\n" 176 | "# ######### # # # ##### ######### ######### # #########\n" 177 | "# # # # # # # # # #\n" 178 | "# @ # ##### ##### ##### ######### ##### # ######### # #\n" 179 | "# # # # # # #\n" 180 | "#########################################################################\n"); 181 | int width = str_find(&maze, "\n") + 1; 182 | deq_point path = astar(&maze, width); 183 | foreach(deq_point, &path, it) maze.value[point_index(it.ref)] = 'x'; 184 | printf("%s", maze.value); 185 | str_free(&maze); 186 | deq_point_free(&path); 187 | } 188 | -------------------------------------------------------------------------------- /examples/json.c: -------------------------------------------------------------------------------- 1 | // 2 | // -- A fast JSON parser written in about 500 lines -- 3 | // 4 | // Note: 5 | // - Support for True, False, and Null is not implemented. 6 | // - Strings are limited to alphanumeric characters and underscores. 7 | // 8 | // * That being said, the parser can easily be modified to include support 9 | // for the above, but a C-like subset of JSON is preferred for 10 | // the purpose of this example. 11 | // 12 | // - Output is alphabetically ordered. 13 | // - Once the JSON has been parsed, values can be erased, modified, 14 | // inserted, and even copied with common vec and set operations. 15 | // 16 | // See: 17 | // https://www.json.org/json-en.html 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #define P 25 | #define T char 26 | #include 27 | 28 | struct val; 29 | 30 | typedef struct val* valp; 31 | 32 | static void 33 | valp_free(valp*); 34 | 35 | static valp 36 | valp_copy(valp*); 37 | 38 | #define T valp 39 | #include 40 | 41 | static vec_valp* 42 | vec_valp_heap_init(void) 43 | { 44 | vec_valp* self = malloc(sizeof(*self)); 45 | *self = vec_valp_init(); 46 | return self; 47 | } 48 | 49 | static void 50 | vec_valp_heap_free(vec_valp* self) 51 | { 52 | vec_valp_free(self); 53 | free(self); 54 | } 55 | 56 | static vec_valp* 57 | vec_valp_heap_copy(vec_valp* self) 58 | { 59 | vec_valp* copy = vec_valp_heap_init(); 60 | *copy = vec_valp_copy(self); 61 | return copy; 62 | } 63 | 64 | typedef enum 65 | { 66 | STRING, 67 | OBJECT, 68 | ARRAY, 69 | NUMBER, 70 | } 71 | fam; 72 | 73 | struct set_pair; 74 | 75 | static void 76 | set_pair_heap_free(struct set_pair*); 77 | 78 | static struct set_pair* 79 | set_pair_heap_copy(struct set_pair*); 80 | 81 | typedef union 82 | { 83 | str string; 84 | struct set_pair* object; 85 | vec_valp* array; 86 | double number; 87 | } 88 | type; 89 | 90 | typedef struct val 91 | { 92 | fam family; 93 | type of; 94 | } 95 | val; 96 | 97 | static void 98 | val_free(valp self) 99 | { 100 | if(self->family == STRING) 101 | str_free(&self->of.string); 102 | else 103 | if(self->family == OBJECT) 104 | set_pair_heap_free(self->of.object); 105 | else 106 | if(self->family == ARRAY) 107 | vec_valp_heap_free(self->of.array); 108 | } 109 | 110 | static val 111 | val_copy(valp self) 112 | { 113 | val temp; 114 | temp.family = self->family; 115 | if(temp.family == STRING) 116 | temp.of.string = str_copy(&self->of.string); 117 | else 118 | if(temp.family == OBJECT) 119 | temp.of.object = set_pair_heap_copy(self->of.object); 120 | else 121 | if(temp.family == ARRAY) 122 | temp.of.array = vec_valp_heap_copy(self->of.array); 123 | else 124 | if(temp.family == NUMBER) 125 | temp.of.number = self->of.number; 126 | return temp; 127 | } 128 | 129 | static valp 130 | valp_init(void) 131 | { 132 | return malloc(sizeof(val)); 133 | } 134 | 135 | static void 136 | valp_free(valp* self) 137 | { 138 | val_free(*self); 139 | free(*self); 140 | } 141 | 142 | static valp 143 | valp_copy(valp* self) 144 | { 145 | valp copy = valp_init(); 146 | *copy = val_copy(*self); 147 | return copy; 148 | } 149 | 150 | typedef struct 151 | { 152 | str string; 153 | valp value; 154 | } 155 | pair; 156 | 157 | static void 158 | pair_free(pair* self) 159 | { 160 | str_free(&self->string); 161 | valp_free(&self->value); 162 | } 163 | 164 | static pair 165 | pair_copy(pair* self) 166 | { 167 | return (pair) { 168 | str_copy(&self->string), 169 | valp_copy(&self->value), 170 | }; 171 | } 172 | 173 | #define T pair 174 | #include 175 | 176 | static int 177 | set_pair_key_compare(pair* a, pair* b) 178 | { 179 | return str_key_compare(&a->string, &b->string); 180 | } 181 | 182 | static set_pair* 183 | set_pair_heap_init(void) 184 | { 185 | set_pair* self = malloc(sizeof(*self)); 186 | *self = set_pair_init(set_pair_key_compare); 187 | return self; 188 | } 189 | 190 | static void 191 | set_pair_heap_free(set_pair* self) 192 | { 193 | set_pair_free(self); 194 | free(self); 195 | } 196 | 197 | static set_pair* 198 | set_pair_heap_copy(set_pair* self) 199 | { 200 | set_pair* copy = set_pair_heap_init(); 201 | *copy = set_pair_copy(self); 202 | return copy; 203 | } 204 | 205 | static stk_char 206 | prime(str* text) 207 | { 208 | stk_char feed = stk_char_init(); 209 | while(text->size) 210 | { 211 | char c = *str_back(text); 212 | stk_char_push(&feed, c); 213 | str_pop_back(text); 214 | } 215 | return feed; 216 | } 217 | 218 | static int 219 | is_space(char c) 220 | { 221 | return c == ' ' 222 | || c == '\n' 223 | || c == '\r' 224 | || c == '\t'; 225 | } 226 | 227 | static int 228 | next(stk_char* feed) 229 | { 230 | char c; 231 | while(is_space(c = *stk_char_top(feed))) 232 | stk_char_pop(feed); 233 | return c; 234 | } 235 | 236 | static void 237 | match(stk_char* feed, char c) 238 | { 239 | if(next(feed) != c) 240 | { 241 | printf("expected '%c' but received '%c'\n", c, next(feed)); 242 | exit(1); 243 | } 244 | stk_char_pop(feed); 245 | } 246 | 247 | static int 248 | is_number(char c) 249 | { 250 | return c == '.' 251 | || c == '+' 252 | || c == '-' 253 | || c == 'e' 254 | || c == 'E' 255 | || (c >= '0' && c <= '9'); 256 | } 257 | 258 | static int 259 | is_string(char c) 260 | { 261 | return c == '_' 262 | || (c >= 'a' && c <= 'z') 263 | || (c >= 'A' && c <= 'Z') 264 | || is_number(c); 265 | } 266 | 267 | static str 268 | read(stk_char* feed, int clause(char c)) 269 | { 270 | next(feed); 271 | str s = str_init(""); 272 | char c; 273 | while(clause(c = *stk_char_top(feed))) 274 | { 275 | str_push_back(&s, c); 276 | stk_char_pop(feed); 277 | } 278 | return s; 279 | } 280 | 281 | static str 282 | read_string(stk_char* feed) 283 | { 284 | match(feed, '"'); 285 | str string = read(feed, is_string); 286 | match(feed, '"'); 287 | return string; 288 | } 289 | 290 | static double 291 | read_number(stk_char* feed) 292 | { 293 | str number = read(feed, is_number); 294 | double converted = atof(number.value); 295 | str_free(&number); 296 | return converted; 297 | } 298 | 299 | static set_pair* 300 | read_object(stk_char*); 301 | 302 | static valp 303 | read_value(stk_char* feed) 304 | { 305 | valp value = valp_init(); 306 | if(is_number(next(feed))) 307 | { 308 | value->family = NUMBER; 309 | value->of.number = read_number(feed); 310 | } 311 | else 312 | if(next(feed) == '"') 313 | { 314 | value->family = STRING; 315 | value->of.string = read_string(feed); 316 | } 317 | else 318 | if(next(feed) == '{') 319 | { 320 | value->family = OBJECT; 321 | value->of.object = read_object(feed); 322 | } 323 | else 324 | if(next(feed) == '[') 325 | { 326 | match(feed, '['); 327 | value->family = ARRAY; 328 | value->of.array = vec_valp_heap_init(); 329 | while(next(feed) != ']') 330 | { 331 | valp sub = read_value(feed); 332 | vec_valp_push_back(value->of.array, sub); 333 | if(next(feed) == ']') 334 | break; 335 | match(feed, ','); 336 | } 337 | match(feed, ']'); 338 | } 339 | return value; 340 | } 341 | 342 | static set_pair* 343 | read_object(stk_char* feed) 344 | { 345 | set_pair* child = set_pair_heap_init(); 346 | match(feed, '{'); 347 | while(next(feed) != '}') 348 | { 349 | str string = read_string(feed); 350 | match(feed, ':'); 351 | valp value = read_value(feed); 352 | set_pair_insert(child, (pair) { string, value }); 353 | if(next(feed) == '}') 354 | break; 355 | match(feed, ','); 356 | } 357 | match(feed, '}'); 358 | return child;; 359 | } 360 | 361 | static valp 362 | jsonify(char* serial) 363 | { 364 | str text = str_init(serial); 365 | stk_char feed = prime(&text); 366 | valp json = read_value(&feed); 367 | stk_char_free(&feed); 368 | str_free(&text); 369 | return json; 370 | } 371 | 372 | static void 373 | tab(int tabs) 374 | { 375 | int spaces = 4; 376 | while(tabs--) 377 | for(int i = 0; i < spaces; i++) 378 | printf(" "); 379 | } 380 | 381 | static void 382 | pprint(valp, int); 383 | 384 | static void 385 | traverse(set_pair* json, int tabs) 386 | { 387 | printf("{\n"); 388 | foreach(set_pair, json, it) 389 | { 390 | tab(tabs); 391 | printf("\"%s\" : ", it.ref->string.value); 392 | pprint(it.ref->value, tabs); 393 | putchar('\n'); 394 | } 395 | tab(tabs - 1); 396 | printf("}"); 397 | } 398 | 399 | static void 400 | pprint(valp value, int tabs) 401 | { 402 | if(value) 403 | { 404 | if(value->family == NUMBER) 405 | printf("%.2f", value->of.number); 406 | else 407 | if(value->family == STRING) 408 | printf("\"%s\"", value->of.string.value); 409 | else 410 | if(value->family == OBJECT) 411 | traverse(value->of.object, tabs + 1); 412 | else 413 | if(value->family == ARRAY) 414 | { 415 | printf("["); 416 | vec_valp* array = value->of.array; 417 | int index = 0; 418 | foreach(vec_valp, array, it) 419 | { 420 | valp v = *it.ref; 421 | printf("[%d] = ", index); 422 | pprint(v, tabs); 423 | if(it.ref < vec_valp_end(array) - 1) 424 | printf(", "); 425 | index += 1; 426 | } 427 | printf("]"); 428 | } 429 | } 430 | } 431 | 432 | static void 433 | print(valp value) 434 | { 435 | pprint(value, 0); 436 | putchar('\n'); 437 | } 438 | 439 | static int 440 | is_array(valp value) 441 | { 442 | return value && value->family == ARRAY; 443 | } 444 | 445 | static int 446 | is_object(valp value) 447 | { 448 | return value && value->family == OBJECT; 449 | } 450 | 451 | static valp 452 | get(valp value, char* s) 453 | { 454 | if(is_object(value)) 455 | { 456 | pair p; 457 | p.string = str_init(s); 458 | set_pair_node* node = set_pair_find(value->of.object, p); 459 | str_free(&p.string); 460 | if(node) 461 | return node->key.value; 462 | } 463 | return NULL; 464 | } 465 | 466 | static int 467 | is_array_in_bounds(valp value, size_t index) 468 | { 469 | return index < value->of.array->size; 470 | } 471 | 472 | static valp 473 | ind(valp value, size_t index) 474 | { 475 | if(is_array(value)) 476 | if(is_array_in_bounds(value, index)) 477 | return value->of.array->value[index]; 478 | return NULL; 479 | } 480 | 481 | static void 482 | erase_obj(valp value, char* string) 483 | { 484 | if(is_object(value)) 485 | { 486 | pair p; 487 | p.string = str_init(string); 488 | set_pair_erase(value->of.object, p); 489 | str_free(&p.string); 490 | } 491 | } 492 | 493 | static void 494 | erase_ind(valp value, size_t index) 495 | { 496 | if(is_array(value)) 497 | if(is_array_in_bounds(value, index)) 498 | vec_valp_erase(value->of.array, index); 499 | } 500 | 501 | int 502 | main(void) 503 | { 504 | valp json = jsonify( 505 | "{\n" 506 | "\"CCC\" : [1.2, 2.2, 3.3],\n" 507 | "\"BBB\" : 2.2," 508 | "\"AAA\" : 1.1," 509 | "\"ZZZ\" : \"this_is_a_test\"," 510 | "\"EEE\" : {" 511 | "\"c\" : 9.3," 512 | "\"Z\" : 9.11321," 513 | "\"d\" : 3.4," 514 | "\"D\" : { \"nested_arrays\": [[[[[[[{}, {}, {}]]]]]]] } ," 515 | "\"b\" : 7.2," 516 | "\"TEST\" : {" 517 | "\"a\" : 9.1," 518 | "\"c\" : 9.3," 519 | "\"e\" : \"name\"," 520 | "\"b\" : 9.2," 521 | "\"something\" : [\"gustav\", \"susan\", 1, 0]," 522 | "\"f\" : \"adam\"," 523 | "\"g\" : \"gustav\"," 524 | "\"d\" : 9.4," 525 | "}" 526 | "}" 527 | "}" 528 | ); 529 | valp copy = valp_copy(&json); 530 | print(get(json, "CCC")); 531 | erase_ind(get(json, "CCC"), 0); 532 | erase_obj(get(json, "EEE"), "TEST"); 533 | erase_obj(get(json, "EEE"), "D"); 534 | print(get(json, "CCC")); 535 | print(ind(get(json, "CCC"), 0)); 536 | puts("--- MODIFIED JSON ---"); 537 | print(json); 538 | puts("--- ORIGINAL COPY ---"); 539 | print(copy); 540 | valp_free(&json); 541 | valp_free(©); 542 | } 543 | -------------------------------------------------------------------------------- /examples/postfix.c: -------------------------------------------------------------------------------- 1 | // 2 | // -- An infix to postfix converter -- 3 | // 4 | 5 | #include 6 | 7 | #include 8 | 9 | // Template signatures can be renamed, such that long form 10 | // lst_str_push_back(lst_str*, ...) can be replaced with 11 | // the a convenient ls_push_back(ls*, ...). 12 | 13 | #define lst_str ls 14 | #define T str 15 | #include 16 | 17 | #define stk_str ss 18 | #define T str 19 | #include 20 | 21 | int 22 | get_prec(char c) 23 | { 24 | switch(c) 25 | { 26 | case '*': 27 | case '/': 28 | return 0; 29 | case '+': 30 | case '-': 31 | return 1; 32 | } 33 | return 0; 34 | } 35 | 36 | int 37 | is_digit(char c) 38 | { 39 | return c >= '0' && c <= '9'; 40 | } 41 | 42 | int 43 | is_of_operator(char c) 44 | { 45 | switch(c) 46 | { 47 | case '+': 48 | case '-': 49 | case '/': 50 | case '*': 51 | return 1; 52 | } 53 | return 0; 54 | } 55 | 56 | int 57 | is_operator(str* s) 58 | { 59 | return str_compare(s, "+") == 0 60 | || str_compare(s, "-") == 0 61 | || str_compare(s, "/") == 0 62 | || str_compare(s, "*") == 0; 63 | } 64 | 65 | int 66 | is_paren(char c) 67 | { 68 | return c == '(' 69 | || c == ')'; 70 | } 71 | 72 | int 73 | is_space(char c) 74 | { 75 | return c == ' '; 76 | } 77 | 78 | str 79 | get_digit(str* s, size_t i) 80 | { 81 | size_t j = i; 82 | while(is_digit(s->value[j])) 83 | j += 1; 84 | return str_substr(s, i, j - i); 85 | } 86 | 87 | str 88 | get_operator(str* s, size_t i) 89 | { 90 | size_t j = i; 91 | while(is_of_operator(s->value[j])) 92 | j += 1; 93 | return str_substr(s, i, j - i); 94 | } 95 | 96 | ls 97 | tokenize(str* s) 98 | { 99 | ls tokens = ls_init(); 100 | for(size_t i = 0; i < s->size; i++) 101 | { 102 | char c = s->value[i]; 103 | if(is_space(c)) 104 | continue; 105 | str token; 106 | if(is_paren(c)) 107 | token = str_substr(s, i, 1); 108 | else 109 | if(is_digit(c)) 110 | token = get_digit(s, i); 111 | else 112 | if(is_of_operator(c)) 113 | token = get_operator(s, i); 114 | else 115 | { 116 | printf("error: tokenize(): unknown token '%c'\n", c); 117 | exit(1); 118 | } 119 | ls_push_back(&tokens, token); 120 | i += token.size - 1; 121 | } 122 | return tokens; 123 | } 124 | 125 | ls 126 | to_postfix(ls* tokens) 127 | { 128 | ls postfix = ls_init(); 129 | ss operators = ss_init(); 130 | foreach(ls, tokens, it) 131 | { 132 | str* token = it.ref; 133 | char c = token->value[0]; 134 | if(is_digit(c)) 135 | { 136 | ls_push_back(&postfix, str_copy(token)); 137 | if(postfix.size > 1 && operators.size) 138 | { 139 | if(it.next) 140 | { 141 | str* next = &it.next->value; 142 | char cc = next->value[0]; 143 | if(get_prec(c) < get_prec(cc)) 144 | { 145 | str* operator = ss_top(&operators); 146 | char ccc = operator->value[0]; 147 | if(ccc != '(') 148 | { 149 | ls_push_back(&postfix, str_copy(operator)); 150 | ss_pop(&operators); 151 | } 152 | } 153 | } 154 | } 155 | } 156 | else 157 | if(is_operator(token)) 158 | ss_push(&operators, str_copy(token)); 159 | else 160 | if(is_paren(c)) 161 | { 162 | if(c == '(') 163 | ss_push(&operators, str_copy(token)); 164 | else 165 | if(c == ')') 166 | { 167 | int done = 0; 168 | while(!done) 169 | { 170 | str* top = ss_top(&operators); 171 | char cc = top->value[0]; 172 | if(cc == '(') 173 | done = 1; 174 | else 175 | ls_push_back(&postfix, str_copy(top)); 176 | ss_pop(&operators); 177 | } 178 | } 179 | } 180 | else 181 | { 182 | printf("error: to_postfix(): unknown token '%c'\n", c); 183 | exit(1); 184 | } 185 | } 186 | while(!ss_empty(&operators)) 187 | { 188 | str* operator = ss_top(&operators); 189 | ls_push_back(&postfix, str_copy(operator)); 190 | ss_pop(&operators); 191 | } 192 | ss_free(&operators); 193 | return postfix; 194 | } 195 | 196 | int 197 | main(void) 198 | { 199 | str s = str_init("64 * (128 / 2 - 128 / (2 - 1))"); 200 | ls tokens = tokenize(&s); 201 | ls postfix = to_postfix(&tokens); 202 | puts(s.value); 203 | foreach(ls, &postfix, it) 204 | puts(it.ref->value); 205 | ls_free(&tokens); 206 | ls_free(&postfix); 207 | str_free(&s); 208 | } 209 | -------------------------------------------------------------------------------- /examples/snow.c: -------------------------------------------------------------------------------- 1 | // 2 | // -- Showcases container-container templating to create a 2D array using vectors, 3 | // and then proceeds to create a neat snow animation -- 4 | // 5 | 6 | #include 7 | #include 8 | 9 | #define P 10 | #define T char 11 | #include 12 | 13 | // P is omitted since the previous inclusion of vec 14 | // defines vec_char_init, vec_char_free, and vec_char_copy 15 | 16 | #define T vec_char // A 2D array, like std::vector>. 17 | #include 18 | 19 | enum 20 | { 21 | SNOWFLAKE = '*', AIR = ' ' 22 | }; 23 | 24 | static char 25 | get(vec_vec_char* snow, size_t x, size_t y) 26 | { 27 | if(x < snow->size) 28 | if(y < snow->value[x].size) 29 | return snow->value[x].value[y]; 30 | return SNOWFLAKE; 31 | } 32 | 33 | static void 34 | set(vec_vec_char* snow, size_t x, size_t y, char c) 35 | { 36 | snow->value[x].value[y] = c; 37 | } 38 | 39 | static vec_vec_char 40 | setup(size_t xres, size_t yres) 41 | { 42 | vec_vec_char snow = vec_vec_char_init(); 43 | vec_vec_char_resize(&snow, xres, vec_char_init()); 44 | foreach(vec_vec_char, &snow, it) 45 | vec_char_resize(it.ref, yres, AIR); 46 | return snow; 47 | } 48 | 49 | static void 50 | add(vec_vec_char* snow, size_t xres) 51 | { 52 | int chance = 16; 53 | for(size_t x = 0; x < xres; x++) 54 | if(rand() % chance == 0) 55 | set(snow, x, 0, SNOWFLAKE); 56 | } 57 | 58 | static void 59 | fall(vec_vec_char* snow, size_t xres, size_t yres) 60 | { 61 | vec_vec_char copy = vec_vec_char_copy(snow); 62 | for(size_t y = 0; y < yres; y++) 63 | for(size_t x = 0; x < xres; x++) 64 | if(get(©, x, y) == SNOWFLAKE) 65 | { 66 | size_t y0 = y + 0; 67 | size_t y1 = y + 1; 68 | if(get(©, x, y1) != SNOWFLAKE) 69 | { 70 | set(snow, x, y1, SNOWFLAKE); 71 | set(snow, x, y0, AIR); 72 | } 73 | } 74 | vec_vec_char_free(©); 75 | } 76 | 77 | static void 78 | delay(size_t usec) 79 | { 80 | struct timeval time; 81 | time.tv_sec = 0; 82 | time.tv_usec = usec; 83 | select(1, NULL, NULL, NULL, &time); 84 | } 85 | 86 | static void 87 | draw(vec_vec_char* snow, size_t xres, size_t yres) 88 | { 89 | for(size_t y = 0; y < yres; y++) 90 | { 91 | for(size_t x = 0; x < xres; x++) 92 | printf("%c", get(snow, x, y)); 93 | putchar('\n'); 94 | } 95 | printf("\x1B[%zuA", yres); // Rewinds stdout by 'yres' rows. 96 | printf("\r"); // Rewinds stdout to the zero column. 97 | delay(25000); 98 | } 99 | 100 | int 101 | main(void) 102 | { 103 | size_t xres = 64; 104 | size_t yres = 32; 105 | vec_vec_char snow = setup(xres, yres); 106 | for(int loops = 512; loops > 0; loops--) 107 | { 108 | add(&snow, xres); 109 | fall(&snow, xres, yres); 110 | draw(&snow, xres, yres); 111 | } 112 | vec_vec_char_free(&snow); 113 | } 114 | -------------------------------------------------------------------------------- /gen_images.sh: -------------------------------------------------------------------------------- 1 | CFLAGS='-O3' 2 | VERSION=$(g++ --version | head -1) 3 | 4 | function perf_graph 5 | { 6 | LOG=$1 7 | TITLE=$2 8 | LIST=$3 9 | OUT=bin 10 | echo $LOG 11 | for TEST in ${LIST[*]} 12 | do 13 | if [[ $TEST == *.c ]] 14 | then 15 | gcc -o $OUT $CFLAGS $TEST -I ctl 16 | else 17 | g++ -o $OUT $CFLAGS $TEST 18 | fi 19 | ./$OUT >> $LOG 20 | done 21 | python3 tests/perf/perf_plot.py $LOG "$TITLE" 22 | mv $LOG.png images/ 23 | rm $LOG 24 | rm $OUT 25 | } 26 | 27 | function perf_compile_two_bar 28 | { 29 | KEY='stamp' 30 | TIMEFORMAT="$KEY %R" 31 | LOG=$1 32 | TITLE=$2 33 | A=$3 34 | B=$4 35 | AA=bina 36 | BB=binb 37 | echo $LOG 38 | X=`(time gcc -o $AA $CFLAGS $A -I ctl) 2>&1 | grep $KEY | cut -d ' ' -f 2` 39 | Y=`(time g++ -o $BB $CFLAGS $B) 2>&1 | grep $KEY | cut -d ' ' -f 2` 40 | I=`stat --printf="%s" $AA` 41 | J=`stat --printf="%s" $BB` 42 | python3 tests/perf/perf_plot_bar.py $LOG "$TITLE" $X $Y $I $J $A $B 43 | mv $LOG.png images/ 44 | rm $AA 45 | rm $BB 46 | } 47 | 48 | perf_graph \ 49 | 'set.log' \ 50 | "std::set vs. CTL set_int ($CFLAGS) ($VERSION)" \ 51 | "tests/perf/set/perf_set_insert.cc \ 52 | tests/perf/set/perf_set_insert.c \ 53 | tests/perf/set/perf_set_erase.cc \ 54 | tests/perf/set/perf_set_erase.c \ 55 | tests/perf/set/perf_set_iterate.cc \ 56 | tests/perf/set/perf_set_iterate.c" 57 | 58 | perf_graph \ 59 | 'ust.log' \ 60 | "std::unordered_set vs. CTL ust_int ($CFLAGS) ($VERSION)" \ 61 | "tests/perf/ust/perf_unordered_set_insert.cc \ 62 | tests/perf/ust/perf_ust_insert.c \ 63 | tests/perf/ust/perf_unordered_set_erase.cc \ 64 | tests/perf/ust/perf_ust_erase.c \ 65 | tests/perf/ust/perf_unordered_set_iterate.cc \ 66 | tests/perf/ust/perf_ust_iterate.c" 67 | 68 | perf_graph \ 69 | 'pqu.log' \ 70 | "std::priority_queue vs. CTL pqu_int ($CFLAGS) ($VERSION)" \ 71 | "tests/perf/pqu/perf_priority_queue_push.cc \ 72 | tests/perf/pqu/perf_pqu_push.c \ 73 | tests/perf/pqu/perf_priority_queue_pop.cc \ 74 | tests/perf/pqu/perf_pqu_pop.c" 75 | 76 | perf_graph \ 77 | 'vec.log' \ 78 | "std::vector vs. CTL vec_int ($CFLAGS) ($VERSION)" \ 79 | "tests/perf/vec/perf_vector_push_back.cc \ 80 | tests/perf/vec/perf_vec_push_back.c \ 81 | tests/perf/vec/perf_vector_pop_back.cc \ 82 | tests/perf/vec/perf_vec_pop_back.c \ 83 | tests/perf/vec/perf_vector_sort.cc \ 84 | tests/perf/vec/perf_vec_sort.c \ 85 | tests/perf/vec/perf_vector_iterate.cc \ 86 | tests/perf/vec/perf_vec_iterate.c" 87 | 88 | perf_graph \ 89 | 'lst.log' \ 90 | "std::list vs. CTL lst_int ($CFLAGS) ($VERSION)" \ 91 | "tests/perf/lst/perf_list_push_back.cc 92 | tests/perf/lst/perf_lst_push_back.c \ 93 | tests/perf/lst/perf_list_pop_back.cc \ 94 | tests/perf/lst/perf_lst_pop_back.c \ 95 | tests/perf/lst/perf_list_pop_front.cc \ 96 | tests/perf/lst/perf_lst_pop_front.c \ 97 | tests/perf/lst/perf_list_push_front.cc \ 98 | tests/perf/lst/perf_lst_push_front.c \ 99 | tests/perf/lst/perf_list_sort.cc \ 100 | tests/perf/lst/perf_lst_sort.c \ 101 | tests/perf/lst/perf_list_iterate.cc \ 102 | tests/perf/lst/perf_lst_iterate.c" 103 | 104 | perf_graph \ 105 | 'deq.log' \ 106 | "std::deque vs. CTL deq_int ($CFLAGS) ($VERSION)" \ 107 | "tests/perf/deq/perf_deque_push_back.cc 108 | tests/perf/deq/perf_deq_push_back.c \ 109 | tests/perf/deq/perf_deque_pop_back.cc \ 110 | tests/perf/deq/perf_deq_pop_back.c \ 111 | tests/perf/deq/perf_deque_pop_front.cc \ 112 | tests/perf/deq/perf_deq_pop_front.c \ 113 | tests/perf/deq/perf_deque_push_front.cc \ 114 | tests/perf/deq/perf_deq_push_front.c \ 115 | tests/perf/deq/perf_deque_sort.cc \ 116 | tests/perf/deq/perf_deq_sort.c \ 117 | tests/perf/deq/perf_deque_iterate.cc \ 118 | tests/perf/deq/perf_deq_iterate.c" 119 | 120 | perf_compile_two_bar \ 121 | 'compile.log' \ 122 | "CTL vs STL Compilation ($CFLAGS) ($VERSION)" \ 123 | 'tests/perf/perf_compile_c11.c' \ 124 | 'tests/perf/perf_compile_cc.cc' 125 | -------------------------------------------------------------------------------- /images/compile.log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glouw/ctl/435a2e6ba6cc4222e890b4c5993a750d29cb04e3/images/compile.log.png -------------------------------------------------------------------------------- /images/deq.log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glouw/ctl/435a2e6ba6cc4222e890b4c5993a750d29cb04e3/images/deq.log.png -------------------------------------------------------------------------------- /images/lst.log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glouw/ctl/435a2e6ba6cc4222e890b4c5993a750d29cb04e3/images/lst.log.png -------------------------------------------------------------------------------- /images/pqu.log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glouw/ctl/435a2e6ba6cc4222e890b4c5993a750d29cb04e3/images/pqu.log.png -------------------------------------------------------------------------------- /images/set.log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glouw/ctl/435a2e6ba6cc4222e890b4c5993a750d29cb04e3/images/set.log.png -------------------------------------------------------------------------------- /images/tankguy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glouw/ctl/435a2e6ba6cc4222e890b4c5993a750d29cb04e3/images/tankguy.png -------------------------------------------------------------------------------- /images/ust.log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glouw/ctl/435a2e6ba6cc4222e890b4c5993a750d29cb04e3/images/ust.log.png -------------------------------------------------------------------------------- /images/vec.log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glouw/ctl/435a2e6ba6cc4222e890b4c5993a750d29cb04e3/images/vec.log.png -------------------------------------------------------------------------------- /tests/func/digi.hh: -------------------------------------------------------------------------------- 1 | #ifndef __DIGI__H__ 2 | #define __DIGI__H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef struct 8 | { 9 | float* value; 10 | } 11 | digi; 12 | 13 | static inline digi 14 | digi_init(float value) 15 | { 16 | digi self = { 17 | (float*) malloc(sizeof(*self.value)) 18 | }; 19 | *self.value = value; 20 | return self; 21 | } 22 | 23 | static inline void 24 | digi_free(digi* self) 25 | { 26 | free(self->value); 27 | } 28 | 29 | static inline int 30 | digi_equal(digi* a, digi* b) 31 | { 32 | return *a->value == *b->value; 33 | } 34 | 35 | static inline int 36 | digi_compare(digi* a, digi* b) 37 | { 38 | return *b->value < *a->value; 39 | } 40 | 41 | size_t 42 | digi_hash(digi* d) 43 | { 44 | return std::hash{}(*d->value); 45 | } 46 | 47 | static inline digi 48 | digi_copy(digi* self) 49 | { 50 | digi copy = digi_init(0); 51 | *copy.value = *self->value; 52 | return copy; 53 | } 54 | 55 | static inline int 56 | digi_is_odd(digi* d) 57 | { 58 | return (int) *d->value % 2; 59 | } 60 | 61 | static inline int 62 | digi_match(digi* a, digi* b) 63 | { 64 | return *a->value == *b->value; 65 | } 66 | 67 | struct DIGI 68 | { 69 | float* value; 70 | DIGI(float _value): value { new float {_value} } 71 | { 72 | } 73 | DIGI(): DIGI(0) 74 | { 75 | } 76 | ~DIGI() 77 | { 78 | delete value; 79 | } 80 | DIGI(const DIGI& a): DIGI() 81 | { 82 | *value = *a.value; 83 | } 84 | DIGI& operator=(const DIGI& a) 85 | { 86 | delete value; 87 | value = new float; 88 | *value = *a.value; 89 | return *this; 90 | } 91 | DIGI& operator=(DIGI&& a) 92 | { 93 | delete value; 94 | value = a.value; 95 | a.value = nullptr; 96 | return *this; 97 | } 98 | DIGI(DIGI&& a) 99 | { 100 | value = a.value; 101 | a.value = nullptr; 102 | } 103 | bool operator<(const DIGI& a) const 104 | { 105 | return *value < *a.value; 106 | } 107 | bool operator==(const DIGI& a) const 108 | { 109 | return *value == *a.value; 110 | } 111 | }; 112 | 113 | static inline bool 114 | DIGI_is_odd(DIGI& d) 115 | { 116 | return (int) *d.value % 2; 117 | } 118 | 119 | namespace std 120 | { 121 | template<> 122 | struct hash 123 | { 124 | std::size_t operator()(const DIGI& d) const 125 | { 126 | return std::hash{}(*d.value); 127 | } 128 | }; 129 | } 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /tests/func/test_c11.c: -------------------------------------------------------------------------------- 1 | #include "../test.h" 2 | 3 | #include // MULTIPLE INCLUDES OKAY. 4 | #include 5 | #include 6 | #include 7 | 8 | #define P 9 | #define T int 10 | #include 11 | 12 | #define P 13 | #define T float 14 | #include 15 | 16 | size_t 17 | int_hash(int* x) 18 | { return abs(*x); } 19 | 20 | int 21 | int_equal(int* a, int* b) 22 | { return *a == *b; } 23 | 24 | size_t 25 | float_hash(float* x) 26 | { return abs((int) *x); } 27 | 28 | int 29 | float_equal(float* a, float* b) 30 | { return *a == *b; } 31 | 32 | #define P 33 | #define T int 34 | #include 35 | 36 | #define P 37 | #define T int 38 | #include 39 | 40 | #define P 41 | #define T int 42 | #include 43 | 44 | #define P 45 | #define T int 46 | #include 47 | 48 | #define P 49 | #define T int 50 | #include 51 | 52 | #define P 53 | #define T int 54 | #include 55 | 56 | #define P 57 | #define T char 58 | #include 59 | 60 | #define P 61 | #define T int 62 | #include 63 | 64 | #define P 65 | #define T unsigned 66 | #include 67 | 68 | #define P 69 | #define T float 70 | #include 71 | 72 | #define P 73 | #define T double 74 | #include 75 | 76 | typedef struct 77 | { 78 | int x; 79 | int y; 80 | } 81 | point; 82 | 83 | #define P 84 | #define T point 85 | #include 86 | 87 | #define T str 88 | #include 89 | 90 | typedef struct 91 | { 92 | vec_point path; 93 | str name; 94 | } 95 | person; 96 | 97 | static person 98 | person_init(size_t path_capacity, const char* first, const char* last) 99 | { 100 | person self; 101 | self.path = vec_point_init(); 102 | self.name = str_init(first); 103 | str_append(&self.name, " "); 104 | str_append(&self.name, last); 105 | vec_point_reserve(&self.path, path_capacity); 106 | return self; 107 | } 108 | 109 | static void 110 | person_free(person* self) 111 | { 112 | vec_point_free(&self->path); 113 | str_free(&self->name); 114 | } 115 | 116 | static person 117 | person_copy(person* self) 118 | { 119 | person copy = { 120 | vec_point_copy(&self->path), 121 | str_copy(&self->name), 122 | }; 123 | return copy; 124 | } 125 | 126 | #define T person 127 | #include 128 | 129 | static int 130 | int_match(int* a, int* b) 131 | { 132 | return *a == *b; 133 | } 134 | 135 | static int 136 | int_compare(int* a, int* b) 137 | { 138 | return *a < *b; 139 | } 140 | 141 | int 142 | main(void) 143 | { 144 | { 145 | vec_int a = vec_int_init(); 146 | vec_int_push_back(&a, 1); 147 | vec_int_push_back(&a, 2); 148 | vec_int_push_back(&a, 3); 149 | vec_int_push_back(&a, 4); 150 | vec_int_free(&a); 151 | }{ 152 | const size_t size = 16; 153 | deq_int a = deq_int_init(); 154 | for(size_t i = 0; i < size; i++) deq_int_push_back(&a, i); 155 | for(size_t i = 0; i < size; i++) deq_int_push_front(&a, i); 156 | deq_int_insert(&a, 1, 99); 157 | deq_int_sort(&a, int_compare); 158 | deq_int_free(&a); 159 | }{ 160 | lst_int a = lst_int_init(); 161 | lst_int_push_back(&a, 1); 162 | lst_int_push_back(&a, 2); 163 | lst_int_push_back(&a, 3); 164 | lst_int_push_back(&a, 4); 165 | lst_int_push_back(&a, 5); 166 | lst_int_push_back(&a, 6); 167 | lst_int_push_back(&a, 7); 168 | lst_int_push_back(&a, 8); 169 | lst_int_free(&a); 170 | }{ 171 | vec_str b = vec_str_init(); 172 | vec_str_push_back(&b, str_init("This")); 173 | vec_str_push_back(&b, str_init("is")); 174 | vec_str_push_back(&b, str_init("a")); 175 | vec_str_push_back(&b, str_init("test")); 176 | vec_str_resize(&b, 512, str_init("")); 177 | vec_str_free(&b); 178 | }{ 179 | vec_person c = vec_person_init(); 180 | vec_person_push_back(&c, person_init(128, "FIRST", "JONES")); 181 | vec_person_push_back(&c, person_init(256, "LAST", "ALEXA")); 182 | vec_person_push_back(&c, person_init(512, "NAME", "ANOTHER")); 183 | vec_person d = vec_person_copy(&c); 184 | vec_person_free(&c); 185 | vec_person_free(&d); 186 | }{ 187 | lst_int a = lst_int_init(); 188 | lst_int_push_back(&a, 1); 189 | lst_int_push_back(&a, 1); 190 | lst_int_push_back(&a, 1); 191 | lst_int_push_back(&a, 2); 192 | lst_int_push_back(&a, 3); 193 | lst_int_push_back(&a, 3); 194 | lst_int_push_back(&a, 4); 195 | lst_int_push_back(&a, 6); 196 | lst_int_push_back(&a, 6); 197 | lst_int_push_back(&a, 6); 198 | lst_int_push_back(&a, 6); 199 | lst_int_push_back(&a, 6); 200 | lst_int_push_back(&a, 8); 201 | lst_int_push_back(&a, 8); 202 | lst_int_unique(&a, int_match); 203 | lst_int_free(&a); 204 | }{ 205 | ust_int a = ust_int_init(int_hash, int_equal); 206 | ust_int_insert(&a, -0); 207 | ust_int_insert(&a, -1); 208 | ust_int_insert(&a, -2); 209 | ust_int_insert(&a, -3); 210 | ust_int_insert(&a, -4); 211 | ust_int_insert(&a, -5); 212 | ust_int_insert(&a, -6); 213 | ust_int_insert(&a, -7); 214 | ust_int_free(&a); 215 | }{ 216 | ust_float a = ust_float_init(float_hash, float_equal); 217 | ust_float_insert(&a, -0); 218 | ust_float_insert(&a, -1); 219 | ust_float_insert(&a, -2); 220 | ust_float_insert(&a, -3); 221 | ust_float_insert(&a, -4); 222 | ust_float_insert(&a, -5); 223 | ust_float_insert(&a, -6); 224 | ust_float_insert(&a, -7); 225 | ust_float_free(&a); 226 | } 227 | TEST_PASS(__FILE__); 228 | } 229 | -------------------------------------------------------------------------------- /tests/func/test_container_composing.cc: -------------------------------------------------------------------------------- 1 | #include "../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #define T deq_int 8 | #include 9 | 10 | #define T deq_int 11 | #include 12 | 13 | #define T deq_int 14 | #include 15 | 16 | #define T deq_int 17 | #include 18 | 19 | #define T deq_int 20 | #include 21 | 22 | #define T deq_int 23 | #include 24 | 25 | #define T deq_int 26 | #include 27 | 28 | #define P 29 | #define T int 30 | #include 31 | 32 | #define T lst_int 33 | #include 34 | 35 | #define T lst_int 36 | #include 37 | 38 | #define T lst_int 39 | #include 40 | 41 | #define T lst_int 42 | #include 43 | 44 | #define T lst_int 45 | #include 46 | 47 | #define T lst_int 48 | #include 49 | 50 | #define T lst_int 51 | #include 52 | 53 | #define P 54 | #define T int 55 | #include 56 | 57 | #define T pqu_int 58 | #include 59 | 60 | #define T pqu_int 61 | #include 62 | 63 | #define T pqu_int 64 | #include 65 | 66 | #define T pqu_int 67 | #include 68 | 69 | #define T pqu_int 70 | #include 71 | 72 | #define T pqu_int 73 | #include 74 | 75 | #define T pqu_int 76 | #include 77 | 78 | #define P 79 | #define T int 80 | #include 81 | 82 | #define T que_int 83 | #include 84 | 85 | #define T que_int 86 | #include 87 | 88 | #define T que_int 89 | #include 90 | 91 | #define T que_int 92 | #include 93 | 94 | #define T que_int 95 | #include 96 | 97 | #define T que_int 98 | #include 99 | 100 | #define T que_int 101 | #include 102 | 103 | #define P 104 | #define T int 105 | #include 106 | 107 | #define T set_int 108 | #include 109 | 110 | #define T set_int 111 | #include 112 | 113 | #define T set_int 114 | #include 115 | 116 | #define T set_int 117 | #include 118 | 119 | #define T set_int 120 | #include 121 | 122 | #define T set_int 123 | #include 124 | 125 | #define T set_int 126 | #include 127 | 128 | #define P 129 | #define T int 130 | #include 131 | 132 | #define T stk_int 133 | #include 134 | 135 | #define T stk_int 136 | #include 137 | 138 | #define T stk_int 139 | #include 140 | 141 | #define T stk_int 142 | #include 143 | 144 | #define T stk_int 145 | #include 146 | 147 | #define T stk_int 148 | #include 149 | 150 | #define T stk_int 151 | #include 152 | 153 | #define P 154 | #define T int 155 | #include 156 | 157 | #define T vec_int 158 | #include 159 | 160 | #define T vec_int 161 | #include 162 | 163 | #define T vec_int 164 | #include 165 | 166 | #define T vec_int 167 | #include 168 | 169 | #define T vec_int 170 | #include 171 | 172 | #define T vec_int 173 | #include 174 | 175 | #define T vec_int 176 | #include 177 | 178 | #define P 179 | #define T int 180 | #include 181 | 182 | #define T ust_int 183 | #include 184 | 185 | #define T ust_int 186 | #include 187 | 188 | #define T ust_int 189 | #include 190 | 191 | #define T ust_int 192 | #include 193 | 194 | #define T ust_int 195 | #include 196 | 197 | #define T ust_int 198 | #include 199 | 200 | #define T ust_int 201 | #include 202 | 203 | int 204 | main(void) 205 | { 206 | TEST_PASS(__FILE__); 207 | } 208 | -------------------------------------------------------------------------------- /tests/func/test_lst.cc: -------------------------------------------------------------------------------- 1 | #include "../test.h" 2 | #include "digi.hh" 3 | 4 | #define T digi 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #define CHECK(_x, _y) { \ 11 | assert(_x.size == _y.size()); \ 12 | assert(lst_digi_empty(&_x) == _y.empty()); \ 13 | if(_x.size > 0) { \ 14 | assert(*_y.front().value == *lst_digi_front(&_x)->value); \ 15 | assert(*_y.back().value == *lst_digi_back(&_x)->value); \ 16 | } \ 17 | std::list::iterator _iter = _y.begin(); \ 18 | foreach(lst_digi, &_x, _it) { \ 19 | assert(*_it.ref->value == *_iter->value); \ 20 | _iter++; \ 21 | } \ 22 | lst_digi_it _it = lst_digi_it_each(&_x); \ 23 | for(auto& _d : _y) { \ 24 | assert(*_it.ref->value == *_d.value); \ 25 | _it.step(&_it); \ 26 | } \ 27 | } 28 | 29 | static void 30 | setup_lists(lst_digi* a, std::list& b, size_t size, int* max_value) 31 | { 32 | *a = lst_digi_init(); 33 | for(size_t pushes = 0; pushes < size; pushes++) 34 | { 35 | int value = TEST_RAND(INT_MAX - 1); // SEE COMMENT IN CASE MERGE. 36 | if(max_value && value > *max_value) 37 | *max_value = value; 38 | lst_digi_push_back(a, digi_init(value)); 39 | b.push_back(DIGI(value)); 40 | } 41 | } 42 | 43 | int 44 | main(void) 45 | { 46 | #ifdef SRAND 47 | srand(time(NULL)); 48 | #endif 49 | const size_t loops = TEST_RAND(TEST_MAX_LOOPS); 50 | for(size_t loop = 0; loop < loops; loop++) 51 | { 52 | lst_digi a; 53 | std::list b; 54 | int max_value = 0; 55 | setup_lists(&a, b, TEST_RAND(TEST_MAX_SIZE), &max_value); 56 | enum 57 | { 58 | TEST_PUSH_BACK, 59 | TEST_PUSH_FRONT, 60 | TEST_POP_BACK, 61 | TEST_POP_FRONT, 62 | TEST_ERASE, 63 | TEST_INSERT, 64 | TEST_CLEAR, 65 | TEST_RESIZE, 66 | TEST_ASSIGN, 67 | TEST_SWAP, 68 | TEST_COPY, 69 | TEST_REVERSE, 70 | TEST_REMOVE_IF, 71 | TEST_SPLICE, 72 | TEST_MERGE, 73 | TEST_EQUAL, 74 | TEST_SORT, 75 | TEST_UNIQUE, 76 | TEST_FIND, 77 | TEST_TOTAL 78 | }; 79 | int which = TEST_RAND(TEST_TOTAL); 80 | switch(which) 81 | { 82 | case TEST_PUSH_FRONT: 83 | { 84 | int value = TEST_RAND(INT_MAX); 85 | lst_digi_push_front(&a, digi_init(value)); 86 | b.push_front(DIGI(value)); 87 | CHECK(a, b); 88 | break; 89 | } 90 | case TEST_PUSH_BACK: 91 | { 92 | int value = TEST_RAND(INT_MAX); 93 | lst_digi_push_back(&a, digi_init(value)); 94 | b.push_back(DIGI(value)); 95 | CHECK(a, b); 96 | break; 97 | } 98 | case TEST_POP_FRONT: 99 | { 100 | if(a.size > 0) 101 | { 102 | lst_digi_pop_front(&a); 103 | b.pop_front(); 104 | } 105 | CHECK(a, b); 106 | break; 107 | } 108 | case TEST_POP_BACK: 109 | { 110 | if(a.size > 0) 111 | { 112 | lst_digi_pop_back(&a); 113 | b.pop_back(); 114 | } 115 | CHECK(a, b); 116 | break; 117 | } 118 | case TEST_ERASE: 119 | { 120 | size_t index = TEST_RAND(a.size); 121 | size_t current = 0; 122 | std::list::iterator iter = b.begin(); 123 | foreach(lst_digi, &a, it) 124 | { 125 | if(current == index) 126 | { 127 | lst_digi_erase(&a, it.node); 128 | b.erase(iter); 129 | break; 130 | } 131 | iter++; 132 | current += 1; 133 | } 134 | CHECK(a, b); 135 | break; 136 | } 137 | case TEST_INSERT: 138 | { 139 | size_t index = TEST_RAND(a.size); 140 | int value = TEST_RAND(INT_MAX); 141 | size_t current = 0; 142 | std::list::iterator iter = b.begin(); 143 | foreach(lst_digi, &a, it) 144 | { 145 | if(current == index) 146 | { 147 | lst_digi_insert(&a, it.node, digi_init(value)); 148 | b.insert(iter, DIGI(value)); 149 | break; 150 | } 151 | iter++; 152 | current += 1; 153 | } 154 | CHECK(a, b); 155 | break; 156 | } 157 | case TEST_CLEAR: 158 | { 159 | lst_digi_clear(&a); 160 | b.clear(); 161 | CHECK(a, b); 162 | break; 163 | } 164 | case TEST_RESIZE: 165 | { 166 | size_t resize = 3 * TEST_RAND(a.size); 167 | lst_digi_resize(&a, resize, digi_init(0)); 168 | b.resize(resize); 169 | CHECK(a, b); 170 | break; 171 | } 172 | case TEST_ASSIGN: 173 | { 174 | size_t width = TEST_RAND(a.size); 175 | if(width > 2) 176 | { 177 | int value = TEST_RAND(INT_MAX); 178 | lst_digi_assign(&a, width, digi_init(value)); 179 | b.assign(width, DIGI(value)); 180 | } 181 | CHECK(a, b); 182 | break; 183 | } 184 | case TEST_SWAP: 185 | { 186 | lst_digi aa = lst_digi_copy(&a); 187 | lst_digi aaa = lst_digi_init(); 188 | std::list bb = b; 189 | std::list bbb; 190 | lst_digi_swap(&aaa, &aa); 191 | std::swap(bb, bbb); 192 | CHECK(aaa, bbb) 193 | lst_digi_free(&aaa); 194 | CHECK(a, b); 195 | break; 196 | } 197 | case TEST_COPY: 198 | { 199 | lst_digi aa = lst_digi_copy(&a); 200 | std::list bb = b; 201 | CHECK(aa, bb); 202 | lst_digi_free(&aa); 203 | CHECK(a, b); 204 | break; 205 | } 206 | case TEST_REVERSE: 207 | { 208 | lst_digi_reverse(&a); 209 | b.reverse(); 210 | CHECK(a, b); 211 | break; 212 | } 213 | case TEST_REMOVE_IF: 214 | { 215 | lst_digi_remove_if(&a, digi_is_odd); 216 | b.remove_if(DIGI_is_odd); 217 | CHECK(a, b); 218 | break; 219 | } 220 | case TEST_SPLICE: 221 | { 222 | size_t index = TEST_RAND(a.size); 223 | size_t current = 0; 224 | std::list::iterator iter = b.begin(); 225 | lst_digi_it it = lst_digi_it_each(&a); 226 | while(!it.done) 227 | { 228 | if(current == index) 229 | break; 230 | iter++; 231 | current += 1; 232 | it.step(&it); 233 | } 234 | lst_digi aa; 235 | std::list bb; 236 | setup_lists(&aa, bb, TEST_RAND(TEST_MAX_SIZE), NULL); 237 | b.splice(iter, bb); 238 | lst_digi_splice(&a, it.node, &aa); 239 | CHECK(a, b); 240 | break; 241 | } 242 | case TEST_MERGE: 243 | { 244 | lst_digi aa = lst_digi_init(); 245 | std::list bb; 246 | size_t size = TEST_RAND(TEST_MAX_SIZE); 247 | int total = 0; 248 | for(size_t pushes = 0; pushes < size; pushes++) 249 | { 250 | int value = TEST_RAND(128); 251 | total += value; 252 | if(pushes == (size - 1)) 253 | total = max_value + 1; // MAX + 1 ENSURES MERGE CAN APPEND TO TAIL. 254 | lst_digi_push_back(&aa, digi_init(total)); 255 | bb.push_back(DIGI(total)); 256 | } 257 | b.merge(bb); 258 | lst_digi_merge(&a, &aa, digi_compare); 259 | CHECK(a, b); 260 | break; 261 | } 262 | case TEST_EQUAL: 263 | { 264 | lst_digi aa = lst_digi_copy(&a); 265 | std::list bb = b; 266 | assert(lst_digi_equal(&a, &aa, digi_match)); 267 | assert(b == bb); 268 | lst_digi_free(&aa); 269 | CHECK(a, b); 270 | break; 271 | } 272 | case TEST_SORT: 273 | { 274 | lst_digi_sort(&a, digi_compare); 275 | b.sort(); 276 | CHECK(a, b); 277 | break; 278 | } 279 | case TEST_UNIQUE: 280 | { 281 | lst_digi_unique(&a, digi_match); 282 | b.unique(); 283 | CHECK(a, b); 284 | break; 285 | } 286 | case TEST_FIND: 287 | { 288 | if(a.size > 0) 289 | { 290 | const size_t index = TEST_RAND(a.size); 291 | int test_value = 0; 292 | size_t current = 0; 293 | foreach(lst_digi, &a, it) 294 | { 295 | if(current == index) 296 | { 297 | test_value = *it.ref->value; 298 | break; 299 | } 300 | current += 1; 301 | } 302 | int value = TEST_RAND(2) ? TEST_RAND(INT_MAX) : test_value; 303 | digi key = digi_init(value); 304 | lst_digi_node* aa = lst_digi_find(&a, key, digi_match); 305 | auto bb = std::find(b.begin(), b.end(), DIGI(value)); 306 | bool found_a = aa != NULL; 307 | bool found_b = bb != b.end(); 308 | assert(found_a == found_b); 309 | if(found_a && found_b) 310 | assert(*aa->value.value == *bb->value); 311 | digi_free(&key); 312 | CHECK(a, b); 313 | } 314 | break; 315 | } 316 | } 317 | CHECK(a, b); 318 | lst_digi_free(&a); 319 | } 320 | TEST_PASS(__FILE__); 321 | } 322 | -------------------------------------------------------------------------------- /tests/func/test_pqu.cc: -------------------------------------------------------------------------------- 1 | #include "../test.h" 2 | #include "digi.hh" 3 | 4 | #define T digi 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #define CHECK(_x, _y) { \ 11 | while(_x.size > 0) { \ 12 | assert(_x.size == _y.size()); \ 13 | assert(pqu_digi_empty(&_x) == _y.empty()); \ 14 | assert(*_y.top().value == *pqu_digi_top(&_x)->value); \ 15 | _y.pop(); \ 16 | pqu_digi_pop(&_x); \ 17 | } \ 18 | } 19 | 20 | int 21 | main(void) 22 | { 23 | #ifdef SRAND 24 | srand(time(NULL)); 25 | #endif 26 | const size_t loops = TEST_RAND(TEST_MAX_LOOPS); 27 | for(size_t loop = 0; loop < loops; loop++) 28 | { 29 | size_t size = TEST_RAND(TEST_MAX_SIZE); 30 | pqu_digi a = pqu_digi_init(digi_compare); 31 | std::priority_queue b; 32 | for(size_t pushes = 0; pushes < size; pushes++) 33 | { 34 | const int value = TEST_RAND(INT_MAX); 35 | pqu_digi_push(&a, digi_init(value)); 36 | b.push(DIGI(value)); 37 | } 38 | enum 39 | { 40 | TEST_PUSH, 41 | TEST_POP, 42 | TEST_SWAP, 43 | TEST_TOTAL, 44 | }; 45 | int which = TEST_RAND(TEST_TOTAL); 46 | switch(which) 47 | { 48 | case TEST_PUSH: 49 | { 50 | const int value = TEST_RAND(INT_MAX); 51 | b.push(DIGI(value)); 52 | pqu_digi_push(&a, digi_init(value)); 53 | CHECK(a, b); 54 | break; 55 | } 56 | case TEST_POP: 57 | { 58 | if(a.size > 0) 59 | { 60 | b.pop(); 61 | pqu_digi_pop(&a); 62 | CHECK(a, b); 63 | } 64 | break; 65 | } 66 | case TEST_SWAP: 67 | { 68 | pqu_digi aa = pqu_digi_copy(&a); 69 | pqu_digi aaa = pqu_digi_init(digi_compare); 70 | std::priority_queue bb = b; 71 | std::priority_queue bbb; 72 | pqu_digi_swap(&aaa, &aa); 73 | std::swap(bb, bbb); 74 | CHECK(aaa, bbb); 75 | pqu_digi_free(&aaa); 76 | CHECK(a, b); 77 | break; 78 | } 79 | } 80 | CHECK(a, b); 81 | pqu_digi_free(&a); 82 | } 83 | TEST_PASS(__FILE__); 84 | } 85 | -------------------------------------------------------------------------------- /tests/func/test_que.cc: -------------------------------------------------------------------------------- 1 | #include "../test.h" 2 | #include "digi.hh" 3 | 4 | #define T digi 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #define CHECK(_x, _y) { \ 11 | while(_x.size > 0) { \ 12 | assert(_x.size == _y.size()); \ 13 | assert(que_digi_empty(&_x) == _y.empty()); \ 14 | assert(*_y.front().value == *que_digi_front(&_x)->value); \ 15 | assert(*_y.back().value == *que_digi_back(&_x)->value); \ 16 | _y.pop(); \ 17 | que_digi_pop(&_x); \ 18 | } \ 19 | } 20 | 21 | int 22 | main(void) 23 | { 24 | #ifdef SRAND 25 | srand(time(NULL)); 26 | #endif 27 | const size_t loops = TEST_RAND(TEST_MAX_LOOPS); 28 | for(size_t loop = 0; loop < loops; loop++) 29 | { 30 | size_t size = TEST_RAND(TEST_MAX_SIZE); 31 | que_digi a = que_digi_init(); 32 | std::queue b; 33 | for(size_t pushes = 0; pushes < size; pushes++) 34 | { 35 | const int value = TEST_RAND(INT_MAX); 36 | que_digi_push(&a, digi_init(value)); 37 | b.push(DIGI(value)); 38 | } 39 | enum 40 | { 41 | TEST_PUSH, 42 | TEST_POP, 43 | TEST_SWAP, 44 | TEST_TOTAL, 45 | }; 46 | int which = TEST_RAND(TEST_TOTAL); 47 | switch(which) 48 | { 49 | case TEST_PUSH: 50 | { 51 | const int value = TEST_RAND(INT_MAX); 52 | b.push(DIGI(value)); 53 | que_digi_push(&a, digi_init(value)); 54 | CHECK(a, b); 55 | break; 56 | } 57 | case TEST_POP: 58 | { 59 | if(a.size > 0) 60 | { 61 | b.pop(); 62 | que_digi_pop(&a); 63 | CHECK(a, b); 64 | } 65 | break; 66 | } 67 | case TEST_SWAP: 68 | { 69 | que_digi aa = que_digi_copy(&a); 70 | que_digi aaa = que_digi_init(); 71 | std::queue bb = b; 72 | std::queue bbb; 73 | que_digi_swap(&aaa, &aa); 74 | std::swap(bb, bbb); 75 | CHECK(aaa, bbb); 76 | que_digi_free(&aaa); 77 | CHECK(a, b); 78 | break; 79 | } 80 | } 81 | CHECK(a, b); 82 | que_digi_free(&a); 83 | } 84 | TEST_PASS(__FILE__); 85 | } 86 | -------------------------------------------------------------------------------- /tests/func/test_set.cc: -------------------------------------------------------------------------------- 1 | #include "../test.h" 2 | #include "digi.hh" 3 | 4 | static inline int 5 | digi_key_compare(digi* a, digi* b) 6 | { 7 | return (*a->value == *b->value) ? 0 : (*a->value < *b->value) ? -1 : 1; 8 | } 9 | 10 | #define USE_INTERNAL_VERIFY 11 | #define T digi 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #define CHECK(_x, _y) { \ 18 | assert(_x.size == _y.size()); \ 19 | std::set::iterator _iter = _y.begin(); \ 20 | foreach(set_digi, &_x, _it) { \ 21 | assert(*_it.ref->value == *_iter->value); \ 22 | _iter++; \ 23 | } \ 24 | set_digi_it _it = set_digi_it_each(&_x); \ 25 | for(auto& _d : _y) { \ 26 | assert(*_it.ref->value == *_d.value); \ 27 | _it.step(&_it); \ 28 | } \ 29 | } 30 | 31 | static void 32 | setup_sets(set_digi* a, std::set& b) 33 | { 34 | size_t iters = TEST_RAND(TEST_MAX_SIZE); 35 | *a = set_digi_init(digi_key_compare); 36 | for(size_t inserts = 0; inserts < iters; inserts++) 37 | { 38 | const int vb = TEST_RAND(TEST_MAX_SIZE); 39 | set_digi_insert(a, digi_init(vb)); 40 | b.insert(DIGI(vb)); 41 | } 42 | } 43 | 44 | int 45 | main(void) 46 | { 47 | #ifdef SRAND 48 | srand(time(NULL)); 49 | #endif 50 | const size_t loops = TEST_RAND(TEST_MAX_LOOPS); 51 | for(size_t loop = 0; loop < loops; loop++) 52 | { 53 | set_digi a; 54 | std::set b; 55 | setup_sets(&a, b); 56 | enum 57 | { 58 | TEST_SELF, 59 | TEST_INSERT, 60 | TEST_ERASE, 61 | TEST_REMOVE_IF, 62 | TEST_CLEAR, 63 | TEST_SWAP, 64 | TEST_COUNT, 65 | TEST_FIND, 66 | TEST_LOWER_BOUND, 67 | TEST_UPPER_BOUND, 68 | TEST_COPY, 69 | TEST_EQUAL, 70 | TEST_UNION, 71 | TEST_INTERSECTION, 72 | TEST_SYMMETRIC_DIFFERENCE, 73 | TEST_DIFFERENCE, 74 | TEST_TOTAL, 75 | }; 76 | int which = TEST_RAND(TEST_TOTAL); 77 | switch(which) 78 | { 79 | case TEST_SELF: 80 | { 81 | set_digi aa = set_digi_copy(&a); 82 | foreach(set_digi, &aa, it) 83 | assert(set_digi_find(&a, *it.ref)); 84 | foreach(set_digi, &a, it) 85 | set_digi_erase(&aa, *it.ref); 86 | assert(set_digi_empty(&aa)); 87 | set_digi_free(&aa); 88 | CHECK(a, b); 89 | break; 90 | } 91 | case TEST_INSERT: 92 | { 93 | const int vb = TEST_RAND(TEST_MAX_SIZE); 94 | set_digi_insert(&a, digi_init(vb)); 95 | b.insert(DIGI(vb)); 96 | CHECK(a, b); 97 | break; 98 | } 99 | case TEST_ERASE: 100 | { 101 | const size_t erases = TEST_RAND(TEST_MAX_SIZE) / 4; 102 | for(size_t i = 0; i < erases; i++) 103 | if(a.size > 0) 104 | { 105 | const int key = TEST_RAND(TEST_MAX_SIZE); 106 | digi kd = digi_init(key); 107 | set_digi_erase(&a, kd); 108 | b.erase(DIGI(key)); 109 | CHECK(a, b); 110 | digi_free(&kd); 111 | } 112 | CHECK(a, b); 113 | break; 114 | } 115 | case TEST_REMOVE_IF: 116 | { 117 | size_t b_erases = 0; 118 | { // C++20 STD::ERASE_IF 119 | auto iter = b.begin(); 120 | auto end = b.end(); 121 | while(iter != end) 122 | { 123 | if((int) *iter->value % 2) 124 | { 125 | iter = b.erase(iter); 126 | b_erases += 1; 127 | } 128 | else 129 | iter++; 130 | } 131 | } 132 | size_t a_erases = set_digi_remove_if(&a, digi_is_odd); 133 | assert(a_erases == b_erases); 134 | CHECK(a, b); 135 | break; 136 | } 137 | case TEST_CLEAR: 138 | { 139 | b.clear(); 140 | set_digi_clear(&a); 141 | CHECK(a, b); 142 | break; 143 | } 144 | case TEST_SWAP: 145 | { 146 | set_digi aa = set_digi_copy(&a); 147 | set_digi aaa = set_digi_init(digi_key_compare); 148 | std::set bb = b; 149 | std::set bbb; 150 | set_digi_swap(&aaa, &aa); 151 | std::swap(bb, bbb); 152 | CHECK(aaa, bbb); 153 | set_digi_free(&aaa); 154 | CHECK(a, b); 155 | break; 156 | } 157 | case TEST_COUNT: 158 | { 159 | int key = TEST_RAND(TEST_MAX_SIZE); 160 | digi kd = digi_init(key); 161 | int aa = set_digi_count(&a, kd); 162 | int bb = b.count(DIGI(key)); 163 | assert(aa == bb); 164 | CHECK(a, b); 165 | digi_free(&kd); 166 | break; 167 | } 168 | case TEST_FIND: 169 | { 170 | int key = TEST_RAND(TEST_MAX_SIZE); 171 | digi kd = digi_init(key); 172 | set_digi_node* aa = set_digi_find(&a, kd); 173 | auto bb = b.find(DIGI(key)); 174 | if(bb == b.end()) 175 | assert(set_digi_end(&a) == aa); 176 | else 177 | assert(*bb->value == *aa->key.value); 178 | CHECK(a, b); 179 | digi_free(&kd); 180 | break; 181 | } 182 | case TEST_LOWER_BOUND: 183 | { 184 | int key = TEST_RAND(TEST_MAX_SIZE); 185 | digi kd = digi_init(key); 186 | set_digi_node* aa = set_digi_lower_bound(&a, kd); 187 | auto bb = b.lower_bound(DIGI(key)); 188 | if(bb == b.end()) 189 | assert(set_digi_end(&a) == aa); 190 | else 191 | assert(*bb->value == *aa->key.value); 192 | CHECK(a, b); 193 | digi_free(&kd); 194 | break; 195 | } 196 | case TEST_UPPER_BOUND: 197 | { 198 | int key = TEST_RAND(TEST_MAX_SIZE); 199 | digi kd = digi_init(key); 200 | set_digi_node* aa = set_digi_upper_bound(&a, kd); 201 | auto bb = b.upper_bound(DIGI(key)); 202 | if(bb == b.end()) 203 | assert(set_digi_end(&a) == aa); 204 | else 205 | assert(*bb->value == *aa->key.value); 206 | CHECK(a, b); 207 | digi_free(&kd); 208 | break; 209 | } 210 | case TEST_COPY: 211 | { 212 | set_digi aa = set_digi_copy(&a); 213 | std::set bb = b; 214 | CHECK(aa, bb); 215 | set_digi_free(&aa); 216 | CHECK(a, b); 217 | break; 218 | } 219 | case TEST_EQUAL: 220 | { 221 | set_digi aa = set_digi_copy(&a); 222 | std::set bb = b; 223 | assert(set_digi_equal(&a, &aa, digi_match)); 224 | assert(b == bb); 225 | set_digi_free(&aa); 226 | CHECK(a, b); 227 | break; 228 | } 229 | case TEST_UNION: 230 | { 231 | set_digi aa; 232 | std::set bb; 233 | setup_sets(&aa, bb); 234 | set_digi aaa = set_digi_union(&a, &aa); 235 | std::set bbb; 236 | std::set_union(b.begin(), b.end(), bb.begin(), bb.end(), std::inserter(bbb, bbb.begin())); 237 | CHECK(a, b); 238 | CHECK(aa, bb); 239 | CHECK(aaa, bbb); 240 | set_digi_free(&aa); 241 | set_digi_free(&aaa); 242 | break; 243 | } 244 | case TEST_INTERSECTION: 245 | { 246 | set_digi aa; 247 | std::set bb; 248 | setup_sets(&aa, bb); 249 | set_digi aaa = set_digi_intersection(&a, &aa); 250 | std::set bbb; 251 | std::set_intersection(b.begin(), b.end(), bb.begin(), bb.end(), std::inserter(bbb, bbb.begin())); 252 | CHECK(a, b); 253 | CHECK(aa, bb); 254 | CHECK(aaa, bbb); 255 | set_digi_free(&aa); 256 | set_digi_free(&aaa); 257 | break; 258 | } 259 | case TEST_SYMMETRIC_DIFFERENCE: 260 | { 261 | set_digi aa; 262 | std::set bb; 263 | setup_sets(&aa, bb); 264 | set_digi aaa = set_digi_symmetric_difference(&a, &aa); 265 | std::set bbb; 266 | std::set_symmetric_difference(b.begin(), b.end(), bb.begin(), bb.end(), std::inserter(bbb, bbb.begin())); 267 | CHECK(a, b); 268 | CHECK(aa, bb); 269 | CHECK(aaa, bbb); 270 | set_digi_free(&aa); 271 | set_digi_free(&aaa); 272 | break; 273 | } 274 | case TEST_DIFFERENCE: 275 | { 276 | set_digi aa; 277 | std::set bb; 278 | setup_sets(&aa, bb); 279 | set_digi aaa = set_digi_difference(&a, &aa); 280 | std::set bbb; 281 | std::set_difference(b.begin(), b.end(), bb.begin(), bb.end(), std::inserter(bbb, bbb.begin())); 282 | CHECK(a, b); 283 | CHECK(aa, bb); 284 | CHECK(aaa, bbb); 285 | set_digi_free(&aa); 286 | set_digi_free(&aaa); 287 | break; 288 | } 289 | } 290 | CHECK(a, b); 291 | set_digi_free(&a); 292 | } 293 | TEST_PASS(__FILE__); 294 | } 295 | -------------------------------------------------------------------------------- /tests/func/test_std_headers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "../test.h" 32 | 33 | #define P 34 | #define T int 35 | #include 36 | 37 | #define P 38 | #define T int 39 | #include 40 | 41 | #define P 42 | #define T int 43 | #include 44 | 45 | #define P 46 | #define T int 47 | #include 48 | 49 | #define P 50 | #define T int 51 | #include 52 | 53 | #define P 54 | #define T int 55 | #include 56 | 57 | #define P 58 | #define T int 59 | #include 60 | 61 | #define P 62 | #define T int 63 | #include 64 | 65 | #include 66 | 67 | int 68 | main(void) 69 | { 70 | TEST_PASS(__FILE__); 71 | } 72 | -------------------------------------------------------------------------------- /tests/func/test_stk.cc: -------------------------------------------------------------------------------- 1 | #include "../test.h" 2 | #include "digi.hh" 3 | 4 | #define T digi 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #define CHECK(_x, _y) { \ 11 | while(_x.size > 0) { \ 12 | assert(_x.size == _y.size()); \ 13 | assert(stk_digi_empty(&_x) == _y.empty()); \ 14 | assert(*_y.top().value == *stk_digi_top(&_x)->value); \ 15 | _y.pop(); \ 16 | stk_digi_pop(&_x); \ 17 | } \ 18 | } 19 | 20 | int 21 | main(void) 22 | { 23 | #ifdef SRAND 24 | srand(time(NULL)); 25 | #endif 26 | const size_t loops = TEST_RAND(TEST_MAX_LOOPS); 27 | for(size_t loop = 0; loop < loops; loop++) 28 | { 29 | size_t size = TEST_RAND(TEST_MAX_SIZE); 30 | stk_digi a = stk_digi_init(); 31 | std::stack b; 32 | for(size_t pushes = 0; pushes < size; pushes++) 33 | { 34 | const int value = TEST_RAND(INT_MAX); 35 | stk_digi_push(&a, digi_init(value)); 36 | b.push(DIGI(value)); 37 | } 38 | enum 39 | { 40 | TEST_EMPTY, 41 | TEST_SIZE, 42 | TEST_TOP, 43 | TEST_PUSH, 44 | TEST_POP, 45 | TEST_SWAP, 46 | TEST_TOTAL, 47 | }; 48 | int which = TEST_RAND(TEST_TOTAL); 49 | switch(which) 50 | { 51 | case TEST_PUSH: 52 | { 53 | const int value = TEST_RAND(INT_MAX); 54 | b.push(DIGI(value)); 55 | stk_digi_push(&a, digi_init(value)); 56 | CHECK(a, b); 57 | break; 58 | } 59 | case TEST_POP: 60 | { 61 | if(a.size > 0) 62 | { 63 | b.pop(); 64 | stk_digi_pop(&a); 65 | CHECK(a, b); 66 | } 67 | break; 68 | } 69 | case TEST_SWAP: 70 | { 71 | stk_digi aa = stk_digi_copy(&a); 72 | stk_digi aaa = stk_digi_init(); 73 | std::stack bb = b; 74 | std::stack bbb; 75 | stk_digi_swap(&aaa, &aa); 76 | std::swap(bb, bbb); 77 | CHECK(aaa, bbb); 78 | stk_digi_free(&aaa); 79 | CHECK(a, b); 80 | break; 81 | } 82 | } 83 | CHECK(a, b); 84 | stk_digi_free(&a); 85 | } 86 | TEST_PASS(__FILE__); 87 | } 88 | -------------------------------------------------------------------------------- /tests/func/test_ust.cc: -------------------------------------------------------------------------------- 1 | #include "../test.h" 2 | #include "digi.hh" 3 | 4 | #define T digi 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #define CHECK(_x, _y) { \ 11 | assert(_x.size == _y.size()); \ 12 | if(_x.bucket_count > 0) \ 13 | assert(_x.bucket_count == _y.bucket_count()); \ 14 | if(_x.size > 0) \ 15 | { \ 16 | size_t a_found = 0; \ 17 | size_t b_found = 0; \ 18 | foreach(ust_digi, &_x, it) \ 19 | { \ 20 | auto found = _y.find(DIGI(*it.ref->value)); \ 21 | assert(found != _y.end()); \ 22 | a_found += 1; \ 23 | } \ 24 | for(auto x : _y) \ 25 | { \ 26 | digi d = digi_init(*x.value); \ 27 | ust_digi_node* found = ust_digi_find(&_x, d); \ 28 | assert(found != NULL); \ 29 | digi_free(&d); \ 30 | b_found += 1; \ 31 | } \ 32 | assert(a_found == b_found); \ 33 | for(size_t i = 0; i < _x.bucket_count; i++) \ 34 | assert(ust_digi_bucket_size(&_x, i) == _y.bucket_size(i)); \ 35 | } \ 36 | } 37 | 38 | static float 39 | frand(void) 40 | { 41 | return 1e6 * rand() / (float) RAND_MAX; 42 | } 43 | 44 | static void 45 | setup_usts(ust_digi* a, std::unordered_set& b) 46 | { 47 | size_t iters = TEST_RAND(TEST_MAX_SIZE); 48 | *a = ust_digi_init(digi_hash, digi_equal); 49 | for(size_t inserts = 0; inserts < iters; inserts++) 50 | { 51 | float f = frand(); 52 | ust_digi_insert(a, digi_init(f)); 53 | b.insert(DIGI(f)); 54 | } 55 | } 56 | 57 | static void 58 | test_small_size(void) 59 | { 60 | ust_digi a = ust_digi_init(digi_hash, digi_equal); 61 | ust_digi_insert(&a, digi_init(1.0f)); 62 | ust_digi_insert(&a, digi_init(2.0f)); 63 | ust_digi_free(&a); 64 | } 65 | 66 | int 67 | main(void) 68 | { 69 | #ifdef SRAND 70 | srand(time(NULL)); 71 | #endif 72 | test_small_size(); 73 | const size_t loops = TEST_RAND(TEST_MAX_LOOPS); 74 | for(size_t loop = 0; loop < loops; loop++) 75 | { 76 | ust_digi a; 77 | std::unordered_set b; 78 | setup_usts(&a, b); 79 | CHECK(a, b); 80 | enum 81 | { 82 | TEST_SELF, 83 | TEST_FIND, 84 | TEST_ERASE, 85 | TEST_REMOVE_IF, 86 | TEST_INSERT, 87 | TEST_RESERVE, 88 | TEST_REHASH, 89 | TEST_CLEAR, 90 | TEST_SWAP, 91 | TEST_COUNT, 92 | TEST_COPY, 93 | TEST_EQUAL, 94 | TEST_TOTAL, 95 | }; 96 | int which = TEST_RAND(TEST_TOTAL); 97 | switch(which) 98 | { 99 | case TEST_SELF: 100 | { 101 | ust_digi aa = ust_digi_copy(&a); 102 | foreach(ust_digi, &aa, it) 103 | assert(ust_digi_find(&a, *it.ref)); 104 | foreach(ust_digi, &a, it) 105 | ust_digi_erase(&aa, *it.ref); 106 | assert(ust_digi_empty(&aa)); 107 | ust_digi_free(&aa); 108 | CHECK(a, b); 109 | break; 110 | } 111 | case TEST_FIND: 112 | { 113 | int key = TEST_RAND(TEST_MAX_SIZE); 114 | digi kd = digi_init(key); 115 | ust_digi_node* aa = ust_digi_find(&a, kd); 116 | auto bb = b.find(DIGI(key)); 117 | if(bb == b.end()) 118 | assert(ust_digi_end(&a) == aa); 119 | else 120 | assert(*bb->value == *aa->key.value); 121 | CHECK(a, b); 122 | digi_free(&kd); 123 | break; 124 | } 125 | case TEST_ERASE: 126 | { 127 | const int temp = 42; 128 | ust_digi_insert(&a, digi_init(temp)); 129 | b.insert(DIGI(temp)); 130 | digi z = digi_init(temp); 131 | ust_digi_erase(&a, z); 132 | b.erase(DIGI(temp)); 133 | digi_free(&z); 134 | CHECK(a, b); 135 | break; 136 | } 137 | case TEST_REMOVE_IF: 138 | { 139 | size_t b_erases = 0; 140 | { // C++20 STD::ERASE_IF 141 | auto iter = b.begin(); 142 | auto end = b.end(); 143 | while(iter != end) 144 | { 145 | if((int) *iter->value % 2) 146 | { 147 | iter = b.erase(iter); 148 | b_erases += 1; 149 | } 150 | else 151 | iter++; 152 | } 153 | } 154 | size_t a_erases = ust_digi_remove_if(&a, digi_is_odd); 155 | assert(a_erases == b_erases); 156 | CHECK(a, b); 157 | break; 158 | } 159 | case TEST_INSERT: 160 | { 161 | const float vb = frand(); 162 | ust_digi_insert(&a, digi_init(vb)); 163 | b.insert(DIGI(vb)); 164 | CHECK(a, b); 165 | break; 166 | } 167 | case TEST_RESERVE: 168 | { 169 | const size_t capacity = TEST_RAND(a.bucket_count) + 1; 170 | b.reserve(capacity); 171 | ust_digi_reserve(&a, capacity); 172 | CHECK(a, b); 173 | break; 174 | } 175 | case TEST_REHASH: 176 | { 177 | const size_t capacity = 3 * TEST_RAND(a.bucket_count) + 1; 178 | b.rehash(capacity); 179 | ust_digi_rehash(&a, capacity); 180 | CHECK(a, b); 181 | break; 182 | } 183 | case TEST_CLEAR: 184 | { 185 | b.clear(); 186 | ust_digi_clear(&a); 187 | CHECK(a, b); 188 | break; 189 | } 190 | case TEST_SWAP: 191 | { 192 | ust_digi aa = ust_digi_copy(&a); 193 | ust_digi aaa = ust_digi_init(digi_hash, digi_equal); 194 | std::unordered_set bb = b; 195 | std::unordered_set bbb; 196 | ust_digi_swap(&aaa, &aa); 197 | std::swap(bb, bbb); 198 | CHECK(aaa, bbb); 199 | ust_digi_free(&aaa); 200 | CHECK(a, b); 201 | break; 202 | } 203 | case TEST_COUNT: 204 | { 205 | size_t which_index = TEST_RAND(a.size); 206 | size_t index = 0; 207 | float value = 0.3f; 208 | if(TEST_RAND(2)) 209 | foreach(ust_digi, &a, it) 210 | { 211 | if(index == which_index) 212 | { 213 | value = *it.ref->value; 214 | break; 215 | } 216 | index += 1; 217 | } 218 | digi kd = digi_init(value); 219 | int aa = ust_digi_count(&a, kd); 220 | int bb = b.count(DIGI(value)); 221 | assert(aa == bb); 222 | CHECK(a, b); 223 | digi_free(&kd); 224 | break; 225 | } 226 | case TEST_COPY: 227 | { 228 | ust_digi aa = ust_digi_copy(&a); 229 | std::unordered_set bb = b; 230 | CHECK(aa, bb); 231 | ust_digi_free(&aa); 232 | CHECK(a, b); 233 | break; 234 | } 235 | case TEST_EQUAL: 236 | { 237 | ust_digi aa = ust_digi_copy(&a); 238 | std::unordered_set bb = b; 239 | assert(ust_digi_equal(&a, &aa)); 240 | assert(b == bb); 241 | ust_digi_free(&aa); 242 | CHECK(a, b); 243 | break; 244 | } 245 | } 246 | CHECK(a, b); 247 | ust_digi_free(&a); 248 | } 249 | TEST_PASS(__FILE__); 250 | } 251 | -------------------------------------------------------------------------------- /tests/func/test_vec.cc: -------------------------------------------------------------------------------- 1 | #include "../test.h" 2 | #include "digi.hh" 3 | 4 | #define T digi 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #define CHECK(_x, _y) { \ 11 | assert(_x.capacity == _y.capacity()); \ 12 | assert(_x.size == _y.size()); \ 13 | assert(vec_digi_empty(&_x) == _y.empty()); \ 14 | if(_x.size > 0) { \ 15 | assert(*_y.front().value == *vec_digi_front(&_x)->value); \ 16 | assert(*_y.back().value == *vec_digi_back(&_x)->value); \ 17 | } \ 18 | std::vector::iterator _iter = _y.begin(); \ 19 | foreach(vec_digi, &_x, _it) { \ 20 | assert(*_it.ref->value == *_iter->value); \ 21 | _iter++; \ 22 | } \ 23 | vec_digi_it _it = vec_digi_it_each(&_x); \ 24 | for(auto& _d : _y) { \ 25 | assert(*_it.ref->value == *_d.value); \ 26 | _it.step(&_it); \ 27 | } \ 28 | for(size_t i = 0; i < _y.size(); i++) \ 29 | assert(*_y.at(i).value == *vec_digi_at(&_x, i)->value); \ 30 | } 31 | 32 | int 33 | main(void) 34 | { 35 | #ifdef SRAND 36 | srand(time(NULL)); 37 | #endif 38 | const size_t loops = TEST_RAND(TEST_MAX_LOOPS); 39 | for(size_t loop = 0; loop < loops; loop++) 40 | { 41 | size_t size = TEST_RAND(TEST_MAX_SIZE); 42 | enum 43 | { 44 | MODE_DIRECT, 45 | MODE_GROWTH, 46 | MODE_TOTAL 47 | }; 48 | for(size_t mode = MODE_DIRECT; mode < MODE_TOTAL; mode++) 49 | { 50 | vec_digi a = vec_digi_init(); 51 | std::vector b; 52 | if(mode == MODE_DIRECT) 53 | { 54 | vec_digi_resize(&a, size, digi_init(0)); 55 | b.resize(size); 56 | } 57 | if(mode == MODE_GROWTH) 58 | { 59 | for(size_t pushes = 0; pushes < size; pushes++) 60 | { 61 | const int value = TEST_RAND(INT_MAX); 62 | vec_digi_push_back(&a, digi_init(value)); 63 | b.push_back(DIGI(value)); 64 | } 65 | } 66 | enum 67 | { 68 | TEST_PUSH_BACK, 69 | TEST_POP_BACK, 70 | TEST_CLEAR, 71 | TEST_ERASE, 72 | TEST_RESIZE, 73 | TEST_RESERVE, 74 | TEST_SHRINK_TO_FIT, 75 | TEST_SORT, 76 | TEST_COPY, 77 | TEST_SWAP, 78 | TEST_INSERT, 79 | TEST_ASSIGN, 80 | TEST_REMOVE_IF, 81 | TEST_EQUAL, 82 | TEST_FIND, 83 | TEST_TOTAL, 84 | }; 85 | int which = TEST_RAND(TEST_TOTAL); 86 | switch(which) 87 | { 88 | case TEST_PUSH_BACK: 89 | { 90 | const int value = TEST_RAND(INT_MAX); 91 | b.push_back(DIGI(value)); 92 | vec_digi_push_back(&a, digi_init(value)); 93 | CHECK(a, b); 94 | break; 95 | } 96 | case TEST_POP_BACK: 97 | { 98 | if(a.size > 0) 99 | { 100 | b.pop_back(); 101 | vec_digi_pop_back(&a); 102 | } 103 | CHECK(a, b); 104 | break; 105 | } 106 | case TEST_CLEAR: 107 | { 108 | b.clear(); 109 | vec_digi_clear(&a); 110 | CHECK(a, b); 111 | break; 112 | } 113 | case TEST_ERASE: 114 | { 115 | if(a.size > 0) 116 | { 117 | const size_t index = TEST_RAND(a.size); 118 | b.erase(b.begin() + index); 119 | vec_digi_erase(&a, index); 120 | } 121 | CHECK(a, b); 122 | break; 123 | } 124 | case TEST_INSERT: 125 | { 126 | size_t amount = TEST_RAND(512); 127 | for(size_t count = 0; count < amount; count++) 128 | { 129 | const int value = TEST_RAND(INT_MAX); 130 | const size_t index = TEST_RAND(a.size); 131 | b.insert(b.begin() + index, DIGI(value)); 132 | vec_digi_insert(&a, index, digi_init(value)); 133 | } 134 | CHECK(a, b); 135 | break; 136 | } 137 | case TEST_RESIZE: 138 | { 139 | const size_t resize = 3 * TEST_RAND(a.size) + 1; 140 | b.resize(resize); 141 | vec_digi_resize(&a, resize, digi_init(0)); 142 | CHECK(a, b); 143 | break; 144 | } 145 | case TEST_RESERVE: 146 | { 147 | const size_t capacity = 3 * TEST_RAND(a.capacity) + 1; 148 | b.reserve(capacity); 149 | vec_digi_reserve(&a, capacity); 150 | CHECK(a, b); 151 | break; 152 | } 153 | case TEST_SHRINK_TO_FIT: 154 | { 155 | b.shrink_to_fit(); 156 | vec_digi_shrink_to_fit(&a); 157 | CHECK(a, b); 158 | break; 159 | } 160 | case TEST_SORT: 161 | { 162 | vec_digi_sort(&a, digi_compare); 163 | std::sort(b.begin(), b.end()); 164 | CHECK(a, b); 165 | break; 166 | } 167 | case TEST_COPY: 168 | { 169 | vec_digi aa = vec_digi_copy(&a); 170 | std::vector bb = b; 171 | CHECK(aa, bb); 172 | vec_digi_free(&aa); 173 | CHECK(a, b); 174 | break; 175 | } 176 | case TEST_ASSIGN: 177 | { 178 | const int value = TEST_RAND(INT_MAX); 179 | size_t assign_size = TEST_RAND(a.size) + 1; 180 | vec_digi_assign(&a, assign_size, digi_init(value)); 181 | b.assign(assign_size, DIGI(value)); 182 | CHECK(a, b); 183 | break; 184 | } 185 | case TEST_SWAP: 186 | { 187 | vec_digi aa = vec_digi_copy(&a); 188 | vec_digi aaa = vec_digi_init(); 189 | std::vector bb = b; 190 | std::vector bbb; 191 | vec_digi_swap(&aaa, &aa); 192 | std::swap(bb, bbb); 193 | CHECK(aaa, bbb); 194 | vec_digi_free(&aaa); 195 | CHECK(a, b); 196 | break; 197 | } 198 | case TEST_REMOVE_IF: 199 | { 200 | vec_digi_remove_if(&a, digi_is_odd); 201 | b.erase(std::remove_if(b.begin(), b.end(), DIGI_is_odd), b.end()); 202 | CHECK(a, b); 203 | break; 204 | } 205 | case TEST_EQUAL: 206 | { 207 | vec_digi aa = vec_digi_copy(&a); 208 | std::vector bb = b; 209 | assert(vec_digi_equal(&a, &aa, digi_match)); 210 | assert(b == bb); 211 | vec_digi_free(&aa); 212 | CHECK(a, b); 213 | break; 214 | } 215 | case TEST_FIND: 216 | { 217 | if(a.size > 0) 218 | { 219 | const size_t index = TEST_RAND(a.size); 220 | int value = TEST_RAND(2) ? TEST_RAND(INT_MAX) : *vec_digi_at(&a, index)->value; 221 | digi key = digi_init(value); 222 | digi* aa = vec_digi_find(&a, key, digi_match); 223 | auto bb = std::find(b.begin(), b.end(), DIGI(value)); 224 | bool found_a = aa != NULL; 225 | bool found_b = bb != b.end(); 226 | assert(found_a == found_b); 227 | if(found_a && found_b) 228 | assert(*aa->value == *bb->value); 229 | digi_free(&key); 230 | CHECK(a, b); 231 | } 232 | break; 233 | } 234 | } 235 | CHECK(a, b); 236 | vec_digi_free(&a); 237 | } 238 | } 239 | TEST_PASS(__FILE__); 240 | } 241 | -------------------------------------------------------------------------------- /tests/func/test_vec_capacity.cc: -------------------------------------------------------------------------------- 1 | #include "../test.h" 2 | 3 | #include 4 | 5 | #define P 6 | #define T uint8_t 7 | #include 8 | 9 | #define P 10 | #define T uint16_t 11 | #include 12 | 13 | #define P 14 | #define T uint32_t 15 | #include 16 | 17 | #define P 18 | #define T uint64_t 19 | #include 20 | 21 | #define P 22 | #define T float 23 | #include 24 | 25 | #define P 26 | #define T double 27 | #include 28 | 29 | #include 30 | 31 | #define ASSERT_EQUAL_SIZE(_x, _y) (assert(_x.size() == _y.size)) 32 | 33 | #define ASSERT_EQUAL_CAP(_x, _y) (assert(_x.capacity() == _y.capacity)) 34 | 35 | int 36 | main(void) 37 | { 38 | #ifdef SRAND 39 | srand(time(NULL)); 40 | #endif 41 | const size_t loops = TEST_RAND(TEST_MAX_LOOPS); 42 | for(size_t loop = 0; loop < loops; loop++) 43 | { 44 | uint8_t value = TEST_RAND(UINT8_MAX); // SMALLEST SIZE. 45 | size_t size = TEST_RAND(TEST_MAX_SIZE); 46 | enum 47 | { 48 | MODE_DIRECT, 49 | MODE_GROWTH, 50 | MODE_TOTAL 51 | }; 52 | for(size_t mode = MODE_DIRECT; mode < MODE_TOTAL; mode++) 53 | { 54 | std::vector a; 55 | std::vector b; 56 | std::vector c; 57 | std::vector d; 58 | std::vector e; 59 | std::vector f; 60 | vec_uint8_t aa = vec_uint8_t_init(); 61 | vec_uint16_t bb = vec_uint16_t_init(); 62 | vec_uint32_t cc = vec_uint32_t_init(); 63 | vec_uint64_t dd = vec_uint64_t_init(); 64 | vec_float ee = vec_float_init(); 65 | vec_double ff = vec_double_init(); 66 | if(mode == MODE_DIRECT) 67 | { 68 | a.resize (size); 69 | b.resize (size); 70 | c.resize (size); 71 | d.resize (size); 72 | e.resize (size); 73 | f.resize (size); 74 | vec_uint8_t_resize (&aa, size, 0); 75 | vec_uint16_t_resize (&bb, size, 0); 76 | vec_uint32_t_resize (&cc, size, 0); 77 | vec_uint64_t_resize (&dd, size, 0); 78 | vec_float_resize (&ee, size, 0.0); 79 | vec_double_resize (&ff, size, 0.0); 80 | } 81 | if(mode == MODE_GROWTH) 82 | { 83 | for(size_t pushes = 0; pushes < size; pushes++) 84 | { 85 | a.push_back (value); 86 | b.push_back (value); 87 | c.push_back (value); 88 | d.push_back (value); 89 | e.push_back (value); 90 | f.push_back (value); 91 | vec_uint8_t_push_back (&aa, value); 92 | vec_uint16_t_push_back (&bb, value); 93 | vec_uint32_t_push_back (&cc, value); 94 | vec_uint64_t_push_back (&dd, value); 95 | vec_float_push_back (&ee, value); 96 | vec_double_push_back (&ff, value); 97 | } 98 | } 99 | ASSERT_EQUAL_SIZE (a, aa); 100 | ASSERT_EQUAL_SIZE (b, bb); 101 | ASSERT_EQUAL_SIZE (c, cc); 102 | ASSERT_EQUAL_SIZE (d, dd); 103 | ASSERT_EQUAL_SIZE (e, ee); 104 | ASSERT_EQUAL_SIZE (f, ff); 105 | ASSERT_EQUAL_CAP (a, aa); 106 | ASSERT_EQUAL_CAP (b, bb); 107 | ASSERT_EQUAL_CAP (c, cc); 108 | ASSERT_EQUAL_CAP (d, dd); 109 | ASSERT_EQUAL_CAP (e, ee); 110 | ASSERT_EQUAL_CAP (f, ff); 111 | vec_uint8_t_free (&aa); 112 | vec_uint16_t_free (&bb); 113 | vec_uint32_t_free (&cc); 114 | vec_uint64_t_free (&dd); 115 | vec_float_free (&ee); 116 | vec_double_free (&ff); 117 | } 118 | } 119 | TEST_PASS(__FILE__); 120 | } 121 | -------------------------------------------------------------------------------- /tests/perf/deq/perf_deq_iterate.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | int main(void) 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | deq_int c = deq_int_init(); 16 | int elems = TEST_PERF_CHUNKS * run; 17 | for(int elem = 0; elem < elems; elem++) 18 | deq_int_push_back(&c, rand()); 19 | int t0 = TEST_TIME(); 20 | volatile int sum = 0; 21 | foreach(deq_int, &c, it) 22 | sum += *it.ref; 23 | int t1 = TEST_TIME(); 24 | printf("%10d %10d\n", elems, t1 - t0); 25 | deq_int_free(&c); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/perf/deq/perf_deq_pop_back.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | int main(void) 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | deq_int c = deq_int_init(); 16 | int elems = TEST_PERF_CHUNKS * run; 17 | for(int elem = 0; elem < elems; elem++) 18 | deq_int_push_back(&c, rand()); 19 | int t0 = TEST_TIME(); 20 | for(int elem = 0; elem < elems; elem++) 21 | deq_int_pop_back(&c); 22 | int t1 = TEST_TIME(); 23 | printf("%10d %10d\n", elems, t1 - t0); 24 | deq_int_free(&c); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/perf/deq/perf_deq_pop_front.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | int main(void) 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | deq_int c = deq_int_init(); 16 | int elems = TEST_PERF_CHUNKS * run; 17 | for(int elem = 0; elem < elems; elem++) 18 | deq_int_push_front(&c, rand()); 19 | int t0 = TEST_TIME(); 20 | for(int elem = 0; elem < elems; elem++) 21 | deq_int_pop_front(&c); 22 | int t1 = TEST_TIME(); 23 | printf("%10d %10d\n", elems, t1 - t0); 24 | deq_int_free(&c); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/perf/deq/perf_deq_push_back.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | int main(void) 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | deq_int c = deq_int_init(); 16 | int elems = TEST_PERF_CHUNKS * run; 17 | int t0 = TEST_TIME(); 18 | for(int elem = 0; elem < elems; elem++) 19 | deq_int_push_back(&c, rand()); 20 | int t1 = TEST_TIME(); 21 | printf("%10d %10d\n", elems, t1 - t0); 22 | deq_int_free(&c); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/perf/deq/perf_deq_push_front.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | int main(void) 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | deq_int c = deq_int_init(); 16 | int elems = TEST_PERF_CHUNKS * run; 17 | int t0 = TEST_TIME(); 18 | for(int elem = 0; elem < elems; elem++) 19 | deq_int_push_front(&c, rand()); 20 | int t1 = TEST_TIME(); 21 | printf("%10d %10d\n", elems, t1 - t0); 22 | deq_int_free(&c); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/perf/deq/perf_deq_sort.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | static int compare(int* a, int* b) { return *a < *b; } 10 | 11 | int main(void) 12 | { 13 | puts(__FILE__); 14 | srand(time(NULL)); 15 | for(int run = 0; run < TEST_PERF_RUNS; run++) 16 | { 17 | deq_int c = deq_int_init(); 18 | int elems = TEST_PERF_CHUNKS * run; 19 | for(int elem = 0; elem < elems; elem++) 20 | deq_int_push_back(&c, rand()); 21 | int t0 = TEST_TIME(); 22 | deq_int_sort(&c, compare); 23 | int t1 = TEST_TIME(); 24 | printf("%10d %10d\n", elems, t1 - t0); 25 | deq_int_free(&c); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/perf/deq/perf_deque_iterate.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | int main() 8 | { 9 | puts(__FILE__); 10 | srand(time(NULL)); 11 | for(int run = 0; run < TEST_PERF_RUNS; run++) 12 | { 13 | std::deque c; 14 | int elems = TEST_PERF_CHUNKS * run; 15 | for(int elem = 0; elem < elems; elem++) 16 | c.push_back(rand()); 17 | int t0 = TEST_TIME(); 18 | volatile int sum = 0; 19 | for(auto& x : c) 20 | sum += x; 21 | int t1 = TEST_TIME(); 22 | printf("%10d %10d\n", elems, t1 - t0); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/perf/deq/perf_deque_pop_back.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | int main() 8 | { 9 | puts(__FILE__); 10 | srand(time(NULL)); 11 | for(int run = 0; run < TEST_PERF_RUNS; run++) 12 | { 13 | std::deque c; 14 | int elems = TEST_PERF_CHUNKS * run; 15 | for(int elem = 0; elem < elems; elem++) 16 | c.push_back(rand()); 17 | int t0 = TEST_TIME(); 18 | for(int elem = 0; elem < elems; elem++) 19 | c.pop_back(); 20 | int t1 = TEST_TIME(); 21 | printf("%10d %10d\n", elems, t1 - t0); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/perf/deq/perf_deque_pop_front.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | int main() 8 | { 9 | puts(__FILE__); 10 | srand(time(NULL)); 11 | for(int run = 0; run < TEST_PERF_RUNS; run++) 12 | { 13 | std::deque c; 14 | int elems = TEST_PERF_CHUNKS * run; 15 | for(int elem = 0; elem < elems; elem++) 16 | c.push_front(rand()); 17 | int t0 = TEST_TIME(); 18 | for(int elem = 0; elem < elems; elem++) 19 | c.pop_front(); 20 | int t1 = TEST_TIME(); 21 | printf("%10d %10d\n", elems, t1 - t0); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/perf/deq/perf_deque_push_back.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | int main() 8 | { 9 | puts(__FILE__); 10 | srand(time(NULL)); 11 | for(int run = 0; run < TEST_PERF_RUNS; run++) 12 | { 13 | std::deque c; 14 | int elems = TEST_PERF_CHUNKS * run; 15 | int t0 = TEST_TIME(); 16 | for(int elem = 0; elem < elems; elem++) 17 | c.push_back(rand()); 18 | int t1 = TEST_TIME(); 19 | printf("%10d %10d\n", elems, t1 - t0); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/perf/deq/perf_deque_push_front.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | int main() 8 | { 9 | puts(__FILE__); 10 | srand(time(NULL)); 11 | for(int run = 0; run < TEST_PERF_RUNS; run++) 12 | { 13 | std::deque c; 14 | int elems = TEST_PERF_CHUNKS * run; 15 | int t0 = TEST_TIME(); 16 | for(int elem = 0; elem < elems; elem++) 17 | c.push_front(rand()); 18 | int t1 = TEST_TIME(); 19 | printf("%10d %10d\n", elems, t1 - t0); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/perf/deq/perf_deque_sort.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | static bool compare(int& a, int& b) { return a < b; } 9 | 10 | int main() 11 | { 12 | puts(__FILE__); 13 | srand(time(NULL)); 14 | for(int run = 0; run < TEST_PERF_RUNS; run++) 15 | { 16 | std::deque c; 17 | int elems = TEST_PERF_CHUNKS * run; 18 | for(int elem = 0; elem < elems; elem++) 19 | c.push_back(rand()); 20 | int t0 = TEST_TIME(); 21 | std::sort(c.begin(), c.end(), compare); 22 | int t1 = TEST_TIME(); 23 | printf("%10d %10d\n", elems, t1 - t0); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/perf/lst/perf_list_iterate.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | int main() 8 | { 9 | puts(__FILE__); 10 | srand(time(NULL)); 11 | for(int run = 0; run < TEST_PERF_RUNS; run++) 12 | { 13 | std::list c; 14 | int elems = TEST_PERF_CHUNKS * run; 15 | for(int elem = 0; elem < elems; elem++) 16 | c.push_back(rand()); 17 | int t0 = TEST_TIME(); 18 | volatile int sum = 0; 19 | for(auto& x : c) 20 | sum += x; 21 | int t1 = TEST_TIME(); 22 | printf("%10d %10d\n", elems, t1 - t0); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/perf/lst/perf_list_pop_back.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | puts(__FILE__); 9 | srand(time(NULL)); 10 | for(int run = 0; run < TEST_PERF_RUNS; run++) 11 | { 12 | std::list c; 13 | int elems = TEST_PERF_CHUNKS * run; 14 | for(int elem = 0; elem < elems; elem++) 15 | c.push_back(rand()); 16 | int t0 = TEST_TIME(); 17 | for(int elem = 0; elem < elems; elem++) 18 | c.pop_back(); 19 | int t1 = TEST_TIME(); 20 | printf("%10d %10d\n", elems, t1 - t0); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/perf/lst/perf_list_pop_front.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | puts(__FILE__); 9 | srand(time(NULL)); 10 | for(int run = 0; run < TEST_PERF_RUNS; run++) 11 | { 12 | std::list c; 13 | int elems = TEST_PERF_CHUNKS * run; 14 | for(int elem = 0; elem < elems; elem++) 15 | c.push_front(rand()); 16 | int t0 = TEST_TIME(); 17 | for(int elem = 0; elem < elems; elem++) 18 | c.pop_front(); 19 | int t1 = TEST_TIME(); 20 | printf("%10d %10d\n", elems, t1 - t0); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/perf/lst/perf_list_push_back.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | puts(__FILE__); 9 | srand(time(NULL)); 10 | for(int run = 0; run < TEST_PERF_RUNS; run++) 11 | { 12 | std::list c; 13 | int elems = TEST_PERF_CHUNKS * run; 14 | int t0 = TEST_TIME(); 15 | for(int elem = 0; elem < elems; elem++) 16 | c.push_back(rand()); 17 | int t1 = TEST_TIME(); 18 | printf("%10d %10d\n", elems, t1 - t0); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/perf/lst/perf_list_push_front.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | puts(__FILE__); 9 | srand(time(NULL)); 10 | for(int run = 0; run < TEST_PERF_RUNS; run++) 11 | { 12 | std::list c; 13 | int elems = TEST_PERF_CHUNKS * run; 14 | int t0 = TEST_TIME(); 15 | for(int elem = 0; elem < elems; elem++) 16 | c.push_front(rand()); 17 | int t1 = TEST_TIME(); 18 | printf("%10d %10d\n", elems, t1 - t0); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/perf/lst/perf_list_sort.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | static bool compare(int& a, int& b) { return a < b; } 7 | 8 | int main() 9 | { 10 | puts(__FILE__); 11 | srand(time(NULL)); 12 | for(int run = 0; run < TEST_PERF_RUNS; run++) 13 | { 14 | std::list c; 15 | int elems = TEST_PERF_CHUNKS * run; 16 | for(int elem = 0; elem < elems; elem++) 17 | c.push_back(rand()); 18 | int t0 = TEST_TIME(); 19 | c.sort(compare); 20 | int t1 = TEST_TIME(); 21 | printf("%10d %10d\n", elems, t1 - t0); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/perf/lst/perf_lst_iterate.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | int main(void) 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | lst_int c = lst_int_init(); 16 | int elems = TEST_PERF_CHUNKS * run; 17 | for(int elem = 0; elem < elems; elem++) 18 | lst_int_push_back(&c, rand()); 19 | int t0 = TEST_TIME(); 20 | volatile int sum = 0; 21 | foreach(lst_int, &c, it) 22 | sum += *it.ref; 23 | int t1 = TEST_TIME(); 24 | printf("%10d %10d\n", elems, t1 - t0); 25 | lst_int_free(&c); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/perf/lst/perf_lst_pop_back.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | int main(void) 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | lst_int c = lst_int_init(); 16 | int elems = TEST_PERF_CHUNKS * run; 17 | for(int elem = 0; elem < elems; elem++) 18 | lst_int_push_back(&c, rand()); 19 | int t0 = TEST_TIME(); 20 | for(int elem = 0; elem < elems; elem++) 21 | lst_int_pop_back(&c); 22 | int t1 = TEST_TIME(); 23 | printf("%10d %10d\n", elems, t1 - t0); 24 | lst_int_free(&c); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/perf/lst/perf_lst_pop_front.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | int main(void) 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | lst_int c = lst_int_init(); 16 | int elems = TEST_PERF_CHUNKS * run; 17 | for(int elem = 0; elem < elems; elem++) 18 | lst_int_push_front(&c, rand()); 19 | int t0 = TEST_TIME(); 20 | for(int elem = 0; elem < elems; elem++) 21 | lst_int_pop_front(&c); 22 | int t1 = TEST_TIME(); 23 | printf("%10d %10d\n", elems, t1 - t0); 24 | lst_int_free(&c); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/perf/lst/perf_lst_push_back.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | int main(void) 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | lst_int c = lst_int_init(); 16 | int elems = TEST_PERF_CHUNKS * run; 17 | int t0 = TEST_TIME(); 18 | for(int elem = 0; elem < elems; elem++) 19 | lst_int_push_back(&c, rand()); 20 | int t1 = TEST_TIME(); 21 | printf("%10d %10d\n", elems, t1 - t0); 22 | lst_int_free(&c); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/perf/lst/perf_lst_push_front.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | int main(void) 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | lst_int c = lst_int_init(); 16 | int elems = TEST_PERF_CHUNKS * run; 17 | int t0 = TEST_TIME(); 18 | for(int elem = 0; elem < elems; elem++) 19 | lst_int_push_front(&c, rand()); 20 | int t1 = TEST_TIME(); 21 | printf("%10d %10d\n", elems, t1 - t0); 22 | lst_int_free(&c); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/perf/lst/perf_lst_sort.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | static int compare(int* a, int* b) { return *a < *b; } 10 | 11 | int main(void) 12 | { 13 | puts(__FILE__); 14 | srand(time(NULL)); 15 | for(int run = 0; run < TEST_PERF_RUNS; run++) 16 | { 17 | lst_int c = lst_int_init(); 18 | int elems = TEST_PERF_CHUNKS * run; 19 | for(int elem = 0; elem < elems; elem++) 20 | lst_int_push_back(&c, rand()); 21 | int t0 = TEST_TIME(); 22 | lst_int_sort(&c, compare); 23 | int t1 = TEST_TIME(); 24 | printf("%10d %10d\n", elems, t1 - t0); 25 | lst_int_free(&c); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/perf/perf_compile_c11.c: -------------------------------------------------------------------------------- 1 | #define P 2 | #define T int 3 | #include 4 | 5 | #define P 6 | #define T int 7 | #include 8 | 9 | #define P 10 | #define T int 11 | #include 12 | 13 | #define P 14 | #define T int 15 | #include 16 | 17 | #define P 18 | #define T int 19 | #include 20 | 21 | #define P 22 | #define T int 23 | #include 24 | 25 | #define P 26 | #define T int 27 | #include 28 | 29 | #include 30 | 31 | #define P 32 | #define T short 33 | #include 34 | 35 | #define P 36 | #define T short 37 | #include 38 | 39 | #define P 40 | #define T short 41 | #include 42 | 43 | #define P 44 | #define T short 45 | #include 46 | 47 | #define P 48 | #define T short 49 | #include 50 | 51 | #define P 52 | #define T short 53 | #include 54 | 55 | #define P 56 | #define T short 57 | #include 58 | 59 | #include 60 | 61 | #define P 62 | #define T float 63 | #include 64 | 65 | #define P 66 | #define T float 67 | #include 68 | 69 | #define P 70 | #define T float 71 | #include 72 | 73 | #define P 74 | #define T float 75 | #include 76 | 77 | #define P 78 | #define T float 79 | #include 80 | 81 | #define P 82 | #define T float 83 | #include 84 | 85 | #define P 86 | #define T float 87 | #include 88 | 89 | #include 90 | 91 | #define P 92 | #define T double 93 | #include 94 | 95 | #define P 96 | #define T double 97 | #include 98 | 99 | #define P 100 | #define T double 101 | #include 102 | 103 | #define P 104 | #define T double 105 | #include 106 | 107 | #define P 108 | #define T double 109 | #include 110 | 111 | #define P 112 | #define T double 113 | #include 114 | 115 | #define P 116 | #define T double 117 | #include 118 | 119 | #include 120 | 121 | static int 122 | compare_key_int(int* a, int* b) 123 | { 124 | return (*a == *b) ? 0 : (*a < *b) ? -1 : 1; 125 | } 126 | 127 | static int 128 | compare_int(int* a, int* b) 129 | { 130 | return *a < *b; 131 | } 132 | 133 | static int 134 | compare_key_short(short* a, short* b) 135 | { 136 | return (*a == *b) ? 0 : (*a < *b) ? -1 : 1; 137 | } 138 | 139 | static int 140 | compare_short(short* a, short* b) 141 | { 142 | return *a < *b; 143 | } 144 | 145 | static int 146 | compare_key_float(float* a, float* b) 147 | { 148 | return (*a == *b) ? 0 : (*a < *b) ? -1 : 1; 149 | } 150 | 151 | static int 152 | compare_float(float* a, float* b) 153 | { 154 | return *a < *b; 155 | } 156 | 157 | static int 158 | compare_key_double(double* a, double* b) 159 | { 160 | return (*a == *b) ? 0 : (*a < *b) ? -1 : 1; 161 | } 162 | 163 | static int 164 | compare_double(double* a, double* b) 165 | { 166 | return *a < *b; 167 | } 168 | 169 | void 170 | A(void) 171 | { 172 | deq_int a = deq_int_init(); 173 | vec_int b = vec_int_init(); 174 | lst_int c = lst_int_init(); 175 | que_int d = que_int_init(); 176 | set_int e = set_int_init(compare_key_int); 177 | stk_int f = stk_int_init(); 178 | str g = str_init("test"); 179 | pqu_int i = pqu_int_init(compare_int); 180 | 181 | deq_int_push_back(&a, 1); 182 | deq_int_push_front(&a, 1); 183 | vec_int_push_back(&b, 1); 184 | lst_int_push_back(&c, 1); 185 | lst_int_push_front(&c, 1); 186 | que_int_push(&d, 1); 187 | set_int_insert(&e, 1); 188 | stk_int_push(&f, 1); 189 | pqu_int_push(&i, 1); 190 | 191 | deq_int_pop_back(&a); 192 | deq_int_pop_front(&a); 193 | vec_int_pop_back(&b); 194 | lst_int_pop_back(&c); 195 | lst_int_pop_front(&c); 196 | que_int_pop(&d); 197 | set_int_erase(&e, 1); 198 | stk_int_pop(&f); 199 | pqu_int_pop(&i); 200 | 201 | deq_int_free(&a); 202 | lst_int_free(&c); 203 | vec_int_free(&b); 204 | que_int_free(&d); 205 | set_int_free(&e); 206 | stk_int_free(&f); 207 | str_free(&g); 208 | pqu_int_free(&i); 209 | } 210 | 211 | void 212 | B(void) 213 | { 214 | deq_short a = deq_short_init(); 215 | vec_short b = vec_short_init(); 216 | lst_short c = lst_short_init(); 217 | que_short d = que_short_init(); 218 | set_short e = set_short_init(compare_key_short); 219 | stk_short f = stk_short_init(); 220 | str g = str_init("test"); 221 | pqu_short i = pqu_short_init(compare_short); 222 | 223 | deq_short_push_back(&a, 1); 224 | deq_short_push_front(&a, 1); 225 | vec_short_push_back(&b, 1); 226 | lst_short_push_back(&c, 1); 227 | lst_short_push_front(&c, 1); 228 | que_short_push(&d, 1); 229 | set_short_insert(&e, 1); 230 | stk_short_push(&f, 1); 231 | pqu_short_push(&i, 1); 232 | 233 | deq_short_pop_back(&a); 234 | deq_short_pop_front(&a); 235 | vec_short_pop_back(&b); 236 | lst_short_pop_back(&c); 237 | lst_short_pop_front(&c); 238 | que_short_pop(&d); 239 | set_short_erase(&e, 1); 240 | stk_short_pop(&f); 241 | pqu_short_pop(&i); 242 | 243 | deq_short_free(&a); 244 | lst_short_free(&c); 245 | vec_short_free(&b); 246 | que_short_free(&d); 247 | set_short_free(&e); 248 | stk_short_free(&f); 249 | str_free(&g); 250 | pqu_short_free(&i); 251 | } 252 | 253 | void 254 | C(void) 255 | { 256 | deq_float a = deq_float_init(); 257 | vec_float b = vec_float_init(); 258 | lst_float c = lst_float_init(); 259 | que_float d = que_float_init(); 260 | set_float e = set_float_init(compare_key_float); 261 | stk_float f = stk_float_init(); 262 | str g = str_init("test"); 263 | pqu_float i = pqu_float_init(compare_float); 264 | 265 | deq_float_push_back(&a, 1.0); 266 | deq_float_push_front(&a, 1.0); 267 | vec_float_push_back(&b, 1.0); 268 | lst_float_push_back(&c, 1.0); 269 | lst_float_push_front(&c, 1.0); 270 | que_float_push(&d, 1.0); 271 | set_float_insert(&e, 1.0); 272 | stk_float_push(&f, 1.0); 273 | pqu_float_push(&i, 1.0); 274 | 275 | deq_float_pop_back(&a); 276 | deq_float_pop_front(&a); 277 | vec_float_pop_back(&b); 278 | lst_float_pop_back(&c); 279 | lst_float_pop_front(&c); 280 | que_float_pop(&d); 281 | set_float_erase(&e, 1.0); 282 | stk_float_pop(&f); 283 | pqu_float_pop(&i); 284 | 285 | deq_float_free(&a); 286 | lst_float_free(&c); 287 | vec_float_free(&b); 288 | que_float_free(&d); 289 | set_float_free(&e); 290 | stk_float_free(&f); 291 | str_free(&g); 292 | pqu_float_free(&i); 293 | } 294 | 295 | void 296 | D(void) 297 | { 298 | deq_double a = deq_double_init(); 299 | vec_double b = vec_double_init(); 300 | lst_double c = lst_double_init(); 301 | que_double d = que_double_init(); 302 | set_double e = set_double_init(compare_key_double); 303 | stk_double f = stk_double_init(); 304 | str g = str_init("test"); 305 | pqu_double i = pqu_double_init(compare_double); 306 | 307 | deq_double_push_back(&a, 1.0); 308 | deq_double_push_front(&a, 1.0); 309 | vec_double_push_back(&b, 1.0); 310 | lst_double_push_back(&c, 1.0); 311 | lst_double_push_front(&c, 1.0); 312 | que_double_push(&d, 1.0); 313 | set_double_insert(&e, 1.0); 314 | stk_double_push(&f, 1.0); 315 | pqu_double_push(&i, 1.0); 316 | 317 | deq_double_pop_back(&a); 318 | deq_double_pop_front(&a); 319 | vec_double_pop_back(&b); 320 | lst_double_pop_back(&c); 321 | lst_double_pop_front(&c); 322 | que_double_pop(&d); 323 | set_double_erase(&e, 1.0); 324 | stk_double_pop(&f); 325 | pqu_double_pop(&i); 326 | 327 | deq_double_free(&a); 328 | lst_double_free(&c); 329 | vec_double_free(&b); 330 | que_double_free(&d); 331 | set_double_free(&e); 332 | stk_double_free(&f); 333 | str_free(&g); 334 | pqu_double_free(&i); 335 | } 336 | 337 | int 338 | main(void) 339 | { 340 | A(); 341 | B(); 342 | C(); 343 | D(); 344 | } 345 | -------------------------------------------------------------------------------- /tests/perf/perf_compile_cc.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void 10 | A() 11 | { 12 | std::deque a; 13 | std::vectorb; 14 | std::list c; 15 | std::queue d; 16 | std::set e; 17 | std::stack f; 18 | std::string g; 19 | std::priority_queue i; 20 | 21 | a.push_back(1); 22 | a.push_front(1); 23 | b.push_back(1); 24 | c.push_back(1); 25 | c.push_front(1); 26 | d.push(1); 27 | e.insert(1); 28 | f.push(1); 29 | i.push(1); 30 | 31 | a.pop_back(); 32 | a.pop_front(); 33 | b.pop_back(); 34 | c.pop_back(); 35 | c.pop_front(); 36 | d.pop(); 37 | e.erase(1); 38 | f.pop(); 39 | i.pop(); 40 | } 41 | 42 | void 43 | B() 44 | { 45 | std::deque a; 46 | std::vectorb; 47 | std::list c; 48 | std::queue d; 49 | std::set e; 50 | std::stack f; 51 | std::string g; 52 | std::priority_queue i; 53 | 54 | a.push_back(1); 55 | a.push_front(1); 56 | b.push_back(1); 57 | c.push_back(1); 58 | c.push_front(1); 59 | d.push(1); 60 | e.insert(1); 61 | f.push(1); 62 | i.push(1); 63 | 64 | a.pop_back(); 65 | a.pop_front(); 66 | b.pop_back(); 67 | c.pop_back(); 68 | c.pop_front(); 69 | d.pop(); 70 | e.erase(1); 71 | f.pop(); 72 | i.pop(); 73 | } 74 | 75 | void 76 | C() 77 | { 78 | std::deque a; 79 | std::vectorb; 80 | std::list c; 81 | std::queue d; 82 | std::set e; 83 | std::stack f; 84 | std::string g; 85 | std::priority_queue i; 86 | 87 | a.push_back(1.0); 88 | a.push_front(1.0); 89 | b.push_back(1.0); 90 | c.push_back(1.0); 91 | c.push_front(1.0); 92 | d.push(1.0); 93 | e.insert(1.0); 94 | f.push(1.0); 95 | i.push(1.0); 96 | 97 | a.pop_back(); 98 | a.pop_front(); 99 | b.pop_back(); 100 | c.pop_back(); 101 | c.pop_front(); 102 | d.pop(); 103 | e.erase(1.0); 104 | f.pop(); 105 | i.pop(); 106 | } 107 | 108 | void 109 | D() 110 | { 111 | std::deque a; 112 | std::vectorb; 113 | std::list c; 114 | std::queue d; 115 | std::set e; 116 | std::stack f; 117 | std::string g; 118 | std::priority_queue i; 119 | 120 | a.push_back(1.0); 121 | a.push_front(1.0); 122 | b.push_back(1.0); 123 | c.push_back(1.0); 124 | c.push_front(1.0); 125 | d.push(1.0); 126 | e.insert(1.0); 127 | f.push(1.0); 128 | i.push(1.0); 129 | 130 | a.pop_back(); 131 | a.pop_front(); 132 | b.pop_back(); 133 | c.pop_back(); 134 | c.pop_front(); 135 | d.pop(); 136 | e.erase(1.0); 137 | f.pop(); 138 | i.pop(); 139 | } 140 | 141 | int 142 | main() 143 | { 144 | A(); 145 | B(); 146 | C(); 147 | D(); 148 | } 149 | -------------------------------------------------------------------------------- /tests/perf/perf_plot.py: -------------------------------------------------------------------------------- 1 | import plotly.graph_objs as go 2 | import sys 3 | import string 4 | 5 | def lines_from_file(log_fname): 6 | with open(log_fname, "r") as f: 7 | file_raw = f.read() 8 | file_lines = file_raw.split("\n") 9 | return file_lines 10 | 11 | def plot_data_from_file(file_lines): 12 | name_plot_hash = {} 13 | fname_base = None 14 | fname_ext = None 15 | for line in file_lines: 16 | if "." in line: 17 | plot_name = line 18 | name_plot_hash[plot_name] = { 19 | "num_of_ints": [], 20 | "time": [] 21 | } 22 | elif line != "": 23 | half_line_len = int(len(line)/2) 24 | x = int(line[:half_line_len]) 25 | y = int(line[half_line_len:]) 26 | name_plot_hash[plot_name]["num_of_ints"].append(x) 27 | name_plot_hash[plot_name]["time"].append(y / 1e6) 28 | return name_plot_hash 29 | 30 | def plot_from_data(name_plot_hash, title): 31 | color_for_c = "#333" 32 | color_for_cpp = "#888" 33 | grid_color = "#C9C9C9" 34 | plot_bgcolor = "#F9F9F9" 35 | paper_bgcolor = "#F6F8FA" 36 | color_list = [ 37 | "#003f5c", 38 | "#444e86", 39 | "#955196", 40 | "#dd5182", 41 | "#ff6e54", 42 | "#ffa600", 43 | ] 44 | used_basenames = [] 45 | trace_list = [] 46 | for idx, name in enumerate(name_plot_hash.keys()): 47 | trace_color = color_list[int(idx / 2)] 48 | trace = go.Scatter( 49 | x=name_plot_hash[name]["num_of_ints"], 50 | y=name_plot_hash[name]["time"], 51 | name=name, 52 | mode="lines", 53 | marker=dict(color=trace_color), 54 | line=dict(width=2, dash=("dot" if name.endswith(".cc") else "solid")) 55 | ) 56 | trace_list.append(trace) 57 | fig = go.Figure(data=trace_list) 58 | fig.update_layout( 59 | plot_bgcolor=plot_bgcolor, 60 | paper_bgcolor=paper_bgcolor, 61 | xaxis=dict(title="Size", nticks=40, showgrid=True, gridcolor=grid_color), 62 | yaxis=dict(title="Seconds", showgrid=True, gridcolor=grid_color, type="log"), 63 | title=title 64 | ) 65 | return fig 66 | 67 | if __name__ == "__main__": 68 | filename = sys.argv[1] 69 | title = sys.argv[2] 70 | file_lines = lines_from_file(filename) 71 | name_plot_hash = plot_data_from_file(file_lines) 72 | fig = plot_from_data(name_plot_hash, title) 73 | fig.write_image("%s.png" % filename, width=1000, height=500) 74 | -------------------------------------------------------------------------------- /tests/perf/perf_plot_bar.py: -------------------------------------------------------------------------------- 1 | import plotly.graph_objects as go 2 | import sys 3 | 4 | if __name__ == '__main__': 5 | filename = sys.argv[1] 6 | title = sys.argv[2] 7 | time_a = sys.argv[3] 8 | time_b = sys.argv[4] 9 | size_a = sys.argv[5] 10 | size_b = sys.argv[6] 11 | name_a = sys.argv[7] 12 | name_b = sys.argv[8] 13 | compiler=[name_a, name_b] 14 | y = [float(time_a), float(time_b)] 15 | sizes = [ 16 | str(int(size_a) / 1000) + ' KB', 17 | str(int(size_b) / 1000) + ' KB', 18 | ] 19 | colors = ['crimson', 'darkslateblue'] 20 | fig = go.Figure([go.Bar(x=compiler, y=y, text=sizes, textposition='auto', marker_color=colors)]) 21 | fig.update_yaxes(title_text="Seconds") 22 | plot_bgcolor = "#F9F9F9" 23 | paper_bgcolor = "#F6F8FA" 24 | fig.update_layout( 25 | title_text=title, 26 | plot_bgcolor=plot_bgcolor, paper_bgcolor=paper_bgcolor) 27 | fig.write_image("%s.png" % filename, width=1000, height=300) 28 | 29 | -------------------------------------------------------------------------------- /tests/perf/pqu/perf_pqu_pop.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | static int compare(int* a, int* b) { return *a < *b; } 10 | 11 | int main(void) 12 | { 13 | puts(__FILE__); 14 | srand(time(NULL)); 15 | for(int run = 0; run < TEST_PERF_RUNS; run++) 16 | { 17 | pqu_int c = pqu_int_init(compare); 18 | int elems = TEST_PERF_CHUNKS * run; 19 | for(int elem = 0; elem < elems; elem++) 20 | pqu_int_push(&c, rand()); 21 | int t0 = TEST_TIME(); 22 | for(int elem = 0; elem < elems; elem++) 23 | pqu_int_pop(&c); 24 | int t1 = TEST_TIME(); 25 | printf("%10d %10d\n", elems, t1 - t0); 26 | pqu_int_free(&c); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/perf/pqu/perf_pqu_push.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | static int compare(int* a, int* b) { return *a < *b; } 10 | 11 | int main(void) 12 | { 13 | puts(__FILE__); 14 | srand(time(NULL)); 15 | for(int run = 0; run < TEST_PERF_RUNS; run++) 16 | { 17 | pqu_int c = pqu_int_init(compare); 18 | int elems = TEST_PERF_CHUNKS * run; 19 | int t0 = TEST_TIME(); 20 | for(int elem = 0; elem < elems; elem++) 21 | pqu_int_push(&c, rand()); 22 | int t1 = TEST_TIME(); 23 | printf("%10d %10d\n", elems, t1 - t0); 24 | pqu_int_free(&c); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/perf/pqu/perf_priority_queue_pop.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | struct compare { bool operator()(const int& a, const int& b) { return a < b; } }; 8 | 9 | int main() 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | std::priority_queue, compare> c; 16 | int elems = TEST_PERF_CHUNKS * run; 17 | for(int elem = 0; elem < elems; elem++) 18 | c.push(rand()); 19 | int t0 = TEST_TIME(); 20 | for(int elem = 0; elem < elems; elem++) 21 | c.pop(); 22 | int t1 = TEST_TIME(); 23 | printf("%10d %10d\n", elems, t1 - t0); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/perf/pqu/perf_priority_queue_push.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | struct compare { bool operator()(const int& a, const int& b) { return a < b; } }; 8 | 9 | int main() 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | std::priority_queue, compare> c; 16 | int elems = TEST_PERF_CHUNKS * run; 17 | int t0 = TEST_TIME(); 18 | for(int elem = 0; elem < elems; elem++) 19 | c.push(rand()); 20 | int t1 = TEST_TIME(); 21 | printf("%10d %10d\n", elems, t1 - t0); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/perf/set/perf_set_erase.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | static int compare(int* a, int* b) { return *a == *b ? 0 : *a < *b ? -1 : 1; } 10 | 11 | int main(void) 12 | { 13 | puts(__FILE__); 14 | srand(time(NULL)); 15 | for(int run = 0; run < TEST_PERF_RUNS; run++) 16 | { 17 | set_int c = set_int_init(compare); 18 | int elems = TEST_PERF_CHUNKS * run; 19 | for(int elem = 0; elem < elems; elem++) 20 | set_int_insert(&c, rand() % elems); 21 | int t0 = TEST_TIME(); 22 | for(int elem = 0; elem < elems; elem++) 23 | set_int_erase(&c, rand() % elems); 24 | int t1 = TEST_TIME(); 25 | printf("%10d %10d\n", elems, t1 - t0); 26 | set_int_free(&c); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/perf/set/perf_set_erase.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | puts(__FILE__); 9 | srand(time(NULL)); 10 | for(int run = 0; run < TEST_PERF_RUNS; run++) 11 | { 12 | std::set c; 13 | int elems = TEST_PERF_CHUNKS * run; 14 | for(int elem = 0; elem < elems; elem++) 15 | c.insert(rand() % elems); 16 | int t0 = TEST_TIME(); 17 | for(int elem = 0; elem < elems; elem++) 18 | c.erase(rand() % elems); 19 | int t1 = TEST_TIME(); 20 | printf("%10d %10d\n", elems, t1 - t0); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/perf/set/perf_set_insert.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | static int compare(int* a, int* b) { return *a == *b ? 0 : *a < *b ? -1 : 1; } 10 | 11 | int main(void) 12 | { 13 | puts(__FILE__); 14 | srand(time(NULL)); 15 | for(int run = 0; run < TEST_PERF_RUNS; run++) 16 | { 17 | set_int c = set_int_init(compare); 18 | int elems = TEST_PERF_CHUNKS * run; 19 | int t0 = TEST_TIME(); 20 | for(int elem = 0; elem < elems; elem++) 21 | set_int_insert(&c, rand() % elems); 22 | int t1 = TEST_TIME(); 23 | printf("%10d %10d\n", elems, t1 - t0); 24 | set_int_free(&c); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/perf/set/perf_set_insert.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | puts(__FILE__); 9 | srand(time(NULL)); 10 | for(int run = 0; run < TEST_PERF_RUNS; run++) 11 | { 12 | std::set c; 13 | int elems = TEST_PERF_CHUNKS * run; 14 | int t0 = TEST_TIME(); 15 | for(int elem = 0; elem < elems; elem++) 16 | c.insert(rand() % elems); 17 | int t1 = TEST_TIME(); 18 | printf("%10d %10d\n", elems, t1 - t0); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/perf/set/perf_set_iterate.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | static int compare(int* a, int* b) { return *a == *b ? 0 : *a < *b ? -1 : 1; } 10 | 11 | int main(void) 12 | { 13 | puts(__FILE__); 14 | srand(time(NULL)); 15 | for(int run = 0; run < TEST_PERF_RUNS; run++) 16 | { 17 | set_int c = set_int_init(compare); 18 | int elems = TEST_PERF_CHUNKS * run; 19 | for(int elem = 0; elem < elems; elem++) 20 | set_int_insert(&c, rand() % elems); 21 | volatile int sum = 0; 22 | int t0 = TEST_TIME(); 23 | foreach(set_int, &c, it) 24 | sum += *it.ref; 25 | int t1 = TEST_TIME(); 26 | printf("%10d %10d\n", elems, t1 - t0); 27 | set_int_free(&c); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/perf/set/perf_set_iterate.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | puts(__FILE__); 9 | srand(time(NULL)); 10 | for(int run = 0; run < TEST_PERF_RUNS; run++) 11 | { 12 | std::set c; 13 | int elems = TEST_PERF_CHUNKS * run; 14 | for(int elem = 0; elem < elems; elem++) 15 | c.insert(rand() % elems); 16 | int t0 = TEST_TIME(); 17 | volatile int sum = 0; 18 | for(auto& x : c) 19 | sum += x; 20 | int t1 = TEST_TIME(); 21 | printf("%10d %10d\n", elems, t1 - t0); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/perf/ust/perf_unordered_set_erase.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | puts(__FILE__); 9 | srand(time(NULL)); 10 | for(int run = 0; run < TEST_PERF_RUNS; run++) 11 | { 12 | std::unordered_set c; 13 | int elems = TEST_PERF_CHUNKS * run; 14 | for(int elem = 0; elem < elems; elem++) 15 | c.insert(rand() % elems); 16 | int t0 = TEST_TIME(); 17 | for(int elem = 0; elem < elems; elem++) 18 | c.erase(rand() % elems); 19 | int t1 = TEST_TIME(); 20 | printf("%10d %10d\n", elems, t1 - t0); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/perf/ust/perf_unordered_set_insert.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | puts(__FILE__); 9 | srand(time(NULL)); 10 | for(int run = 0; run < TEST_PERF_RUNS; run++) 11 | { 12 | std::unordered_set c; 13 | int elems = TEST_PERF_CHUNKS * run; 14 | int t0 = TEST_TIME(); 15 | for(int elem = 0; elem < elems; elem++) 16 | c.insert(rand() % elems); 17 | int t1 = TEST_TIME(); 18 | printf("%10d %10d\n", elems, t1 - t0); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/perf/ust/perf_unordered_set_iterate.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | puts(__FILE__); 9 | srand(time(NULL)); 10 | for(int run = 0; run < TEST_PERF_RUNS; run++) 11 | { 12 | std::unordered_set c; 13 | int elems = TEST_PERF_CHUNKS * run; 14 | for(int elem = 0; elem < elems; elem++) 15 | c.insert(rand() % elems); 16 | int t0 = TEST_TIME(); 17 | volatile int sum = 0; 18 | for(auto& x : c) 19 | sum += x; 20 | int t1 = TEST_TIME(); 21 | printf("%10d %10d\n", elems, t1 - t0); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/perf/ust/perf_ust_erase.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | size_t 10 | int_hash(int* x) 11 | { return abs(*x); } 12 | 13 | int 14 | int_equal(int* a, int* b) 15 | { return *a == *b; } 16 | 17 | int main(void) 18 | { 19 | puts(__FILE__); 20 | srand(time(NULL)); 21 | for(int run = 0; run < TEST_PERF_RUNS; run++) 22 | { 23 | ust_int c = ust_int_init(int_hash, int_equal); 24 | int elems = TEST_PERF_CHUNKS * run; 25 | for(int elem = 0; elem < elems; elem++) 26 | ust_int_insert(&c, rand() % elems); 27 | int t0 = TEST_TIME(); 28 | for(int elem = 0; elem < elems; elem++) 29 | ust_int_erase(&c, rand() % elems); 30 | int t1 = TEST_TIME(); 31 | printf("%10d %10d\n", elems, t1 - t0); 32 | ust_int_free(&c); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/perf/ust/perf_ust_insert.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | size_t 10 | int_hash(int* x) 11 | { return abs(*x); } 12 | 13 | int 14 | int_equal(int* a, int* b) 15 | { return *a == *b; } 16 | 17 | int main(void) 18 | { 19 | puts(__FILE__); 20 | srand(time(NULL)); 21 | for(int run = 0; run < TEST_PERF_RUNS; run++) 22 | { 23 | ust_int c = ust_int_init(int_hash, int_equal); 24 | int elems = TEST_PERF_CHUNKS * run; 25 | int t0 = TEST_TIME(); 26 | for(int elem = 0; elem < elems; elem++) 27 | ust_int_insert(&c, rand() % elems); 28 | int t1 = TEST_TIME(); 29 | printf("%10d %10d\n", elems, t1 - t0); 30 | ust_int_free(&c); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/perf/ust/perf_ust_iterate.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | size_t 10 | int_hash(int* x) 11 | { return abs(*x); } 12 | 13 | int 14 | int_equal(int* a, int* b) 15 | { return *a == *b; } 16 | 17 | int main(void) 18 | { 19 | puts(__FILE__); 20 | srand(time(NULL)); 21 | for(int run = 0; run < TEST_PERF_RUNS; run++) 22 | { 23 | ust_int c = ust_int_init(int_hash, int_equal); 24 | int elems = TEST_PERF_CHUNKS * run; 25 | for(int elem = 0; elem < elems; elem++) 26 | ust_int_insert(&c, rand() % elems); 27 | volatile int sum = 0; 28 | int t0 = TEST_TIME(); 29 | foreach(ust_int, &c, it) 30 | sum += *it.ref; 31 | int t1 = TEST_TIME(); 32 | printf("%10d %10d\n", elems, t1 - t0); 33 | ust_int_free(&c); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/perf/vec/perf_vec_iterate.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | int main(void) 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | vec_int c = vec_int_init(); 16 | int elems = TEST_PERF_CHUNKS * run; 17 | for(int elem = 0; elem < elems; elem++) 18 | vec_int_push_back(&c, rand()); 19 | int t0 = TEST_TIME(); 20 | volatile int sum = 0; 21 | foreach(vec_int, &c, it) 22 | sum += *it.ref; 23 | int t1 = TEST_TIME(); 24 | printf("%10d %10d\n", elems, t1 - t0); 25 | vec_int_free(&c); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/perf/vec/perf_vec_pop_back.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | int main(void) 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | vec_int c = vec_int_init(); 16 | int elems = TEST_PERF_CHUNKS * run; 17 | for(int elem = 0; elem < elems; elem++) 18 | vec_int_push_back(&c, rand()); 19 | int t0 = TEST_TIME(); 20 | for(int elem = 0; elem < elems; elem++) 21 | vec_int_pop_back(&c); 22 | int t1 = TEST_TIME(); 23 | printf("%10d %10d\n", elems, t1 - t0); 24 | vec_int_free(&c); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/perf/vec/perf_vec_push_back.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | int main(void) 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | vec_int c = vec_int_init(); 16 | int elems = TEST_PERF_CHUNKS * run; 17 | int t0 = TEST_TIME(); 18 | for(int elem = 0; elem < elems; elem++) 19 | vec_int_push_back(&c, rand()); 20 | int t1 = TEST_TIME(); 21 | printf("%10d %10d\n", elems, t1 - t0); 22 | vec_int_free(&c); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/perf/vec/perf_vec_sort.c: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #define P 4 | #define T int 5 | #include 6 | 7 | #include 8 | 9 | static int compare(int* a, int* b) { return *a < *b; } 10 | 11 | int main(void) 12 | { 13 | puts(__FILE__); 14 | srand(time(NULL)); 15 | for(int run = 0; run < TEST_PERF_RUNS; run++) 16 | { 17 | vec_int c = vec_int_init(); 18 | int elems = TEST_PERF_CHUNKS * run; 19 | for(int elem = 0; elem < elems; elem++) 20 | vec_int_push_back(&c, rand()); 21 | int t0 = TEST_TIME(); 22 | vec_int_sort(&c, compare); 23 | int t1 = TEST_TIME(); 24 | printf("%10d %10d\n", elems, t1 - t0); 25 | vec_int_free(&c); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/perf/vec/perf_vector_iterate.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | int main() 8 | { 9 | puts(__FILE__); 10 | srand(time(NULL)); 11 | for(int run = 0; run < TEST_PERF_RUNS; run++) 12 | { 13 | std::vector c; 14 | int elems = TEST_PERF_CHUNKS * run; 15 | for(int elem = 0; elem < elems; elem++) 16 | c.push_back(rand()); 17 | int t0 = TEST_TIME(); 18 | volatile int sum = 0; 19 | for(auto& x : c) 20 | sum += x; 21 | int t1 = TEST_TIME(); 22 | printf("%10d %10d\n", elems, t1 - t0); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/perf/vec/perf_vector_pop_back.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | puts(__FILE__); 9 | srand(time(NULL)); 10 | for(int run = 0; run < TEST_PERF_RUNS; run++) 11 | { 12 | std::vector c; 13 | int elems = TEST_PERF_CHUNKS * run; 14 | for(int elem = 0; elem < elems; elem++) 15 | c.push_back(rand()); 16 | int t0 = TEST_TIME(); 17 | for(int elem = 0; elem < elems; elem++) 18 | c.pop_back(); 19 | int t1 = TEST_TIME(); 20 | printf("%10d %10d\n", elems, t1 - t0); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/perf/vec/perf_vector_push_back.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | puts(__FILE__); 9 | srand(time(NULL)); 10 | for(int run = 0; run < TEST_PERF_RUNS; run++) 11 | { 12 | std::vector c; 13 | int elems = TEST_PERF_CHUNKS * run; 14 | int t0 = TEST_TIME(); 15 | for(int elem = 0; elem < elems; elem++) 16 | c.push_back(rand()); 17 | int t1 = TEST_TIME(); 18 | printf("%10d %10d\n", elems, t1 - t0); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/perf/vec/perf_vector_sort.cc: -------------------------------------------------------------------------------- 1 | #include "../../test.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | static bool compare(int& a, int& b) { return a < b; } 8 | 9 | int main() 10 | { 11 | puts(__FILE__); 12 | srand(time(NULL)); 13 | for(int run = 0; run < TEST_PERF_RUNS; run++) 14 | { 15 | std::vector c; 16 | int elems = TEST_PERF_CHUNKS * run; 17 | for(int elem = 0; elem < elems; elem++) 18 | c.push_back(rand()); 19 | int t0 = TEST_TIME(); 20 | std::sort(c.begin(), c.end(), compare); 21 | int t1 = TEST_TIME(); 22 | printf("%10d %10d\n", elems, t1 - t0); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/test.h: -------------------------------------------------------------------------------- 1 | #ifndef __TEST__H__ 2 | #define __TEST__H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #ifdef LONG 14 | #define TEST_MAX_SIZE (4096) 15 | #define TEST_MAX_LOOPS (8096) 16 | #else 17 | #define TEST_MAX_SIZE (512) 18 | #define TEST_MAX_LOOPS (512) 19 | #endif 20 | 21 | #define TEST_SIGN(a) ((a < 0) ? (-1) : (a > 0) ? (1) : (0)) 22 | 23 | #define TEST_PASS(f) printf("%s: PASS\n", f) 24 | 25 | #define TEST_RAND(max) (((max) == 0) ? 0 : (rand() % (max))) 26 | 27 | #define TEST_PERF_RUNS (100) 28 | 29 | #define TEST_PERF_CHUNKS (256) 30 | 31 | static inline int 32 | TEST_TIME(void) 33 | { 34 | struct timeval now; 35 | gettimeofday(&now, NULL); 36 | return 1000000 * now.tv_sec + now.tv_usec; 37 | } 38 | 39 | #endif 40 | --------------------------------------------------------------------------------