More refactoring

This commit is contained in:
Leonardo Vencovsky committed 2023-01-17 17:09:48 +01:00
1 parent 0e6c44ac46
commit f6bc58a3d7
59 files changed
+10562 -98

No files matched your search

+2 -2
View File
@@ -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
+3
View File
@@ -59,3 +59,6 @@ experimental/
# Test / Code Coverage build folder
build
tests/coverage
tests/out
-24
View File
@@ -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)
+19
View File
@@ -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
+266
View File
@@ -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;
}
+18
View File
@@ -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;
}
+102
View File
@@ -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);
}
+17
View File
@@ -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,
-16
View File
@@ -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);
};
+845
View File
@@ -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];
}
+393
View File
@@ -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 */
+86
View File
@@ -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 */
+51
View File
@@ -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 */
+91
View File
@@ -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_);
+69
View File
@@ -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];
};
+636
View File
@@ -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];
}
+438
View File
@@ -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 */
+82
View File
@@ -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 */
+51
View File
@@ -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 */
+90
View File
@@ -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_);
+60
View File
@@ -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;
};
+870
View File
@@ -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];
}
+397
View File
@@ -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 */
+75
View File
@@ -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 */
+53
View File
@@ -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 */
+93
View File
@@ -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_);
+59
View File
@@ -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;
};
-3
View File
@@ -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;
};
+17
View File
@@ -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,
-16
View File
@@ -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);
};
+324
View File
@@ -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;
}
+354
View File
@@ -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 */
+80
View File
@@ -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 */
+47
View File
@@ -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 */
+66
View File
@@ -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_);
+45
View File
@@ -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;
};
+17
View File
@@ -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,
-16
View File
@@ -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);
};
+10
View File
@@ -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
View File
@@ -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"
/**/
+85
View File
@@ -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"
+78
View File
@@ -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"
+103
View File
@@ -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
View File
@@ -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"
/**/
+99
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+1
View File
@@ -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){
+818
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+1
View File
@@ -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){
+958
View File
@@ -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 */
+1
View File
@@ -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){