More refactoring
This commit is contained in:
1 parent
0e6c44ac46
commit
f6bc58a3d7
59 files changed
+10562
-98
No files matched your search
@@ -17,9 +17,9 @@ jobs:
|
||||
make --version \
|
||||
valgrind --version \
|
||||
- name: Test Suite
|
||||
run: cd tests && make
|
||||
run: make tests
|
||||
- name: Upload Coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
directory: ./tests/coverage
|
||||
directory: ./tests
|
||||
verbose: true
|
||||
@@ -59,3 +59,6 @@ experimental/
|
||||
|
||||
# Test / Code Coverage build folder
|
||||
build
|
||||
|
||||
tests/coverage
|
||||
tests/out
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
dist: xenial
|
||||
os: linux
|
||||
language: c
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- deadsnakes
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-9
|
||||
- cmake
|
||||
- python3.8
|
||||
script:
|
||||
- sudo rm -f /usr/bin/gcc /usr/bin/gcov /usr/bin/python
|
||||
- sudo ln -s /usr/bin/gcc-9 /usr/bin/gcc
|
||||
- sudo ln -s /usr/bin/gcov-9 /usr/bin/gcov
|
||||
- sudo ln -s /usr/bin/python3.8 /usr/bin/python
|
||||
- gcc --version
|
||||
- gcov --version
|
||||
- python --version
|
||||
- python autogen.py -e -b -cv -r -nf -nt
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
help:
|
||||
@echo Welcome to the C Macro Collections Library. Targets:
|
||||
@echo
|
||||
@echo - tests: run tests
|
||||
@echo - format: formats the entire project
|
||||
|
||||
tests:
|
||||
make -C ./tests
|
||||
|
||||
tests_dev:
|
||||
make -C ./tests dev
|
||||
|
||||
format:
|
||||
- find ./ -name *.h -type f | xargs clang-format --style=file --verbose -i
|
||||
|
||||
bench:
|
||||
gcc ./benchmarks/benchmark.c -o ./benchmarks/benchmark.exe -I ./src -O3
|
||||
./benchmarks/benchmark.exe
|
||||
@@ -0,0 +1,266 @@
|
||||
/**
|
||||
* benchmark.c
|
||||
*
|
||||
* Creation Date: 13/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Benchmarks:
|
||||
* - Input
|
||||
* - Search
|
||||
* - Iteration
|
||||
* - Output
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "util/twister.c"
|
||||
|
||||
#include "cmc/utl/foreach.h"
|
||||
#include "cmc/utl/futils.h"
|
||||
#include "cmc/utl/timer.h"
|
||||
|
||||
#define NTOTAL UINT64_C(10000000)
|
||||
#define NMIN UINT64_C(100)
|
||||
|
||||
// Percentage % macro
|
||||
#define PC(x) x * 100.0
|
||||
|
||||
static int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
size_t randsize(size_t min, size_t max, mt_state_ptr st)
|
||||
{
|
||||
return (size_t)floor(twist_real(st) * ((double)max - (double)min + 1.0) + (double)min);
|
||||
}
|
||||
|
||||
void shuffle(int *array, mt_state_ptr st)
|
||||
{
|
||||
for (size_t i = 0; i < NTOTAL; i++)
|
||||
{
|
||||
size_t j = randsize(0, NTOTAL - 1, st);
|
||||
int tmp = array[j];
|
||||
array[j] = array[i];
|
||||
array[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
#define K int32_t
|
||||
#define V int32_t
|
||||
#define PFX d
|
||||
#define SNAME deque
|
||||
#define CMC_EXT_DEQUE_ITER
|
||||
#include "cmc/deque.h"
|
||||
|
||||
// CMC_COLLECTION_GENERATE(DEQUE, d, deque, /* K */, int)
|
||||
// CMC_COLLECTION_GENERATE(HASHMAP, hm, hmap, int, int)
|
||||
// CMC_COLLECTION_GENERATE(HASHSET, hs, hset, /* K */, int)
|
||||
// CMC_COLLECTION_GENERATE(HEAP, h, heap, /* K */, int)
|
||||
// CMC_COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* K */, int)
|
||||
// CMC_COLLECTION_GENERATE(LIST, l, list, /* K */, int)
|
||||
// CMC_COLLECTION_GENERATE(QUEUE, q, queue, /* K */, int)
|
||||
// CMC_COLLECTION_GENERATE(STACK, s, stack, /* K */, int)
|
||||
// CMC_COLLECTION_GENERATE(TREEMAP, tm, tmap, int, int)
|
||||
// CMC_COLLECTION_GENERATE(TREESET, ts, tset, /* K */, int)
|
||||
|
||||
// CMC_COLLECTION_GENERATE(INTERVALHEAP, ih, iheap, /* k */, int)
|
||||
// CMC_COLLECTION_GENERATE(MULTIMAP, mm, mmap, int, int)
|
||||
// CMC_COLLECTION_GENERATE(MULTISET, ms, mset, /* K */, int)
|
||||
|
||||
#define BENCHMARK(NAME, PFX, sname, initfunc, insertbody, removebody, searchbody) \
|
||||
void NAME##_io_benchmark(int *array, int *sarray, size_t s) \
|
||||
{ \
|
||||
printf("+------------------------------------------------------------ %10s\n", #NAME); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
struct cmc_timer timer, total; \
|
||||
int r, k, v; \
|
||||
size_t j; \
|
||||
\
|
||||
struct sname *coll = initfunc; \
|
||||
\
|
||||
cmc_timer_start(total); \
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
insertbody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
size_t s1 = PFX##_count(coll); \
|
||||
\
|
||||
printf(" INPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double input_time = timer.result; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < s; i++) \
|
||||
{ \
|
||||
searchbody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
|
||||
\
|
||||
double search_time = timer.result; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
CMC_FOREACH (PFX, sname, iter, coll) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
printf("ITERATION %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double iter_time = timer.result; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
removebody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
size_t s2 = PFX##_count(coll); \
|
||||
\
|
||||
printf(" OUTPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double output_time = timer.result; \
|
||||
\
|
||||
cmc_timer_stop(total); \
|
||||
\
|
||||
PFX##_free(coll); \
|
||||
\
|
||||
double adj_search_time = (total.result - search_time) + (search_time * (double)NTOTAL) / (double)s; \
|
||||
double no_search = input_time + iter_time + output_time; \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf("TOTAL TIME : %.0lf milliseconds\n", total.result); \
|
||||
printf("ADJUSTED TIME : %.0lf milliseconds\n", adj_search_time); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf(" INPUT : %5.2lf%% (%5.2f%%)\n", PC(input_time / total.result), PC(input_time / no_search)); \
|
||||
printf(" SEARCH : %5.2lf%%\n", PC(search_time / total.result)); \
|
||||
printf("ITERATION : %5.2lf%% (%5.2f%%)\n", PC(iter_time / total.result), PC(iter_time / no_search)); \
|
||||
printf(" OUTPUT : %5.2lf%% (%5.2f%%)\n", PC(output_time / total.result), PC(output_time / no_search)); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
\
|
||||
assert(s1 == NTOTAL && s2 == 0); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ %10s\n\n", #NAME); \
|
||||
}
|
||||
|
||||
BENCHMARK(DEQUE, d, deque, d_new(NTOTAL, &(struct deque_fval){ .cmp = cmc_i32_cmp }), d_push_back(coll, array[i]),
|
||||
d_pop_back(coll), d_contains(coll, sarray[i]))
|
||||
// BENCHMARK(HASHMAP, hm, hmap, hm_new(NTOTAL, 0.6, intcmp, inthash), hm_insert(coll, array[i], array[i]),
|
||||
// hm_remove(coll, array[i], &r), hm_contains(coll, sarray[i]))
|
||||
// BENCHMARK(HASHSET, hs, hset, hs_new(NTOTAL, 0.6, intcmp, inthash), hs_insert(coll, array[i]), hs_remove(coll,
|
||||
// array[i]),
|
||||
// hs_contains(coll, sarray[i]))
|
||||
// BENCHMARK(HEAP, h, heap, h_new(NTOTAL, cmc_min_heap, intcmp), h_insert(coll, array[i]), h_remove(coll, &r),
|
||||
// h_contains(coll, sarray[i]))
|
||||
// BENCHMARK(LINKEDLIST, ll, linked, ll_new(), ll_push_back(coll, array[i]), ll_pop_back(coll),
|
||||
// ll_contains(coll, sarray[i], intcmp))
|
||||
// BENCHMARK(LIST, l, list, l_new(NTOTAL), l_push_back(coll, array[i]), l_pop_back(coll),
|
||||
// l_contains(coll, sarray[i], intcmp))
|
||||
// BENCHMARK(QUEUE, q, queue, q_new(NTOTAL), q_enqueue(coll, array[i]), q_dequeue(coll),
|
||||
// q_contains(coll, sarray[i], intcmp))
|
||||
// BENCHMARK(STACK, s, stack, s_new(NTOTAL), s_push(coll, array[i]), s_pop(coll), s_contains(coll, sarray[i], intcmp))
|
||||
// BENCHMARK(TREEMAP, tm, tmap, tm_new(intcmp), tm_insert(coll, array[i], array[i]), tm_remove(coll, array[i], &r),
|
||||
// tm_contains(coll, sarray[i]))
|
||||
// BENCHMARK(TREESET, ts, tset, ts_new(intcmp), ts_insert(coll, array[i]), ts_remove(coll, array[i]),
|
||||
// ts_contains(coll, sarray[i]))
|
||||
|
||||
// BENCHMARK(INTERVALHEAP, ih, iheap, ih_new(NTOTAL, intcmp), ih_insert(coll, array[i]), ih_remove_max(coll, &r),
|
||||
// ih_contains(coll, sarray[i]))
|
||||
// BENCHMARK(MULTIMAP, mm, mmap, mm_new(NTOTAL, 0.8, intcmp, inthash), mm_insert(coll, array[i], array[i]),
|
||||
// mm_remove(coll, array[i], &r), mm_contains(coll, sarray[i]))
|
||||
// BENCHMARK(MULTISET, ms, mset, ms_new(NTOTAL, 0.6, intcmp, inthash), ms_insert(coll, array[i]),
|
||||
// ms_remove(coll, array[i]), ms_contains(coll, sarray[i]))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Using the Mersenne Twister to generate random numbers. This seed
|
||||
// guarantees that everytime this program runs it will generate the same
|
||||
// random numbers. The random numbers influence on the shuffling of the
|
||||
// array.
|
||||
mt_state st;
|
||||
twist_init(&st, UINT64_C(12604951237));
|
||||
|
||||
int *array = malloc(NTOTAL * sizeof(int));
|
||||
int *sarray = malloc(NTOTAL * sizeof(int));
|
||||
|
||||
if (!array)
|
||||
{
|
||||
printf("Allocation failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = -5000000; i < 5000000; i++)
|
||||
array[i + 5000000] = i;
|
||||
|
||||
shuffle(array, &st);
|
||||
|
||||
memcpy(sarray, array, NTOTAL * sizeof(int));
|
||||
|
||||
shuffle(sarray, &st);
|
||||
|
||||
printf("\nNote: Adjusted Time refers to if the container had done a search over all %" PRIuMAX " elements.\n\n",
|
||||
NTOTAL);
|
||||
|
||||
// Linear containers have to search for NMIN elements and non-linear (hash
|
||||
// and tree) have to search for all elements.
|
||||
struct cmc_timer timer;
|
||||
cmc_timer_start(timer);
|
||||
|
||||
DEQUE_io_benchmark(array, sarray, NMIN);
|
||||
// HASHMAP_io_benchmark(array, sarray, NTOTAL);
|
||||
// HASHSET_io_benchmark(array, sarray, NTOTAL);
|
||||
// HEAP_io_benchmark(array, sarray, NMIN);
|
||||
// LINKEDLIST_io_benchmark(array, sarray, NMIN);
|
||||
// LIST_io_benchmark(array, sarray, NMIN);
|
||||
// QUEUE_io_benchmark(array, sarray, NMIN);
|
||||
// STACK_io_benchmark(array, sarray, NMIN);
|
||||
// TREEMAP_io_benchmark(array, sarray, NTOTAL);
|
||||
// TREESET_io_benchmark(array, sarray, NTOTAL);
|
||||
|
||||
// INTERVALHEAP_io_benchmark(array, array, NMIN);
|
||||
// MULTIMAP_io_benchmark(array, array, NTOTAL);
|
||||
// MULTISET_io_benchmark(array, array, NTOTAL);
|
||||
|
||||
cmc_timer_stop(timer);
|
||||
|
||||
printf("+-----------------------------------------------------------+ \n");
|
||||
printf("| Total Benchmark Running Time : %12.0lf seconds | \n", timer.result / 1000);
|
||||
printf("+-----------------------------------------------------------+ \n");
|
||||
|
||||
free(array);
|
||||
free(sarray);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
INCLUDE=-I ../../../src
|
||||
CFLAGS=-O3 -Wall -DCOUNT=20000000 -DCMC_NO_CALLBACKS
|
||||
|
||||
# Install hyperfine
|
||||
# https://github.com/sharkdp/hyperfine
|
||||
|
||||
run: build
|
||||
hyperfine --warmup 2 --runs 5 './hashmap.exe'
|
||||
hyperfine --warmup 2 --runs 5 './hashmultimap.exe'
|
||||
hyperfine --warmup 2 --runs 5 './unorderedmap.exe'
|
||||
|
||||
build:
|
||||
gcc hashmap.c -o hashmap.exe $(INCLUDE) $(CFLAGS)
|
||||
gcc hashmultimap.c -o hashmultimap.exe $(INCLUDE) $(CFLAGS)
|
||||
g++ unorderedmap.cpp $(INCLUDE) -o unorderedmap.exe $(CFLAGS)
|
||||
|
||||
clean:
|
||||
rm *.exe
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef COUNT
|
||||
#error "Please define COUNT"
|
||||
#endif
|
||||
|
||||
#include "murmurhash.h"
|
||||
|
||||
#include "../../util/twister.c"
|
||||
|
||||
#define K uint64_t
|
||||
#define V uint64_t
|
||||
#define PFX hm
|
||||
#define SNAME hashmap
|
||||
#include "cmc/hashmap.h"
|
||||
|
||||
int cmp(uint64_t a, uint64_t b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
// size_t hash(uint64_t a)
|
||||
// {
|
||||
// size_t x = (size_t)a;
|
||||
// x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
// x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
// x = (x >> 16) ^ x;
|
||||
// return x;
|
||||
// }
|
||||
|
||||
size_t hash(uint64_t k)
|
||||
{
|
||||
static size_t seed = 211106232532969;
|
||||
return MurMurHash(&k, sizeof(k), seed);
|
||||
}
|
||||
|
||||
struct hashmap_fkey *fkey = &(struct hashmap_fkey){ .cmp = cmp, .hash = hash, NULL };
|
||||
|
||||
struct hashmap_fval *fval = &(struct hashmap_fval){ .cmp = cmp, .hash = hash, NULL };
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mt_state tw;
|
||||
twist_init(&tw, 50331653);
|
||||
|
||||
struct hashmap *map = hm_new(COUNT, 0.6, fkey, fval);
|
||||
|
||||
for (uint64_t i = 0; i < COUNT; i++)
|
||||
{
|
||||
uint64_t v = twist_uint64(&tw);
|
||||
hm_insert(map, v, v);
|
||||
}
|
||||
|
||||
hm_free(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef COUNT
|
||||
#error "Please define COUNT"
|
||||
#endif
|
||||
|
||||
#include "murmurhash.h"
|
||||
|
||||
#include "../../util/twister.c"
|
||||
|
||||
#define K uint64_t
|
||||
#define V uint64_t
|
||||
#define PFX hmm
|
||||
#define SNAME hashmultimap
|
||||
#include "cmc/hashmultimap.h"
|
||||
|
||||
int cmp(uint64_t a, uint64_t b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
// size_t hash(uint64_t a)
|
||||
// {
|
||||
// size_t x = (size_t)a;
|
||||
// x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
// x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
// x = (x >> 16) ^ x;
|
||||
// return x;
|
||||
// }
|
||||
|
||||
size_t hash(uint64_t k)
|
||||
{
|
||||
static size_t seed = 211106232532969;
|
||||
return MurMurHash(&k, sizeof(k), seed);
|
||||
}
|
||||
|
||||
struct hashmultimap_fkey *fkey = &(struct hashmultimap_fkey){ .cmp = cmp, .hash = hash, NULL };
|
||||
|
||||
struct hashmultimap_fval *fval = &(struct hashmultimap_fval){ .cmp = cmp, .hash = hash, NULL };
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mt_state tw;
|
||||
twist_init(&tw, 50331653);
|
||||
|
||||
struct hashmultimap *map = hmm_new(COUNT, 0.6, fkey, fval);
|
||||
|
||||
for (uint64_t i = 0; i < COUNT; i++)
|
||||
{
|
||||
uint64_t v = twist_uint64(&tw);
|
||||
hmm_insert(map, v, v);
|
||||
}
|
||||
|
||||
hmm_free(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/hash_bytes.cc
|
||||
|
||||
#ifndef MURMURHASH
|
||||
#define MURMURHASH
|
||||
|
||||
#include <string.h>
|
||||
|
||||
inline size_t unaligned_load(const char *p)
|
||||
{
|
||||
size_t result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline size_t load_bytes(const char *p, int n)
|
||||
{
|
||||
size_t result = 0;
|
||||
--n;
|
||||
do
|
||||
{
|
||||
result = (result << 8) + (unsigned char)(p[n]);
|
||||
} while (--n >= 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline size_t shift_mix(size_t v)
|
||||
{
|
||||
return v ^ (v >> 47);
|
||||
}
|
||||
|
||||
size_t MurMurHash(const void *ptr, size_t len, size_t seed)
|
||||
{
|
||||
static const size_t mul = (((size_t)0xc6a4a793UL) << 32UL) + (size_t)0x5bd1e995UL;
|
||||
const char *const buf = (const char *)(ptr);
|
||||
|
||||
// Remove the bytes not divisible by the sizeof(size_t). This
|
||||
// allows the main loop to process the data as 64-bit integers.
|
||||
const size_t len_aligned = len & ~(size_t)0x7;
|
||||
const char *const end = buf + len_aligned;
|
||||
size_t hash = seed ^ (len * mul);
|
||||
for (const char *p = buf; p != end; p += 8)
|
||||
{
|
||||
const size_t data = shift_mix(unaligned_load(p) * mul) * mul;
|
||||
hash ^= data;
|
||||
hash *= mul;
|
||||
}
|
||||
if ((len & 0x7) != 0)
|
||||
{
|
||||
const size_t data = load_bytes(end, len & 0x7);
|
||||
hash ^= data;
|
||||
hash *= mul;
|
||||
}
|
||||
hash = shift_mix(hash) * mul;
|
||||
hash = shift_mix(hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
#endif /* MURMURHASH */
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef COUNT
|
||||
#error "Please define COUNT"
|
||||
#endif
|
||||
|
||||
#include "murmurhash.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../../util/twister.c"
|
||||
|
||||
struct IntHasher
|
||||
{
|
||||
std::size_t operator()(const uint64_t &k) const
|
||||
{
|
||||
static size_t seed = 211106232532969;
|
||||
return MurMurHash(&k, sizeof(k), seed);
|
||||
}
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mt_state tw;
|
||||
twist_init(&tw, 50331653);
|
||||
|
||||
std::unordered_map<uint64_t, uint64_t, IntHasher> map(COUNT);
|
||||
|
||||
for (uint64_t i = 0; i < COUNT; i++)
|
||||
{
|
||||
uint64_t v = twist_uint64(&tw);
|
||||
map.insert({ v, v });
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* twister.c
|
||||
*
|
||||
* Creation Date: 09/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Mersenne Twister PRNG utility
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define NN 312
|
||||
#define MM 156
|
||||
#define MATRIX_A UINT64_C(0xB5026F5AA96619E9)
|
||||
#define UM UINT64_C(0xFFFFFFFF80000000) // Most significant 33 bits
|
||||
#define LM UINT64_C(0x7FFFFFFF) // Least significant 31 bits
|
||||
|
||||
// State vector
|
||||
typedef struct mt_state_s
|
||||
{
|
||||
uint64_t mt[NN];
|
||||
int mti;
|
||||
} mt_state, *mt_state_ptr;
|
||||
|
||||
// Initializes mt[NN] with a seed
|
||||
void twist_init(mt_state_ptr st, uint64_t seed);
|
||||
|
||||
// Generates a random uint64_t in [0, 2^64-1] interval
|
||||
uint64_t twist_uint64(mt_state_ptr st);
|
||||
|
||||
// Generates a double in [0, 1) interval
|
||||
double twist_real(mt_state_ptr st);
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
|
||||
// Initialize a state mt[NN] with a seed
|
||||
void twist_init(mt_state_ptr st, uint64_t seed)
|
||||
{
|
||||
st->mti = NN + 1;
|
||||
|
||||
st->mt[0] = seed;
|
||||
|
||||
for (st->mti = 1; st->mti < NN; st->mti++)
|
||||
{
|
||||
st->mt[st->mti] = (UINT64_C(6364136223846793005) * (st->mt[st->mti - 1] ^ (st->mt[st->mti - 1] >> 62)) + st->mti);
|
||||
}
|
||||
}
|
||||
|
||||
// Generates a random uint64_t in [0, 2^64-1] interval
|
||||
uint64_t twist_uint64(mt_state_ptr st)
|
||||
{
|
||||
int i;
|
||||
uint64_t x;
|
||||
static uint64_t mag01[2] = {UINT64_C(0), MATRIX_A};
|
||||
|
||||
if (st->mti >= NN)
|
||||
{
|
||||
// Generate NN words at one time if twist_init() has not been called
|
||||
// A default initial seed is used
|
||||
if (st->mti == NN + 1)
|
||||
twist_init(st, UINT64_C(5489));
|
||||
|
||||
for (i = 0; i < NN - MM; i++)
|
||||
{
|
||||
x = (st->mt[i] & UM) | (st->mt[i + 1] & LM);
|
||||
st->mt[i] = st->mt[i + MM] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
|
||||
}
|
||||
|
||||
for (; i < NN - 1; i++)
|
||||
{
|
||||
x = (st->mt[i] & UM) | (st->mt[i + 1] & LM);
|
||||
st->mt[i] = st->mt[i + (MM - NN)] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
|
||||
}
|
||||
|
||||
x = (st->mt[NN - 1] & UM) | (st->mt[0] & LM);
|
||||
|
||||
st->mt[NN - 1] = st->mt[MM - 1] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
|
||||
|
||||
st->mti = 0;
|
||||
}
|
||||
|
||||
x = st->mt[st->mti++];
|
||||
|
||||
x ^= (x >> 29) & UINT64_C(0x5555555555555555);
|
||||
x ^= (x << 17) & UINT64_C(0x71D67FFFEDA60000);
|
||||
x ^= (x << 37) & UINT64_C(0xFFF7EEE000000000);
|
||||
x ^= (x >> 43);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// Generates a double in [0, 1) interval
|
||||
double twist_real(mt_state_ptr st)
|
||||
{
|
||||
return (twist_uint64(st) >> 11) * (1.0 / 9007199254740992.0);
|
||||
}
|
||||
@@ -22,6 +22,23 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
|
||||
@@ -43,19 +43,3 @@ struct SNAME
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
@@ -0,0 +1,845 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value);
|
||||
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_key)(struct SNAME *_map_, K key);
|
||||
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_val)(struct SNAME *_map_, V val);
|
||||
static struct CMC_DEF_ENTRY(SNAME) *
|
||||
*CMC_(PFX, _impl_add_entry_to_key)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry);
|
||||
static struct CMC_DEF_ENTRY(SNAME) *
|
||||
*CMC_(PFX, _impl_add_entry_to_val)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry);
|
||||
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
return CMC_(PFX, _new_custom)(capacity, load, f_key, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity == 0 || load <= 0 || load >= 1)
|
||||
return NULL;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= UINTMAX_MAX * load)
|
||||
return NULL;
|
||||
|
||||
if (!f_key || !f_val)
|
||||
return NULL;
|
||||
|
||||
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_map_)
|
||||
return NULL;
|
||||
|
||||
_map_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]));
|
||||
|
||||
if (!_map_->buffer)
|
||||
{
|
||||
alloc->free(_map_->buffer);
|
||||
alloc->free(_map_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_map_->count = 0;
|
||||
_map_->capacity = real_capacity;
|
||||
_map_->load = load;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
_map_->f_key = f_key;
|
||||
_map_->f_val = f_val;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
_map_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
|
||||
|
||||
return _map_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_map_)
|
||||
{
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
if (_map_->f_key->free)
|
||||
_map_->f_key->free(entry->key);
|
||||
if (_map_->f_val->free)
|
||||
_map_->f_val->free(entry->value);
|
||||
|
||||
_map_->alloc->free(entry);
|
||||
}
|
||||
|
||||
_map_->buffer[i][0] = NULL;
|
||||
_map_->buffer[i][1] = NULL;
|
||||
}
|
||||
|
||||
_map_->count = 0;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_map_)
|
||||
{
|
||||
CMC_(PFX, _clear)(_map_);
|
||||
|
||||
_map_->alloc->free(_map_->buffer);
|
||||
_map_->alloc->free(_map_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_map_, struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_map_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_map_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value)
|
||||
{
|
||||
if (CMC_(PFX, _full)(_map_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_map_, _map_->capacity + 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry_by_key)(_map_, key) != NULL ||
|
||||
CMC_(PFX, _impl_get_entry_by_val)(_map_, value) != NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_DUPLICATE;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_new_entry)(_map_, key, value);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **key_entry = CMC_(PFX, _impl_add_entry_to_key)(_map_, entry);
|
||||
struct CMC_DEF_ENTRY(SNAME) **val_entry = CMC_(PFX, _impl_add_entry_to_val)(_map_, entry);
|
||||
|
||||
if (!key_entry || !val_entry)
|
||||
{
|
||||
if (key_entry)
|
||||
*key_entry = CMC_ENTRY_DELETED;
|
||||
if (val_entry)
|
||||
*val_entry = CMC_ENTRY_DELETED;
|
||||
|
||||
_map_->alloc->free(entry);
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_map_->count++;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, create);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _update_key)(struct SNAME *_map_, V val, K new_key)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
|
||||
|
||||
val_entry = CMC_(PFX, _impl_get_entry_by_val)(_map_, val);
|
||||
|
||||
if (!val_entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The mapping val -> new_key is already true */
|
||||
if (_map_->f_key->cmp(new_key, (*val_entry)->key) == 0)
|
||||
goto success;
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry_by_key)(_map_, new_key) != NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_DUPLICATE;
|
||||
return false;
|
||||
}
|
||||
|
||||
key_entry = (*val_entry)->ref[0];
|
||||
|
||||
if (!key_entry || *key_entry != *val_entry)
|
||||
{
|
||||
/* Should never happen */
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Remove entry from key buffer and add it again with new key */
|
||||
struct CMC_DEF_ENTRY(SNAME) *to_add = *key_entry;
|
||||
K tmp_key = to_add->key;
|
||||
to_add->key = new_key;
|
||||
|
||||
*key_entry = CMC_ENTRY_DELETED;
|
||||
|
||||
if (!CMC_(PFX, _impl_add_entry_to_key)(_map_, to_add))
|
||||
{
|
||||
/* Revert changes */
|
||||
to_add->key = tmp_key;
|
||||
*key_entry = to_add;
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
success:
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, update);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _update_val)(struct SNAME *_map_, K key, V new_val)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
|
||||
|
||||
key_entry = CMC_(PFX, _impl_get_entry_by_key)(_map_, key);
|
||||
|
||||
if (!key_entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The mapping key -> new_val is already true */
|
||||
if (_map_->f_val->cmp(new_val, (*key_entry)->value) == 0)
|
||||
goto success;
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry_by_val)(_map_, new_val) != NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_DUPLICATE;
|
||||
return false;
|
||||
}
|
||||
|
||||
val_entry = (*key_entry)->ref[1];
|
||||
|
||||
if (!val_entry || *val_entry != *key_entry)
|
||||
{
|
||||
/* Should never happen */
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Remove entry from value buffer and add it again with new value */
|
||||
struct CMC_DEF_ENTRY(SNAME) *to_add = *val_entry;
|
||||
V tmp_val = to_add->value;
|
||||
to_add->value = new_val;
|
||||
|
||||
*val_entry = CMC_ENTRY_DELETED;
|
||||
|
||||
if (!CMC_(PFX, _impl_add_entry_to_val)(_map_, to_add))
|
||||
{
|
||||
/* Revert changes */
|
||||
to_add->value = tmp_val;
|
||||
*val_entry = to_add;
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
success:
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, update);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _remove_by_key)(struct SNAME *_map_, K key, K *out_key, V *out_val)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
|
||||
|
||||
key_entry = CMC_(PFX, _impl_get_entry_by_key)(_map_, key);
|
||||
|
||||
if (!key_entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
val_entry = (*key_entry)->ref[1];
|
||||
|
||||
if (!val_entry || *val_entry != *key_entry)
|
||||
{
|
||||
/* Should never happen */
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out_key)
|
||||
*out_key = (*key_entry)->key;
|
||||
if (out_val)
|
||||
*out_val = (*key_entry)->value;
|
||||
|
||||
_map_->alloc->free(*key_entry);
|
||||
|
||||
*key_entry = CMC_ENTRY_DELETED;
|
||||
*val_entry = CMC_ENTRY_DELETED;
|
||||
|
||||
_map_->count--;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, delete);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _remove_by_val)(struct SNAME *_map_, V val, K *out_key, V *out_val)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
|
||||
|
||||
val_entry = CMC_(PFX, _impl_get_entry_by_val)(_map_, val);
|
||||
|
||||
if (!val_entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
key_entry = (*val_entry)->ref[0];
|
||||
|
||||
if (!key_entry || *key_entry != *val_entry)
|
||||
{
|
||||
/* Should never happen */
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out_key)
|
||||
*out_key = (*val_entry)->key;
|
||||
if (out_val)
|
||||
*out_val = (*val_entry)->value;
|
||||
|
||||
_map_->alloc->free(*val_entry);
|
||||
|
||||
*key_entry = CMC_ENTRY_DELETED;
|
||||
*val_entry = CMC_ENTRY_DELETED;
|
||||
|
||||
_map_->count--;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, delete);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
K CMC_(PFX, _get_key)(struct SNAME *_map_, V val)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) **entry = CMC_(PFX, _impl_get_entry_by_val)(_map_, val);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return (K){ 0 };
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return (*entry)->key;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _get_val)(struct SNAME *_map_, K key)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) **entry = CMC_(PFX, _impl_get_entry_by_key)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return (*entry)->value;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains_key)(struct SNAME *_map_, K key)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = CMC_(PFX, _impl_get_entry_by_key)(_map_, key) != NULL;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains_val)(struct SNAME *_map_, V val)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = CMC_(PFX, _impl_get_entry_by_val)(_map_, val) != NULL;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_map_)
|
||||
{
|
||||
return (double)_map_->capacity * _map_->load <= (double)_map_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->capacity;
|
||||
}
|
||||
|
||||
double CMC_(PFX, _load)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->load;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_map_->capacity == capacity)
|
||||
goto success;
|
||||
|
||||
if (_map_->capacity > capacity / _map_->load)
|
||||
goto success;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= UINTMAX_MAX * _map_->load)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Calculate required capacity based on the prime numbers */
|
||||
size_t new_cap = CMC_(PFX, _impl_calculate_size)(capacity);
|
||||
|
||||
/* Not possible to shrink with current available prime numbers */
|
||||
if (new_cap < _map_->count / _map_->load)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* No callbacks since _new_map_ is just a temporary hashtable */
|
||||
struct SNAME *_new_map_ =
|
||||
CMC_(PFX, _new_custom)(capacity, _map_->load, _map_->f_key, _map_->f_val, _map_->alloc, NULL);
|
||||
|
||||
if (!_new_map_)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
if (scan && scan != CMC_ENTRY_DELETED)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) **e1 = CMC_(PFX, _impl_add_entry_to_key)(_new_map_, scan);
|
||||
struct CMC_DEF_ENTRY(SNAME) **e2 = CMC_(PFX, _impl_add_entry_to_val)(_new_map_, scan);
|
||||
|
||||
if (!e1 || !e2)
|
||||
{
|
||||
/* Prevent the map from freeing the data */
|
||||
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ NULL };
|
||||
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ NULL };
|
||||
|
||||
_map_->alloc->free(_new_map_->buffer);
|
||||
_map_->alloc->free(_new_map_);
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_new_map_->count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (_map_->count != _new_map_->count)
|
||||
{
|
||||
/* Prevent the map from freeing the data */
|
||||
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ NULL };
|
||||
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ NULL };
|
||||
|
||||
_map_->alloc->free(_new_map_->buffer);
|
||||
_map_->alloc->free(_new_map_);
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * (*tmp_buff)[2] = _map_->buffer;
|
||||
|
||||
_map_->buffer = _new_map_->buffer;
|
||||
_map_->capacity = _new_map_->capacity;
|
||||
|
||||
_map_->alloc->free(tmp_buff);
|
||||
_map_->alloc->free(_new_map_);
|
||||
|
||||
success:
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, resize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_)
|
||||
{
|
||||
/* TODO this function can be optimized */
|
||||
struct SNAME *result = CMC_(PFX, _new_custom)(_map_->capacity * _map_->load, _map_->load, _map_->f_key,
|
||||
_map_->f_val, _map_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _map_->callbacks);
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
if (scan && scan != CMC_ENTRY_DELETED)
|
||||
{
|
||||
K tmp_key;
|
||||
V tmp_val;
|
||||
|
||||
if (_map_->f_key->cpy)
|
||||
tmp_key = _map_->f_key->cpy(scan->key);
|
||||
else
|
||||
tmp_key = scan->key;
|
||||
|
||||
if (_map_->f_val->cpy)
|
||||
tmp_val = _map_->f_val->cpy(scan->value);
|
||||
else
|
||||
tmp_val = scan->value;
|
||||
|
||||
/* TODO treat the possible errors */
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_new_entry)(result, tmp_key, tmp_val);
|
||||
|
||||
CMC_(PFX, _impl_add_entry_to_key)(result, entry);
|
||||
CMC_(PFX, _impl_add_entry_to_val)(result, entry);
|
||||
|
||||
result->count++;
|
||||
}
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_)
|
||||
{
|
||||
_map1_->flag = CMC_FLAG_OK;
|
||||
_map2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_map1_->count != _map2_->count)
|
||||
return false;
|
||||
|
||||
struct SNAME *_mapA_;
|
||||
struct SNAME *_mapB_;
|
||||
|
||||
if (_map1_->capacity < _map2_->capacity)
|
||||
{
|
||||
_mapA_ = _map1_;
|
||||
_mapB_ = _map2_;
|
||||
}
|
||||
else
|
||||
{
|
||||
_mapA_ = _map2_;
|
||||
_mapB_ = _map1_;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _mapA_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _mapA_->buffer[i][0];
|
||||
|
||||
if (scan && scan != CMC_ENTRY_DELETED)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) **entry_B = CMC_(PFX, _impl_get_entry_by_key)(_mapB_, scan->key);
|
||||
|
||||
if (!entry_B)
|
||||
return false;
|
||||
|
||||
if (_mapA_->f_val->cmp((*entry_B)->value, scan->value) != 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->alloc->malloc(sizeof(struct CMC_DEF_ENTRY(SNAME)));
|
||||
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
entry->key = key;
|
||||
entry->value = value;
|
||||
entry->dist[0] = 0;
|
||||
entry->dist[1] = 0;
|
||||
entry->ref[0] = NULL;
|
||||
entry->ref[1] = NULL;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_key)(struct SNAME *_map_, K key)
|
||||
{
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
size_t pos = hash % _map_->capacity;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = _map_->buffer[pos][0];
|
||||
|
||||
while (target != NULL)
|
||||
{
|
||||
if (target != CMC_ENTRY_DELETED && _map_->f_key->cmp(target->key, key) == 0)
|
||||
return &(_map_->buffer[pos % _map_->capacity][0]);
|
||||
|
||||
pos++;
|
||||
target = _map_->buffer[pos % _map_->capacity][0];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_val)(struct SNAME *_map_, V val)
|
||||
{
|
||||
size_t hash = _map_->f_val->hash(val);
|
||||
size_t pos = hash % _map_->capacity;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = _map_->buffer[pos][1];
|
||||
|
||||
while (target != NULL)
|
||||
{
|
||||
if (target != CMC_ENTRY_DELETED && _map_->f_val->cmp(target->value, val) == 0)
|
||||
return &(_map_->buffer[pos % _map_->capacity][1]);
|
||||
|
||||
pos++;
|
||||
target = _map_->buffer[pos % _map_->capacity][1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) *
|
||||
*CMC_(PFX, _impl_add_entry_to_key)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) **to_return = NULL;
|
||||
|
||||
size_t hash = _map_->f_key->hash(entry->key);
|
||||
size_t original_pos = hash % _map_->capacity;
|
||||
size_t pos = original_pos;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **scan = &(_map_->buffer[hash % _map_->capacity][0]);
|
||||
|
||||
if (*scan == NULL)
|
||||
{
|
||||
*scan = entry;
|
||||
|
||||
entry->ref[0] = scan;
|
||||
|
||||
return scan;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
pos++;
|
||||
scan = &(_map_->buffer[pos % _map_->capacity][0]);
|
||||
|
||||
if (*scan == NULL || *scan == CMC_ENTRY_DELETED)
|
||||
{
|
||||
if (!to_return)
|
||||
to_return = scan;
|
||||
|
||||
*scan = entry;
|
||||
entry->ref[0] = scan;
|
||||
entry->dist[0] = pos - original_pos;
|
||||
|
||||
return to_return;
|
||||
}
|
||||
else if ((*scan)->dist[0] < pos - original_pos)
|
||||
{
|
||||
if (!to_return)
|
||||
to_return = scan;
|
||||
|
||||
size_t tmp_dist = (*scan)->dist[0];
|
||||
entry->dist[0] = pos - original_pos;
|
||||
original_pos = pos - tmp_dist;
|
||||
|
||||
entry->ref[0] = scan;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *_tmp_ = *scan;
|
||||
*scan = entry;
|
||||
entry = _tmp_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) *
|
||||
*CMC_(PFX, _impl_add_entry_to_val)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) **to_return = NULL;
|
||||
|
||||
size_t hash = _map_->f_val->hash(entry->value);
|
||||
size_t original_pos = hash % _map_->capacity;
|
||||
size_t pos = original_pos;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **scan = &(_map_->buffer[hash % _map_->capacity][1]);
|
||||
|
||||
if (*scan == NULL)
|
||||
{
|
||||
*scan = entry;
|
||||
|
||||
entry->ref[1] = scan;
|
||||
|
||||
return scan;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
pos++;
|
||||
scan = &(_map_->buffer[pos % _map_->capacity][1]);
|
||||
|
||||
if (*scan == NULL || *scan == CMC_ENTRY_DELETED)
|
||||
{
|
||||
if (!to_return)
|
||||
to_return = scan;
|
||||
|
||||
*scan = entry;
|
||||
entry->ref[1] = scan;
|
||||
entry->dist[1] = pos - original_pos;
|
||||
|
||||
return to_return;
|
||||
}
|
||||
else if ((*scan)->dist[1] < pos - original_pos)
|
||||
{
|
||||
if (!to_return)
|
||||
to_return = scan;
|
||||
|
||||
size_t tmp_dist = (*scan)->dist[1];
|
||||
entry->dist[1] = pos - original_pos;
|
||||
original_pos = pos - tmp_dist;
|
||||
|
||||
entry->ref[1] = scan;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *_tmp_ = *scan;
|
||||
*scan = entry;
|
||||
entry = _tmp_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
|
||||
{
|
||||
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
|
||||
|
||||
if (cmc_hashtable_primes[count - 1] < required)
|
||||
return required;
|
||||
|
||||
size_t i = 0;
|
||||
while (cmc_hashtable_primes[i] < required)
|
||||
i++;
|
||||
|
||||
return cmc_hashtable_primes[i];
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHBIDIMAP_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
return CMC_(PFX, _init_custom)(capacity, load, f_key, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
struct SNAME _map_ = { 0 };
|
||||
|
||||
if (capacity == 0 || load <= 0 || load >= 1)
|
||||
return _map_;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= UINTMAX_MAX * load)
|
||||
return _map_;
|
||||
|
||||
if (!f_key || !f_val)
|
||||
return _map_;
|
||||
|
||||
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
_map_.buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]));
|
||||
|
||||
if (!_map_.buffer)
|
||||
return _map_;
|
||||
|
||||
_map_.count = 0;
|
||||
_map_.capacity = real_capacity;
|
||||
_map_.load = load;
|
||||
_map_.flag = CMC_FLAG_OK;
|
||||
_map_.f_key = f_key;
|
||||
_map_.f_val = f_val;
|
||||
_map_.flag = CMC_FLAG_OK;
|
||||
_map_.alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(&_map_, callbacks);
|
||||
|
||||
return _map_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _release)(struct SNAME _map_)
|
||||
{
|
||||
CMC_(PFX, _clear)(&_map_);
|
||||
|
||||
_map_.alloc->free(_map_.buffer);
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_HASHBIDIMAP_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashbidimap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHBIDIMAP_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) * CMC_(PFX, _iter_new)(struct SNAME *target)
|
||||
{
|
||||
struct CMC_DEF_ITER(SNAME) *iter = target->alloc->malloc(sizeof(struct CMC_DEF_ITER(SNAME)));
|
||||
|
||||
if (!iter)
|
||||
return NULL;
|
||||
|
||||
CMC_(PFX, _iter_init)(iter, target);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _iter_free)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
iter->target->alloc->free(iter);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _iter_init)(struct CMC_DEF_ITER(SNAME) * iter, struct SNAME *target)
|
||||
{
|
||||
memset(iter, 0, sizeof(struct CMC_DEF_ITER(SNAME)));
|
||||
|
||||
iter->target = target;
|
||||
iter->start = true;
|
||||
iter->end = CMC_(PFX, _empty)(target);
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
iter->first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter->cursor = iter->first;
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i - 1][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
iter->last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->first;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->last;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = false;
|
||||
iter->end = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = iter->target->buffer[iter->cursor][0];
|
||||
|
||||
iter->index++;
|
||||
|
||||
while (1)
|
||||
{
|
||||
iter->cursor++;
|
||||
scan = iter->target->buffer[iter->cursor][0];
|
||||
|
||||
if (scan != NULL && scan != CMC_ENTRY_DELETED)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = iter->target->buffer[iter->cursor][0];
|
||||
|
||||
iter->index--;
|
||||
|
||||
while (1)
|
||||
{
|
||||
iter->cursor--;
|
||||
scan = iter->target->buffer[iter->cursor][0];
|
||||
|
||||
if (scan != NULL && scan != CMC_ENTRY_DELETED)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_next)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index < steps)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_prev)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at */
|
||||
/* the given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->index > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
|
||||
else if (iter->index < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->target->flag = CMC_FLAG_EMPTY;
|
||||
return (K){ 0 };
|
||||
}
|
||||
|
||||
return iter->target->buffer[iter->cursor][0]->key;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->target->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
return iter->target->buffer[iter->cursor][0]->value;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return iter->index;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_HASHBIDIMAP_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHBIDIMAP_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr)
|
||||
{
|
||||
struct SNAME *m_ = _map_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s, %s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"load:%lf, "
|
||||
"flag:%d, "
|
||||
"f_key:%p, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(K), CMC_TO_STRING(V), m_, m_->buffer, m_->capacity,
|
||||
m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, m_->alloc, CMC_CALLBACKS_GET(m_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *key_val_sep)
|
||||
{
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
size_t last = 0;
|
||||
for (size_t i = _map_->capacity; i > 0; i--)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i - 1][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
if (!_map_->f_key->str(fptr, entry->key))
|
||||
return false;
|
||||
|
||||
fprintf(fptr, "%s", key_val_sep);
|
||||
|
||||
if (!_map_->f_val->str(fptr, entry->value))
|
||||
return false;
|
||||
|
||||
if (i + 1 < last)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_HASHBIDIMAP_STR */
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHBIDIMAP_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks);
|
||||
void CMC_(PFX, _release)(struct SNAME _map_);
|
||||
|
||||
#endif /* CMC_EXT_HASHBIDIMAP_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashbidimap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHBIDIMAP_ITER
|
||||
|
||||
/* Iterator Functions */
|
||||
/* Iterator Allocation and Deallocation */
|
||||
struct CMC_DEF_ITER(SNAME) * CMC_(PFX, _iter_new)(struct SNAME *target);
|
||||
void CMC_(PFX, _iter_free)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Initialization */
|
||||
void CMC_(PFX, _iter_init)(struct CMC_DEF_ITER(SNAME) * iter, struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
void CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
void CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_HASHBIDIMAP_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHBIDIMAP_STR
|
||||
|
||||
/* Debug prints the struct to fptr */
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr);
|
||||
/* Prints each item in the hashbidimap as an array */
|
||||
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *key_val_sep);
|
||||
|
||||
#endif /* CMC_EXT_HASHBIDIMAP_STR */
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashbidimap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHBIDIMAP_ITER
|
||||
|
||||
/* HashBidiMap Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target hashbidimap */
|
||||
struct SNAME *target;
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
/* Keeps track of relative index to the iteration of elements */
|
||||
size_t index;
|
||||
/* The index of the first element */
|
||||
size_t first;
|
||||
/* The index of the last element */
|
||||
size_t last;
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#endif /* CMC_EXT_HASHBIDIMAP_ITER */
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Key struct function table */
|
||||
struct CMC_DEF_FKEY(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(K);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(K);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(K);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(K);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(K);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(K);
|
||||
};
|
||||
|
||||
/* Value struct function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_map_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_map_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_map_, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value);
|
||||
bool CMC_(PFX, _update_key)(struct SNAME *_map_, V val, K new_key);
|
||||
bool CMC_(PFX, _update_val)(struct SNAME *_map_, K key, V new_val);
|
||||
bool CMC_(PFX, _remove_by_key)(struct SNAME *_map_, K key, K *out_key, V *out_val);
|
||||
bool CMC_(PFX, _remove_by_val)(struct SNAME *_map_, V val, K *out_key, V *out_val);
|
||||
/* Element Access */
|
||||
K CMC_(PFX, _get_key)(struct SNAME *_map_, V val);
|
||||
V CMC_(PFX, _get_val)(struct SNAME *_map_, K key);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains_key)(struct SNAME *_map_, K key);
|
||||
bool CMC_(PFX, _contains_val)(struct SNAME *_map_, V val);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_map_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_map_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_map_);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_map_);
|
||||
double CMC_(PFX, _load)(struct SNAME *_map_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_map_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_);
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
struct SNAME
|
||||
{
|
||||
/* Array 0 is K -> V and array 1 is V -> K */
|
||||
struct CMC_DEF_ENTRY(SNAME) * (*buffer)[2];
|
||||
/* Current arrays capacity */
|
||||
size_t capacity;
|
||||
/* Current amount of keys */
|
||||
size_t count;
|
||||
/* Load factor in range (0.0, 1.0) */
|
||||
double load;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Key function table */
|
||||
struct CMC_DEF_FKEY(SNAME) * f_key;
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
struct CMC_ALLOC_NODE_NAME *alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
/* Methods */
|
||||
/* Returns an iterator to the start of the hashbidimap */
|
||||
struct CMC_DEF_ITER(SNAME) (*it_start)(struct SNAME *);
|
||||
/* Returns an iterator to the end of the hashbidimap */
|
||||
struct CMC_DEF_ITER(SNAME) (*it_end)(struct SNAME *);
|
||||
};
|
||||
|
||||
/* HashBidiMap Entry */
|
||||
struct CMC_DEF_ENTRY(SNAME)
|
||||
{
|
||||
/* Entry Key */
|
||||
K key;
|
||||
/* Entry Value */
|
||||
V value;
|
||||
/* The distance of this node to its original position */
|
||||
/* dist[0] is relative to K -> V */
|
||||
/* dist[1] is relative to V -> K */
|
||||
size_t dist[2];
|
||||
/* References to this node in the hashbidimap buffer. Used to */
|
||||
/* prevent searching for this node twice for update() and */
|
||||
/* remove(). Increases memory overhead but reduces execution time */
|
||||
/* ref[0] is relative to K -> V */
|
||||
/* ref[1] is relative to V -> K */
|
||||
struct CMC_DEF_ENTRY(SNAME) * *ref[2];
|
||||
};
|
||||
@@ -0,0 +1,636 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key);
|
||||
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
return CMC_(PFX, _new_custom)(capacity, load, f_key, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity == 0 || load <= 0 || load >= 1)
|
||||
return NULL;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= UINTMAX_MAX * load)
|
||||
return NULL;
|
||||
|
||||
if (!f_key || !f_val)
|
||||
return NULL;
|
||||
|
||||
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_map_)
|
||||
return NULL;
|
||||
|
||||
_map_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
|
||||
|
||||
if (!_map_->buffer)
|
||||
{
|
||||
alloc->free(_map_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_map_->count = 0;
|
||||
_map_->capacity = real_capacity;
|
||||
_map_->load = load;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
_map_->f_key = f_key;
|
||||
_map_->f_val = f_val;
|
||||
_map_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
|
||||
|
||||
return _map_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_map_)
|
||||
{
|
||||
if (_map_->f_key->free || _map_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_->buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
if (_map_->f_key->free)
|
||||
_map_->f_key->free(entry->key);
|
||||
if (_map_->f_val->free)
|
||||
_map_->f_val->free(entry->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(_map_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _map_->capacity);
|
||||
|
||||
_map_->count = 0;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_map_)
|
||||
{
|
||||
if (_map_->f_key->free || _map_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_->buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
if (_map_->f_key->free)
|
||||
_map_->f_key->free(entry->key);
|
||||
if (_map_->f_val->free)
|
||||
_map_->f_val->free(entry->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_map_->alloc->free(_map_->buffer);
|
||||
_map_->alloc->free(_map_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_map_, struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_map_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_map_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value)
|
||||
{
|
||||
if (CMC_(PFX, _full)(_map_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_map_, _map_->capacity + 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CMC_(PFX, _impl_get_entry)(_map_, key) != NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_DUPLICATE;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
size_t original_pos = hash % _map_->capacity;
|
||||
size_t pos = original_pos;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = &(_map_->buffer[pos]);
|
||||
|
||||
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
target->key = key;
|
||||
target->value = value;
|
||||
target->dist = 0;
|
||||
target->state = CMC_ES_FILLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
pos++;
|
||||
target = &(_map_->buffer[pos % _map_->capacity]);
|
||||
|
||||
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
target->key = key;
|
||||
target->value = value;
|
||||
target->dist = pos - original_pos;
|
||||
target->state = CMC_ES_FILLED;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (target->dist < pos - original_pos)
|
||||
{
|
||||
K tmp_k = target->key;
|
||||
V tmp_v = target->value;
|
||||
size_t tmp_dist = target->dist;
|
||||
|
||||
target->key = key;
|
||||
target->value = value;
|
||||
target->dist = pos - original_pos;
|
||||
|
||||
key = tmp_k;
|
||||
value = tmp_v;
|
||||
original_pos = pos - tmp_dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_map_->count++;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, create);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (old_value)
|
||||
*old_value = entry->value;
|
||||
|
||||
entry->value = new_value;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, update);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (result == NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out_value)
|
||||
*out_value = result->value;
|
||||
|
||||
result->key = (K){ 0 };
|
||||
result->value = (V){ 0 };
|
||||
result->dist = 0;
|
||||
result->state = CMC_ES_DELETED;
|
||||
|
||||
_map_->count--;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, delete);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
K max_key = (K){ 0 };
|
||||
V max_val = (V){ 0 };
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
if (_map_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
max_key = _map_->buffer[i].key;
|
||||
max_val = _map_->buffer[i].value;
|
||||
first = false;
|
||||
}
|
||||
else if (_map_->f_key->cmp(_map_->buffer[i].key, max_key) > 0)
|
||||
{
|
||||
max_key = _map_->buffer[i].key;
|
||||
max_val = _map_->buffer[i].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (key)
|
||||
*key = max_key;
|
||||
if (value)
|
||||
*value = max_val;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
K min_key = (K){ 0 };
|
||||
V min_val = (V){ 0 };
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
if (_map_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
min_key = _map_->buffer[i].key;
|
||||
min_val = _map_->buffer[i].value;
|
||||
first = false;
|
||||
}
|
||||
else if (_map_->f_key->cmp(_map_->buffer[i].key, min_key) < 0)
|
||||
{
|
||||
min_key = _map_->buffer[i].key;
|
||||
min_val = _map_->buffer[i].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (key)
|
||||
*key = min_key;
|
||||
if (value)
|
||||
*value = min_val;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _get)(struct SNAME *_map_, K key)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return entry->value;
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return &(entry->value);
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = CMC_(PFX, _impl_get_entry)(_map_, key) != NULL;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_map_)
|
||||
{
|
||||
return (double)_map_->capacity * _map_->load <= (double)_map_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->capacity;
|
||||
}
|
||||
|
||||
double CMC_(PFX, _load)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->load;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_map_->capacity == capacity)
|
||||
goto success;
|
||||
|
||||
if (_map_->capacity > capacity / _map_->load)
|
||||
goto success;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= UINTMAX_MAX * _map_->load)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Calculate required capacity based on the prime numbers */
|
||||
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
|
||||
|
||||
/* Not possible to shrink with current available prime numbers */
|
||||
if (theoretical_size < _map_->count / _map_->load)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* No callbacks since _new_map_ is just a temporary hashtable */
|
||||
struct SNAME *_new_map_ =
|
||||
CMC_(PFX, _new_custom)(capacity, _map_->load, _map_->f_key, _map_->f_val, _map_->alloc, NULL);
|
||||
|
||||
if (!_new_map_)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
if (_map_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
K key = _map_->buffer[i].key;
|
||||
V value = _map_->buffer[i].value;
|
||||
|
||||
/* TODO check this for possible errors */
|
||||
CMC_(PFX, _insert)(_new_map_, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Unlikely */
|
||||
if (_map_->count != _new_map_->count)
|
||||
{
|
||||
CMC_(PFX, _free)(_new_map_);
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *tmp_b = _map_->buffer;
|
||||
_map_->buffer = _new_map_->buffer;
|
||||
_new_map_->buffer = tmp_b;
|
||||
|
||||
size_t tmp_c = _map_->capacity;
|
||||
_map_->capacity = _new_map_->capacity;
|
||||
_new_map_->capacity = tmp_c;
|
||||
|
||||
/* Prevent the map from freeing the data */
|
||||
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ NULL };
|
||||
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ NULL };
|
||||
|
||||
CMC_(PFX, _free)(_new_map_);
|
||||
|
||||
success:
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, resize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_)
|
||||
{
|
||||
struct SNAME *result = CMC_(PFX, _new_custom)(_map_->capacity * _map_->load, _map_->load, _map_->f_key,
|
||||
_map_->f_val, _map_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _map_->callbacks);
|
||||
|
||||
if (_map_->f_key->cpy || _map_->f_val->cpy)
|
||||
{
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = &(_map_->buffer[i]);
|
||||
|
||||
if (scan->state != CMC_ES_EMPTY)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = &(result->buffer[i]);
|
||||
|
||||
if (scan->state == CMC_ES_DELETED)
|
||||
target->state = CMC_ES_DELETED;
|
||||
else
|
||||
{
|
||||
target->state = scan->state;
|
||||
target->dist = scan->dist;
|
||||
|
||||
if (_map_->f_key->cpy)
|
||||
target->key = _map_->f_key->cpy(scan->key);
|
||||
else
|
||||
target->key = scan->key;
|
||||
|
||||
if (_map_->f_val->cpy)
|
||||
target->value = _map_->f_val->cpy(scan->value);
|
||||
else
|
||||
target->value = scan->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
memcpy(result->buffer, _map_->buffer, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _map_->capacity);
|
||||
|
||||
result->count = _map_->count;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_)
|
||||
{
|
||||
_map1_->flag = CMC_FLAG_OK;
|
||||
_map2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_map1_->count != _map2_->count)
|
||||
return false;
|
||||
|
||||
/* Optimize loop using the smallest hashtable */
|
||||
struct SNAME *_map_a_;
|
||||
struct SNAME *_map_b_;
|
||||
|
||||
_map_a_ = _map1_->capacity < _map2_->capacity ? _map1_ : _map2_;
|
||||
_map_b_ = _map_a_ == _map1_ ? _map2_ : _map1_;
|
||||
|
||||
for (size_t i = 0; i < _map_a_->capacity; i++)
|
||||
{
|
||||
if (_map_a_->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry_a = &(_map_a_->buffer[i]);
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry_b = CMC_(PFX, _impl_get_entry)(_map_b_, entry_a->key);
|
||||
|
||||
if (!entry_b)
|
||||
return false;
|
||||
|
||||
if (_map_a_->f_val->cmp(entry_a->value, entry_b->value) != 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key)
|
||||
{
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
size_t pos = hash % _map_->capacity;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *target = &(_map_->buffer[pos]);
|
||||
|
||||
while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED)
|
||||
{
|
||||
if (target->state != CMC_ES_DELETED && _map_->f_key->cmp(target->key, key) == 0)
|
||||
return target;
|
||||
|
||||
pos++;
|
||||
target = &(_map_->buffer[pos % _map_->capacity]);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
|
||||
{
|
||||
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
|
||||
|
||||
if (cmc_hashtable_primes[count - 1] < required)
|
||||
return required;
|
||||
|
||||
size_t i = 0;
|
||||
while (cmc_hashtable_primes[i] < required)
|
||||
i++;
|
||||
|
||||
return cmc_hashtable_primes[i];
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMAP_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
return CMC_(PFX, _init_custom)(capacity, load, f_key, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
struct SNAME _map_ = { 0 };
|
||||
|
||||
if (capacity == 0 || load <= 0 || load >= 1)
|
||||
return _map_;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= UINTMAX_MAX * load)
|
||||
return _map_;
|
||||
|
||||
if (!f_key || !f_val)
|
||||
return _map_;
|
||||
|
||||
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
_map_.buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
|
||||
|
||||
if (!_map_.buffer)
|
||||
return _map_;
|
||||
|
||||
_map_.count = 0;
|
||||
_map_.capacity = real_capacity;
|
||||
_map_.load = load;
|
||||
_map_.flag = CMC_FLAG_OK;
|
||||
_map_.f_key = f_key;
|
||||
_map_.f_val = f_val;
|
||||
_map_.alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(&_map_, callbacks);
|
||||
|
||||
return _map_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _release)(struct SNAME _map_)
|
||||
{
|
||||
if (_map_.f_key->free || _map_.f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _map_.capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_.buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
if (_map_.f_key->free)
|
||||
_map_.f_key->free(entry->key);
|
||||
if (_map_.f_val->free)
|
||||
_map_.f_val->free(entry->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_map_.alloc->free(_map_.buffer);
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_HASHMAP_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashmap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMAP_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
|
||||
{
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
iter.first = 0;
|
||||
iter.last = 0;
|
||||
iter.start = true;
|
||||
iter.end = CMC_(PFX, _empty)(target);
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
if (target->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter.cursor = iter.first;
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
if (target->buffer[i - 1].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
|
||||
{
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
iter.first = 0;
|
||||
iter.last = 0;
|
||||
iter.start = CMC_(PFX, _empty)(target);
|
||||
iter.end = true;
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
if (target->buffer[i].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
if (target->buffer[i - 1].state == CMC_ES_FILLED)
|
||||
{
|
||||
iter.last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter.cursor = iter.last;
|
||||
iter.index = target->count - 1;
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->first;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->last;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
iter->end = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
iter->index++;
|
||||
|
||||
while (1)
|
||||
{
|
||||
iter->cursor++;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
if (scan->state == CMC_ES_FILLED)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
iter->index--;
|
||||
|
||||
while (1)
|
||||
{
|
||||
iter->cursor--;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
|
||||
if (scan->state == CMC_ES_FILLED)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_next)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index < steps)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_prev)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at the */
|
||||
/* given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->index > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
|
||||
else if (iter->index < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (K){ 0 };
|
||||
|
||||
return iter->target->buffer[iter->cursor].key;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (V){ 0 };
|
||||
|
||||
return iter->target->buffer[iter->cursor].value;
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return NULL;
|
||||
|
||||
return &(iter->target->buffer[iter->cursor].value);
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return iter->index;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_HASHMAP_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMAP_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr)
|
||||
{
|
||||
struct SNAME *m_ = _map_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s, %s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"load:%lf, "
|
||||
"flag:%d, "
|
||||
"f_key:%p, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(K), CMC_TO_STRING(V), m_, m_->buffer, m_->capacity,
|
||||
m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, m_->alloc, CMC_CALLBACKS_GET(m_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *key_val_sep)
|
||||
{
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
size_t last = 0;
|
||||
for (size_t i = _map_->capacity; i > 0; i--)
|
||||
{
|
||||
if ((_map_->buffer[i - 1]).state == CMC_ES_FILLED)
|
||||
{
|
||||
last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_->buffer[i]);
|
||||
|
||||
if (entry->state == CMC_ES_FILLED)
|
||||
{
|
||||
if (!_map_->f_key->str(fptr, entry->key))
|
||||
return false;
|
||||
|
||||
fprintf(fptr, "%s", key_val_sep);
|
||||
|
||||
if (!_map_->f_val->str(fptr, entry->value))
|
||||
return false;
|
||||
|
||||
if (i + 1 < last)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_HASHMAP_STR */
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMAP_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks);
|
||||
void CMC_(PFX, _release)(struct SNAME _map_);
|
||||
|
||||
#endif /* CMC_EXT_HASHMAP_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashmap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMAP_ITER
|
||||
|
||||
/* Iterator Initialization */
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_HASHMAP_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMAP_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr);
|
||||
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *key_val_sep);
|
||||
|
||||
#endif /* CMC_EXT_HASHMAP_STR */
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* List bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMAP_ITER
|
||||
|
||||
/* HashMap Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target hashmap */
|
||||
struct SNAME *target;
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
/* Keeps track of relative index to the iteration of elements */
|
||||
size_t index;
|
||||
/* The index of the first element */
|
||||
size_t first;
|
||||
/* The index of the last element */
|
||||
size_t last;
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#endif /* CMC_EXT_HASHMAP_ITER */
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Key struct function table */
|
||||
struct CMC_DEF_FKEY(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(K);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(K);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(K);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(K);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(K);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(K);
|
||||
};
|
||||
|
||||
/* Value struct function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_map_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_map_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_map_, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value);
|
||||
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value);
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value);
|
||||
/* Element Access */
|
||||
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value);
|
||||
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value);
|
||||
V CMC_(PFX, _get)(struct SNAME *_map_, K key);
|
||||
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_map_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_map_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_map_);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_map_);
|
||||
double CMC_(PFX, _load)(struct SNAME *_map_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_map_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_);
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* HashMap Structure */
|
||||
struct SNAME
|
||||
{
|
||||
/* Array of Entries */
|
||||
struct CMC_DEF_ENTRY(SNAME) * buffer;
|
||||
/* Current array capacity */
|
||||
size_t capacity;
|
||||
/* Current amount of keys */
|
||||
size_t count;
|
||||
/* Load factor in range (0.0, 1.0) */
|
||||
double load;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Key function table */
|
||||
struct CMC_DEF_FKEY(SNAME) * f_key;
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
struct CMC_ALLOC_NODE_NAME *alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
|
||||
/* HashMap Entry */
|
||||
struct CMC_DEF_ENTRY(SNAME)
|
||||
{
|
||||
/* Entry Key */
|
||||
K key;
|
||||
/* Entry Value */
|
||||
V value;
|
||||
/* The distance of this node to its original position, used by */
|
||||
/* robin-hood hashing */
|
||||
size_t dist;
|
||||
/* The sate of this node (DELETED, EMPTY, FILLED) */
|
||||
enum cmc_entry_state state;
|
||||
};
|
||||
@@ -0,0 +1,870 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value);
|
||||
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key);
|
||||
size_t CMC_(PFX, _impl_key_count)(struct SNAME *_map_, K key);
|
||||
size_t CMC_(PFX, _impl_calculate_size)(size_t required);
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
return CMC_(PFX, _new_custom)(capacity, load, f_key, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity == 0 || load <= 0)
|
||||
return NULL;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= UINTMAX_MAX * load)
|
||||
return NULL;
|
||||
|
||||
if (!f_key || !f_val)
|
||||
return NULL;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
|
||||
|
||||
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_map_)
|
||||
return NULL;
|
||||
|
||||
_map_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]));
|
||||
|
||||
if (!_map_->buffer)
|
||||
{
|
||||
alloc->free(_map_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_map_->count = 0;
|
||||
_map_->capacity = real_capacity;
|
||||
_map_->load = load;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
_map_->f_key = f_key;
|
||||
_map_->f_val = f_val;
|
||||
_map_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
|
||||
|
||||
return _map_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_map_)
|
||||
{
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
while (scan)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *next = scan->next;
|
||||
|
||||
if (_map_->f_key->free)
|
||||
_map_->f_key->free(scan->key);
|
||||
if (_map_->f_val->free)
|
||||
_map_->f_val->free(scan->value);
|
||||
|
||||
_map_->alloc->free(scan);
|
||||
|
||||
scan = next;
|
||||
}
|
||||
}
|
||||
|
||||
memset(_map_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]) * _map_->capacity);
|
||||
|
||||
_map_->count = 0;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_map_)
|
||||
{
|
||||
size_t index = 0;
|
||||
|
||||
while (index < _map_->capacity)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[index][0];
|
||||
|
||||
if (scan)
|
||||
{
|
||||
if (scan->next == NULL && scan->prev == NULL)
|
||||
{
|
||||
if (_map_->f_key->free)
|
||||
_map_->f_key->free(scan->key);
|
||||
if (_map_->f_val->free)
|
||||
_map_->f_val->free(scan->value);
|
||||
|
||||
_map_->alloc->free(scan);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (scan)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *tmp = scan;
|
||||
|
||||
scan = scan->next;
|
||||
|
||||
if (_map_->f_key->free)
|
||||
_map_->f_key->free(tmp->key);
|
||||
if (_map_->f_val->free)
|
||||
_map_->f_val->free(tmp->value);
|
||||
|
||||
_map_->alloc->free(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
_map_->alloc->free(_map_->buffer);
|
||||
_map_->alloc->free(_map_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_map_, struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_map_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_map_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value)
|
||||
{
|
||||
if (CMC_(PFX, _full)(_map_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_map_, _map_->capacity + 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
size_t pos = hash % _map_->capacity;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_new_entry)(_map_, key, value);
|
||||
|
||||
if (_map_->buffer[pos][0] == NULL)
|
||||
{
|
||||
_map_->buffer[pos][0] = entry;
|
||||
_map_->buffer[pos][1] = entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->prev = _map_->buffer[pos][1];
|
||||
|
||||
_map_->buffer[pos][1]->next = entry;
|
||||
_map_->buffer[pos][1] = entry;
|
||||
}
|
||||
|
||||
_map_->count++;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, create);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (old_value)
|
||||
*old_value = entry->value;
|
||||
|
||||
entry->value = new_value;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, update);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _update_all)(struct SNAME *_map_, K key, V new_value, V **old_values)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[hash % _map_->capacity][0];
|
||||
|
||||
if (entry == NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (old_values)
|
||||
{
|
||||
size_t total = CMC_(PFX, _impl_key_count)(_map_, key);
|
||||
|
||||
if (total == 0)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*old_values = _map_->alloc->malloc(sizeof(V) * total);
|
||||
|
||||
if (!(*old_values))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ALLOC;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
if (_map_->f_key->cmp(entry->key, key) == 0)
|
||||
{
|
||||
if (old_values)
|
||||
(*old_values)[index] = entry->value;
|
||||
|
||||
index++;
|
||||
entry->value = new_value;
|
||||
}
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, update);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **head = &(_map_->buffer[hash % _map_->capacity][0]);
|
||||
struct CMC_DEF_ENTRY(SNAME) **tail = &(_map_->buffer[hash % _map_->capacity][1]);
|
||||
|
||||
if (*head == NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = *head;
|
||||
|
||||
if (entry->next == NULL && entry->prev == NULL)
|
||||
{
|
||||
if (_map_->f_key->cmp(entry->key, key) == 0)
|
||||
{
|
||||
*head = NULL;
|
||||
*tail = NULL;
|
||||
|
||||
if (out_value)
|
||||
*out_value = entry->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
if (_map_->f_key->cmp(entry->key, key) == 0)
|
||||
{
|
||||
if (*head == entry)
|
||||
*head = entry->next;
|
||||
if (*tail == entry)
|
||||
*tail = entry->prev;
|
||||
|
||||
if (entry->prev)
|
||||
entry->prev->next = entry->next;
|
||||
if (entry->next)
|
||||
entry->next->prev = entry->prev;
|
||||
|
||||
if (out_value)
|
||||
*out_value = entry->value;
|
||||
|
||||
found = true;
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_map_->alloc->free(entry);
|
||||
|
||||
_map_->count--;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, delete);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _remove_all)(struct SNAME *_map_, K key, V **out_values)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) **head = &(_map_->buffer[hash % _map_->capacity][0]);
|
||||
struct CMC_DEF_ENTRY(SNAME) **tail = &(_map_->buffer[hash % _map_->capacity][1]);
|
||||
|
||||
if (*head == NULL)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (out_values)
|
||||
{
|
||||
size_t total = CMC_(PFX, _impl_key_count)(_map_, key);
|
||||
|
||||
if (total == 0)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out_values = _map_->alloc->malloc(sizeof(V) * total);
|
||||
|
||||
if (!(*out_values))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ALLOC;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = *head;
|
||||
|
||||
if (entry->next == NULL)
|
||||
{
|
||||
*head = NULL;
|
||||
*tail = NULL;
|
||||
|
||||
if (out_values)
|
||||
(*out_values)[index] = entry->value;
|
||||
|
||||
index++;
|
||||
_map_->alloc->free(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (entry)
|
||||
{
|
||||
if (_map_->f_key->cmp(entry->key, key) == 0)
|
||||
{
|
||||
if (*head == entry)
|
||||
*head = entry->next;
|
||||
if (*tail == entry)
|
||||
*tail = entry->prev;
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *next = entry->next;
|
||||
|
||||
if (entry->prev)
|
||||
entry->prev->next = entry->next;
|
||||
if (entry->next)
|
||||
entry->next->prev = entry->prev;
|
||||
|
||||
if (out_values)
|
||||
(*out_values)[index] = entry->value;
|
||||
|
||||
index++;
|
||||
_map_->alloc->free(entry);
|
||||
|
||||
entry = next;
|
||||
}
|
||||
else
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
_map_->count -= index;
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, delete);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
K max_key = (K){ 0 };
|
||||
V max_val = (V){ 0 };
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
while (scan)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
max_key = scan->key;
|
||||
max_val = scan->value;
|
||||
|
||||
first = false;
|
||||
}
|
||||
else if (_map_->f_key->cmp(scan->key, max_key) > 0)
|
||||
{
|
||||
max_key = scan->key;
|
||||
max_val = scan->value;
|
||||
}
|
||||
|
||||
scan = scan->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (key)
|
||||
*key = max_key;
|
||||
if (value)
|
||||
*value = max_val;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
K min_key = (K){ 0 };
|
||||
V min_val = (V){ 0 };
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
while (scan)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
min_key = scan->key;
|
||||
min_val = scan->value;
|
||||
|
||||
first = false;
|
||||
}
|
||||
else if (_map_->f_key->cmp(scan->key, min_key) < 0)
|
||||
{
|
||||
min_key = scan->key;
|
||||
min_val = scan->value;
|
||||
}
|
||||
|
||||
scan = scan->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (key)
|
||||
*key = min_key;
|
||||
if (value)
|
||||
*value = min_val;
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _get)(struct SNAME *_map_, K key)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return entry->value;
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_map_))
|
||||
{
|
||||
_map_->flag = CMC_FLAG_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_NOT_FOUND;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return &(entry->value);
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = CMC_(PFX, _impl_get_entry)(_map_, key) != NULL;
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, read);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_map_)
|
||||
{
|
||||
return (double)_map_->capacity * _map_->load <= (double)_map_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _key_count)(struct SNAME *_map_, K key)
|
||||
{
|
||||
return CMC_(PFX, _impl_key_count)(_map_, key);
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->capacity;
|
||||
}
|
||||
|
||||
double CMC_(PFX, _load)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->load;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_map_)
|
||||
{
|
||||
return _map_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_map_->capacity == capacity)
|
||||
goto success;
|
||||
|
||||
if (_map_->capacity > capacity / _map_->load)
|
||||
goto success;
|
||||
|
||||
/* Prevent integer overflow */
|
||||
if (capacity >= UINTMAX_MAX * _map_->load)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Calculate required capacity based on the prime numbers */
|
||||
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
|
||||
|
||||
/* Not possible to shrink with current available prime numbers */
|
||||
if (theoretical_size < _map_->count / _map_->load)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* No callbacks since _new_map_ is just a temporary hashtable */
|
||||
struct SNAME *_new_map_ =
|
||||
CMC_(PFX, _new_custom)(capacity, _map_->load, _map_->f_key, _map_->f_val, _map_->alloc, NULL);
|
||||
|
||||
if (!_new_map_)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
while (scan)
|
||||
{
|
||||
/* TODO check for errors */
|
||||
CMC_(PFX, _insert)(_new_map_, scan->key, scan->value);
|
||||
|
||||
scan = scan->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (_map_->count != _new_map_->count)
|
||||
{
|
||||
CMC_(PFX, _free)(_new_map_);
|
||||
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * (*tmp_b)[2] = _map_->buffer;
|
||||
_map_->buffer = _new_map_->buffer;
|
||||
_new_map_->buffer = tmp_b;
|
||||
|
||||
size_t tmp_c = _map_->capacity;
|
||||
_map_->capacity = _new_map_->capacity;
|
||||
_new_map_->capacity = tmp_c;
|
||||
|
||||
/* Prevent the map from freeing the data */
|
||||
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ NULL };
|
||||
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ NULL };
|
||||
|
||||
CMC_(PFX, _free)(_new_map_);
|
||||
|
||||
success:
|
||||
|
||||
CMC_CALLBACKS_CALL(_map_, resize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_)
|
||||
{
|
||||
/* Callback will be added later */
|
||||
struct SNAME *result = CMC_(PFX, _new_custom)(_map_->capacity * _map_->load, _map_->load, _map_->f_key,
|
||||
_map_->f_val, _map_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_map_->flag = CMC_FLAG_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
while (scan)
|
||||
{
|
||||
K key;
|
||||
V value;
|
||||
|
||||
if (_map_->f_key->cpy)
|
||||
key = _map_->f_key->cpy(scan->key);
|
||||
else
|
||||
key = scan->key;
|
||||
if (_map_->f_val->cpy)
|
||||
value = _map_->f_val->cpy(scan->value);
|
||||
else
|
||||
value = scan->value;
|
||||
|
||||
/* TODO check for errors */
|
||||
CMC_(PFX, _insert)(result, key, value);
|
||||
|
||||
scan = scan->next;
|
||||
}
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _map_->callbacks);
|
||||
_map_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_)
|
||||
{
|
||||
_map1_->flag = CMC_FLAG_OK;
|
||||
_map2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_map1_->count != _map2_->count)
|
||||
return false;
|
||||
|
||||
/* Optimize loop using the smallest hashtable */
|
||||
struct SNAME *_map_a_;
|
||||
struct SNAME *_map_b_;
|
||||
|
||||
_map_a_ = _map1_->capacity < _map2_->capacity ? _map1_ : _map2_;
|
||||
_map_b_ = _map_a_ == _map1_ ? _map2_ : _map1_;
|
||||
|
||||
for (size_t i = 0; i < _map_a_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_a_->buffer[i][0];
|
||||
|
||||
while (scan)
|
||||
{
|
||||
/* OPTIMIZE - This is calling key_count for repeating keys */
|
||||
if (CMC_(PFX, _impl_key_count)(_map_a_, scan->key) != CMC_(PFX, _impl_key_count)(_map_b_, scan->key))
|
||||
return false;
|
||||
|
||||
scan = scan->next;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->alloc->malloc(sizeof(struct CMC_DEF_ENTRY(SNAME)));
|
||||
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
entry->key = key;
|
||||
entry->value = value;
|
||||
entry->next = NULL;
|
||||
entry->prev = NULL;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key)
|
||||
{
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[hash % _map_->capacity][0];
|
||||
|
||||
while (entry)
|
||||
{
|
||||
if (_map_->f_key->cmp(entry->key, key) == 0)
|
||||
return entry;
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _impl_key_count)(struct SNAME *_map_, K key)
|
||||
{
|
||||
size_t hash = _map_->f_key->hash(key);
|
||||
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[hash % _map_->capacity][0];
|
||||
|
||||
size_t total_count = 0;
|
||||
|
||||
if (!entry)
|
||||
return total_count;
|
||||
|
||||
while (entry)
|
||||
{
|
||||
if (_map_->f_key->cmp(entry->key, key) == 0)
|
||||
total_count++;
|
||||
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
return total_count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _impl_calculate_size)(size_t required)
|
||||
{
|
||||
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
|
||||
|
||||
if (cmc_hashtable_primes[count - 1] < required)
|
||||
return required;
|
||||
|
||||
size_t i = 0;
|
||||
while (cmc_hashtable_primes[i] < required)
|
||||
i++;
|
||||
|
||||
return cmc_hashtable_primes[i];
|
||||
}
|
||||
@@ -0,0 +1,397 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMULTIMAP_INIT
|
||||
|
||||
#endif /* CMC_EXT_HASHMULTIMAP_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* List bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMULTIMAP_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
|
||||
{
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.curr_entry = NULL;
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
iter.first = 0;
|
||||
iter.last = 0;
|
||||
iter.start = true;
|
||||
iter.end = CMC_(PFX, _empty)(target);
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
iter.curr_entry = target->buffer[i][0];
|
||||
iter.first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter.cursor = iter.first;
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i - 1][1];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
iter.last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
|
||||
{
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.curr_entry = NULL;
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
iter.first = 0;
|
||||
iter.last = 0;
|
||||
iter.start = CMC_(PFX, _empty)(target);
|
||||
iter.end = true;
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i][0];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
iter.first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = target->capacity; i > 0; i--)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i - 1][1];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
iter.curr_entry = target->buffer[i - 1][1];
|
||||
iter.last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iter.cursor = iter.last;
|
||||
iter.index = target->count - 1;
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->first;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
iter->curr_entry = iter->target->buffer[iter->first][0];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->last;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
iter->end = true;
|
||||
iter->curr_entry = iter->target->buffer[iter->last][1];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->curr_entry->next != NULL)
|
||||
{
|
||||
iter->curr_entry = iter->curr_entry->next;
|
||||
iter->index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iter->cursor == iter->last)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->cursor++;
|
||||
|
||||
while (iter->target->buffer[iter->cursor][0] == NULL)
|
||||
iter->cursor++;
|
||||
|
||||
iter->curr_entry = iter->target->buffer[iter->cursor][0];
|
||||
|
||||
iter->index++;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->curr_entry->prev != NULL)
|
||||
{
|
||||
iter->curr_entry = iter->curr_entry->prev;
|
||||
iter->index--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iter->cursor == iter->first)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->cursor--;
|
||||
|
||||
while (iter->target->buffer[iter->cursor][1] == NULL)
|
||||
iter->cursor--;
|
||||
|
||||
iter->curr_entry = iter->target->buffer[iter->cursor][1];
|
||||
|
||||
iter->index--;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_next)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index < steps)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < steps; i++)
|
||||
CMC_(PFX, _iter_prev)(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at the */
|
||||
/* given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->index > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
|
||||
else if (iter->index < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (K){ 0 };
|
||||
|
||||
return iter->curr_entry->key;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (V){ 0 };
|
||||
|
||||
return iter->curr_entry->value;
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return NULL;
|
||||
|
||||
return &(iter->curr_entry->value);
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return iter->index;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_HASHMULTIMAP_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMULTIMAP_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr)
|
||||
{
|
||||
struct SNAME *m_ = _map_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s, %s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"load:%lf, "
|
||||
"flag:%d, "
|
||||
"f_key:%p, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(K), CMC_TO_STRING(V), m_, m_->buffer, m_->capacity,
|
||||
m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, m_->alloc, CMC_CALLBACKS_GET(m_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *key_val_sep)
|
||||
{
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
size_t last = 0;
|
||||
for (size_t i = _map_->capacity; i > 0; i--)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i - 1][1];
|
||||
|
||||
if (entry && entry != CMC_ENTRY_DELETED)
|
||||
{
|
||||
last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _map_->capacity; i++)
|
||||
{
|
||||
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
|
||||
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (!_map_->f_key->str(fptr, scan->key))
|
||||
return false;
|
||||
|
||||
fprintf(fptr, "%s", key_val_sep);
|
||||
|
||||
if (!_map_->f_val->str(fptr, scan->value))
|
||||
return false;
|
||||
|
||||
scan = scan->next;
|
||||
|
||||
if (i + 1 < last)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_HASHMULTIMAP_STR */
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMULTIMAP_INIT
|
||||
|
||||
#endif /* CMC_EXT_HASHMULTIMAP_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashmultimap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMULTIMAP_ITER
|
||||
|
||||
/* Iterator Initialization */
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_HASHMULTIMAP_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMULTIMAP_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr);
|
||||
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
|
||||
const char *key_val_sep);
|
||||
|
||||
#endif /* CMC_EXT_HASHMULTIMAP_STR */
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Hashmultimap bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_HASHMULTIMAP_ITER
|
||||
|
||||
/* HashMultiMap Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target hashmultimap */
|
||||
struct SNAME *target;
|
||||
/* Current entry */
|
||||
struct CMC_DEF_ENTRY(SNAME) * curr_entry;
|
||||
/* Cursor`s position (index) */
|
||||
size_t cursor;
|
||||
/* Keeps track of relative index to the iteration of elements */
|
||||
size_t index;
|
||||
/* The index of the first element */
|
||||
size_t first;
|
||||
/* The index of the last element */
|
||||
size_t last;
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#endif /* CMC_EXT_HASHMULTIMAP_ITER */
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Key struct function table */
|
||||
struct CMC_DEF_FKEY(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(K);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(K);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(K);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(K);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(K);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(K);
|
||||
};
|
||||
|
||||
/* Value struct function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_map_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_map_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_map_, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value);
|
||||
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value);
|
||||
size_t CMC_(PFX, _update_all)(struct SNAME *_map_, K key, V new_value, V **old_values);
|
||||
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value);
|
||||
size_t CMC_(PFX, _remove_all)(struct SNAME *_map_, K key, V **out_values);
|
||||
/* Element Access */
|
||||
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value);
|
||||
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value);
|
||||
V CMC_(PFX, _get)(struct SNAME *_map_, K key);
|
||||
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_map_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_map_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_map_);
|
||||
size_t CMC_(PFX, _key_count)(struct SNAME *_map_, K key);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_map_);
|
||||
double CMC_(PFX, _load)(struct SNAME *_map_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_map_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_);
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* HashMultimap Structure */
|
||||
struct SNAME
|
||||
{
|
||||
/* Array of linked list to entries */
|
||||
struct CMC_DEF_ENTRY(SNAME) * (*buffer)[2];
|
||||
/* Current array capacity */
|
||||
size_t capacity;
|
||||
/* Current amount of keys */
|
||||
size_t count;
|
||||
/* Load factor in range (0.0, infinity) */
|
||||
double load;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Key function table */
|
||||
struct CMC_DEF_FKEY(SNAME) * f_key;
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
struct CMC_ALLOC_NODE_NAME *alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
|
||||
/* HashMultimap Entry */
|
||||
struct CMC_DEF_ENTRY(SNAME)
|
||||
{
|
||||
/* Entry Key */
|
||||
K key;
|
||||
/* Entry Value */
|
||||
V value;
|
||||
/* Next entry on the linked list */
|
||||
struct CMC_DEF_ENTRY(SNAME) * next;
|
||||
/* Previous entry on the linked list */
|
||||
struct CMC_DEF_ENTRY(SNAME) * prev;
|
||||
};
|
||||
@@ -34,13 +34,10 @@ struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target List */
|
||||
struct SNAME *target;
|
||||
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
@@ -22,6 +22,23 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
|
||||
@@ -39,19 +39,3 @@ struct SNAME
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
@@ -0,0 +1,324 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
/* None */
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
return CMC_(PFX, _new_custom)(capacity, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity < 1)
|
||||
return NULL;
|
||||
|
||||
if (!f_val)
|
||||
return NULL;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
struct SNAME *_queue_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_queue_)
|
||||
return NULL;
|
||||
|
||||
_queue_->buffer = alloc->calloc(capacity, sizeof(V));
|
||||
|
||||
if (!_queue_->buffer)
|
||||
{
|
||||
alloc->free(_queue_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_queue_->capacity = capacity;
|
||||
_queue_->count = 0;
|
||||
_queue_->front = 0;
|
||||
_queue_->back = 0;
|
||||
_queue_->flag = CMC_FLAG_OK;
|
||||
_queue_->f_val = f_val;
|
||||
_queue_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_queue_, callbacks);
|
||||
|
||||
return _queue_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_queue_)
|
||||
{
|
||||
if (_queue_->f_val->free)
|
||||
{
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++)
|
||||
{
|
||||
_queue_->f_val->free(_queue_->buffer[i]);
|
||||
|
||||
i = (i + 1) % _queue_->capacity;
|
||||
}
|
||||
}
|
||||
|
||||
memset(_queue_->buffer, 0, sizeof(V) * _queue_->capacity);
|
||||
|
||||
_queue_->count = 0;
|
||||
_queue_->front = 0;
|
||||
_queue_->back = 0;
|
||||
_queue_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_queue_)
|
||||
{
|
||||
if (_queue_->f_val->free)
|
||||
{
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++)
|
||||
{
|
||||
_queue_->f_val->free(_queue_->buffer[i]);
|
||||
|
||||
i = (i + 1) % _queue_->capacity;
|
||||
}
|
||||
}
|
||||
|
||||
_queue_->alloc->free(_queue_->buffer);
|
||||
_queue_->alloc->free(_queue_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_queue_, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_queue_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_queue_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_queue_, callbacks);
|
||||
|
||||
_queue_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _enqueue)(struct SNAME *_queue_, V value)
|
||||
{
|
||||
if (CMC_(PFX, _full)(_queue_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_queue_, _queue_->capacity * 2))
|
||||
return false;
|
||||
}
|
||||
|
||||
_queue_->buffer[_queue_->back] = value;
|
||||
|
||||
_queue_->back = (_queue_->back == _queue_->capacity - 1) ? 0 : _queue_->back + 1;
|
||||
_queue_->count++;
|
||||
_queue_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_queue_, create);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _dequeue)(struct SNAME *_queue_)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_queue_))
|
||||
{
|
||||
_queue_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
_queue_->buffer[_queue_->front] = (V){ 0 };
|
||||
|
||||
_queue_->front = (_queue_->front == _queue_->capacity - 1) ? 0 : _queue_->front + 1;
|
||||
_queue_->count--;
|
||||
_queue_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_queue_, delete);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _peek)(struct SNAME *_queue_)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_queue_))
|
||||
{
|
||||
_queue_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_queue_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_queue_, read);
|
||||
|
||||
return _queue_->buffer[_queue_->front];
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_queue_, V value)
|
||||
{
|
||||
_queue_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++)
|
||||
{
|
||||
if (_queue_->f_val->cmp(_queue_->buffer[i], value) == 0)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
i = (i + 1) % _queue_->capacity;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_CALL(_queue_, read);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_queue_)
|
||||
{
|
||||
return _queue_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_queue_)
|
||||
{
|
||||
return _queue_->count >= _queue_->capacity;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_queue_)
|
||||
{
|
||||
return _queue_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_queue_)
|
||||
{
|
||||
return _queue_->capacity;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_queue_)
|
||||
{
|
||||
return _queue_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_queue_, size_t capacity)
|
||||
{
|
||||
if (_queue_->capacity == capacity)
|
||||
goto success;
|
||||
|
||||
if (capacity < _queue_->count)
|
||||
{
|
||||
_queue_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
V *new_buffer = _queue_->alloc->malloc(sizeof(V) * capacity);
|
||||
|
||||
if (!new_buffer)
|
||||
{
|
||||
_queue_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++)
|
||||
{
|
||||
new_buffer[j] = _queue_->buffer[i];
|
||||
|
||||
i = (i + 1) % _queue_->capacity;
|
||||
}
|
||||
|
||||
_queue_->alloc->free(_queue_->buffer);
|
||||
|
||||
_queue_->buffer = new_buffer;
|
||||
_queue_->capacity = capacity;
|
||||
_queue_->front = 0;
|
||||
_queue_->back = _queue_->count;
|
||||
|
||||
success:
|
||||
|
||||
_queue_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_queue_, resize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_queue_)
|
||||
{
|
||||
struct SNAME *result = CMC_(PFX, _new_custom)(_queue_->capacity, _queue_->f_val, _queue_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_queue_->flag = CMC_FLAG_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _queue_->callbacks);
|
||||
|
||||
if (_queue_->f_val->cpy)
|
||||
{
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++)
|
||||
{
|
||||
result->buffer[j] = _queue_->f_val->cpy(_queue_->buffer[i]);
|
||||
|
||||
i = (i + 1) % _queue_->capacity;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++)
|
||||
{
|
||||
result->buffer[j] = _queue_->buffer[i];
|
||||
|
||||
i = (i + 1) % _queue_->capacity;
|
||||
}
|
||||
}
|
||||
|
||||
result->count = _queue_->count;
|
||||
result->front = 0;
|
||||
result->back = _queue_->count;
|
||||
|
||||
_queue_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_queue1_, struct SNAME *_queue2_)
|
||||
{
|
||||
_queue1_->flag = CMC_FLAG_OK;
|
||||
_queue2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_queue1_->count != _queue2_->count)
|
||||
return false;
|
||||
|
||||
size_t i, j, k;
|
||||
for (i = _queue1_->front, j = _queue2_->front, k = 0; k < _queue1_->count; k++)
|
||||
{
|
||||
if (_queue1_->f_val->cmp(_queue1_->buffer[i], _queue2_->buffer[j]) != 0)
|
||||
return false;
|
||||
|
||||
i = (i + 1) % _queue1_->capacity;
|
||||
j = (j + 1) % _queue2_->capacity;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_QUEUE_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
return CMC_(PFX, _init_custom)(capacity, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
struct SNAME _queue_ = { 0 };
|
||||
|
||||
if (capacity < 1)
|
||||
return _queue_;
|
||||
|
||||
if (!f_val)
|
||||
return _queue_;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
_queue_.buffer = alloc->calloc(capacity, sizeof(V));
|
||||
|
||||
if (!_queue_.buffer)
|
||||
return _queue_;
|
||||
|
||||
_queue_.capacity = capacity;
|
||||
_queue_.count = 0;
|
||||
_queue_.front = 0;
|
||||
_queue_.back = 0;
|
||||
_queue_.flag = CMC_FLAG_OK;
|
||||
_queue_.f_val = f_val;
|
||||
_queue_.alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(&_queue_, callbacks);
|
||||
|
||||
return _queue_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _release)(struct SNAME _queue_)
|
||||
{
|
||||
if (_queue_.f_val->free)
|
||||
{
|
||||
for (size_t i = _queue_.front, j = 0; j < _queue_.count; j++)
|
||||
{
|
||||
_queue_.f_val->free(_queue_.buffer[i]);
|
||||
|
||||
i = (i + 1) % _queue_.capacity;
|
||||
}
|
||||
}
|
||||
|
||||
_queue_.alloc->free(_queue_.buffer);
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_QUEUE_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Queue bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_QUEUE_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
|
||||
{
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = target->front;
|
||||
iter.index = 0;
|
||||
iter.start = true;
|
||||
iter.end = CMC_(PFX, _empty)(target);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
|
||||
{
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
if (iter.target->back == 0)
|
||||
iter.cursor = iter.target->capacity - 1;
|
||||
else
|
||||
iter.cursor = iter.target->back - 1;
|
||||
|
||||
iter.index = iter.target->count - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
}
|
||||
|
||||
iter.start = CMC_(PFX, _empty)(target);
|
||||
iter.end = true;
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->target->front;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
if (iter->target->back == 0)
|
||||
iter->cursor = iter->target->capacity - 1;
|
||||
else
|
||||
iter->cursor = iter->target->back - 1;
|
||||
|
||||
iter->index = iter->target->count - 1;
|
||||
|
||||
iter->start = false;
|
||||
iter->end = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor = (iter->cursor + 1) % (iter->target->capacity);
|
||||
iter->index++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1;
|
||||
iter->index--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->index += steps;
|
||||
iter->cursor = (iter->cursor + steps) % iter->target->capacity;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index < steps)
|
||||
return false;
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->index -= steps;
|
||||
|
||||
/* Prevent underflow */
|
||||
if (iter->cursor < steps)
|
||||
iter->cursor += iter->target->capacity;
|
||||
|
||||
iter->cursor -= steps;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at the */
|
||||
/* given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->index > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
|
||||
else if (iter->index < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (V){ 0 };
|
||||
|
||||
return iter->target->buffer[iter->cursor];
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return NULL;
|
||||
|
||||
return &(iter->target->buffer[iter->cursor]);
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return iter->index;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_QUEUE_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_QUEUE_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_queue_, FILE *fptr)
|
||||
{
|
||||
struct SNAME *q_ = _queue_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"front:%" PRIuMAX ", "
|
||||
"back:%" PRIuMAX ", "
|
||||
"flag:%d, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), q_, q_->buffer, q_->capacity, q_->count, q_->front,
|
||||
q_->back, q_->flag, q_->f_val, q_->alloc, CMC_CALLBACKS_GET(q_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_queue_, FILE *fptr, const char *start, const char *separator, const char *end)
|
||||
{
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++)
|
||||
{
|
||||
if (!_queue_->f_val->str(fptr, _queue_->buffer[i]))
|
||||
return false;
|
||||
|
||||
i = (i + 1) % _queue_->capacity;
|
||||
|
||||
if (j + 1 < _queue_->count)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_QUEUE_STR */
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_QUEUE_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks);
|
||||
void CMC_(PFX, _release)(struct SNAME _queue_);
|
||||
|
||||
#endif /* CMC_EXT_QUEUE_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Queue bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_QUEUE_ITER
|
||||
|
||||
/* Iterator Initialization */
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_QUEUE_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_QUEUE_STR
|
||||
|
||||
/* Debug prints the struct to fptr */
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_queue_, FILE *fptr);
|
||||
/* Prints each item in the queue as an array */
|
||||
bool CMC_(PFX, _print)(struct SNAME *_queue_, FILE *fptr, const char *start, const char *separator, const char *end);
|
||||
|
||||
#endif /* CMC_EXT_QUEUE_STR */
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Queue bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_QUEUE_ITER
|
||||
|
||||
/* Queue Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target queue */
|
||||
struct SNAME *target;
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
/* Keeps track of relative index to the iteration of elements */
|
||||
size_t index;
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#endif /* CMC_EXT_QUEUE_ITER */
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_queue_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_queue_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_queue_, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _enqueue)(struct SNAME *_queue_, V value);
|
||||
bool CMC_(PFX, _dequeue)(struct SNAME *_queue_);
|
||||
/* Element Access */
|
||||
V CMC_(PFX, _peek)(struct SNAME *_queue_);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_queue_, V value);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_queue_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_queue_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_queue_);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_queue_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_queue_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_queue_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_queue_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_queue1_, struct SNAME *_queue2_);
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
struct SNAME
|
||||
{
|
||||
/* Dynamic circular array of elements */
|
||||
V *buffer;
|
||||
/* Current circular array capacity */
|
||||
size_t capacity;
|
||||
/* Current amount of elements */
|
||||
size_t count;
|
||||
/* Index representing the front of the queue */
|
||||
size_t front;
|
||||
/* Index representing the back of the queue */
|
||||
size_t back;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
struct CMC_ALLOC_NODE_NAME *alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
@@ -22,6 +22,23 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
|
||||
@@ -40,19 +40,3 @@ struct SNAME
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
/* Value struct function table */
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
@@ -49,12 +49,22 @@
|
||||
#undef CMC_EXT_DEQUE_ITER
|
||||
#undef CMC_EXT_DEQUE_STR
|
||||
|
||||
/* Hashbidimap */
|
||||
#undef CMC_EXT_HASHBIDIMAP_INIT
|
||||
#undef CMC_EXT_HASHBIDIMAP_ITER
|
||||
#undef CMC_EXT_HASHBIDIMAP_STR
|
||||
|
||||
/* List */
|
||||
#undef CMC_EXT_LIST_INIT
|
||||
#undef CMC_EXT_LIST_ITER
|
||||
#undef CMC_EXT_LIST_SEQ
|
||||
#undef CMC_EXT_LIST_STR
|
||||
|
||||
/* Queue */
|
||||
#undef CMC_EXT_QUEUE_INIT
|
||||
#undef CMC_EXT_QUEUE_ITER
|
||||
#undef CMC_EXT_QUEUE_STR
|
||||
|
||||
/* Stack */
|
||||
#undef CMC_EXT_STACK_INIT
|
||||
#undef CMC_EXT_STACK_ITER
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* cmc_deque.h
|
||||
* deque.h
|
||||
*
|
||||
* Creation Date: 20/03/2019
|
||||
*
|
||||
@@ -77,7 +77,7 @@
|
||||
* ITER - Deque iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_CMC_DEQUE_PARTS INIT, ITER, STR
|
||||
#define CMC_EXT_DEQUE_PARTS INIT, ITER, STR
|
||||
/**/
|
||||
#include "cmc/deque/ext/struct.h"
|
||||
/**/
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* hashbidimap.h
|
||||
*
|
||||
* Creation Date: 26/09/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* HashBidiMap
|
||||
*
|
||||
* A bidirectional map is a map that allows you to create a bijection in both
|
||||
* directions between two sets of elements (K <-> V). It is possible to retrieve
|
||||
* the value using a key or retrieve a key using a value. The naming (key and
|
||||
* value) is simply used to differentiate between one set of elements and the
|
||||
* other set of elements.
|
||||
*
|
||||
* Implementation
|
||||
*
|
||||
* This implementation uses two arrays of pointers to an entry containing both
|
||||
* the key and the value.
|
||||
*/
|
||||
|
||||
#include "cor/core.h"
|
||||
#include "cor/hashtable.h"
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* K - hashbidimap key data type
|
||||
* V - hashbidimap value data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/hashbidimap/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/hashbidimap/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/hashbidimap/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - Hashbidimap iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_HASHBIDIMAP_PARTS INIT, ITER, STR
|
||||
/**/
|
||||
#include "cmc/hashbidimap/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/hashbidimap/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/hashbidimap/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* hashmap.h
|
||||
*
|
||||
* Creation Date: 03/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* HashMap
|
||||
*
|
||||
* A HashMap is an implementation of a Map with unique keys, where every key is
|
||||
* mapped to a value. The keys are not sorted. It is implemented as a flat
|
||||
* hashtable with linear probing and robin hood hashing.
|
||||
*/
|
||||
|
||||
#include "cor/core.h"
|
||||
#include "cor/hashtable.h"
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* K - hashmap key data type
|
||||
* V - hashmap value data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/hashmap/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/hashmap/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/hashmap/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - hashmap iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_HASHMAP_PARTS INIT, ITER, STR
|
||||
/**/
|
||||
#include "cmc/hashmap/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/hashmap/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/hashmap/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* hashmultimap.h
|
||||
*
|
||||
* Creation Date: 26/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* HashMultiMap
|
||||
*
|
||||
* The HashMultiMap is a Map that allows for multiple keys. This is a data
|
||||
* structure that has a very narrow usage. A Map (either TreeMap or HashMap) can
|
||||
* also work like a HashMultiMap if a certain key is mapped to another
|
||||
* collection.
|
||||
*
|
||||
* Map<K = int, V = List<int>> maps an integer to a list of integer.
|
||||
* HashMultiMap<K = int, V = int> maps many integer keys to integer values.
|
||||
*
|
||||
* The difference is that in a HashMultiMap you can store keys that are the same
|
||||
* but might be different instances of the same value. This is also relevant if
|
||||
* your data type is more complex like a struct where its ID is the same but
|
||||
* some other members of this data type are different.
|
||||
*
|
||||
* Implementation
|
||||
*
|
||||
* The map uses separate chaining and robin hood hashing. Its internal buffer
|
||||
* is made of a pair of pointers to entries that represent a linked list. So
|
||||
* accessing map->buffer[0] would give the first pair of pointers. Each entry
|
||||
* has both a pointer to a previous entry and a next entry. This design choice
|
||||
* was made so that every collection in this library has a two-way iterator
|
||||
* with a very few exceptions.
|
||||
*
|
||||
* Each entry is composed of a Key and a Value. Entries with the same key should
|
||||
* always hash to the same linked list. Also, keys that hash to the same bucket
|
||||
* will also be in the same linked list.
|
||||
*
|
||||
* The order of inserting and removing the same keys will behave like a FIFO. So
|
||||
* the first key added will be the first to be removed.
|
||||
*/
|
||||
|
||||
#include "cor/core.h"
|
||||
#include "cor/hashtable.h"
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* K - hashmap key data type
|
||||
* V - hashmap value data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/hashmultimap/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/hashmultimap/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/hashmultimap/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - hashmultimap iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_HASHMULTIMAP_PARTS INIT, ITER, STR
|
||||
/**/
|
||||
#include "cmc/hashmultimap/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/hashmultimap/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/hashmultimap/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
+3
-2
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* cmc_list.h
|
||||
* list.h
|
||||
*
|
||||
* Creation Date: 12/02/2019
|
||||
*
|
||||
@@ -85,11 +85,12 @@
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* INIT - Initializes the struct on the stack
|
||||
* ITER - List iterator
|
||||
* SEQ - Push and pop sequence of items
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_CMC_LIST_PARTS INIT, ITER, SEQ, STR
|
||||
#define CMC_EXT_LIST_PARTS INIT, ITER, SEQ, STR
|
||||
/**/
|
||||
#include "cmc/list/ext/struct.h"
|
||||
/**/
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* queue.h
|
||||
*
|
||||
* Creation Date: 15/02/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Queue
|
||||
*
|
||||
* A Queue is a First-In First-out (or Last-in Last-out) data structure. It is
|
||||
* a Dynamic Circular Array where elements are added from one end of the array
|
||||
* and removed from the other end. The circular array here (also known as
|
||||
* circular buffer or ring buffer) is very important so that both adding and
|
||||
* removing elements from the Queue are done instantly. The array is linear but
|
||||
* with the modulo operator it is treated as a circular sequence of elements.
|
||||
*
|
||||
* If the Queue was implemented as a regular Dynamic Array, when adding or
|
||||
* removing an element at the front, it would be necessary to shift all elements
|
||||
* currently present in the Queue and this would add up a lot of computing time.
|
||||
* Shifting `100000` elements in memory by one position every time an element is
|
||||
* added to the Queue is simply not efficient.
|
||||
*
|
||||
* The Queue has two ends. The `front` and `back`. In this implementation all
|
||||
* elements are added to the back of the Queue and removed from the front, which
|
||||
* is more or less how queues work in real life. Unlike a Stack that only has
|
||||
* operations at one end of the buffer, the Queue needs to be implemented as a
|
||||
* circular array in order to quickly add or remove elements.
|
||||
*
|
||||
* The Queue has three main functions: `enqueue` which adds an element to the
|
||||
* Queue; `dequeue` which removes an element from the Queue; and `peek` which
|
||||
* return the element at the front of the Queue, that is, the next element to
|
||||
* be removed from it.
|
||||
*
|
||||
* The Queue is used in many applications where a resource is shared among
|
||||
* multiple consumers and the Queue is responsible for scheduling the access to
|
||||
* the resource.
|
||||
*/
|
||||
|
||||
#include "cor/core.h"
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* V - queue data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
|
||||
/* Structs definition */
|
||||
#include "cmc/queue/struct.h"
|
||||
|
||||
/* Function declaration */
|
||||
#include "cmc/queue/header.h"
|
||||
|
||||
/* Function implementation */
|
||||
#include "cmc/queue/code.h"
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*
|
||||
* ITER - List iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_QUEUE_PARTS INIT, ITER, STR
|
||||
/**/
|
||||
#include "cmc/queue/ext/struct.h"
|
||||
/**/
|
||||
#include "cmc/queue/ext/header.h"
|
||||
/**/
|
||||
#include "cmc/queue/ext/code.h"
|
||||
|
||||
#include "cor/undef.h"
|
||||
+3
-3
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* cmc_stack.h
|
||||
* stack.h
|
||||
*
|
||||
* Creation Date: 14/02/2019
|
||||
*
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
/**
|
||||
* Used values
|
||||
* V - Stack data type
|
||||
* V - stack data type
|
||||
* SNAME - struct name and prefix of other related structs
|
||||
* PFX - functions prefix
|
||||
*/
|
||||
@@ -73,7 +73,7 @@
|
||||
* ITER - Stack iterator
|
||||
* STR - Print helper functions
|
||||
*/
|
||||
#define CMC_EXT_CMC_STACK_PARTS INIT, ITER, STR
|
||||
#define CMC_EXT_STACK_PARTS INIT, ITER, STR
|
||||
/**/
|
||||
#include "cmc/stack/ext/struct.h"
|
||||
/**/
|
||||
|
||||
+9
-5
@@ -3,11 +3,15 @@ CFLAGS=-Wall -fprofile-arcs -ftest-coverage -g -O0
|
||||
INCLUDE=-I ../src
|
||||
|
||||
main:
|
||||
$(CC) ./main.c $(INCLUDE) $(CFLAGS) -o $@.exe
|
||||
valgrind --leak-check=yes ./$@.exe
|
||||
mkdir -p ./out
|
||||
$(CC) ./main.c $(INCLUDE) $(CFLAGS) -o ./out/$@.exe
|
||||
valgrind --leak-check=yes ./out/$@.exe
|
||||
gcov -p ./out/$@.gcda
|
||||
|
||||
dev: main
|
||||
mkdir -p ./coverage
|
||||
cd ./coverage && gcov -p ../main.gcda
|
||||
mv *.gcov ./coverage
|
||||
|
||||
clean:
|
||||
rm ./*.gcda ./*.gcno ./*.exe -f
|
||||
rm ./coverage -rf
|
||||
rm ./*.gcov ./*.gcda ./*.gcno ./*.exe -f
|
||||
rm ./coverage ./out -rf
|
||||
+9
-9
@@ -3,9 +3,9 @@
|
||||
|
||||
// #include "unt_bitset.h"
|
||||
#include "unt_deque.h"
|
||||
// #include "unt_hashbidimap.h"
|
||||
// #include "unt_hashmap.h"
|
||||
// #include "unt_hashmultimap.h"
|
||||
#include "unt_hashbidimap.h"
|
||||
#include "unt_hashmap.h"
|
||||
#include "unt_hashmultimap.h"
|
||||
// #include "unt_hashmultiset.h"
|
||||
// #include "unt_hashset.h"
|
||||
// #include "unt_heap.h"
|
||||
@@ -56,12 +56,12 @@ int main(void)
|
||||
// cmc_run(CMCBitSetIter, units, tests);
|
||||
cmc_run(CMCDeque, units, tests);
|
||||
cmc_run(CMCDequeIter, units, tests);
|
||||
// cmc_run(CMCHashBidiMap, units, tests);
|
||||
// cmc_run(CMCHashBidiMapIter, units, tests);
|
||||
// cmc_run(CMCHashMap, units, tests);
|
||||
// cmc_run(CMCHashMapIter, units, tests);
|
||||
// cmc_run(CMCHashMultiMap, units, tests);
|
||||
// cmc_run(CMCHashMultiMapIter, units, tests);
|
||||
cmc_run(CMCHashBidiMap, units, tests);
|
||||
cmc_run(CMCHashBidiMapIter, units, tests);
|
||||
cmc_run(CMCHashMap, units, tests);
|
||||
cmc_run(CMCHashMapIter, units, tests);
|
||||
cmc_run(CMCHashMultiMap, units, tests);
|
||||
cmc_run(CMCHashMultiMapIter, units, tests);
|
||||
// cmc_run(CMCHashMultiSet, units, tests);
|
||||
// cmc_run(CMCHashMultiSetIter, units, tests);
|
||||
// cmc_run(CMCHashSet, units, tests);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define SNAME deque
|
||||
#define CMC_EXT_DEQUE_INIT
|
||||
#define CMC_EXT_DEQUE_ITER
|
||||
#define CMC_EXT_DEQUE_STR
|
||||
#include "cmc/deque.h"
|
||||
|
||||
struct deque_fval *d_fval = &(struct deque_fval){
|
||||
|
||||
@@ -0,0 +1,818 @@
|
||||
#ifndef CMC_TESTS_UNT_HASHBIDIMAP_H
|
||||
#define CMC_TESTS_UNT_HASHBIDIMAP_H
|
||||
|
||||
#include "utl.h"
|
||||
|
||||
#define V size_t
|
||||
#define K size_t
|
||||
#define PFX hbm
|
||||
#define SNAME hashbidimap
|
||||
#define CMC_EXT_HASHBIDIMAP_INIT
|
||||
#define CMC_EXT_HASHBIDIMAP_ITER
|
||||
#define CMC_EXT_HASHBIDIMAP_STR
|
||||
#include "cmc/hashbidimap.h"
|
||||
|
||||
struct hashbidimap_fkey *hbm_fkey = &(struct hashbidimap_fkey){
|
||||
.cmp = cmc_size_cmp, .cpy = NULL, .str = cmc_size_str, .free = NULL, .hash = cmc_size_hash, .pri = cmc_size_cmp
|
||||
};
|
||||
|
||||
struct hashbidimap_fval *hbm_fval = &(struct hashbidimap_fval){
|
||||
.cmp = cmc_size_cmp, .cpy = NULL, .str = cmc_size_str, .free = NULL, .hash = cmc_size_hash, .pri = cmc_size_cmp
|
||||
};
|
||||
|
||||
struct hashbidimap_fkey *hbm_fkey_counter = &(struct hashbidimap_fkey){
|
||||
.cmp = k_c_cmp, .cpy = k_c_cpy, .str = k_c_str, .free = k_c_free, .hash = k_c_hash, .pri = k_c_pri
|
||||
};
|
||||
|
||||
struct hashbidimap_fval *hbm_fval_counter = &(struct hashbidimap_fval){
|
||||
.cmp = v_c_cmp, .cpy = v_c_cpy, .str = v_c_str, .free = v_c_free, .hash = v_c_hash, .pri = v_c_pri
|
||||
};
|
||||
|
||||
struct cmc_alloc_node *hbm_alloc_node =
|
||||
&(struct cmc_alloc_node){ .malloc = malloc, .calloc = calloc, .realloc = realloc, .free = free };
|
||||
|
||||
CMC_CREATE_UNIT(CMCHashBidiMap, true, {
|
||||
CMC_CREATE_TEST(PFX##_new(), {
|
||||
struct hashbidimap *map = hbm_new(943722, 0.6, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
cmc_assert_not_equals(ptr, NULL, map->buffer);
|
||||
cmc_assert_equals(size_t, 0, map->count);
|
||||
cmc_assert_equals(double, 0.6, map->load);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, map->flag);
|
||||
cmc_assert_equals(ptr, hbm_fkey, map->f_key);
|
||||
cmc_assert_equals(ptr, hbm_fval, map->f_val);
|
||||
cmc_assert_equals(ptr, cmc_alloc_node_default.malloc, map->alloc->malloc);
|
||||
cmc_assert_equals(ptr, cmc_alloc_node_default.calloc, map->alloc->calloc);
|
||||
cmc_assert_equals(ptr, cmc_alloc_node_default.realloc, map->alloc->realloc);
|
||||
cmc_assert_equals(ptr, cmc_alloc_node_default.free, map->alloc->free);
|
||||
cmc_assert_equals(ptr, NULL, map->callbacks);
|
||||
|
||||
cmc_assert_greater_equals(size_t, (943722 / 0.6), hbm_capacity(map));
|
||||
|
||||
hbm_free(map);
|
||||
|
||||
map = hbm_new(100, 0.6, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < map->capacity; i++)
|
||||
{
|
||||
cmc_assert_equals(ptr, NULL, map->buffer[i][0]);
|
||||
cmc_assert_equals(ptr, NULL, map->buffer[i][1]);
|
||||
}
|
||||
|
||||
hbm_free(map);
|
||||
|
||||
map = hbm_new(0, 0.6, hbm_fkey, hbm_fval);
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
map = hbm_new(UINT64_MAX, 0.99, hbm_fkey, hbm_fval);
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
map = hbm_new(1000, 0.6, hbm_fkey, NULL);
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
map = hbm_new(1000, 0.6, NULL, hbm_fval);
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
map = hbm_new(1000, 0.6, NULL, NULL);
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_new_custom(), {
|
||||
struct hashbidimap *map = hbm_new_custom(943722, 0.6, hbm_fkey, hbm_fval, hbm_alloc_node, callbacks);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
cmc_assert_not_equals(ptr, NULL, map->buffer);
|
||||
cmc_assert_equals(size_t, 0, map->count);
|
||||
cmc_assert_equals(double, 0.6, map->load);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, map->flag);
|
||||
cmc_assert_equals(ptr, hbm_fkey, map->f_key);
|
||||
cmc_assert_equals(ptr, hbm_fval, map->f_val);
|
||||
cmc_assert_equals(ptr, hbm_alloc_node, map->alloc);
|
||||
cmc_assert_equals(ptr, callbacks, map->callbacks);
|
||||
|
||||
cmc_assert_greater_equals(size_t, (943722 / 0.6), hbm_capacity(map));
|
||||
|
||||
hbm_free(map);
|
||||
|
||||
map = hbm_new_custom(0, 0.6, hbm_fkey, hbm_fval, NULL, NULL);
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
map = hbm_new_custom(UINT64_MAX, 0.99, hbm_fkey, hbm_fval, NULL, NULL);
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
map = hbm_new_custom(1000, 0.6, hbm_fkey, NULL, NULL, NULL);
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
map = hbm_new_custom(1000, 0.6, NULL, hbm_fval, NULL, NULL);
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
map = hbm_new_custom(1000, 0.6, NULL, NULL, NULL, NULL);
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_clear(), {
|
||||
k_total_free = 0;
|
||||
v_total_free = 0;
|
||||
struct hashbidimap *map = hbm_new(100, 0.6, hbm_fkey_counter, hbm_fval_counter);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 1; i <= 1000; i++)
|
||||
hbm_insert(map, i, i);
|
||||
|
||||
cmc_assert_equals(size_t, 1000, map->count);
|
||||
|
||||
map->flag = CMC_FLAG_ERROR;
|
||||
hbm_clear(map);
|
||||
|
||||
cmc_assert_equals(size_t, 0, map->count);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, map->flag);
|
||||
cmc_assert_equals(int32_t, 1000, k_total_free);
|
||||
cmc_assert_equals(int32_t, 1000, v_total_free);
|
||||
|
||||
hbm_free(map);
|
||||
k_total_free = 0;
|
||||
v_total_free = 0;
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_free(), {
|
||||
k_total_free = 0;
|
||||
v_total_free = 0;
|
||||
struct hashbidimap *map = hbm_new(100, 0.6, hbm_fkey_counter, hbm_fval_counter);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 1; i <= 1000; i++)
|
||||
hbm_insert(map, i, i);
|
||||
|
||||
cmc_assert_equals(size_t, 1000, map->count);
|
||||
|
||||
hbm_free(map);
|
||||
|
||||
cmc_assert_equals(int32_t, 1000, k_total_free);
|
||||
cmc_assert_equals(int32_t, 1000, v_total_free);
|
||||
|
||||
map = hbm_new(1000, 0.6, hbm_fkey_counter, hbm_fval_counter);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
cmc_assert_not_equals(ptr, NULL, map->buffer);
|
||||
|
||||
hbm_free(map);
|
||||
|
||||
cmc_assert_equals(int32_t, 1000, k_total_free);
|
||||
cmc_assert_equals(int32_t, 1000, v_total_free);
|
||||
k_total_free = 0;
|
||||
v_total_free = 0;
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(customize, {
|
||||
struct hashbidimap *map = hbm_new_custom(100, 0.6, hbm_fkey, hbm_fval, NULL, NULL);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert_equals(ptr, cmc_alloc_node_default.malloc, map->alloc->malloc);
|
||||
cmc_assert_equals(ptr, cmc_alloc_node_default.calloc, map->alloc->calloc);
|
||||
cmc_assert_equals(ptr, cmc_alloc_node_default.realloc, map->alloc->realloc);
|
||||
cmc_assert_equals(ptr, cmc_alloc_node_default.free, map->alloc->free);
|
||||
cmc_assert_equals(ptr, NULL, map->callbacks);
|
||||
|
||||
hbm_free(map);
|
||||
|
||||
struct cmc_alloc_node node;
|
||||
node.malloc = malloc;
|
||||
node.realloc = realloc;
|
||||
node.free = free;
|
||||
node.calloc = calloc;
|
||||
|
||||
map = hbm_new_custom(100, 0.6, hbm_fkey, hbm_fval, &node, callbacks);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert_equals(ptr, &node, map->alloc);
|
||||
cmc_assert_equals(ptr, callbacks, map->callbacks);
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[capacity = 1], {
|
||||
struct hashbidimap *map = hbm_new(1, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 1; i <= 10000; i++)
|
||||
cmc_assert(hbm_insert(map, i, i));
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = 0; i < hbm_capacity(map); i++)
|
||||
{
|
||||
if (map->buffer[i][0] && map->buffer[i][0] != CMC_ENTRY_DELETED)
|
||||
{
|
||||
sum += map->buffer[i][0]->key;
|
||||
}
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 50005000, sum);
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert, {
|
||||
struct hashbidimap *map = hbm_new(100, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert(hbm_insert(map, 1, 1));
|
||||
cmc_assert(hbm_insert(map, 2, 2));
|
||||
cmc_assert(hbm_insert(map, 3, 3));
|
||||
|
||||
cmc_assert_equals(size_t, 3, hbm_count(map));
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[duplicate], {
|
||||
struct hashbidimap *map = hbm_new(100, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert(hbm_insert(map, 1, 1));
|
||||
cmc_assert(!hbm_insert(map, 1, 1));
|
||||
cmc_assert(!hbm_insert(map, 2, 1));
|
||||
cmc_assert(!hbm_insert(map, 1, 2));
|
||||
cmc_assert(hbm_insert(map, 2, 2));
|
||||
|
||||
cmc_assert_equals(size_t, 2, hbm_count(map));
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[references], {
|
||||
struct hashbidimap *map = hbm_new(500, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 500; i++)
|
||||
cmc_assert(hbm_insert(map, i, i));
|
||||
|
||||
for (size_t i = 0; i < map->capacity; i++)
|
||||
{
|
||||
struct hashbidimap_entry *kentry = map->buffer[i][0];
|
||||
struct hashbidimap_entry *ventry = map->buffer[i][1];
|
||||
|
||||
if (kentry && kentry != CMC_ENTRY_DELETED)
|
||||
cmc_assert_equals(ptr, kentry, *(kentry->ref[0]));
|
||||
if (ventry && ventry != CMC_ENTRY_DELETED)
|
||||
cmc_assert_equals(ptr, ventry, *(ventry->ref[1]));
|
||||
}
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[growth remove clear], {
|
||||
struct hashbidimap *map = hbm_new(100, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 1; i <= 1000; i++)
|
||||
cmc_assert(hbm_insert(map, i, i));
|
||||
|
||||
cmc_assert_equals(size_t, 1000, hbm_count(map));
|
||||
|
||||
size_t j = 1;
|
||||
while (!hbm_empty(map))
|
||||
{
|
||||
if (hbm_count(map) % 2 == 0)
|
||||
cmc_assert(hbm_remove_by_key(map, j++, NULL, NULL));
|
||||
else
|
||||
cmc_assert(hbm_remove_by_val(map, j++, NULL, NULL));
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 0, hbm_count(map));
|
||||
|
||||
for (size_t i = 1; i <= 1000; i++)
|
||||
cmc_assert(hbm_insert(map, i, i));
|
||||
|
||||
cmc_assert_equals(size_t, 1000, hbm_count(map));
|
||||
|
||||
hbm_clear(map);
|
||||
|
||||
cmc_assert_equals(size_t, 0, hbm_count(map));
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[ftab hash calls], {
|
||||
struct hashbidimap *map = hbm_new(100, 0.7, hbm_fkey_counter, hbm_fval_counter);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
k_total_hash = 0;
|
||||
v_total_hash = 0;
|
||||
|
||||
for (size_t i = 1; i <= 1000; i++)
|
||||
cmc_assert(hbm_insert(map, i, i));
|
||||
|
||||
cmc_assert_greater_equals(int32_t, 1000, k_total_hash);
|
||||
cmc_assert_greater_equals(int32_t, 1000, v_total_hash);
|
||||
|
||||
hbm_free(map);
|
||||
|
||||
k_total_hash = 0;
|
||||
v_total_hash = 0;
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(update_key, {
|
||||
struct hashbidimap *map = hbm_new(100, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(hbm_insert(map, i, i));
|
||||
|
||||
cmc_assert_equals(size_t, 100, hbm_count(map));
|
||||
|
||||
for (size_t i = 100; i > 0; i--)
|
||||
cmc_assert(hbm_update_key(map, i, i + 10));
|
||||
|
||||
cmc_assert_equals(size_t, 100, hbm_count(map));
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert_equals(size_t, i + 10, hbm_get_key(map, i));
|
||||
|
||||
cmc_assert_equals(size_t, 100, hbm_count(map));
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(update_key[empty], {
|
||||
struct hashbidimap *map = hbm_new(100, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert_equals(size_t, 0, hbm_count(map));
|
||||
|
||||
cmc_assert(!hbm_update_key(map, 1, 1));
|
||||
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, hbm_flag(map));
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(update_key[not_found duplicate], {
|
||||
struct hashbidimap *map = hbm_new(100, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert(hbm_insert(map, 1, 1));
|
||||
|
||||
cmc_assert_equals(size_t, 1, hbm_count(map));
|
||||
|
||||
map->flag = CMC_FLAG_ERROR;
|
||||
cmc_assert(hbm_update_key(map, 1, 1));
|
||||
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
|
||||
cmc_assert(!hbm_update_key(map, 2, 2));
|
||||
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_NOT_FOUND, hbm_flag(map));
|
||||
|
||||
cmc_assert(hbm_insert(map, 2, 2));
|
||||
|
||||
cmc_assert(!hbm_update_key(map, 1, 2));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_DUPLICATE, hbm_flag(map));
|
||||
cmc_assert(!hbm_update_key(map, 2, 1));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_DUPLICATE, hbm_flag(map));
|
||||
|
||||
cmc_assert(hbm_update_key(map, 2, 2));
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(update_val, {
|
||||
struct hashbidimap *map = hbm_new(100, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(hbm_insert(map, i, i));
|
||||
|
||||
cmc_assert_equals(size_t, 100, hbm_count(map));
|
||||
|
||||
for (size_t i = 100; i > 0; i--)
|
||||
cmc_assert(hbm_update_val(map, i, i + 10));
|
||||
|
||||
cmc_assert_equals(size_t, 100, hbm_count(map));
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert_equals(size_t, i + 10, hbm_get_val(map, i));
|
||||
|
||||
cmc_assert_equals(size_t, 100, hbm_count(map));
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(update_val[empty], {
|
||||
struct hashbidimap *map = hbm_new(100, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert_equals(size_t, 0, hbm_count(map));
|
||||
|
||||
cmc_assert(!hbm_update_val(map, 1, 1));
|
||||
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, hbm_flag(map));
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(update_val[not_found duplicate], {
|
||||
struct hashbidimap *map = hbm_new(100, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert(hbm_insert(map, 1, 1));
|
||||
|
||||
cmc_assert_equals(size_t, 1, hbm_count(map));
|
||||
|
||||
map->flag = CMC_FLAG_ERROR;
|
||||
cmc_assert(hbm_update_val(map, 1, 1));
|
||||
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
|
||||
cmc_assert(!hbm_update_val(map, 2, 2));
|
||||
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_NOT_FOUND, hbm_flag(map));
|
||||
|
||||
cmc_assert(hbm_insert(map, 2, 2));
|
||||
|
||||
cmc_assert(!hbm_update_val(map, 1, 2));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_DUPLICATE, hbm_flag(map));
|
||||
cmc_assert(!hbm_update_val(map, 2, 1));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_DUPLICATE, hbm_flag(map));
|
||||
|
||||
cmc_assert(hbm_update_val(map, 2, 2));
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove_by_key[cleanup custom], {
|
||||
struct hashbidimap *map = hbm_new_custom(
|
||||
10000, 0.6, hbm_fkey, hbm_fval,
|
||||
&(struct cmc_alloc_node){ .malloc = malloc, .calloc = calloc, .realloc = realloc, .free = free },
|
||||
&(struct cmc_callbacks){ 0 });
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 10000; i++)
|
||||
{
|
||||
cmc_assert(hbm_insert(map, i, i));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 10000; i++)
|
||||
{
|
||||
cmc_assert(hbm_remove_by_key(map, i, NULL, NULL));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < map->capacity; i++)
|
||||
{
|
||||
struct hashbidimap_entry *k = map->buffer[i][0];
|
||||
struct hashbidimap_entry *v = map->buffer[i][1];
|
||||
|
||||
cmc_assert((k == NULL || k == CMC_ENTRY_DELETED) && (v == NULL || v == CMC_ENTRY_DELETED));
|
||||
}
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove_by_val[cleanup custom], {
|
||||
struct hashbidimap *map = hbm_new_custom(
|
||||
10000, 0.6, hbm_fkey, hbm_fval,
|
||||
&(struct cmc_alloc_node){ .malloc = malloc, .calloc = calloc, .realloc = realloc, .free = free },
|
||||
&(struct cmc_callbacks){ 0 });
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 10000; i++)
|
||||
{
|
||||
cmc_assert(hbm_insert(map, i, i));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 10000; i++)
|
||||
{
|
||||
cmc_assert(hbm_remove_by_val(map, i, NULL, NULL));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < map->capacity; i++)
|
||||
{
|
||||
struct hashbidimap_entry *k = map->buffer[i][0];
|
||||
struct hashbidimap_entry *v = map->buffer[i][1];
|
||||
|
||||
cmc_assert((k == NULL || k == CMC_ENTRY_DELETED) && (v == NULL || v == CMC_ENTRY_DELETED));
|
||||
}
|
||||
|
||||
hbm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(copy_of, {
|
||||
struct hashbidimap *map1 = hbm_new(100, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(hbm_insert(map1, i, i));
|
||||
|
||||
struct hashbidimap *map2 = hbm_copy_of(map1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map2);
|
||||
cmc_assert_equals(size_t, hbm_count(map1), hbm_count(map2));
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
{
|
||||
cmc_assert(hbm_contains_key(map2, i) && hbm_contains_key(map1, i));
|
||||
cmc_assert(hbm_contains_val(map2, i) && hbm_contains_val(map1, i));
|
||||
}
|
||||
|
||||
hbm_free(map1);
|
||||
hbm_free(map2);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(equals, {
|
||||
struct hashbidimap *map1 = hbm_new(100, 0.7, hbm_fkey, hbm_fval);
|
||||
struct hashbidimap *map2 = hbm_new(1000, 0.9, hbm_fkey, hbm_fval);
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
{
|
||||
cmc_assert(hbm_insert(map1, i, i));
|
||||
cmc_assert(hbm_insert(map2, 99 - i, 99 - i));
|
||||
}
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map1);
|
||||
cmc_assert_not_equals(ptr, NULL, map2);
|
||||
cmc_assert_equals(size_t, hbm_count(map1), hbm_count(map2));
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
{
|
||||
cmc_assert(hbm_contains_key(map2, i) && hbm_contains_key(map1, i));
|
||||
cmc_assert(hbm_contains_val(map2, i) && hbm_contains_val(map1, i));
|
||||
}
|
||||
|
||||
hbm_free(map1);
|
||||
hbm_free(map2);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(equals[from copy], {
|
||||
struct hashbidimap *map1 = hbm_new(100, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(hbm_insert(map1, i, i));
|
||||
|
||||
struct hashbidimap *map2 = hbm_copy_of(map1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map2);
|
||||
|
||||
cmc_assert(hbm_equals(map1, map2));
|
||||
|
||||
hbm_free(map1);
|
||||
hbm_free(map2);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(flags, {
|
||||
struct hashbidimap *map = hbm_new(100, 0.7, hbm_fkey, hbm_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
|
||||
// customize
|
||||
hbm_customize(map, &cmc_alloc_node_default, &(struct cmc_callbacks){ 0 });
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
|
||||
// Insert
|
||||
cmc_assert(hbm_insert(map, 1, 1));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
|
||||
cmc_assert(!hbm_insert(map, 1, 2));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_DUPLICATE, hbm_flag(map));
|
||||
map->flag = CMC_FLAG_ERROR;
|
||||
cmc_assert(!hbm_insert(map, 2, 1));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_DUPLICATE, hbm_flag(map));
|
||||
|
||||
// clear
|
||||
hbm_clear(map);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
|
||||
// hbm_update_key
|
||||
cmc_assert(!hbm_update_key(map, 1, 1));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, hbm_flag(map));
|
||||
|
||||
cmc_assert(hbm_insert(map, 1, 1));
|
||||
cmc_assert(!hbm_update_key(map, 2, 1));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_NOT_FOUND, hbm_flag(map));
|
||||
|
||||
cmc_assert(hbm_insert(map, 2, 2));
|
||||
cmc_assert(!hbm_update_key(map, 2, 1));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_DUPLICATE, hbm_flag(map));
|
||||
map->flag = CMC_FLAG_ERROR;
|
||||
cmc_assert(!hbm_update_key(map, 1, 2));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_DUPLICATE, hbm_flag(map));
|
||||
|
||||
// clear
|
||||
hbm_clear(map);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
|
||||
// hbm_update_val
|
||||
cmc_assert(!hbm_update_val(map, 1, 1));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, hbm_flag(map));
|
||||
|
||||
cmc_assert(hbm_insert(map, 1, 1));
|
||||
cmc_assert(!hbm_update_val(map, 2, 1));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_NOT_FOUND, hbm_flag(map));
|
||||
|
||||
cmc_assert(hbm_insert(map, 2, 2));
|
||||
cmc_assert(!hbm_update_val(map, 2, 1));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_DUPLICATE, hbm_flag(map));
|
||||
map->flag = CMC_FLAG_ERROR;
|
||||
cmc_assert(!hbm_update_val(map, 1, 2));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_DUPLICATE, hbm_flag(map));
|
||||
|
||||
// remove_by_key
|
||||
cmc_assert(hbm_remove_by_key(map, 1, NULL, NULL));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
|
||||
cmc_assert(!hbm_remove_by_key(map, 1, NULL, NULL));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_NOT_FOUND, hbm_flag(map));
|
||||
|
||||
cmc_assert(hbm_remove_by_key(map, 2, NULL, NULL));
|
||||
cmc_assert(!hbm_remove_by_key(map, 2, NULL, NULL));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, hbm_flag(map));
|
||||
|
||||
// remove_by_val
|
||||
cmc_assert(hbm_insert(map, 1, 1) && hbm_insert(map, 2, 2));
|
||||
|
||||
cmc_assert(hbm_remove_by_val(map, 1, NULL, NULL));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
|
||||
cmc_assert(!hbm_remove_by_val(map, 1, NULL, NULL));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_NOT_FOUND, hbm_flag(map));
|
||||
|
||||
cmc_assert(hbm_remove_by_val(map, 2, NULL, NULL));
|
||||
cmc_assert(!hbm_remove_by_val(map, 2, NULL, NULL));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, hbm_flag(map));
|
||||
|
||||
// get_key and get_val
|
||||
cmc_assert(hbm_insert(map, 2, 1));
|
||||
|
||||
cmc_assert_equals(size_t, 2, hbm_get_key(map, 1));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
map->flag = CMC_FLAG_ERROR;
|
||||
cmc_assert_equals(size_t, 1, hbm_get_val(map, 2));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
|
||||
cmc_assert_equals(size_t, 0, hbm_get_key(map, 2));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_NOT_FOUND, hbm_flag(map));
|
||||
map->flag = CMC_FLAG_ERROR;
|
||||
cmc_assert_equals(size_t, 0, hbm_get_val(map, 1));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_NOT_FOUND, hbm_flag(map));
|
||||
|
||||
// contains_key
|
||||
cmc_assert(hbm_contains_key(map, 2));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
|
||||
// contains_val
|
||||
map->flag = CMC_FLAG_ERROR;
|
||||
cmc_assert(hbm_contains_val(map, 1));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
|
||||
// copy_of
|
||||
map->flag = CMC_FLAG_ERROR;
|
||||
struct hashbidimap *map2 = hbm_copy_of(map);
|
||||
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map2));
|
||||
|
||||
size_t tmp = map->capacity;
|
||||
map->capacity = 0;
|
||||
|
||||
struct hashbidimap *map3 = hbm_copy_of(map);
|
||||
cmc_assert_equals(ptr, NULL, map3);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_ERROR, hbm_flag(map));
|
||||
|
||||
map->capacity = tmp;
|
||||
|
||||
// equals
|
||||
hbm_get_key(map, 100);
|
||||
hbm_get_key(map2, 100);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_NOT_FOUND, hbm_flag(map));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_NOT_FOUND, hbm_flag(map2));
|
||||
map->flag = CMC_FLAG_ERROR;
|
||||
cmc_assert(hbm_equals(map, map2));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, hbm_flag(map2));
|
||||
|
||||
hbm_free(map);
|
||||
hbm_free(map2);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(callbacks, {
|
||||
struct hashbidimap *map = hbm_new_custom(100, 0.7, hbm_fkey, hbm_fval, NULL, callbacks);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
cmc_assert_equals(ptr, callbacks, map->callbacks);
|
||||
|
||||
total_create = 0;
|
||||
total_read = 0;
|
||||
total_update = 0;
|
||||
total_delete = 0;
|
||||
total_resize = 0;
|
||||
|
||||
cmc_assert(hbm_insert(map, 10, 10));
|
||||
cmc_assert_equals(int32_t, 1, total_create);
|
||||
|
||||
cmc_assert(hbm_update_key(map, 10, 5));
|
||||
cmc_assert_equals(int32_t, 1, total_update);
|
||||
|
||||
cmc_assert(hbm_update_val(map, 5, 5));
|
||||
cmc_assert_equals(int32_t, 2, total_update);
|
||||
|
||||
cmc_assert(hbm_insert(map, 10, 10));
|
||||
cmc_assert_equals(int32_t, 2, total_create);
|
||||
|
||||
cmc_assert(hbm_remove_by_key(map, 5, NULL, NULL));
|
||||
cmc_assert_equals(int32_t, 1, total_delete);
|
||||
|
||||
cmc_assert(hbm_remove_by_val(map, 10, NULL, NULL));
|
||||
cmc_assert_equals(int32_t, 2, total_delete);
|
||||
|
||||
cmc_assert(hbm_insert(map, 1, 2));
|
||||
cmc_assert_equals(int32_t, 3, total_create);
|
||||
|
||||
cmc_assert_equals(size_t, 1, hbm_get_key(map, 2));
|
||||
cmc_assert_equals(int32_t, 1, total_read);
|
||||
|
||||
cmc_assert_equals(size_t, 2, hbm_get_val(map, 1));
|
||||
cmc_assert_equals(int32_t, 2, total_read);
|
||||
|
||||
cmc_assert(hbm_resize(map, 1000));
|
||||
cmc_assert_equals(int32_t, 1, total_resize);
|
||||
|
||||
cmc_assert(hbm_resize(map, 200));
|
||||
cmc_assert_equals(int32_t, 2, total_resize);
|
||||
|
||||
cmc_assert(hbm_contains_key(map, 1));
|
||||
cmc_assert_equals(int32_t, 3, total_read);
|
||||
|
||||
cmc_assert(hbm_contains_val(map, 2));
|
||||
cmc_assert_equals(int32_t, 4, total_read);
|
||||
|
||||
cmc_assert_equals(int32_t, 3, total_create);
|
||||
cmc_assert_equals(int32_t, 4, total_read);
|
||||
cmc_assert_equals(int32_t, 2, total_update);
|
||||
cmc_assert_equals(int32_t, 2, total_delete);
|
||||
cmc_assert_equals(int32_t, 2, total_resize);
|
||||
|
||||
hbm_customize(map, NULL, NULL);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, map->callbacks);
|
||||
|
||||
hbm_clear(map);
|
||||
cmc_assert(hbm_insert(map, 10, 10));
|
||||
cmc_assert(hbm_update_key(map, 10, 5));
|
||||
cmc_assert(hbm_update_val(map, 5, 5));
|
||||
cmc_assert(hbm_insert(map, 10, 10));
|
||||
cmc_assert(hbm_remove_by_key(map, 5, NULL, NULL));
|
||||
cmc_assert(hbm_remove_by_val(map, 10, NULL, NULL));
|
||||
cmc_assert(hbm_insert(map, 1, 2));
|
||||
cmc_assert_equals(size_t, 1, hbm_get_key(map, 2));
|
||||
cmc_assert_equals(size_t, 2, hbm_get_val(map, 1));
|
||||
cmc_assert(hbm_resize(map, 1000));
|
||||
cmc_assert(hbm_resize(map, 200));
|
||||
cmc_assert(hbm_contains_key(map, 1));
|
||||
cmc_assert(hbm_contains_val(map, 2));
|
||||
|
||||
cmc_assert_equals(int32_t, 3, total_create);
|
||||
cmc_assert_equals(int32_t, 4, total_read);
|
||||
cmc_assert_equals(int32_t, 2, total_update);
|
||||
cmc_assert_equals(int32_t, 2, total_delete);
|
||||
cmc_assert_equals(int32_t, 2, total_resize);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, map->callbacks);
|
||||
|
||||
hbm_free(map);
|
||||
|
||||
total_create = 0;
|
||||
total_read = 0;
|
||||
total_update = 0;
|
||||
total_delete = 0;
|
||||
total_resize = 0;
|
||||
});
|
||||
});
|
||||
|
||||
CMC_CREATE_UNIT(CMCHashBidiMapIter, true, {
|
||||
CMC_CREATE_TEST(PFX##_iter_start, {
|
||||
// WIP
|
||||
cmc_assert(true);
|
||||
cmc_assert(true);
|
||||
});
|
||||
});
|
||||
|
||||
#endif /* CMC_TESTS_UNT_HASHBIDIMAP_H */
|
||||
+1333
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -9,6 +9,7 @@
|
||||
#define CMC_EXT_LIST_INIT
|
||||
#define CMC_EXT_LIST_ITER
|
||||
#define CMC_EXT_LIST_SEQ
|
||||
#define CMC_EXT_LIST_STR
|
||||
#include "cmc/list.h"
|
||||
|
||||
struct list_fval *l_fval = &(struct list_fval){
|
||||
|
||||
@@ -0,0 +1,958 @@
|
||||
#ifndef CMC_TESTS_UNT_QUEUE_H
|
||||
#define CMC_TESTS_UNT_QUEUE_H
|
||||
|
||||
#include "utl.h"
|
||||
|
||||
#define V size_t
|
||||
#define PFX q
|
||||
#define SNAME queue
|
||||
#define CMC_EXT_QUEUE_INIT
|
||||
#define CMC_EXT_QUEUE_ITER
|
||||
#define CMC_EXT_QUEUE_STR
|
||||
#include "cmc/queue.h"
|
||||
|
||||
struct queue_fval *q_fval = &(struct queue_fval){
|
||||
.cmp = cmc_size_cmp, .cpy = NULL, .str = cmc_size_str, .free = NULL, .hash = cmc_size_hash, .pri = cmc_size_cmp
|
||||
};
|
||||
|
||||
CMC_CREATE_UNIT(CMCQueue, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
struct queue *q = q_new(1000000, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
cmc_assert_not_equals(ptr, NULL, q->buffer);
|
||||
cmc_assert_equals(size_t, 1000000, q_capacity(q));
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
cmc_assert_not_equals(ptr, NULL, q->buffer);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[capacity = 0], {
|
||||
struct queue *q = q_new(0, q_fval);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[capacity = UINT64_MAX], {
|
||||
struct queue *q = q_new(UINT64_MAX, q_fval);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, q_count(q));
|
||||
|
||||
q_clear(q);
|
||||
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
cmc_assert_equals(size_t, 100, q_capacity(q));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[capacity = 1], {
|
||||
struct queue *q = q_new(1, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, q_count(q));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[item preservation], {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 1; i <= 1200; i++)
|
||||
{
|
||||
q_enqueue(q, i);
|
||||
}
|
||||
|
||||
size_t sum = 0;
|
||||
for (size_t i = q->front, j = 0; j < q->count; i = (i + 1) % q->capacity, j++)
|
||||
sum += q->buffer[i];
|
||||
|
||||
cmc_assert_equals(size_t, 1200, q_count(q));
|
||||
cmc_assert_equals(size_t, 720600, sum);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(enqueue[count capacity], {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i < 150; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert_equals(size_t, 150, q_count(q));
|
||||
cmc_assert_greater(size_t, 100, q_capacity(q));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(enqueue[item preservation], {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = q->front, j = 0; j < q->count; i = (i + 1) % q->capacity, j++)
|
||||
{
|
||||
sum += q->buffer[i];
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 5050, sum);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(dequeue[count capacity], {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert(q_enqueue(q, 10));
|
||||
cmc_assert(q_dequeue(q));
|
||||
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
|
||||
cmc_assert(q_enqueue(q, 10));
|
||||
cmc_assert(q_dequeue(q));
|
||||
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(dequeue[item preservation], {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 200; i > 0; i--)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(q_dequeue(q));
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = q->front, j = 0; j < q->count; i = (i + 1) % q->capacity, j++)
|
||||
{
|
||||
sum += q->buffer[i];
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 5050, sum);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(peek[count = 0], {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
size_t r = q_peek(q);
|
||||
|
||||
cmc_assert_equals(size_t, (size_t){ 0 }, r);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(peek[sum], {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = 0; i <= 100; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
while (!q_empty(q))
|
||||
{
|
||||
size_t r = q_peek(q);
|
||||
|
||||
sum += r;
|
||||
|
||||
cmc_assert(q_dequeue(q));
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 5050, sum);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains, {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 1; i <= 20; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
for (size_t i = 1; i <= 20; i++)
|
||||
cmc_assert(q_contains(q, i));
|
||||
|
||||
q_clear(q);
|
||||
|
||||
for (size_t i = 1; i <= 20; i++)
|
||||
cmc_assert(!q_contains(q, i));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains[count = 0], {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert(!q_contains(q, 10));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains[count = 1], {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert(!q_contains(q, 10));
|
||||
|
||||
cmc_assert(q_enqueue(q, 100));
|
||||
|
||||
cmc_assert(q_contains(q, 100));
|
||||
cmc_assert(!q_contains(q, 101));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(empty, {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert(q_empty(q));
|
||||
|
||||
cmc_assert(q_enqueue(q, 1));
|
||||
|
||||
cmc_assert(!q_empty(q));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(full, {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert(!q_full(q));
|
||||
|
||||
for (size_t i = 0; i != q_capacity(q); i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert(q_full(q));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(count, {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert_equals(size_t, 100, q_count(q));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(capacity, {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert_equals(size_t, 100, q_capacity(q));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(resize, {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i < 150; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert_equals(size_t, 150, q_count(q));
|
||||
cmc_assert(q_resize(q, q_count(q)));
|
||||
cmc_assert_equals(size_t, 150, q_capacity(q));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(resize[item preservation], {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 1; i <= 150; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert(q_resize(q, q_count(q)));
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = q->front, j = 0; j < q->count; i = (i + 1) % q->capacity, j++)
|
||||
{
|
||||
sum += q->buffer[i];
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 11325, sum);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(copy_of, {
|
||||
struct queue *q1 = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q1);
|
||||
|
||||
for (size_t i = 1; i <= 150; i++)
|
||||
cmc_assert(q_enqueue(q1, i));
|
||||
|
||||
struct queue *q2 = q_copy_of(q1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q2);
|
||||
cmc_assert_equals(size_t, q_count(q1), q_count(q2));
|
||||
|
||||
for (size_t i1 = q1->front, i2 = q2->front, j = 0; j < q1->count; j++)
|
||||
{
|
||||
cmc_assert_equals(size_t, q1->buffer[i1], q2->buffer[i2]);
|
||||
|
||||
i1 = (i1 + 1) % q1->capacity;
|
||||
i2 = (i2 + 1) % q2->capacity;
|
||||
}
|
||||
|
||||
q_free(q1);
|
||||
q_free(q2);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(equals, {
|
||||
struct queue *q1 = q_new(100, q_fval);
|
||||
struct queue *q2 = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q1);
|
||||
cmc_assert_not_equals(ptr, NULL, q2);
|
||||
|
||||
for (size_t i = 1; i <= 150; i++)
|
||||
{
|
||||
cmc_assert(q_enqueue(q1, i));
|
||||
cmc_assert(q_enqueue(q2, i));
|
||||
}
|
||||
|
||||
cmc_assert(q_equals(q1, q2));
|
||||
|
||||
q_free(q1);
|
||||
q_free(q2);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(equals[from copy], {
|
||||
struct queue *q1 = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q1);
|
||||
|
||||
for (size_t i = 1; i <= 150; i++)
|
||||
{
|
||||
cmc_assert(q_enqueue(q1, i));
|
||||
}
|
||||
|
||||
struct queue *q2 = q_copy_of(q1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q2);
|
||||
|
||||
cmc_assert(q_equals(q1, q2));
|
||||
|
||||
q_free(q1);
|
||||
q_free(q2);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(equals[count = 0], {
|
||||
struct queue *q1 = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q1);
|
||||
|
||||
struct queue *q2 = q_copy_of(q1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q2);
|
||||
|
||||
cmc_assert(q_equals(q1, q2));
|
||||
|
||||
q_free(q1);
|
||||
q_free(q2);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(flag, {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, q_flag(q));
|
||||
|
||||
// clear
|
||||
q->flag = CMC_FLAG_ERROR;
|
||||
q_clear(q);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, q_flag(q));
|
||||
|
||||
// customize
|
||||
q->flag = CMC_FLAG_ERROR;
|
||||
q_customize(q, NULL, NULL);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, q_flag(q));
|
||||
|
||||
// enqueue
|
||||
q->flag = CMC_FLAG_ERROR;
|
||||
q_enqueue(q, 10);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, q_flag(q));
|
||||
|
||||
// dequeue
|
||||
q->flag = CMC_FLAG_ERROR;
|
||||
q_dequeue(q);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, q_flag(q));
|
||||
|
||||
q_dequeue(q);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, q_flag(q));
|
||||
|
||||
// peek
|
||||
q->flag = CMC_FLAG_ERROR;
|
||||
q_peek(q);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, q_flag(q));
|
||||
|
||||
cmc_assert(q_enqueue(q, 10));
|
||||
q_peek(q);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, q_flag(q));
|
||||
|
||||
// contains
|
||||
q->flag = CMC_FLAG_ERROR;
|
||||
cmc_assert(q_contains(q, 10));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, q_flag(q));
|
||||
|
||||
// copy_of
|
||||
q->flag = CMC_FLAG_OK;
|
||||
struct queue *q2 = q_copy_of(q);
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, q_flag(q));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, q_flag(q2));
|
||||
|
||||
// equals
|
||||
q->flag = CMC_FLAG_OK;
|
||||
q2->flag = CMC_FLAG_OK;
|
||||
cmc_assert(q_equals(q, q2));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, q_flag(q));
|
||||
cmc_assert_equals(int32_t, CMC_FLAG_OK, q_flag(q2));
|
||||
|
||||
q_free(q);
|
||||
q_free(q2);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(callbacks, {
|
||||
struct queue *q = q_new_custom(100, q_fval, NULL, callbacks);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
total_create = 0;
|
||||
total_read = 0;
|
||||
total_update = 0;
|
||||
total_delete = 0;
|
||||
total_resize = 0;
|
||||
|
||||
cmc_assert(q_enqueue(q, 10));
|
||||
cmc_assert_equals(int32_t, 1, total_create);
|
||||
|
||||
cmc_assert(q_dequeue(q));
|
||||
cmc_assert_equals(int32_t, 1, total_delete);
|
||||
|
||||
cmc_assert(q_enqueue(q, 10));
|
||||
cmc_assert_equals(int32_t, 2, total_create);
|
||||
|
||||
cmc_assert_equals(size_t, 10, q_peek(q));
|
||||
cmc_assert_equals(int32_t, 1, total_read);
|
||||
|
||||
cmc_assert(q_contains(q, 10));
|
||||
cmc_assert_equals(int32_t, 2, total_read);
|
||||
|
||||
cmc_assert(q_resize(q, 1000));
|
||||
cmc_assert_equals(int32_t, 1, total_resize);
|
||||
|
||||
cmc_assert(q_resize(q, 100));
|
||||
cmc_assert_equals(int32_t, 2, total_resize);
|
||||
|
||||
cmc_assert_equals(int32_t, 2, total_create);
|
||||
cmc_assert_equals(int32_t, 2, total_read);
|
||||
cmc_assert_equals(int32_t, 0, total_update);
|
||||
cmc_assert_equals(int32_t, 1, total_delete);
|
||||
cmc_assert_equals(int32_t, 2, total_resize);
|
||||
|
||||
q_customize(q, NULL, NULL);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, q->callbacks);
|
||||
|
||||
q_clear(q);
|
||||
cmc_assert(q_enqueue(q, 10));
|
||||
cmc_assert(q_dequeue(q));
|
||||
cmc_assert(q_enqueue(q, 10));
|
||||
cmc_assert_equals(size_t, 10, q_peek(q));
|
||||
cmc_assert(q_contains(q, 10));
|
||||
cmc_assert(q_resize(q, 1000));
|
||||
cmc_assert(q_resize(q, 100));
|
||||
|
||||
cmc_assert_equals(int32_t, 2, total_create);
|
||||
cmc_assert_equals(int32_t, 2, total_read);
|
||||
cmc_assert_equals(int32_t, 0, total_update);
|
||||
cmc_assert_equals(int32_t, 1, total_delete);
|
||||
cmc_assert_equals(int32_t, 2, total_resize);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, q->callbacks);
|
||||
|
||||
q_free(q);
|
||||
|
||||
total_create = 0;
|
||||
total_read = 0;
|
||||
total_update = 0;
|
||||
total_delete = 0;
|
||||
total_resize = 0;
|
||||
});
|
||||
});
|
||||
|
||||
CMC_CREATE_UNIT(CMCQueueIter, true, {
|
||||
CMC_CREATE_TEST(PFX##_iter_start(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
struct queue_iter it = q_iter_start(q);
|
||||
|
||||
cmc_assert_equals(ptr, q, it.target);
|
||||
cmc_assert_equals(size_t, q->front, it.cursor);
|
||||
cmc_assert_equals(size_t, 0, it.index);
|
||||
cmc_assert_equals(bool, true, it.start);
|
||||
cmc_assert_equals(bool, true, it.end);
|
||||
|
||||
cmc_assert(q_iter_at_start(&it));
|
||||
cmc_assert(q_iter_at_end(&it));
|
||||
|
||||
cmc_assert(q_enqueue(q, 1));
|
||||
cmc_assert(q_enqueue(q, 2));
|
||||
|
||||
it = q_iter_start(q);
|
||||
|
||||
cmc_assert_equals(size_t, 0, it.index);
|
||||
cmc_assert_equals(bool, false, it.end);
|
||||
cmc_assert_equals(size_t, q->front, it.cursor);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_iter_end(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
struct queue_iter it = q_iter_end(q);
|
||||
|
||||
cmc_assert_equals(ptr, q, it.target);
|
||||
cmc_assert_equals(size_t, q->back, it.cursor);
|
||||
cmc_assert_equals(size_t, 0, it.index);
|
||||
cmc_assert_equals(bool, true, it.start);
|
||||
cmc_assert_equals(bool, true, it.end);
|
||||
|
||||
cmc_assert(q_iter_at_start(&it));
|
||||
cmc_assert(q_iter_at_end(&it));
|
||||
|
||||
cmc_assert(q_enqueue(q, 1));
|
||||
cmc_assert(q_enqueue(q, 2));
|
||||
cmc_assert(q_enqueue(q, 3));
|
||||
|
||||
it = q_iter_end(q);
|
||||
|
||||
cmc_assert_equals(size_t, q->count - 1, it.index);
|
||||
cmc_assert_equals(size_t, q->back - 1, it.cursor);
|
||||
cmc_assert_equals(bool, false, it.start);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_iter_at_start(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
struct queue_iter it = q_iter_start(q);
|
||||
|
||||
// Empty checks
|
||||
cmc_assert(q_iter_at_start(&it));
|
||||
it = q_iter_end(q);
|
||||
cmc_assert(q_iter_at_start(&it));
|
||||
|
||||
// Non-empty check
|
||||
cmc_assert(q_enqueue(q, 1));
|
||||
it = q_iter_end(q);
|
||||
cmc_assert(!q_iter_at_start(&it));
|
||||
it = q_iter_start(q);
|
||||
cmc_assert(q_iter_at_start(&it));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_iter_at_end(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
struct queue_iter it = q_iter_start(q);
|
||||
|
||||
// Empty check
|
||||
cmc_assert(q_iter_at_end(&it));
|
||||
it = q_iter_end(q);
|
||||
cmc_assert(q_iter_at_end(&it));
|
||||
|
||||
// Non-empty check
|
||||
cmc_assert(q_enqueue(q, 1));
|
||||
it = q_iter_end(q);
|
||||
cmc_assert(q_iter_at_end(&it));
|
||||
it = q_iter_start(q);
|
||||
cmc_assert(!q_iter_at_end(&it));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_iter_to_start(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
struct queue_iter it = q_iter_start(q);
|
||||
|
||||
cmc_assert(!q_iter_to_start(&it));
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
q_enqueue(q, i);
|
||||
|
||||
cmc_assert_equals(size_t, 100, q->count);
|
||||
|
||||
it = q_iter_end(q);
|
||||
|
||||
cmc_assert(!q_iter_at_start(&it));
|
||||
cmc_assert(q_iter_at_end(&it));
|
||||
|
||||
cmc_assert_equals(size_t, 100, q_iter_value(&it));
|
||||
|
||||
cmc_assert(q_iter_to_start(&it));
|
||||
|
||||
cmc_assert(q_iter_at_start(&it));
|
||||
cmc_assert(!q_iter_at_end(&it));
|
||||
|
||||
cmc_assert_equals(size_t, 1, q_iter_value(&it));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_iter_to_end(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
struct queue_iter it = q_iter_end(q);
|
||||
|
||||
cmc_assert(!q_iter_to_end(&it));
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
q_enqueue(q, i);
|
||||
|
||||
it = q_iter_start(q);
|
||||
|
||||
cmc_assert(q_iter_at_start(&it));
|
||||
cmc_assert(!q_iter_at_end(&it));
|
||||
|
||||
cmc_assert_equals(size_t, 1, q_iter_value(&it));
|
||||
|
||||
cmc_assert(q_iter_to_end(&it));
|
||||
|
||||
cmc_assert(!q_iter_at_start(&it));
|
||||
cmc_assert(q_iter_at_end(&it));
|
||||
|
||||
cmc_assert_equals(size_t, 100, q_iter_value(&it));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_iter_next(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
struct queue_iter it = q_iter_start(q);
|
||||
|
||||
cmc_assert(!q_iter_next(&it));
|
||||
|
||||
for (size_t i = 1; i <= 1000; i++)
|
||||
q_enqueue(q, i);
|
||||
|
||||
size_t sum = 0;
|
||||
for (it = q_iter_start(q); !q_iter_at_end(&it); q_iter_next(&it))
|
||||
{
|
||||
sum += q_iter_value(&it);
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 500500, sum);
|
||||
|
||||
sum = 0;
|
||||
|
||||
q_iter_to_start(&it);
|
||||
do
|
||||
{
|
||||
sum += q_iter_value(&it);
|
||||
} while (q_iter_next(&it));
|
||||
|
||||
cmc_assert_equals(size_t, 500500, sum);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_iter_prev(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
struct queue_iter it = q_iter_end(q);
|
||||
|
||||
cmc_assert(!q_iter_prev(&it));
|
||||
|
||||
for (size_t i = 1; i <= 1000; i++)
|
||||
q_enqueue(q, i);
|
||||
|
||||
size_t sum = 0;
|
||||
for (it = q_iter_end(q); !q_iter_at_start(&it); q_iter_prev(&it))
|
||||
{
|
||||
sum += q_iter_value(&it);
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 500500, sum);
|
||||
|
||||
sum = 0;
|
||||
|
||||
q_iter_to_end(&it);
|
||||
do
|
||||
{
|
||||
sum += q_iter_value(&it);
|
||||
} while (q_iter_prev(&it));
|
||||
|
||||
cmc_assert_equals(size_t, 500500, sum);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_iter_advance(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
struct queue_iter it = q_iter_start(q);
|
||||
|
||||
cmc_assert(!q_iter_advance(&it, 1));
|
||||
|
||||
for (size_t i = 0; i <= 1000; i++)
|
||||
q_enqueue(q, i);
|
||||
|
||||
it = q_iter_start(q);
|
||||
|
||||
cmc_assert(!q_iter_advance(&it, 0));
|
||||
cmc_assert(!q_iter_advance(&it, q->count));
|
||||
|
||||
size_t sum = 0;
|
||||
for (it = q_iter_start(q);;)
|
||||
{
|
||||
sum += q_iter_value(&it);
|
||||
|
||||
if (!q_iter_advance(&it, 2))
|
||||
break;
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 250500, sum);
|
||||
|
||||
q_iter_to_start(&it);
|
||||
cmc_assert(q_iter_advance(&it, q->count - 1));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_iter_rewind(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
struct queue_iter it = q_iter_end(q);
|
||||
|
||||
cmc_assert(!q_iter_rewind(&it, 1));
|
||||
|
||||
for (size_t i = 0; i <= 1000; i++)
|
||||
q_enqueue(q, i);
|
||||
|
||||
it = q_iter_end(q);
|
||||
|
||||
cmc_assert(!q_iter_rewind(&it, 0));
|
||||
cmc_assert(!q_iter_rewind(&it, q->count));
|
||||
|
||||
size_t sum = 0;
|
||||
for (it = q_iter_end(q);;)
|
||||
{
|
||||
sum += q_iter_value(&it);
|
||||
|
||||
if (!q_iter_rewind(&it, 2))
|
||||
break;
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 250500, sum);
|
||||
|
||||
q_iter_to_end(&it);
|
||||
cmc_assert(q_iter_rewind(&it, q->count - 1));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_iter_go_to(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
struct queue_iter it = q_iter_end(q);
|
||||
cmc_assert(!q_iter_go_to(&it, 0));
|
||||
|
||||
it = q_iter_start(q);
|
||||
cmc_assert(!q_iter_go_to(&it, 0));
|
||||
|
||||
for (size_t i = 0; i <= 1000; i++)
|
||||
q_enqueue(q, i);
|
||||
|
||||
it = q_iter_start(q);
|
||||
|
||||
size_t sum = 0;
|
||||
for (size_t i = 0; i < 1001; i++)
|
||||
{
|
||||
q_iter_go_to(&it, i);
|
||||
|
||||
sum += q_iter_value(&it);
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 500500, sum);
|
||||
|
||||
sum = 0;
|
||||
for (size_t i = 1001; i > 0; i--)
|
||||
{
|
||||
cmc_assert(q_iter_go_to(&it, i - 1));
|
||||
|
||||
sum += q_iter_value(&it);
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 500500, sum);
|
||||
|
||||
sum = 0;
|
||||
for (size_t i = 0; i < 1001; i += 100)
|
||||
{
|
||||
cmc_assert(q_iter_go_to(&it, i));
|
||||
cmc_assert_equals(size_t, i, q_iter_index(&it));
|
||||
|
||||
sum += q_iter_value(&it);
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 5500, sum);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_iter_value(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
struct queue_iter it = q_iter_end(q);
|
||||
|
||||
cmc_assert_equals(size_t, (size_t){ 0 }, q_iter_value(&it));
|
||||
|
||||
cmc_assert(q_enqueue(q, 10));
|
||||
|
||||
it = q_iter_start(q);
|
||||
|
||||
cmc_assert_equals(size_t, 10, q_iter_value(&it));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_iter_rvalue(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
struct queue_iter it = q_iter_end(q);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, q_iter_rvalue(&it));
|
||||
|
||||
cmc_assert(q_enqueue(q, 10));
|
||||
|
||||
it = q_iter_start(q);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q_iter_rvalue(&it));
|
||||
cmc_assert_equals(size_t, 10, *q_iter_rvalue(&it));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(PFX##_iter_index(), {
|
||||
struct queue *q = q_new(100, q_fval);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i <= 1000; i++)
|
||||
q_enqueue(q, i);
|
||||
|
||||
struct queue_iter it = q_iter_start(q);
|
||||
|
||||
for (size_t i = 0; i < 1001; i++)
|
||||
{
|
||||
cmc_assert_equals(size_t, i, q_iter_index(&it));
|
||||
q_iter_next(&it);
|
||||
}
|
||||
|
||||
it = q_iter_end(q);
|
||||
for (size_t i = 1001; i > 0; i--)
|
||||
{
|
||||
cmc_assert_equals(size_t, i - 1, q_iter_index(&it));
|
||||
q_iter_prev(&it);
|
||||
}
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
});
|
||||
|
||||
#endif /* CMC_TESTS_UNT_QUEUE_H */
|
||||
@@ -8,6 +8,7 @@
|
||||
#define SNAME stack
|
||||
#define CMC_EXT_STACK_INIT
|
||||
#define CMC_EXT_STACK_ITER
|
||||
#define CMC_EXT_STACK_STR
|
||||
#include "cmc/stack.h"
|
||||
|
||||
struct stack_fval *s_fval = &(struct stack_fval){
|
||||
|
||||
Reference in new issue
Block a user