Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8142f96b1 | ||
|
|
97d50bc3d9 | ||
|
|
8c457eeb12 | ||
|
|
846d0bbba6 | ||
|
|
a9314ee8f7 | ||
|
|
9bff706bba | ||
|
|
31c871c4c2 | ||
|
|
82b374ec83 | ||
|
|
940552d6cd | ||
|
|
6a2cb70fb5 | ||
|
|
78cfc0c335 | ||
|
|
f454934b07 | ||
|
|
5504f82052 | ||
|
|
d01997b7cb | ||
|
|
7b349ea426 | ||
|
|
1edb12a83c | ||
|
|
176bbc66ad | ||
|
|
41eebe546a | ||
|
|
afaecb2dde | ||
|
|
9062415322 |
No files matched your search
@@ -0,0 +1,5 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
*.h linguist-language=C
|
||||
*.c linguist-language=C
|
||||
@@ -14,3 +14,7 @@ script:
|
||||
- export CC=gcc-7
|
||||
- cd ./tests
|
||||
- make
|
||||
- cd main
|
||||
- make
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
@@ -1,4 +1,23 @@
|
||||
# MAJOR.MINOR.ADJUSTMENTS
|
||||
# RELEASE.MAJOR.MINOR
|
||||
|
||||
1.5.3
|
||||
Tests completely reorganized and now with full code coverage
|
||||
Some fixes where there was a missing return statement
|
||||
Expanded utl/assert.h
|
||||
|
||||
1.5.2
|
||||
Added utl/test.h
|
||||
Added utl/assert.h
|
||||
Added tests/list.c - UnitTest for LIST
|
||||
Small fixes on utl/foreach.h, utl/test.h and redone utl/timer.h
|
||||
Removed utl/log.h functions that were unnecessary
|
||||
Added the CMC namespace to CONCATC and CONCATH at macro_collections.h
|
||||
|
||||
1.5.1
|
||||
New queue benchmark
|
||||
Added sac/queue.h
|
||||
Added utl/timer.h
|
||||
Fixing descriptions and other minor fixes
|
||||
|
||||
1.5.0
|
||||
Changed tests compilation and execution to a single Makefile
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
Generate Simple Data Structures of any type in C for you to use in your projects.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
[](https://travis-ci.org/LeoVen/C-Macro-Collections)
|
||||
[](https://codecov.io/gh/LeoVen/C-Macro-Collections)
|
||||
|
||||
## Project Structure
|
||||
|
||||
@@ -37,6 +38,7 @@ Only Collections located in __cmc__ are to be documented at *Documentation.md*.
|
||||
* Extra Collections Library
|
||||
* LinkedQueue
|
||||
* Stack Allocated Collections Library
|
||||
* Queue
|
||||
* Stack
|
||||
|
||||
### More to Come
|
||||
|
||||
@@ -10,6 +10,7 @@ TODO
|
||||
[ ] Iterator based functions (like C++ collections)
|
||||
[ ] Add Stack Allocated Collections
|
||||
[ ] Finish all Dev Collections
|
||||
[ ] ToString method to all Collections
|
||||
|
||||
|
||||
MAYBE
|
||||
|
||||
+15
-16
@@ -13,7 +13,6 @@
|
||||
* - Output
|
||||
*/
|
||||
#include "macro_collections.h"
|
||||
#include "util/timer.h"
|
||||
#include "util/twister.c"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
@@ -82,17 +81,17 @@ COLLECTION_GENERATE(HASHMAP, hm, hmap, /* FMOD */, int, int)
|
||||
\
|
||||
sname *coll = initfunc; \
|
||||
\
|
||||
TIMER_START(total) \
|
||||
TIMER_START(timer) \
|
||||
timer_start(total); \
|
||||
timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
insertbody; \
|
||||
} \
|
||||
\
|
||||
TIMER_STOP(timer) \
|
||||
timer_stop(timer); \
|
||||
\
|
||||
TIMER_CALC(timer) \
|
||||
timer_calc(timer); \
|
||||
\
|
||||
size_t s1 = PFX##_count(coll); \
|
||||
\
|
||||
@@ -100,16 +99,16 @@ COLLECTION_GENERATE(HASHMAP, hm, hmap, /* FMOD */, int, int)
|
||||
\
|
||||
double input_time = timer.result; \
|
||||
\
|
||||
TIMER_START(timer) \
|
||||
timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < s; i++) \
|
||||
{ \
|
||||
searchbody; \
|
||||
} \
|
||||
\
|
||||
TIMER_STOP(timer) \
|
||||
timer_stop(timer); \
|
||||
\
|
||||
TIMER_CALC(timer) \
|
||||
timer_calc(timer); \
|
||||
\
|
||||
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
|
||||
\
|
||||
@@ -117,30 +116,30 @@ COLLECTION_GENERATE(HASHMAP, hm, hmap, /* FMOD */, int, int)
|
||||
\
|
||||
sname##_iter iter; \
|
||||
\
|
||||
TIMER_START(timer) \
|
||||
timer_start(timer); \
|
||||
\
|
||||
for (PFX##_iter_init(&iter, coll); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
TIMER_STOP(timer) \
|
||||
timer_stop(timer); \
|
||||
\
|
||||
TIMER_CALC(timer) \
|
||||
timer_calc(timer); \
|
||||
\
|
||||
printf("ITERATION %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double iter_time = timer.result; \
|
||||
\
|
||||
TIMER_START(timer); \
|
||||
timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
removebody; \
|
||||
} \
|
||||
\
|
||||
TIMER_STOP(timer) \
|
||||
timer_stop(timer); \
|
||||
\
|
||||
TIMER_CALC(timer) \
|
||||
timer_calc(timer); \
|
||||
\
|
||||
size_t s2 = PFX##_count(coll); \
|
||||
\
|
||||
@@ -148,8 +147,8 @@ COLLECTION_GENERATE(HASHMAP, hm, hmap, /* FMOD */, int, int)
|
||||
\
|
||||
double output_time = timer.result; \
|
||||
\
|
||||
TIMER_STOP(total) \
|
||||
TIMER_CALC(total) \
|
||||
timer_stop(total); \
|
||||
timer_calc(total); \
|
||||
\
|
||||
PFX##_free(coll); \
|
||||
\
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
CFLAGS = -Wall -Wextra
|
||||
INCLUDE = ../../src
|
||||
|
||||
main:
|
||||
gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DCMC_QUEUE
|
||||
a.exe
|
||||
gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DSAC_QUEUE
|
||||
a.exe
|
||||
gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DEXT_QUEUE
|
||||
a.exe
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* queue.c
|
||||
*
|
||||
* Creation Date: 24/06/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/* Showing off how different queue implementations affect runtime cost */
|
||||
|
||||
#include "utl/timer.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define MAX 200000
|
||||
|
||||
#if defined(CMC_QUEUE)
|
||||
#include "cmc/queue.h"
|
||||
QUEUE_GENERATE(q, queue, , int)
|
||||
#define TARGET "QUEUE"
|
||||
#elif defined(SAC_QUEUE)
|
||||
#include "sac/queue.h"
|
||||
SAC_QUEUE_GENERATE(q, queue, , int, MAX)
|
||||
#define TARGET "SAC QUEUE"
|
||||
#elif defined(EXT_QUEUE)
|
||||
#include "ext/linkedqueue.h"
|
||||
LINKEDQUEUE_GENERATE(q, queue, , int)
|
||||
#define TARGET "LINKED QUEUE"
|
||||
#else
|
||||
#error Please define either CMC_QUEUE, SAC_QUEUE or EXT_QUEUE
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
#if defined(CMC_QUEUE)
|
||||
queue *q = q_new(MAX);
|
||||
#elif defined(SAC_QUEUE)
|
||||
queue _q = q_new();
|
||||
queue_ptr q = &_q;
|
||||
#elif defined(EXT_QUEUE)
|
||||
queue *q = q_new();
|
||||
#endif
|
||||
|
||||
size_t sum = 0;
|
||||
int i = 0;
|
||||
|
||||
timer_t timer;
|
||||
TIMER_START(timer);
|
||||
|
||||
while (q_count(q) != MAX)
|
||||
{
|
||||
q_enqueue(q, i++);
|
||||
|
||||
if (i % 10 == 0)
|
||||
{
|
||||
for (size_t i = 0; i < 9; i++)
|
||||
{
|
||||
sum += q_peek(q);
|
||||
q_dequeue(q);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TIMER_STOP(timer);
|
||||
TIMER_CALC(timer);
|
||||
|
||||
printf("----------------------------------------\n");
|
||||
printf("%s\n", TARGET);
|
||||
printf("Execution time: %.0lf milliseconds\n", timer.result);
|
||||
printf("SUM: %" PRIuMAX "\n", sum);
|
||||
printf("----------------------------------------\n");
|
||||
|
||||
#if defined(CMC_QUEUE) || defined(EXT_QUEUE)
|
||||
q_free(q);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* timer.h
|
||||
*
|
||||
* Creation Date: 12/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Simple timer macros.
|
||||
*/
|
||||
#include <time.h>
|
||||
|
||||
typedef struct timer_s
|
||||
{
|
||||
clock_t start;
|
||||
clock_t stop;
|
||||
double result;
|
||||
} timer_t;
|
||||
|
||||
#define TIMER_START(timer) \
|
||||
timer.start = clock();
|
||||
|
||||
#define TIMER_STOP(timer) \
|
||||
timer.stop = clock();
|
||||
|
||||
#define TIMER_CALC(timer) \
|
||||
timer.result = (double)(((timer.stop - timer.start) * 1000.0) / CLOCKS_PER_SEC);
|
||||
@@ -57,7 +57,7 @@ int main(void)
|
||||
// Inside, the variable 'iter' will be available and from it you can access
|
||||
// the key, value or index.
|
||||
printf("MAP[%4d] = %.3lf\n", hm_iter_key(&iter), hm_iter_value(&iter));
|
||||
})
|
||||
});
|
||||
|
||||
hm_free(map);
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ int main(int argc, char const *argv[])
|
||||
|
||||
map_insert(library, value->isbn, value->name);
|
||||
set_insert(counter, value->name);
|
||||
})
|
||||
});
|
||||
|
||||
printf("Library Size: %d\n", map_count(library));
|
||||
printf("Unique book titles: %d\n\n", set_count(counter));
|
||||
@@ -69,7 +69,7 @@ int main(int argc, char const *argv[])
|
||||
FOR_EACH(q, queue, shelf, {
|
||||
book *value = q_iter_value(&iter);
|
||||
printf("[ %d : %-45s ]\n", value->isbn, value->name);
|
||||
})
|
||||
});
|
||||
printf("\n");
|
||||
|
||||
set_free(counter);
|
||||
@@ -122,11 +122,11 @@ int main(int argc, char const *argv[])
|
||||
|
||||
if (chrcmp(buffer, value) == 0)
|
||||
il_push_back(search_list, key);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(il, intlist, search_list, {
|
||||
printf("[ %d ]\n", il_iter_value(&iter));
|
||||
})
|
||||
});
|
||||
|
||||
il_free(search_list);
|
||||
}
|
||||
@@ -140,7 +140,7 @@ int main(int argc, char const *argv[])
|
||||
free(b->name);
|
||||
|
||||
free(b);
|
||||
})
|
||||
});
|
||||
|
||||
l_free(books);
|
||||
q_free(shelf);
|
||||
|
||||
@@ -67,7 +67,7 @@ int main(int argc, char const *argv[])
|
||||
printf("%d ]\n", value);
|
||||
else
|
||||
printf("%d, ", value);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(s, stack, s, {
|
||||
int value = s_iter_value(&iter);
|
||||
@@ -78,7 +78,7 @@ int main(int argc, char const *argv[])
|
||||
printf("%d ]\n", value);
|
||||
else
|
||||
printf("%d, ", value);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(q, queue, q, {
|
||||
int value = q_iter_value(&iter);
|
||||
@@ -89,7 +89,7 @@ int main(int argc, char const *argv[])
|
||||
printf("%d ]\n", value);
|
||||
else
|
||||
printf("%d, ", value);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(d, deque, d, {
|
||||
int value = d_iter_value(&iter);
|
||||
@@ -100,7 +100,7 @@ int main(int argc, char const *argv[])
|
||||
printf("%d ]\n", value);
|
||||
else
|
||||
printf("%d, ", value);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(ll, llist, ll, {
|
||||
int value = ll_iter_value(&iter);
|
||||
@@ -111,7 +111,7 @@ int main(int argc, char const *argv[])
|
||||
printf("%d ]\n", value);
|
||||
else
|
||||
printf("%d, ", value);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(ts, tset, ts, {
|
||||
int value = ts_iter_value(&iter);
|
||||
@@ -122,7 +122,7 @@ int main(int argc, char const *argv[])
|
||||
printf("%d ]\n", value);
|
||||
else
|
||||
printf("%d, ", value);
|
||||
})
|
||||
});
|
||||
|
||||
l_free(l);
|
||||
ll_free(ll);
|
||||
|
||||
@@ -186,7 +186,7 @@ int main(void)
|
||||
int sum = 0;
|
||||
FOR_EACH(il, int_list, integers, {
|
||||
sum += il_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
printf("\n\nSUM: %d\n", sum);
|
||||
|
||||
@@ -256,7 +256,7 @@ int main(void)
|
||||
|
||||
FOR_EACH(dq, deque, d, {
|
||||
sum3 += dq_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
printf("Deque sum: %d\n", sum3);
|
||||
|
||||
|
||||
+3
-4
@@ -283,7 +283,7 @@
|
||||
FMOD V PFX##_front(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return _deque_->buffer[_deque_->front]; \
|
||||
} \
|
||||
@@ -291,7 +291,7 @@
|
||||
FMOD V PFX##_back(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return _deque_->buffer[(_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1]; \
|
||||
} \
|
||||
@@ -422,7 +422,7 @@
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
@@ -442,7 +442,6 @@
|
||||
\
|
||||
static bool PFX##_impl_grow(SNAME *_deque_) \
|
||||
{ \
|
||||
\
|
||||
size_t new_capacity = _deque_->capacity * 2; \
|
||||
\
|
||||
V *new_buffer = malloc(sizeof(V) * new_capacity); \
|
||||
|
||||
+3
-3
@@ -425,7 +425,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \
|
||||
\
|
||||
if (!entry) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return entry->value; \
|
||||
} \
|
||||
@@ -598,7 +598,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
FMOD K PFX##_iter_key(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
PFX##_impl_default_key(); \
|
||||
return PFX##_impl_default_key(); \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor].key; \
|
||||
} \
|
||||
@@ -606,7 +606,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor].value; \
|
||||
} \
|
||||
|
||||
@@ -376,7 +376,7 @@
|
||||
FMOD V PFX##_front(SNAME *_list_) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return _list_->head->data; \
|
||||
} \
|
||||
@@ -384,7 +384,7 @@
|
||||
FMOD V PFX##_get(SNAME *_list_, size_t index) \
|
||||
{ \
|
||||
if (index >= _list_->count || PFX##_empty(_list_)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
SNAME##_node *scan = PFX##_get_node(_list_, index); \
|
||||
\
|
||||
|
||||
+2
-2
@@ -229,7 +229,7 @@
|
||||
FMOD V PFX##_peek(SNAME *_queue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_queue_)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return _queue_->buffer[_queue_->front]; \
|
||||
} \
|
||||
@@ -360,7 +360,7 @@
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
|
||||
+2
-2
@@ -210,7 +210,7 @@
|
||||
FMOD V PFX##_top(SNAME *_stack_) \
|
||||
{ \
|
||||
if (PFX##_empty(_stack_)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return _stack_->buffer[_stack_->count - 1]; \
|
||||
} \
|
||||
@@ -328,7 +328,7 @@
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
|
||||
+2
-2
@@ -677,7 +677,7 @@
|
||||
FMOD K PFX##_iter_key(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
PFX##_impl_default_key(); \
|
||||
return PFX##_impl_default_key(); \
|
||||
\
|
||||
return iter->cursor->key; \
|
||||
} \
|
||||
@@ -685,7 +685,7 @@
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return iter->cursor->value; \
|
||||
} \
|
||||
|
||||
+1
-1
@@ -847,7 +847,7 @@
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return iter->cursor->value; \
|
||||
} \
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
FMOD V PFX##_peek(SNAME *_lqueue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_lqueue_)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return _lqueue_->head->data; \
|
||||
} \
|
||||
@@ -348,7 +348,7 @@
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
NULL; \
|
||||
return NULL; \
|
||||
\
|
||||
return &(iter->cursor->data); \
|
||||
} \
|
||||
|
||||
+19
-18
@@ -11,43 +11,44 @@
|
||||
#ifndef CMC_MACRO_COLLECTIONS
|
||||
#define CMC_MACRO_COLLECTIONS
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#define CMC_CONCATH_(C) C##_WRAPGEN_HEADER
|
||||
#define CMC_CONCATC_(C) C##_WRAPGEN_SOURCE
|
||||
|
||||
#define CONCATH_(C) C##_WRAPGEN_HEADER
|
||||
#define CONCATC_(C) C##_WRAPGEN_SOURCE
|
||||
|
||||
#define CONCATH(C) CONCATH_(C)
|
||||
#define CONCATC(C) CONCATC_(C)
|
||||
#define CMC_CONCATH(C) CMC_CONCATH_(C)
|
||||
#define CMC_CONCATC(C) CMC_CONCATC_(C)
|
||||
|
||||
#define COLLECTION_GENERATE(C, PFX, SNAME, FMOD, K, V) \
|
||||
COLLECTION_GENERATE_HEADER(C, PFX, SNAME, FMOD, K, V) \
|
||||
COLLECTION_GENERATE_SOURCE(C, PFX, SNAME, FMOD, K, V)
|
||||
|
||||
#define COLLECTION_GENERATE_HEADER(C, PFX, SNAME, FMOD, K, V) \
|
||||
CONCATH(C) \
|
||||
CMC_CONCATH(C) \
|
||||
(PFX, SNAME, FMOD, K, V)
|
||||
|
||||
#define COLLECTION_GENERATE_SOURCE(C, PFX, SNAME, FMOD, K, V) \
|
||||
CONCATC(C) \
|
||||
CMC_CONCATC(C) \
|
||||
(PFX, SNAME, FMOD, K, V)
|
||||
|
||||
#include "cmc/list.h"
|
||||
#include "cmc/linkedlist.h"
|
||||
#include "cmc/stack.h"
|
||||
#include "cmc/queue.h"
|
||||
#include "cmc/deque.h"
|
||||
#include "cmc/heap.h"
|
||||
#include "cmc/treeset.h"
|
||||
#include "cmc/treemap.h"
|
||||
#include "cmc/hashset.h"
|
||||
#include "cmc/hashmap.h"
|
||||
#include "cmc/hashset.h"
|
||||
#include "cmc/heap.h"
|
||||
#include "cmc/linkedlist.h"
|
||||
#include "cmc/list.h"
|
||||
#include "cmc/queue.h"
|
||||
#include "cmc/stack.h"
|
||||
#include "cmc/treemap.h"
|
||||
#include "cmc/treeset.h"
|
||||
|
||||
#include "ext/linkedqueue.h"
|
||||
|
||||
#include "sac/queue.h"
|
||||
#include "sac/stack.h"
|
||||
|
||||
#include "utl/assert.h"
|
||||
#include "utl/foreach.h"
|
||||
#include "utl/log.h"
|
||||
#include "utl/test.h"
|
||||
#include "utl/timer.h"
|
||||
|
||||
#endif /* CMC_MACRO_COLLECTIONS */
|
||||
#endif /* CMC_MACRO_COLLECTIONS */
|
||||
+357
@@ -0,0 +1,357 @@
|
||||
/**
|
||||
* queue.h
|
||||
*
|
||||
* Creation Date: 24/06/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* A Purely Stack Allocated Queue
|
||||
*
|
||||
* This means that the Queue has a fixed size, but it also has the advantage of
|
||||
* not requiring for manually allocating and deallocating the struct.
|
||||
*
|
||||
* Generating a collection with too big of a storage can be dangerous and might
|
||||
* quickly cause a stack overflow.
|
||||
*
|
||||
* It is recommended to not generate any Stack Allocated Collection with less
|
||||
* than 1000 internal storage.
|
||||
*/
|
||||
|
||||
#ifndef CMC_SAC_QUEUE_H
|
||||
#define CMC_SAC_QUEUE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SAC_QUEUE_GENERATE(PFX, SNAME, FMOD, V, SIZE) \
|
||||
SAC_QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V, SIZE) \
|
||||
SAC_QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V, SIZE)
|
||||
|
||||
#define SAC_QUEUE_WRAPGEN_HEADER(PFX, SNAME, FMOD, K, V, SIZE) \
|
||||
SAC_QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V, SIZE)
|
||||
|
||||
#define SAC_QUEUE_WRAPGEN_SOURCE(PFX, SNAME, FMOD, K, V, SIZE) \
|
||||
SAC_QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V, SIZE)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define SAC_QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V, SIZE) \
|
||||
\
|
||||
/* Queue Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
{ \
|
||||
/* Internal Storage */ \
|
||||
V buffer[SIZE]; \
|
||||
\
|
||||
/* 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 rear; \
|
||||
\
|
||||
/* Function that returns an iterator to the start of the queue */ \
|
||||
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the queue */ \
|
||||
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||
\
|
||||
} SNAME, *SNAME##_ptr; \
|
||||
\
|
||||
/* Queue Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target queue */ \
|
||||
struct SNAME##_s *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; \
|
||||
\
|
||||
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME PFX##_new(void); \
|
||||
FMOD void PFX##_clear(SNAME *_queue_); \
|
||||
/* Collection Input and Output */ \
|
||||
FMOD bool PFX##_enqueue(SNAME *_queue_, V element); \
|
||||
FMOD bool PFX##_dequeue(SNAME *_queue_); \
|
||||
/* Conditional Input and Output */ \
|
||||
FMOD bool PFX##_enqueue_if(SNAME *_queue_, V element, bool condition); \
|
||||
FMOD bool PFX##_dequeue_if(SNAME *_queue_, bool condition); \
|
||||
/* Element Access */ \
|
||||
FMOD V PFX##_peek(SNAME *_queue_); \
|
||||
/* Collection State */ \
|
||||
FMOD bool PFX##_contains(SNAME *_queue_, V element, int (*comparator)(V, V)); \
|
||||
FMOD bool PFX##_empty(SNAME *_queue_); \
|
||||
FMOD bool PFX##_full(SNAME *_queue_); \
|
||||
FMOD size_t PFX##_count(SNAME *_queue_); \
|
||||
FMOD size_t PFX##_capacity(void); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Initialization */ \
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
/* Iterator Movement */ \
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
/* Iterator Access */ \
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* Default Value */ \
|
||||
static inline V PFX##_impl_default_value(void) \
|
||||
{ \
|
||||
V _empty_value_; \
|
||||
\
|
||||
memset(&_empty_value_, 0, sizeof(V)); \
|
||||
\
|
||||
return _empty_value_; \
|
||||
} \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define SAC_QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V, SIZE) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_queue_); \
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_); \
|
||||
\
|
||||
FMOD SNAME PFX##_new(void) \
|
||||
{ \
|
||||
SNAME result; \
|
||||
\
|
||||
memset(&result, 0, sizeof(SNAME)); \
|
||||
\
|
||||
result.it_start = PFX##_impl_it_start; \
|
||||
result.it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return result; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_queue_) \
|
||||
{ \
|
||||
memset(_queue_->buffer, 0, sizeof(_queue_->buffer)); \
|
||||
\
|
||||
_queue_->count = 0; \
|
||||
_queue_->front = 0; \
|
||||
_queue_->rear = 0; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_enqueue(SNAME *_queue_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_queue_)) \
|
||||
return false; \
|
||||
\
|
||||
_queue_->buffer[_queue_->rear] = element; \
|
||||
\
|
||||
_queue_->rear = (_queue_->rear == SIZE - 1) ? 0 : _queue_->rear + 1; \
|
||||
_queue_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_dequeue(SNAME *_queue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_queue_)) \
|
||||
return false; \
|
||||
\
|
||||
_queue_->buffer[_queue_->front] = PFX##_impl_default_value(); \
|
||||
\
|
||||
_queue_->front = (_queue_->front == SIZE - 1) ? 0 : _queue_->front + 1; \
|
||||
_queue_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_enqueue_if(SNAME *_queue_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_enqueue(_queue_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_dequeue_if(SNAME *_queue_, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_dequeue(_queue_); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_peek(SNAME *_queue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_queue_)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return _queue_->buffer[_queue_->front]; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_contains(SNAME *_queue_, V element, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->count, j++) \
|
||||
{ \
|
||||
if (comparator(_queue_->buffer[i], element) == 0) \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->count == 0; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_full(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->count >= SIZE; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_count(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_capacity(void) \
|
||||
{ \
|
||||
return SIZE; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
iter->cursor = 0; \
|
||||
else \
|
||||
iter->cursor = (iter->target->rear == 0) ? SIZE - 1 : iter->target->rear - 1; \
|
||||
\
|
||||
iter->index = iter->target->count - 1; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
if (iter->index == iter->target->count - 1) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->cursor = (iter->cursor + 1) % (SIZE); \
|
||||
iter->index++; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
if (iter->index == 0) \
|
||||
iter->start = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->cursor = (iter->cursor == 0) ? SIZE - 1 : iter->cursor - 1; \
|
||||
iter->index--; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
\
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(iter->target->buffer[iter->cursor]); \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->index; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_queue_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _queue_); \
|
||||
PFX##_iter_to_start(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _queue_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_SAC_QUEUE_H */
|
||||
+3
-10
@@ -79,7 +79,6 @@
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME PFX##_new(void); \
|
||||
FMOD void PFX##_clear(SNAME *_stack_); \
|
||||
FMOD void PFX##_free(SNAME *_stack_); \
|
||||
/* Collection Input and Output */ \
|
||||
FMOD bool PFX##_push(SNAME *_stack_, V element); \
|
||||
FMOD bool PFX##_pop(SNAME *_stack_); \
|
||||
@@ -142,17 +141,11 @@
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_stack_) \
|
||||
{ \
|
||||
memset(_stack_->buffer, 0, sizeof(V) * SIZE); \
|
||||
memset(_stack_->buffer, 0, sizeof(_stack_->buffer)); \
|
||||
\
|
||||
_stack_->count = 0; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_free(SNAME *_stack_) \
|
||||
{ \
|
||||
free(_stack_->buffer); \
|
||||
free(_stack_); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push(SNAME *_stack_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_stack_)) \
|
||||
@@ -192,7 +185,7 @@
|
||||
FMOD V PFX##_top(SNAME *_stack_) \
|
||||
{ \
|
||||
if (PFX##_empty(_stack_)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return _stack_->buffer[_stack_->count - 1]; \
|
||||
} \
|
||||
@@ -293,7 +286,7 @@
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
PFX##_impl_default_value(); \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
|
||||
+1870
File diff suppressed because it is too large.
Load diff
+9
-3
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file for_each.h
|
||||
* for_each.h
|
||||
*
|
||||
* Creation Date: 25/02/2019
|
||||
*
|
||||
@@ -8,6 +8,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* ForEach utility
|
||||
*
|
||||
* Read Documentation.md for more information
|
||||
*/
|
||||
|
||||
#ifndef CMC_FOR_EACH
|
||||
#define CMC_FOR_EACH
|
||||
|
||||
@@ -18,7 +24,7 @@
|
||||
{ \
|
||||
BODY; \
|
||||
} \
|
||||
} while (0);
|
||||
} while (0)
|
||||
|
||||
#define FOR_EACH_REV(PFX, SNAME, TARGET, BODY) \
|
||||
do \
|
||||
@@ -27,6 +33,6 @@
|
||||
{ \
|
||||
BODY; \
|
||||
} \
|
||||
} while (0);
|
||||
} while (0)
|
||||
|
||||
#endif /* CMC_FOR_EACH */
|
||||
+35
-68
@@ -8,9 +8,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* Simple logging macros */
|
||||
/* You can toggle colors defining the macro CMC_LOG_COLOR but be sure that */
|
||||
/* your terminal supports ANSI color escape codes */
|
||||
/**
|
||||
* Simple logging macros
|
||||
* You can toggle colors defining the macro CMC_LOG_COLOR but be sure that
|
||||
* your terminal supports ANSI color escape codes.
|
||||
*
|
||||
* You can customize the logging utility by accessing cmc_log_config and
|
||||
* directly modifying its values to better suit your needs.
|
||||
*/
|
||||
|
||||
/**
|
||||
* What each error code means
|
||||
@@ -40,21 +45,6 @@
|
||||
* ERROR - 5
|
||||
* FATAL - 6
|
||||
*
|
||||
* Functions API
|
||||
*
|
||||
* void cmc_log_tlevel(int level)
|
||||
* Set level for the Terminal Output to stderr.
|
||||
* void cmc_log_flevel(int level)
|
||||
* Set level for the File Output to FILE pointer.
|
||||
* void cmc_log_tenable(bool enabled)
|
||||
* Enables or disables Terminal Output to stderr.
|
||||
* void cmc_log_fenable(bool enabled)
|
||||
* Enables or disables File Output.
|
||||
* void cmc_log_file(FILE *file)
|
||||
* Set a file for writing the logging messages to it.
|
||||
* void cmc_log_set(bool enabled)
|
||||
* Sets on or off all the logging messages.
|
||||
*
|
||||
* How the Log Level is calculated
|
||||
*
|
||||
* - If the log level is 0 all logs are enabled.
|
||||
@@ -74,8 +64,13 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
static const char *names[] = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
|
||||
static const char *color[] = {"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"};
|
||||
static const char *cmc_log_names[] = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
|
||||
|
||||
#ifdef CMC_LOG_COLOR
|
||||
|
||||
static const char *cmc_log_color[] = {"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"};
|
||||
|
||||
#endif
|
||||
|
||||
static struct
|
||||
{
|
||||
@@ -85,9 +80,10 @@ static struct
|
||||
bool fenabled; /* File Output Enabled */
|
||||
FILE *file; /* File for Output */
|
||||
bool enabled; /* Logging enabled */
|
||||
} log_config = {0, 0, true, true, NULL, true};
|
||||
|
||||
typedef enum log_type_e
|
||||
} cmc_log_config = {0, 0, true, true, NULL, true};
|
||||
|
||||
typedef enum cmc_log_type_e
|
||||
{
|
||||
LOG_TRACE = 1,
|
||||
LOG_DEBUG = 2,
|
||||
@@ -95,7 +91,8 @@ typedef enum log_type_e
|
||||
LOG_WARN = 4,
|
||||
LOG_ERROR = 5,
|
||||
LOG_FATAL = 6
|
||||
} log_type;
|
||||
|
||||
} cmc_log_type;
|
||||
|
||||
#define log_trace(fmt, ...) cmc_log(LOG_TRACE, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define log_debug(fmt, ...) cmc_log(LOG_DEBUG, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
@@ -104,46 +101,16 @@ typedef enum log_type_e
|
||||
#define log_error(fmt, ...) cmc_log(LOG_ERROR, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define log_fatal(fmt, ...) cmc_log(LOG_FATAL, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
|
||||
static void cmc_log_tlevel(int terminal_level)
|
||||
static void cmc_log(cmc_log_type log, const char *filename, const char *funcname, int line, const char *fmt, ...)
|
||||
{
|
||||
log_config.tlevel = terminal_level;
|
||||
}
|
||||
|
||||
static void cmc_log_flevel(int file_level)
|
||||
{
|
||||
log_config.flevel = file_level;
|
||||
}
|
||||
|
||||
static void cmc_log_tenable(bool enabled)
|
||||
{
|
||||
log_config.tenabled = enabled;
|
||||
}
|
||||
|
||||
static void cmc_log_fenable(bool enabled)
|
||||
{
|
||||
log_config.fenabled = enabled;
|
||||
}
|
||||
|
||||
static void cmc_log_file(FILE *file)
|
||||
{
|
||||
log_config.file = file;
|
||||
}
|
||||
|
||||
static void cmc_log_set(bool enabled)
|
||||
{
|
||||
log_config.enabled = enabled;
|
||||
}
|
||||
|
||||
static void cmc_log(log_type log, const char *filename, const char *funcname, int line, const char *fmt, ...)
|
||||
{
|
||||
if (!log_config.enabled)
|
||||
if (!cmc_log_config.enabled)
|
||||
return;
|
||||
|
||||
if (log_config.tenabled)
|
||||
if (cmc_log_config.tenabled)
|
||||
{
|
||||
if (log_config.tlevel < 0 && ((int)log * -1) < log_config.tlevel)
|
||||
if (cmc_log_config.tlevel < 0 && ((int)log * -1) < cmc_log_config.tlevel)
|
||||
return;
|
||||
else if (log_config.tlevel > 0 && (int)log < log_config.tlevel)
|
||||
else if (cmc_log_config.tlevel > 0 && (int)log < cmc_log_config.tlevel)
|
||||
return;
|
||||
|
||||
int i = (int)log - 1;
|
||||
@@ -154,14 +121,14 @@ static void cmc_log(log_type log, const char *filename, const char *funcname, in
|
||||
char time[16];
|
||||
time[strftime(time, sizeof(time), "%H:%M:%S", lt)] = '\0';
|
||||
|
||||
#if defined(CMC_LOG_COLOR)
|
||||
#ifdef CMC_LOG_COLOR
|
||||
fprintf(stderr,
|
||||
"%s %s%5s\x1b[0m \x1b[90m%s at %s:%d:\x1b[0m ",
|
||||
time, color[i], names[i], filename, funcname, line);
|
||||
time, cmc_log_color[i], cmc_log_names[i], filename, funcname, line);
|
||||
#else
|
||||
fprintf(stderr,
|
||||
"%s %5s %s at %s:%d: ",
|
||||
time, names[i], filename, funcname, line);
|
||||
time, cmc_log_names[i], filename, funcname, line);
|
||||
#endif
|
||||
|
||||
va_list args;
|
||||
@@ -173,11 +140,11 @@ static void cmc_log(log_type log, const char *filename, const char *funcname, in
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
if (log_config.file && log_config.fenabled)
|
||||
if (cmc_log_config.file && cmc_log_config.fenabled)
|
||||
{
|
||||
if (log_config.flevel < 0 && ((int)log * -1) < log_config.flevel)
|
||||
if (cmc_log_config.flevel < 0 && ((int)log * -1) < cmc_log_config.flevel)
|
||||
return;
|
||||
else if (log_config.flevel > 0 && (int)log < log_config.flevel)
|
||||
else if (cmc_log_config.flevel > 0 && (int)log < cmc_log_config.flevel)
|
||||
return;
|
||||
|
||||
int i = (int)log - 1;
|
||||
@@ -188,15 +155,15 @@ static void cmc_log(log_type log, const char *filename, const char *funcname, in
|
||||
char time[32];
|
||||
time[strftime(time, sizeof(time), "%Y-%m-%d %H:%M:%S", lt)] = '\0';
|
||||
|
||||
fprintf(log_config.file, "%s %5s %s at %s:%d: ", time, names[i], filename, funcname, line);
|
||||
fprintf(cmc_log_config.file, "%s %5s %s at %s:%d: ", time, cmc_log_names[i], filename, funcname, line);
|
||||
|
||||
va_list file_args;
|
||||
va_start(file_args, fmt);
|
||||
vfprintf(log_config.file, fmt, file_args);
|
||||
vfprintf(cmc_log_config.file, fmt, file_args);
|
||||
va_end(file_args);
|
||||
|
||||
fprintf(log_config.file, "\n");
|
||||
fflush(log_config.file);
|
||||
fprintf(cmc_log_config.file, "\n");
|
||||
fflush(cmc_log_config.file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* test.h
|
||||
*
|
||||
* Creation Date: 26/06/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simple Unit Test Utility
|
||||
*
|
||||
* CMC_CREATE_UNIT
|
||||
* Create a UnitTest
|
||||
* Parameters:
|
||||
* - UNAME : UnitTest name (const char *)
|
||||
* - VERBOSE : Print PASSED / FAILED messages if true (bool)
|
||||
* - BODY : Body containing all tests related to this UnitTest
|
||||
*
|
||||
* CMC_CREATE_TEST
|
||||
* Create a Test inside a UnitTest.
|
||||
* Parameters:
|
||||
* - TNAME : Test name (const char *)
|
||||
* - BODY : Block of code containing a specific test
|
||||
* Inside the BODY use the following macros:
|
||||
* - CMC_TEST_PASS
|
||||
* Pass current test.
|
||||
* - CMC_TEST_FAIL
|
||||
* Fail current test.
|
||||
* - CMC_TEST_PASS_ELSE_FAIL
|
||||
* If given expression is true, pass current test, else fail.
|
||||
* - CMC_TEST_ABORT
|
||||
* Abort current unit test and displays error message. All tests
|
||||
* after the abort won't be called.
|
||||
* All of these macros can only be called once per test.
|
||||
*
|
||||
* CMC_TEST_COLOR
|
||||
* Define this macro to allow colored output.
|
||||
*/
|
||||
|
||||
#ifndef CMC_TEST_H
|
||||
#define CMC_TEST_H
|
||||
|
||||
#include "timer.h"
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef CMC_TEST_COLOR
|
||||
static const char *cmc_test_color[] = {"\x1b[32m", "\x1b[31m", "\x1b[35m"};
|
||||
#endif
|
||||
|
||||
typedef struct cmc_test_info_s
|
||||
{
|
||||
uintmax_t total;
|
||||
uintmax_t passed;
|
||||
uintmax_t failed;
|
||||
bool aborted;
|
||||
bool verbose;
|
||||
} cmc_test_info;
|
||||
|
||||
/* Logging function */
|
||||
static void cmc_test_log(const char *unit_name, const char *current_test, bool aborted, bool passed)
|
||||
{
|
||||
if (aborted)
|
||||
{
|
||||
#ifdef CMC_TEST_COLOR
|
||||
printf("UNIT_TEST %s %sABORTED\x1b[0m AT %s\n",
|
||||
unit_name,
|
||||
cmc_test_color[2],
|
||||
current_test);
|
||||
#else
|
||||
printf("UNIT_TEST %s ABORTED at %s\n", unit_name, current_test);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef CMC_TEST_COLOR
|
||||
printf("Test from %s %s%7s\x1b[0m %s\n",
|
||||
unit_name,
|
||||
passed ? cmc_test_color[0] : cmc_test_color[1],
|
||||
passed ? "PASSED" : "FAILED",
|
||||
current_test);
|
||||
#else
|
||||
printf("Test from %s %7s %s\n", unit_name, passed ? "PASSED" : "FAILED", current_test);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#define CMC_CREATE_UNIT(UNAME, VERBOSE, BODY) \
|
||||
void UNAME(void) \
|
||||
{ \
|
||||
const char *unit_name = #UNAME; \
|
||||
const char *current_test = NULL; \
|
||||
\
|
||||
cmc_test_info tinfo = {0}; \
|
||||
timer_t timer = {0}; \
|
||||
\
|
||||
tinfo.verbose = VERBOSE; \
|
||||
\
|
||||
/* Tests */ \
|
||||
timer_start(timer); \
|
||||
BODY; \
|
||||
timer_stop(timer); \
|
||||
timer_calc(timer); \
|
||||
\
|
||||
unittest_abort: \
|
||||
if (tinfo.aborted) \
|
||||
{ \
|
||||
cmc_test_log(unit_name, current_test, true, false); \
|
||||
} \
|
||||
\
|
||||
printf("+--------------------------------------------------+\n"); \
|
||||
printf("| Unit Test Report : %-30s|\n", unit_name); \
|
||||
printf("| TOTAL : %10" PRIuMAX " |\n", tinfo.total); \
|
||||
printf("| PASSED : %10" PRIuMAX " |\n", tinfo.passed); \
|
||||
printf("| FAILED : %10" PRIuMAX " |\n", tinfo.failed); \
|
||||
printf("| |\n"); \
|
||||
printf("| Total Unit Test Runtime : %9.0f milliseconds |\n", timer.result); \
|
||||
printf("+--------------------------------------------------+\n"); \
|
||||
}
|
||||
|
||||
#define CMC_CREATE_TEST(TNAME, BODY) \
|
||||
do \
|
||||
{ \
|
||||
current_test = #TNAME; \
|
||||
\
|
||||
tinfo.total += 1; \
|
||||
\
|
||||
BODY; \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define CMC_TEST_PASS() \
|
||||
do \
|
||||
{ \
|
||||
tinfo.passed += 1; \
|
||||
if (tinfo.verbose) \
|
||||
cmc_test_log(unit_name, current_test, false, true); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define CMC_TEST_FAIL() \
|
||||
do \
|
||||
{ \
|
||||
tinfo.failed += 1; \
|
||||
if (tinfo.verbose) \
|
||||
cmc_test_log(unit_name, current_test, false, false); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define CMC_TEST_PASS_ELSE_FAIL(EXPRESSION) \
|
||||
do \
|
||||
{ \
|
||||
if (EXPRESSION) \
|
||||
CMC_TEST_PASS(); \
|
||||
else \
|
||||
CMC_TEST_FAIL(); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define CMC_TEST_ABORT() \
|
||||
do \
|
||||
{ \
|
||||
\
|
||||
tinfo.aborted = true; \
|
||||
tinfo.total -= 1; \
|
||||
goto unittest_abort; \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#endif /* CMC_TEST_H */
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* timer.h
|
||||
*
|
||||
* Creation Date: 12/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/* Simple timer macros utility */
|
||||
|
||||
#ifndef CMC_TIMER_H
|
||||
#define CMC_TIMER_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
typedef struct timer_s
|
||||
{
|
||||
clock_t start;
|
||||
clock_t stop;
|
||||
double result;
|
||||
} timer_t;
|
||||
|
||||
#define timer_start(timer) \
|
||||
do \
|
||||
{ \
|
||||
(timer).start = clock(); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define timer_stop(timer) \
|
||||
do \
|
||||
{ \
|
||||
(timer).stop = clock(); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define timer_calc(timer) \
|
||||
do \
|
||||
{ \
|
||||
timer_t *t = &(timer); \
|
||||
t->result = (double)(t->stop - t->start) * 1000.0 / CLOCKS_PER_SEC; \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#endif /* CMC_TIMER_H */
|
||||
+10
-8
@@ -1,15 +1,17 @@
|
||||
CFLAGS= -Wno-unused-function -Wno-unused-paramter -Wno-unused-variable -std=c11 -Wall -Wextra
|
||||
CC = gcc
|
||||
CFLAGS = -std=c11 -Wall -Wextra
|
||||
CFLAGS += -Wno-unused-function -Wno-unused-paramter -Wno-unused-variable -Wno-unused-label
|
||||
|
||||
main:
|
||||
gcc foreach.c -o foreach $(CFLAGS)
|
||||
$(CC) foreach.c -o foreach $(CFLAGS)
|
||||
./foreach
|
||||
gcc iterators.c -o iterators $(CFLAGS)
|
||||
$(CC) iterators.c -o iterators $(CFLAGS)
|
||||
./iterators
|
||||
gcc contains.c -o contains $(CFLAGS)
|
||||
$(CC) contains.c -o contains $(CFLAGS)
|
||||
./contains
|
||||
gcc types.c -o types $(CFLAGS)
|
||||
$(CC) types.c -o types $(CFLAGS)
|
||||
./types
|
||||
gcc -c ./sep/sep.c -o ./sep/sep.o $(CFLAGS)
|
||||
gcc -c ./sep/main.c -o ./sep/main.o $(CFLAGS)
|
||||
gcc ./sep/sep.o ./sep/main.o -o ./sep/sep
|
||||
$(CC) -c ./sep/sep.c -o ./sep/sep.o $(CFLAGS)
|
||||
$(CC) -c ./sep/main.c -o ./sep/main.o $(CFLAGS)
|
||||
$(CC) ./sep/sep.o ./sep/main.o -o ./sep/sep
|
||||
./sep/sep
|
||||
@@ -1,5 +1,6 @@
|
||||
# Tests
|
||||
|
||||
* `main` - Unit tests for the main C Macro Collections library with code coverage;
|
||||
* `sep/main.c`, `sep/sep.c` and `sep/sep.h` - Tests separate header and source compilation;
|
||||
* `contains.c` - Tests the `contains` function for all collections;
|
||||
* `foreach.c` - Tests the ForEach macros for all collections;
|
||||
|
||||
+20
-20
@@ -72,45 +72,45 @@ int main(void)
|
||||
|
||||
FOR_EACH(d, deque, d, {
|
||||
sum3 += d_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(hm, hmap, hm, {
|
||||
sum10 += hm_iter_key(&iter);
|
||||
sum11 += hm_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(hs, hset, hs, {
|
||||
sum9 += hs_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(h, heap, h, {
|
||||
sum5 += h_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(ll, linked, ll, {
|
||||
sum4 += ll_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(l, list, l, {
|
||||
sum0 += l_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(q, queue, q, {
|
||||
sum2 += q_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(s, stack, s, {
|
||||
sum1 += s_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(tm, tmap, tm, {
|
||||
sum7 += tm_iter_key(&iter);
|
||||
sum8 += tm_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH(ts, tset, ts, {
|
||||
sum6 += ts_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
printf("\n-------------------- FOR_EACH --------------------\n");
|
||||
if (sum3 == 50005000)
|
||||
@@ -161,45 +161,45 @@ int main(void)
|
||||
|
||||
FOR_EACH_REV(d, deque, d, {
|
||||
sum3 += d_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH_REV(hm, hmap, hm, {
|
||||
sum10 += hm_iter_key(&iter);
|
||||
sum11 += hm_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH_REV(hs, hset, hs, {
|
||||
sum9 += hs_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH_REV(h, heap, h, {
|
||||
sum5 += h_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH_REV(ll, linked, ll, {
|
||||
sum4 += ll_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH_REV(l, list, l, {
|
||||
sum0 += l_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH_REV(q, queue, q, {
|
||||
sum2 += q_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH_REV(s, stack, s, {
|
||||
sum1 += s_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH_REV(tm, tmap, tm, {
|
||||
sum7 += tm_iter_key(&iter);
|
||||
sum8 += tm_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
FOR_EACH_REV(ts, tset, ts, {
|
||||
sum6 += ts_iter_value(&iter);
|
||||
})
|
||||
});
|
||||
|
||||
printf("-------------------- FOR_EACH_REV --------------------\n");
|
||||
if (sum3 == 50005000)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
CC = gcc
|
||||
CFLAGS = -std=c11 -Wall -Wextra
|
||||
CFLAGS += -Wno-unused-function -Wno-unused-parameter -Wno-unused-variable -Wno-unused-label
|
||||
CVFLAGS = --coverage -O0
|
||||
INCLUDE = ../../src/
|
||||
|
||||
main:
|
||||
$(CC) main.c -o main $(CFLAGS) $(CVFLAGS) -I $(INCLUDE)
|
||||
./main
|
||||
gcov ./main.c
|
||||
|
||||
dev:
|
||||
$(CC) main.c -o main $(CFLAGS) $(CVFLAGS) -I $(INCLUDE)
|
||||
./main
|
||||
gcov ./main.c -n
|
||||
rm *.gcda *.gcno *.exe
|
||||
@@ -0,0 +1,7 @@
|
||||
# main
|
||||
|
||||
Tests for the main C Macro Collections library. In order to provide a good code coverage, all macros have been expanded and added to `src/*.c`.
|
||||
|
||||
* `src` - Since gcov fails to detect code that was expanded by macro, all collections where manually expanded and dumped into their respective source files;
|
||||
* `unt` - Unit Tests;
|
||||
* `main.c` - Where all tests are compiled together and called by main().
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "unt/deque.c"
|
||||
#include "unt/hashmap.c"
|
||||
#include "unt/hashset.c"
|
||||
#include "unt/heap.c"
|
||||
#include "unt/linkedlist.c"
|
||||
#include "unt/list.c"
|
||||
#include "unt/queue.c"
|
||||
#include "unt/stack.c"
|
||||
#include "unt/treemap.c"
|
||||
#include "unt/treeset.c"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
deque_test();
|
||||
hashmap_test();
|
||||
hashset_test();
|
||||
heap_test();
|
||||
linkedlist_test();
|
||||
list_test();
|
||||
queue_test();
|
||||
stack_test();
|
||||
treemap_test();
|
||||
treeset_test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
#include "cmc/deque.h"
|
||||
|
||||
typedef struct deque_s
|
||||
{
|
||||
size_t *buffer;
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
size_t front;
|
||||
size_t back;
|
||||
struct deque_iter_s (*it_start)(struct deque_s *);
|
||||
struct deque_iter_s (*it_end)(struct deque_s *);
|
||||
} deque, *deque_ptr;
|
||||
typedef struct deque_iter_s
|
||||
{
|
||||
struct deque_s *target;
|
||||
size_t cursor;
|
||||
size_t index;
|
||||
bool start;
|
||||
bool end;
|
||||
} deque_iter, *deque_iter_ptr;
|
||||
deque *d_new(size_t capacity);
|
||||
void d_clear(deque *_deque_);
|
||||
void d_free(deque *_deque_);
|
||||
bool d_push_front(deque *_deque_, size_t element);
|
||||
bool d_push_back(deque *_deque_, size_t element);
|
||||
bool d_pop_front(deque *_deque_);
|
||||
bool d_pop_back(deque *_deque_);
|
||||
bool d_push_front_if(deque *_deque_, size_t element, bool condition);
|
||||
bool d_push_back_if(deque *_deque_, size_t element, bool condition);
|
||||
bool d_pop_front_if(deque *_deque_, bool condition);
|
||||
bool d_pop_back_if(deque *_deque_, bool condition);
|
||||
size_t d_front(deque *_deque_);
|
||||
size_t d_back(deque *_deque_);
|
||||
bool d_contains(deque *_deque_, size_t element, int (*comparator)(size_t, size_t));
|
||||
bool d_empty(deque *_deque_);
|
||||
bool d_full(deque *_deque_);
|
||||
size_t d_count(deque *_deque_);
|
||||
size_t d_capacity(deque *_deque_);
|
||||
deque_iter *d_iter_new(deque *target);
|
||||
void d_iter_free(deque_iter *iter);
|
||||
void d_iter_init(deque_iter *iter, deque *target);
|
||||
bool d_iter_start(deque_iter *iter);
|
||||
bool d_iter_end(deque_iter *iter);
|
||||
void d_iter_to_start(deque_iter *iter);
|
||||
void d_iter_to_end(deque_iter *iter);
|
||||
bool d_iter_next(deque_iter *iter);
|
||||
bool d_iter_prev(deque_iter *iter);
|
||||
size_t d_iter_value(deque_iter *iter);
|
||||
size_t *d_iter_rvalue(deque_iter *iter);
|
||||
size_t d_iter_index(deque_iter *iter);
|
||||
static inline size_t d_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
static bool d_impl_grow(deque *_deque_);
|
||||
static deque_iter d_impl_it_start(deque *_deque_);
|
||||
static deque_iter d_impl_it_end(deque *_deque_);
|
||||
deque *d_new(size_t capacity)
|
||||
{
|
||||
if (capacity < 1)
|
||||
return NULL;
|
||||
deque *_deque_ = malloc(sizeof(deque));
|
||||
if (!_deque_)
|
||||
return NULL;
|
||||
_deque_->buffer = malloc(sizeof(size_t) * capacity);
|
||||
if (!_deque_->buffer)
|
||||
{
|
||||
free(_deque_);
|
||||
return NULL;
|
||||
}
|
||||
memset(_deque_->buffer, 0, sizeof(size_t) * capacity);
|
||||
_deque_->capacity = capacity;
|
||||
_deque_->count = 0;
|
||||
_deque_->front = 0;
|
||||
_deque_->back = 0;
|
||||
_deque_->it_start = d_impl_it_start;
|
||||
_deque_->it_end = d_impl_it_end;
|
||||
return _deque_;
|
||||
}
|
||||
void d_clear(deque *_deque_)
|
||||
{
|
||||
memset(_deque_->buffer, 0, sizeof(size_t) * _deque_->capacity);
|
||||
_deque_->count = 0;
|
||||
_deque_->front = 0;
|
||||
_deque_->back = 0;
|
||||
}
|
||||
void d_free(deque *_deque_)
|
||||
{
|
||||
free(_deque_->buffer);
|
||||
free(_deque_);
|
||||
}
|
||||
bool d_push_front(deque *_deque_, size_t element)
|
||||
{
|
||||
if (d_full(_deque_))
|
||||
{
|
||||
if (!d_impl_grow(_deque_))
|
||||
return false;
|
||||
}
|
||||
_deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1;
|
||||
_deque_->buffer[_deque_->front] = element;
|
||||
_deque_->count++;
|
||||
return true;
|
||||
}
|
||||
bool d_push_back(deque *_deque_, size_t element)
|
||||
{
|
||||
if (d_full(_deque_))
|
||||
{
|
||||
if (!d_impl_grow(_deque_))
|
||||
return false;
|
||||
}
|
||||
_deque_->buffer[_deque_->back] = element;
|
||||
_deque_->back = (_deque_->back == _deque_->capacity - 1) ? 0 : _deque_->back + 1;
|
||||
_deque_->count++;
|
||||
return true;
|
||||
}
|
||||
bool d_pop_front(deque *_deque_)
|
||||
{
|
||||
if (d_empty(_deque_))
|
||||
return false;
|
||||
_deque_->buffer[_deque_->front] = d_impl_default_value();
|
||||
_deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1;
|
||||
_deque_->count--;
|
||||
return true;
|
||||
}
|
||||
bool d_pop_back(deque *_deque_)
|
||||
{
|
||||
if (d_empty(_deque_))
|
||||
return false;
|
||||
_deque_->back = (_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1;
|
||||
_deque_->buffer[_deque_->back] = d_impl_default_value();
|
||||
_deque_->count--;
|
||||
return true;
|
||||
}
|
||||
bool d_push_front_if(deque *_deque_, size_t element, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return d_push_front(_deque_, element);
|
||||
return false;
|
||||
}
|
||||
bool d_push_back_if(deque *_deque_, size_t element, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return d_push_back(_deque_, element);
|
||||
return false;
|
||||
}
|
||||
bool d_pop_front_if(deque *_deque_, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return d_pop_front(_deque_);
|
||||
return false;
|
||||
}
|
||||
bool d_pop_back_if(deque *_deque_, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return d_pop_back(_deque_);
|
||||
return false;
|
||||
}
|
||||
size_t d_front(deque *_deque_)
|
||||
{
|
||||
if (d_empty(_deque_))
|
||||
return d_impl_default_value();
|
||||
return _deque_->buffer[_deque_->front];
|
||||
}
|
||||
size_t d_back(deque *_deque_)
|
||||
{
|
||||
if (d_empty(_deque_))
|
||||
return d_impl_default_value();
|
||||
return _deque_->buffer[(_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1];
|
||||
}
|
||||
bool d_contains(deque *_deque_, size_t element, int (*comparator)(size_t, size_t))
|
||||
{
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->count, j++)
|
||||
{
|
||||
if (comparator(_deque_->buffer[i], element) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool d_empty(deque *_deque_) { return _deque_->count == 0; }
|
||||
bool d_full(deque *_deque_) { return _deque_->count >= _deque_->capacity; }
|
||||
size_t d_count(deque *_deque_) { return _deque_->count; }
|
||||
size_t d_capacity(deque *_deque_) { return _deque_->capacity; }
|
||||
deque_iter *d_iter_new(deque *target)
|
||||
{
|
||||
deque_iter *iter = malloc(sizeof(deque_iter));
|
||||
if (!iter)
|
||||
return NULL;
|
||||
d_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void d_iter_free(deque_iter *iter) { free(iter); }
|
||||
void d_iter_init(deque_iter *iter, deque *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->cursor = target->front;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = d_empty(target);
|
||||
}
|
||||
bool d_iter_start(deque_iter *iter) { return d_empty(iter->target) || iter->start; }
|
||||
bool d_iter_end(deque_iter *iter) { return d_empty(iter->target) || iter->end; }
|
||||
void d_iter_to_start(deque_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->target->front;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = d_empty(iter->target);
|
||||
}
|
||||
void d_iter_to_end(deque_iter *iter)
|
||||
{
|
||||
if (d_empty(iter->target))
|
||||
iter->cursor = 0;
|
||||
else
|
||||
iter->cursor = (iter->target->back == 0) ? iter->target->capacity - 1 : iter->target->back - 1;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = d_empty(iter->target);
|
||||
iter->end = true;
|
||||
}
|
||||
bool d_iter_next(deque_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
iter->start = d_empty(iter->target);
|
||||
if (iter->index == iter->target->count - 1)
|
||||
iter->end = true;
|
||||
else
|
||||
{
|
||||
iter->cursor = (iter->cursor + 1) % (iter->target->capacity);
|
||||
iter->index++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool d_iter_prev(deque_iter *iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
iter->end = d_empty(iter->target);
|
||||
if (iter->index == 0)
|
||||
iter->start = true;
|
||||
else
|
||||
{
|
||||
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1;
|
||||
iter->index--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
size_t d_iter_value(deque_iter *iter)
|
||||
{
|
||||
if (d_empty(iter->target))
|
||||
return d_impl_default_value();
|
||||
return iter->target->buffer[iter->cursor];
|
||||
}
|
||||
size_t *d_iter_rvalue(deque_iter *iter)
|
||||
{
|
||||
if (d_empty(iter->target))
|
||||
return NULL;
|
||||
return &(iter->target->buffer[iter->cursor]);
|
||||
}
|
||||
size_t d_iter_index(deque_iter *iter) { return iter->index; }
|
||||
static bool d_impl_grow(deque *_deque_)
|
||||
{
|
||||
size_t new_capacity = _deque_->capacity * 2;
|
||||
size_t *new_buffer = malloc(sizeof(size_t) * new_capacity);
|
||||
if (!new_buffer)
|
||||
return false;
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->capacity, j++)
|
||||
{
|
||||
new_buffer[j] = _deque_->buffer[i];
|
||||
}
|
||||
free(_deque_->buffer);
|
||||
_deque_->buffer = new_buffer;
|
||||
_deque_->capacity = new_capacity;
|
||||
_deque_->front = 0;
|
||||
_deque_->back = _deque_->count;
|
||||
return true;
|
||||
}
|
||||
static deque_iter d_impl_it_start(deque *_deque_)
|
||||
{
|
||||
deque_iter iter;
|
||||
d_iter_init(&iter, _deque_);
|
||||
return iter;
|
||||
}
|
||||
static deque_iter d_impl_it_end(deque *_deque_)
|
||||
{
|
||||
deque_iter iter;
|
||||
d_iter_init(&iter, _deque_);
|
||||
d_iter_to_end(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,425 @@
|
||||
#include "cmc/hashmap.h"
|
||||
|
||||
typedef struct hashmap_s
|
||||
{
|
||||
struct hashmap_entry_s *buffer;
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
double load;
|
||||
int (*cmp)(size_t, size_t);
|
||||
size_t (*hash)(size_t);
|
||||
struct hashmap_iter_s (*it_start)(struct hashmap_s *);
|
||||
struct hashmap_iter_s (*it_end)(struct hashmap_s *);
|
||||
} hashmap, *hashmap_ptr;
|
||||
typedef struct hashmap_entry_s
|
||||
{
|
||||
size_t key;
|
||||
size_t value;
|
||||
size_t dist;
|
||||
enum EntryState_e state;
|
||||
} hashmap_entry, *hashmap_entry_ptr;
|
||||
typedef struct hashmap_iter_s
|
||||
{
|
||||
struct hashmap_s *target;
|
||||
size_t cursor;
|
||||
size_t index;
|
||||
size_t first;
|
||||
size_t last;
|
||||
bool start;
|
||||
bool end;
|
||||
} hashmap_iter, *hashmap_iter_ptr;
|
||||
hashmap *hm_new(size_t capacity, double load, int (*compare)(size_t, size_t), size_t (*hash)(size_t));
|
||||
void hm_clear(hashmap *_map_);
|
||||
void hm_free(hashmap *_map_);
|
||||
bool hm_insert(hashmap *_map_, size_t key, size_t value);
|
||||
bool hm_remove(hashmap *_map_, size_t key, size_t *value);
|
||||
bool hm_insert_if(hashmap *_map_, size_t key, size_t value, bool condition);
|
||||
bool hm_remove_if(hashmap *_map_, size_t key, size_t *value, bool condition);
|
||||
bool hm_max(hashmap *_map_, size_t *key, size_t *value);
|
||||
bool hm_min(hashmap *_map_, size_t *key, size_t *value);
|
||||
size_t hm_get(hashmap *_map_, size_t key);
|
||||
size_t *hm_get_ref(hashmap *_map_, size_t key);
|
||||
bool hm_contains(hashmap *_map_, size_t key);
|
||||
bool hm_empty(hashmap *_map_);
|
||||
size_t hm_count(hashmap *_map_);
|
||||
size_t hm_capacity(hashmap *_map_);
|
||||
hashmap_iter *hm_iter_new(hashmap *target);
|
||||
void hm_iter_free(hashmap_iter *iter);
|
||||
void hm_iter_init(hashmap_iter *iter, hashmap *target);
|
||||
bool hm_iter_start(hashmap_iter *iter);
|
||||
bool hm_iter_end(hashmap_iter *iter);
|
||||
void hm_iter_to_start(hashmap_iter *iter);
|
||||
void hm_iter_to_end(hashmap_iter *iter);
|
||||
bool hm_iter_next(hashmap_iter *iter);
|
||||
bool hm_iter_prev(hashmap_iter *iter);
|
||||
size_t hm_iter_key(hashmap_iter *iter);
|
||||
size_t hm_iter_value(hashmap_iter *iter);
|
||||
size_t *hm_iter_rvalue(hashmap_iter *iter);
|
||||
size_t hm_iter_index(hashmap_iter *iter);
|
||||
static inline size_t hm_impl_default_key(void)
|
||||
{
|
||||
size_t _empty_key_;
|
||||
memset(&_empty_key_, 0, sizeof(size_t));
|
||||
return _empty_key_;
|
||||
}
|
||||
static inline size_t hm_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
static bool hm_impl_grow(hashmap *_map_);
|
||||
static hashmap_entry *hm_impl_get_entry(hashmap *_map_, size_t key);
|
||||
static size_t hm_impl_calculate_size(size_t required);
|
||||
static hashmap_iter hm_impl_it_start(hashmap *_map_);
|
||||
static hashmap_iter hm_impl_it_end(hashmap *_map_);
|
||||
hashmap *hm_new(size_t capacity, double load, int (*compare)(size_t, size_t), size_t (*hash)(size_t))
|
||||
{
|
||||
if (capacity == 0 || load <= 0 || load >= 1)
|
||||
return NULL;
|
||||
size_t real_capacity = hm_impl_calculate_size(capacity / load);
|
||||
hashmap *_map_ = malloc(sizeof(hashmap));
|
||||
if (!_map_)
|
||||
return NULL;
|
||||
_map_->buffer = malloc(sizeof(hashmap_entry) * real_capacity);
|
||||
if (!_map_->buffer)
|
||||
{
|
||||
free(_map_);
|
||||
return NULL;
|
||||
}
|
||||
memset(_map_->buffer, 0, sizeof(hashmap_entry) * real_capacity);
|
||||
_map_->count = 0;
|
||||
_map_->capacity = real_capacity;
|
||||
_map_->load = load;
|
||||
_map_->cmp = compare;
|
||||
_map_->hash = hash;
|
||||
_map_->it_start = hm_impl_it_start;
|
||||
_map_->it_end = hm_impl_it_end;
|
||||
return _map_;
|
||||
}
|
||||
void hm_clear(hashmap *_map_)
|
||||
{
|
||||
memset(_map_->buffer, 0, sizeof(hashmap_entry) * _map_->capacity);
|
||||
_map_->count = 0;
|
||||
}
|
||||
void hm_free(hashmap *_map_)
|
||||
{
|
||||
free(_map_->buffer);
|
||||
free(_map_);
|
||||
}
|
||||
bool hm_insert(hashmap *_map_, size_t key, size_t value)
|
||||
{
|
||||
if ((double)_map_->capacity * _map_->load <= (double)_map_->count)
|
||||
{
|
||||
if (!hm_impl_grow(_map_))
|
||||
return false;
|
||||
}
|
||||
size_t hash = _map_->hash(key);
|
||||
size_t original_pos = hash % _map_->capacity;
|
||||
size_t pos = original_pos;
|
||||
hashmap_entry *target = &(_map_->buffer[pos]);
|
||||
if (hm_impl_get_entry(_map_, key) != NULL)
|
||||
return false;
|
||||
if (target->state == ES_EMPTY || target->state == ES_DELETED)
|
||||
{
|
||||
target->key = key;
|
||||
target->value = value;
|
||||
target->dist = original_pos - pos;
|
||||
target->state = ES_FILLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
pos++;
|
||||
target = &(_map_->buffer[pos % _map_->capacity]);
|
||||
if (target->state == ES_EMPTY || target->state == ES_DELETED)
|
||||
{
|
||||
target->key = key;
|
||||
target->value = value;
|
||||
target->dist = pos - original_pos;
|
||||
target->state = ES_FILLED;
|
||||
break;
|
||||
}
|
||||
else if (target->dist < original_pos - pos)
|
||||
{
|
||||
size_t tmp_k = target->key;
|
||||
size_t 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++;
|
||||
return true;
|
||||
}
|
||||
bool hm_remove(hashmap *_map_, size_t key, size_t *value)
|
||||
{
|
||||
hashmap_entry *result = hm_impl_get_entry(_map_, key);
|
||||
if (result == NULL)
|
||||
return false;
|
||||
*value = result->value;
|
||||
result->key = hm_impl_default_key();
|
||||
result->value = hm_impl_default_value();
|
||||
result->dist = 0;
|
||||
result->state = ES_DELETED;
|
||||
_map_->count--;
|
||||
return true;
|
||||
}
|
||||
bool hm_insert_if(hashmap *_map_, size_t key, size_t value, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return hm_insert(_map_, key, value);
|
||||
return false;
|
||||
}
|
||||
bool hm_remove_if(hashmap *_map_, size_t key, size_t *value, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return hm_remove(_map_, key, value);
|
||||
return false;
|
||||
}
|
||||
bool hm_max(hashmap *_map_, size_t *key, size_t *value)
|
||||
{
|
||||
if (hm_empty(_map_))
|
||||
return false;
|
||||
hashmap_iter iter;
|
||||
for (hm_iter_init(&iter, _map_); !hm_iter_end(&iter); hm_iter_next(&iter))
|
||||
{
|
||||
size_t result_key = hm_iter_key(&iter);
|
||||
size_t result_value = hm_iter_value(&iter);
|
||||
size_t index = hm_iter_index(&iter);
|
||||
if (index == 0)
|
||||
{
|
||||
*key = result_key;
|
||||
*value = result_value;
|
||||
}
|
||||
else if (_map_->cmp(result_key, *key) > 0)
|
||||
{
|
||||
*key = result_key;
|
||||
*value = result_value;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool hm_min(hashmap *_map_, size_t *key, size_t *value)
|
||||
{
|
||||
if (hm_empty(_map_))
|
||||
return false;
|
||||
hashmap_iter iter;
|
||||
for (hm_iter_init(&iter, _map_); !hm_iter_end(&iter); hm_iter_next(&iter))
|
||||
{
|
||||
size_t result_key = hm_iter_key(&iter);
|
||||
size_t result_value = hm_iter_value(&iter);
|
||||
size_t index = hm_iter_index(&iter);
|
||||
if (index == 0)
|
||||
{
|
||||
*key = result_key;
|
||||
*value = result_value;
|
||||
}
|
||||
else if (_map_->cmp(result_key, *key) < 0)
|
||||
{
|
||||
*key = result_key;
|
||||
*value = result_value;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
size_t hm_get(hashmap *_map_, size_t key)
|
||||
{
|
||||
hashmap_entry *entry = hm_impl_get_entry(_map_, key);
|
||||
if (!entry)
|
||||
return hm_impl_default_value();
|
||||
return entry->value;
|
||||
}
|
||||
size_t *hm_get_ref(hashmap *_map_, size_t key)
|
||||
{
|
||||
hashmap_entry *entry = hm_impl_get_entry(_map_, key);
|
||||
if (!entry)
|
||||
return NULL;
|
||||
return &(entry->value);
|
||||
}
|
||||
bool hm_contains(hashmap *_map_, size_t key) { return hm_impl_get_entry(_map_, key) != NULL; }
|
||||
bool hm_empty(hashmap *_map_) { return _map_->count == 0; }
|
||||
size_t hm_count(hashmap *_map_) { return _map_->count; }
|
||||
size_t hm_capacity(hashmap *_map_) { return _map_->capacity; }
|
||||
hashmap_iter *hm_iter_new(hashmap *target)
|
||||
{
|
||||
hashmap_iter *iter = malloc(sizeof(hashmap_iter));
|
||||
if (!iter)
|
||||
return NULL;
|
||||
hm_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void hm_iter_free(hashmap_iter *iter) { free(iter); }
|
||||
void hm_iter_init(hashmap_iter *iter, hashmap *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->cursor = 0;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = hm_empty(target);
|
||||
if (!hm_empty(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
if (target->buffer[i].state == 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 == ES_FILLED)
|
||||
{
|
||||
iter->last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bool hm_iter_start(hashmap_iter *iter) { return hm_empty(iter->target) || iter->start; }
|
||||
bool hm_iter_end(hashmap_iter *iter) { return hm_empty(iter->target) || iter->end; }
|
||||
void hm_iter_to_start(hashmap_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->first;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = hm_empty(iter->target);
|
||||
}
|
||||
void hm_iter_to_end(hashmap_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->last;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = hm_empty(iter->target);
|
||||
iter->end = true;
|
||||
}
|
||||
bool hm_iter_next(hashmap_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
hashmap_entry *scan = &(iter->target->buffer[iter->cursor]);
|
||||
if (iter->cursor == iter->last)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
iter->index++;
|
||||
while (1)
|
||||
{
|
||||
iter->cursor++;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
if (scan->state == ES_FILLED)
|
||||
break;
|
||||
}
|
||||
iter->start = hm_empty(iter->target);
|
||||
return true;
|
||||
}
|
||||
bool hm_iter_prev(hashmap_iter *iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
hashmap_entry *scan = &(iter->target->buffer[iter->cursor]);
|
||||
if (iter->cursor == iter->first)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
iter->index--;
|
||||
while (1)
|
||||
{
|
||||
iter->cursor--;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
if (scan->state == ES_FILLED)
|
||||
break;
|
||||
}
|
||||
iter->end = hm_empty(iter->target);
|
||||
return true;
|
||||
}
|
||||
size_t hm_iter_key(hashmap_iter *iter)
|
||||
{
|
||||
if (hm_empty(iter->target))
|
||||
return hm_impl_default_key();
|
||||
return iter->target->buffer[iter->cursor].key;
|
||||
}
|
||||
size_t hm_iter_value(hashmap_iter *iter)
|
||||
{
|
||||
if (hm_empty(iter->target))
|
||||
return hm_impl_default_value();
|
||||
return iter->target->buffer[iter->cursor].value;
|
||||
}
|
||||
size_t *hm_iter_rvalue(hashmap_iter *iter)
|
||||
{
|
||||
if (hm_empty(iter->target))
|
||||
return NULL;
|
||||
return &(iter->target->buffer[iter->cursor].value);
|
||||
}
|
||||
size_t hm_iter_index(hashmap_iter *iter) { return iter->index; }
|
||||
static bool hm_impl_grow(hashmap *_map_)
|
||||
{
|
||||
size_t new_size = hm_impl_calculate_size(_map_->capacity + _map_->capacity / 2);
|
||||
hashmap *_new_map_ = hm_new(new_size, _map_->load, _map_->cmp, _map_->hash);
|
||||
if (!_new_map_)
|
||||
return false;
|
||||
hashmap_iter iter;
|
||||
for (hm_iter_init(&iter, _map_); !hm_iter_end(&iter); hm_iter_next(&iter))
|
||||
{
|
||||
size_t key = hm_iter_key(&iter);
|
||||
size_t value = hm_iter_value(&iter);
|
||||
hm_insert(_new_map_, key, value);
|
||||
}
|
||||
if (_map_->count != _new_map_->count)
|
||||
{
|
||||
hm_free(_new_map_);
|
||||
return false;
|
||||
}
|
||||
hashmap_entry *tmp = _map_->buffer;
|
||||
_map_->buffer = _new_map_->buffer;
|
||||
_new_map_->buffer = tmp;
|
||||
_map_->capacity = _new_map_->capacity;
|
||||
hm_free(_new_map_);
|
||||
return true;
|
||||
}
|
||||
static hashmap_entry *hm_impl_get_entry(hashmap *_map_, size_t key)
|
||||
{
|
||||
size_t hash = _map_->hash(key);
|
||||
size_t pos = hash % _map_->capacity;
|
||||
hashmap_entry *target = &(_map_->buffer[pos]);
|
||||
while (target->state == ES_FILLED || target->state == ES_DELETED)
|
||||
{
|
||||
if (_map_->cmp(target->key, key) == 0)
|
||||
return target;
|
||||
pos++;
|
||||
target = &(_map_->buffer[pos % _map_->capacity]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
static size_t hm_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];
|
||||
}
|
||||
static hashmap_iter hm_impl_it_start(hashmap *_map_)
|
||||
{
|
||||
hashmap_iter iter;
|
||||
hm_iter_init(&iter, _map_);
|
||||
return iter;
|
||||
}
|
||||
static hashmap_iter hm_impl_it_end(hashmap *_map_)
|
||||
{
|
||||
hashmap_iter iter;
|
||||
hm_iter_init(&iter, _map_);
|
||||
hm_iter_to_end(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,499 @@
|
||||
#include "cmc/hashset.h"
|
||||
|
||||
typedef struct hashset_s
|
||||
{
|
||||
struct hashset_entry_s *buffer;
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
double load;
|
||||
int (*cmp)(size_t, size_t);
|
||||
size_t (*hash)(size_t);
|
||||
struct hashset_iter_s (*it_start)(struct hashset_s *);
|
||||
struct hashset_iter_s (*it_end)(struct hashset_s *);
|
||||
} hashset, *hashset_ptr;
|
||||
typedef struct hashset_entry_s
|
||||
{
|
||||
size_t value;
|
||||
size_t dist;
|
||||
enum EntryState_e state;
|
||||
} hashset_entry, *hashset_entry_ptr;
|
||||
typedef struct hashset_iter_s
|
||||
{
|
||||
struct hashset_s *target;
|
||||
size_t cursor;
|
||||
size_t index;
|
||||
size_t first;
|
||||
size_t last;
|
||||
bool start;
|
||||
bool end;
|
||||
} hashset_iter, *hashset_iter_ptr;
|
||||
hashset *hs_new(size_t capacity, double load, int (*compare)(size_t, size_t), size_t (*hash)(size_t));
|
||||
void hs_clear(hashset *_set_);
|
||||
void hs_free(hashset *_set_);
|
||||
bool hs_insert(hashset *_set_, size_t element);
|
||||
bool hs_remove(hashset *_set_, size_t element);
|
||||
bool hs_insert_if(hashset *_set_, size_t element, bool condition);
|
||||
bool hs_remove_if(hashset *_set_, size_t element, bool condition);
|
||||
bool hs_max(hashset *_set_, size_t *value);
|
||||
bool hs_min(hashset *_set_, size_t *value);
|
||||
bool hs_contains(hashset *_set_, size_t element);
|
||||
bool hs_empty(hashset *_set_);
|
||||
size_t hs_count(hashset *_set_);
|
||||
size_t hs_capacity(hashset *_set_);
|
||||
hashset *hs_union(hashset *_set1_, hashset *_set2_);
|
||||
hashset *hs_intersection(hashset *_set1_, hashset *_set2_);
|
||||
hashset *hs_difference(hashset *_set1_, hashset *_set2_);
|
||||
hashset *hs_symmetric_difference(hashset *_set1_, hashset *_set2_);
|
||||
bool hs_is_subset(hashset *_set1_, hashset *_set2_);
|
||||
bool hs_is_superset(hashset *_set1_, hashset *_set2_);
|
||||
bool hs_is_proper_subset(hashset *_set1_, hashset *_set2_);
|
||||
bool hs_is_proper_superset(hashset *_set1_, hashset *_set2_);
|
||||
bool hs_is_disjointset(hashset *_set1_, hashset *_set2_);
|
||||
hashset_iter *hs_iter_new(hashset *target);
|
||||
void hs_iter_free(hashset_iter *iter);
|
||||
void hs_iter_init(hashset_iter *iter, hashset *target);
|
||||
bool hs_iter_start(hashset_iter *iter);
|
||||
bool hs_iter_end(hashset_iter *iter);
|
||||
void hs_iter_to_start(hashset_iter *iter);
|
||||
void hs_iter_to_end(hashset_iter *iter);
|
||||
bool hs_iter_next(hashset_iter *iter);
|
||||
bool hs_iter_prev(hashset_iter *iter);
|
||||
size_t hs_iter_value(hashset_iter *iter);
|
||||
size_t hs_iter_index(hashset_iter *iter);
|
||||
static inline size_t hs_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
static bool hs_impl_grow(hashset *_set_);
|
||||
static hashset_entry *hs_impl_get_entry(hashset *_set_, size_t element);
|
||||
static size_t hs_impl_calculate_size(size_t required);
|
||||
static hashset_iter hs_impl_it_start(hashset *_set_);
|
||||
static hashset_iter hs_impl_it_end(hashset *_set_);
|
||||
hashset *hs_new(size_t capacity, double load, int (*compare)(size_t, size_t), size_t (*hash)(size_t))
|
||||
{
|
||||
if (capacity == 0 || load <= 0 || load >= 1)
|
||||
return NULL;
|
||||
size_t real_capacity = hs_impl_calculate_size(capacity / load);
|
||||
hashset *_set_ = malloc(sizeof(hashset));
|
||||
if (!_set_)
|
||||
return NULL;
|
||||
_set_->buffer = malloc(sizeof(hashset_entry) * real_capacity);
|
||||
if (!_set_->buffer)
|
||||
{
|
||||
free(_set_);
|
||||
return NULL;
|
||||
}
|
||||
memset(_set_->buffer, 0, sizeof(hashset_entry) * real_capacity);
|
||||
_set_->count = 0;
|
||||
_set_->capacity = real_capacity;
|
||||
_set_->load = load;
|
||||
_set_->cmp = compare;
|
||||
_set_->hash = hash;
|
||||
_set_->it_start = hs_impl_it_start;
|
||||
_set_->it_end = hs_impl_it_end;
|
||||
return _set_;
|
||||
}
|
||||
void hs_clear(hashset *_set_)
|
||||
{
|
||||
memset(_set_->buffer, 0, sizeof(hashset_entry) * _set_->capacity);
|
||||
_set_->count = 0;
|
||||
}
|
||||
void hs_free(hashset *_set_)
|
||||
{
|
||||
free(_set_->buffer);
|
||||
free(_set_);
|
||||
}
|
||||
bool hs_insert(hashset *_set_, size_t element)
|
||||
{
|
||||
if ((double)_set_->capacity * _set_->load <= (double)_set_->count)
|
||||
{
|
||||
if (!hs_impl_grow(_set_))
|
||||
return false;
|
||||
}
|
||||
size_t hash = _set_->hash(element);
|
||||
size_t original_pos = hash % _set_->capacity;
|
||||
size_t pos = original_pos;
|
||||
hashset_entry *target = &(_set_->buffer[pos]);
|
||||
if (hs_impl_get_entry(_set_, element) != NULL)
|
||||
return false;
|
||||
if (target->state == ES_EMPTY || target->state == ES_DELETED)
|
||||
{
|
||||
target->value = element;
|
||||
target->dist = pos - original_pos;
|
||||
target->state = ES_FILLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
pos++;
|
||||
target = &(_set_->buffer[pos % _set_->capacity]);
|
||||
if (target->state == ES_EMPTY || target->state == ES_DELETED)
|
||||
{
|
||||
target->value = element;
|
||||
target->dist = pos - original_pos;
|
||||
target->state = ES_FILLED;
|
||||
break;
|
||||
}
|
||||
else if (target->dist < pos - original_pos)
|
||||
{
|
||||
size_t tmp = target->value;
|
||||
size_t tmp_dist = target->dist;
|
||||
target->value = element;
|
||||
target->dist = pos - original_pos;
|
||||
element = tmp;
|
||||
original_pos = pos - tmp_dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
_set_->count++;
|
||||
return true;
|
||||
}
|
||||
bool hs_remove(hashset *_set_, size_t element)
|
||||
{
|
||||
hashset_entry *result = hs_impl_get_entry(_set_, element);
|
||||
if (result == NULL)
|
||||
return false;
|
||||
result->value = hs_impl_default_value();
|
||||
result->dist = 0;
|
||||
result->state = ES_DELETED;
|
||||
_set_->count--;
|
||||
return true;
|
||||
}
|
||||
bool hs_insert_if(hashset *_set_, size_t element, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return hs_insert(_set_, element);
|
||||
return false;
|
||||
}
|
||||
bool hs_remove_if(hashset *_set_, size_t element, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return hs_remove(_set_, element);
|
||||
return false;
|
||||
}
|
||||
bool hs_max(hashset *_set_, size_t *value)
|
||||
{
|
||||
if (hs_empty(_set_))
|
||||
return false;
|
||||
hashset_iter iter;
|
||||
for (hs_iter_init(&iter, _set_); !hs_iter_end(&iter); hs_iter_next(&iter))
|
||||
{
|
||||
size_t result = hs_iter_value(&iter);
|
||||
size_t index = hs_iter_index(&iter);
|
||||
if (index == 0)
|
||||
*value = result;
|
||||
else if (_set_->cmp(result, *value) > 0)
|
||||
*value = result;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool hs_min(hashset *_set_, size_t *value)
|
||||
{
|
||||
if (hs_empty(_set_))
|
||||
return false;
|
||||
hashset_iter iter;
|
||||
for (hs_iter_init(&iter, _set_); !hs_iter_end(&iter); hs_iter_next(&iter))
|
||||
{
|
||||
size_t result = hs_iter_value(&iter);
|
||||
size_t index = hs_iter_index(&iter);
|
||||
if (index == 0)
|
||||
*value = result;
|
||||
else if (_set_->cmp(result, *value) < 0)
|
||||
*value = result;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool hs_contains(hashset *_set_, size_t element) { return hs_impl_get_entry(_set_, element) != NULL; }
|
||||
bool hs_empty(hashset *_set_) { return _set_->count == 0; }
|
||||
size_t hs_count(hashset *_set_) { return _set_->count; }
|
||||
size_t hs_capacity(hashset *_set_) { return _set_->capacity; }
|
||||
hashset *hs_union(hashset *_set1_, hashset *_set2_)
|
||||
{
|
||||
hashset *_set_r_ = hs_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
|
||||
if (!_set_r_)
|
||||
return false;
|
||||
hashset_iter iter1, iter2;
|
||||
hs_iter_init(&iter1, _set1_);
|
||||
hs_iter_init(&iter2, _set2_);
|
||||
for (hs_iter_to_start(&iter1); !hs_iter_end(&iter1); hs_iter_next(&iter1))
|
||||
{
|
||||
hs_insert(_set_r_, hs_iter_value(&iter1));
|
||||
}
|
||||
for (hs_iter_to_start(&iter2); !hs_iter_end(&iter2); hs_iter_next(&iter2))
|
||||
{
|
||||
hs_insert(_set_r_, hs_iter_value(&iter2));
|
||||
}
|
||||
return _set_r_;
|
||||
}
|
||||
hashset *hs_intersection(hashset *_set1_, hashset *_set2_)
|
||||
{
|
||||
hashset *_set_r_ = hs_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
|
||||
if (!_set_r_)
|
||||
return false;
|
||||
hashset *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_;
|
||||
hashset *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_;
|
||||
hashset_iter iter;
|
||||
hs_iter_init(&iter, _set_A_);
|
||||
for (hs_iter_to_start(&iter); !hs_iter_end(&iter); hs_iter_next(&iter))
|
||||
{
|
||||
size_t value = hs_iter_value(&iter);
|
||||
if (hs_impl_get_entry(_set_B_, value) != NULL)
|
||||
hs_insert(_set_r_, value);
|
||||
}
|
||||
return _set_r_;
|
||||
}
|
||||
hashset *hs_difference(hashset *_set1_, hashset *_set2_)
|
||||
{
|
||||
hashset *_set_r_ = hs_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
|
||||
if (!_set_r_)
|
||||
return false;
|
||||
hashset_iter iter;
|
||||
hs_iter_init(&iter, _set1_);
|
||||
for (hs_iter_to_start(&iter); !hs_iter_end(&iter); hs_iter_next(&iter))
|
||||
{
|
||||
size_t value = hs_iter_value(&iter);
|
||||
if (hs_impl_get_entry(_set2_, value) == NULL)
|
||||
hs_insert(_set_r_, value);
|
||||
}
|
||||
return _set_r_;
|
||||
}
|
||||
hashset *hs_symmetric_difference(hashset *_set1_, hashset *_set2_)
|
||||
{
|
||||
hashset_iter iter1, iter2;
|
||||
hashset *_set_r_ = hs_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
|
||||
if (!_set_r_)
|
||||
return false;
|
||||
hs_iter_init(&iter1, _set1_);
|
||||
hs_iter_init(&iter2, _set2_);
|
||||
for (hs_iter_to_start(&iter1); !hs_iter_end(&iter1); hs_iter_next(&iter1))
|
||||
{
|
||||
size_t value = hs_iter_value(&iter1);
|
||||
if (hs_impl_get_entry(_set2_, value) == NULL)
|
||||
hs_insert(_set_r_, value);
|
||||
}
|
||||
for (hs_iter_to_start(&iter2); !hs_iter_end(&iter2); hs_iter_next(&iter2))
|
||||
{
|
||||
size_t value = hs_iter_value(&iter2);
|
||||
if (hs_impl_get_entry(_set1_, value) == NULL)
|
||||
hs_insert(_set_r_, value);
|
||||
}
|
||||
return _set_r_;
|
||||
}
|
||||
bool hs_is_subset(hashset *_set1_, hashset *_set2_)
|
||||
{
|
||||
if (hs_count(_set1_) > hs_count(_set2_))
|
||||
return false;
|
||||
if (hs_empty(_set1_))
|
||||
return true;
|
||||
hashset_iter iter;
|
||||
hs_iter_init(&iter, _set1_);
|
||||
for (hs_iter_to_start(&iter); !hs_iter_end(&iter); hs_iter_next(&iter))
|
||||
{
|
||||
size_t value = hs_iter_value(&iter);
|
||||
if (!hs_contains(_set2_, value))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool hs_is_superset(hashset *_set1_, hashset *_set2_) { return hs_is_subset(_set2_, _set1_); }
|
||||
bool hs_is_proper_subset(hashset *_set1_, hashset *_set2_)
|
||||
{
|
||||
if (hs_count(_set1_) >= hs_count(_set2_))
|
||||
return false;
|
||||
if (hs_empty(_set1_))
|
||||
{
|
||||
if (!hs_empty(_set2_))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
hashset_iter iter;
|
||||
hs_iter_init(&iter, _set1_);
|
||||
for (hs_iter_to_start(&iter); !hs_iter_end(&iter); hs_iter_next(&iter))
|
||||
{
|
||||
size_t value = hs_iter_value(&iter);
|
||||
if (!hs_contains(_set2_, value))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool hs_is_proper_superset(hashset *_set1_, hashset *_set2_) { return hs_is_proper_subset(_set2_, _set1_); }
|
||||
bool hs_is_disjointset(hashset *_set1_, hashset *_set2_)
|
||||
{
|
||||
if (hs_empty(_set1_))
|
||||
return true;
|
||||
hashset_iter iter;
|
||||
hs_iter_init(&iter, _set1_);
|
||||
for (hs_iter_to_start(&iter); !hs_iter_end(&iter); hs_iter_next(&iter))
|
||||
{
|
||||
size_t value = hs_iter_value(&iter);
|
||||
if (hs_contains(_set2_, value))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
hashset_iter *hs_iter_new(hashset *target)
|
||||
{
|
||||
hashset_iter *iter = malloc(sizeof(hashset_iter));
|
||||
if (!iter)
|
||||
return NULL;
|
||||
hs_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void hs_iter_free(hashset_iter *iter) { free(iter); }
|
||||
void hs_iter_init(hashset_iter *iter, hashset *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->cursor = 0;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = hs_empty(target);
|
||||
if (!hs_empty(target))
|
||||
{
|
||||
for (size_t i = 0; i < target->capacity; i++)
|
||||
{
|
||||
if (target->buffer[i].state == 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 == ES_FILLED)
|
||||
{
|
||||
iter->last = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bool hs_iter_start(hashset_iter *iter) { return hs_empty(iter->target) || iter->start; }
|
||||
bool hs_iter_end(hashset_iter *iter) { return hs_empty(iter->target) || iter->end; }
|
||||
void hs_iter_to_start(hashset_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->first;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = hs_empty(iter->target);
|
||||
}
|
||||
void hs_iter_to_end(hashset_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->last;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = hs_empty(iter->target);
|
||||
iter->end = true;
|
||||
}
|
||||
bool hs_iter_next(hashset_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
hashset_entry *scan = &(iter->target->buffer[iter->cursor]);
|
||||
if (iter->cursor == iter->last)
|
||||
iter->end = true;
|
||||
else
|
||||
{
|
||||
iter->index++;
|
||||
while (1)
|
||||
{
|
||||
iter->cursor++;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
if (scan->state == ES_FILLED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
iter->start = hs_empty(iter->target);
|
||||
return true;
|
||||
}
|
||||
bool hs_iter_prev(hashset_iter *iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
hashset_entry *scan = &(iter->target->buffer[iter->cursor]);
|
||||
if (iter->cursor == iter->first)
|
||||
iter->start = true;
|
||||
else
|
||||
{
|
||||
iter->index--;
|
||||
while (1)
|
||||
{
|
||||
iter->cursor--;
|
||||
scan = &(iter->target->buffer[iter->cursor]);
|
||||
if (scan->state == ES_FILLED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
iter->end = hs_empty(iter->target);
|
||||
return true;
|
||||
}
|
||||
size_t hs_iter_value(hashset_iter *iter)
|
||||
{
|
||||
if (hs_empty(iter->target))
|
||||
return hs_impl_default_value();
|
||||
return iter->target->buffer[iter->cursor].value;
|
||||
}
|
||||
size_t hs_iter_index(hashset_iter *iter) { return iter->index; }
|
||||
static bool hs_impl_grow(hashset *_set_)
|
||||
{
|
||||
size_t new_size = hs_impl_calculate_size(_set_->capacity + _set_->capacity / 2);
|
||||
hashset *_new_set_ = hs_new(new_size, _set_->load, _set_->cmp, _set_->hash);
|
||||
if (!_new_set_)
|
||||
return false;
|
||||
hashset_iter iter;
|
||||
for (hs_iter_init(&iter, _set_); !hs_iter_end(&iter); hs_iter_next(&iter))
|
||||
{
|
||||
hs_insert(_new_set_, hs_iter_value(&iter));
|
||||
}
|
||||
if (_set_->count != _new_set_->count)
|
||||
{
|
||||
hs_free(_new_set_);
|
||||
return false;
|
||||
}
|
||||
hashset_entry *tmp = _set_->buffer;
|
||||
_set_->buffer = _new_set_->buffer;
|
||||
_new_set_->buffer = tmp;
|
||||
_set_->capacity = _new_set_->capacity;
|
||||
hs_free(_new_set_);
|
||||
return true;
|
||||
}
|
||||
static hashset_entry *hs_impl_get_entry(hashset *_set_, size_t element)
|
||||
{
|
||||
size_t hash = _set_->hash(element);
|
||||
size_t pos = hash % _set_->capacity;
|
||||
hashset_entry *target = &(_set_->buffer[pos]);
|
||||
while (target->state == ES_FILLED || target->state == ES_DELETED)
|
||||
{
|
||||
if (_set_->cmp(target->value, element) == 0)
|
||||
return target;
|
||||
pos++;
|
||||
target = &(_set_->buffer[pos % _set_->capacity]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
static size_t hs_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];
|
||||
}
|
||||
static hashset_iter hs_impl_it_start(hashset *_set_)
|
||||
{
|
||||
hashset_iter iter;
|
||||
hs_iter_init(&iter, _set_);
|
||||
return iter;
|
||||
}
|
||||
static hashset_iter hs_impl_it_end(hashset *_set_)
|
||||
{
|
||||
hashset_iter iter;
|
||||
hs_iter_init(&iter, _set_);
|
||||
hs_iter_to_end(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
#include "cmc/heap.h"
|
||||
|
||||
typedef struct heap_s
|
||||
{
|
||||
size_t *buffer;
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
enum HeapOrder HO;
|
||||
int (*cmp)(size_t, size_t);
|
||||
struct heap_iter_s (*it_start)(struct heap_s *);
|
||||
struct heap_iter_s (*it_end)(struct heap_s *);
|
||||
} heap, *heap_ptr;
|
||||
typedef struct heap_iter_s
|
||||
{
|
||||
struct heap_s *target;
|
||||
size_t cursor;
|
||||
bool start;
|
||||
bool end;
|
||||
} heap_iter, *heap_iter_ptr;
|
||||
heap *h_new(size_t capacity, HeapOrder HO, int (*compare)(size_t, size_t));
|
||||
void h_clear(heap *_heap_);
|
||||
void h_free(heap *_heap_);
|
||||
bool h_insert(heap *_heap_, size_t element);
|
||||
bool h_remove(heap *_heap_, size_t *result);
|
||||
bool h_insert_if(heap *_heap_, size_t element, bool condition);
|
||||
bool h_remove_if(heap *_heap_, size_t *result, bool condition);
|
||||
size_t h_peek(heap *_heap_);
|
||||
size_t *h_peek_ref(heap *_heap_);
|
||||
bool h_contains(heap *_heap_, size_t element);
|
||||
bool h_empty(heap *_heap_);
|
||||
bool h_full(heap *_heap_);
|
||||
size_t h_count(heap *_heap_);
|
||||
size_t h_capacity(heap *_heap_);
|
||||
heap_iter *h_iter_new(heap *target);
|
||||
void h_iter_free(heap_iter *iter);
|
||||
void h_iter_init(heap_iter *iter, heap *target);
|
||||
bool h_iter_start(heap_iter *iter);
|
||||
bool h_iter_end(heap_iter *iter);
|
||||
void h_iter_to_start(heap_iter *iter);
|
||||
void h_iter_to_end(heap_iter *iter);
|
||||
bool h_iter_next(heap_iter *iter);
|
||||
bool h_iter_prev(heap_iter *iter);
|
||||
size_t h_iter_value(heap_iter *iter);
|
||||
size_t h_iter_index(heap_iter *iter);
|
||||
static inline size_t h_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
static bool h_impl_grow(heap *_heap_);
|
||||
static size_t h_impl_p(size_t index);
|
||||
static size_t h_impl_l(size_t index);
|
||||
static size_t h_impl_r(size_t index);
|
||||
static bool h_impl_float_up(heap *_heap_, size_t index);
|
||||
static bool h_impl_float_down(heap *_heap_, size_t index);
|
||||
static heap_iter h_impl_it_start(heap *_heap_);
|
||||
static heap_iter h_impl_it_end(heap *_heap_);
|
||||
heap *h_new(size_t capacity, HeapOrder HO, int (*compare)(size_t, size_t))
|
||||
{
|
||||
if (capacity < 1)
|
||||
return NULL;
|
||||
if (HO != MinHeap && HO != MaxHeap)
|
||||
return NULL;
|
||||
heap *_heap_ = malloc(sizeof(heap));
|
||||
if (!_heap_)
|
||||
return NULL;
|
||||
_heap_->buffer = malloc(sizeof(size_t) * capacity);
|
||||
if (!_heap_->buffer)
|
||||
{
|
||||
free(_heap_);
|
||||
return NULL;
|
||||
}
|
||||
memset(_heap_->buffer, 0, sizeof(size_t) * capacity);
|
||||
_heap_->capacity = capacity;
|
||||
_heap_->count = 0;
|
||||
_heap_->HO = HO;
|
||||
_heap_->cmp = compare;
|
||||
_heap_->it_start = h_impl_it_start;
|
||||
_heap_->it_end = h_impl_it_end;
|
||||
return _heap_;
|
||||
}
|
||||
void h_clear(heap *_heap_)
|
||||
{
|
||||
memset(_heap_->buffer, 0, sizeof(size_t) * _heap_->capacity);
|
||||
_heap_->count = 0;
|
||||
}
|
||||
void h_free(heap *_heap_)
|
||||
{
|
||||
free(_heap_->buffer);
|
||||
free(_heap_);
|
||||
}
|
||||
bool h_insert(heap *_heap_, size_t element)
|
||||
{
|
||||
if (h_full(_heap_))
|
||||
{
|
||||
if (!h_impl_grow(_heap_))
|
||||
return false;
|
||||
}
|
||||
if (_heap_->count == 0)
|
||||
{
|
||||
_heap_->buffer[_heap_->count++] = element;
|
||||
return true;
|
||||
}
|
||||
_heap_->buffer[_heap_->count++] = element;
|
||||
if (!h_impl_float_up(_heap_, _heap_->count - 1))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool h_remove(heap *_heap_, size_t *result)
|
||||
{
|
||||
if (h_empty(_heap_))
|
||||
return false;
|
||||
*result = _heap_->buffer[0];
|
||||
_heap_->buffer[0] = _heap_->buffer[_heap_->count - 1];
|
||||
_heap_->buffer[_heap_->count - 1] = h_impl_default_value();
|
||||
_heap_->count--;
|
||||
if (!h_impl_float_down(_heap_, 0))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool h_insert_if(heap *_heap_, size_t element, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return h_insert(_heap_, element);
|
||||
return false;
|
||||
}
|
||||
bool h_remove_if(heap *_heap_, size_t *result, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return h_remove(_heap_, result);
|
||||
return false;
|
||||
}
|
||||
size_t h_peek(heap *_heap_)
|
||||
{
|
||||
if (h_empty(_heap_))
|
||||
return h_impl_default_value();
|
||||
return _heap_->buffer[0];
|
||||
}
|
||||
size_t *h_peek_ref(heap *_heap_)
|
||||
{
|
||||
if (h_empty(_heap_))
|
||||
return NULL;
|
||||
return &(_heap_->buffer[0]);
|
||||
}
|
||||
bool h_contains(heap *_heap_, size_t element)
|
||||
{
|
||||
for (size_t i = 0; i < _heap_->count; i++)
|
||||
{
|
||||
if (_heap_->cmp(_heap_->buffer[i], element) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool h_empty(heap *_heap_) { return _heap_->count == 0; }
|
||||
bool h_full(heap *_heap_) { return _heap_->count >= _heap_->capacity; }
|
||||
size_t h_count(heap *_heap_) { return _heap_->count; }
|
||||
size_t h_capacity(heap *_heap_) { return _heap_->capacity; }
|
||||
heap_iter *h_iter_new(heap *target)
|
||||
{
|
||||
heap_iter *iter = malloc(sizeof(heap_iter));
|
||||
if (!iter)
|
||||
return NULL;
|
||||
h_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void h_iter_free(heap_iter *iter) { free(iter); }
|
||||
void h_iter_init(heap_iter *iter, heap *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->cursor = 0;
|
||||
iter->start = true;
|
||||
iter->end = h_empty(target);
|
||||
}
|
||||
bool h_iter_start(heap_iter *iter) { return h_empty(iter->target) || iter->start; }
|
||||
bool h_iter_end(heap_iter *iter) { return h_empty(iter->target) || iter->end; }
|
||||
void h_iter_to_start(heap_iter *iter)
|
||||
{
|
||||
iter->cursor = 0;
|
||||
iter->start = true;
|
||||
iter->end = h_empty(iter->target);
|
||||
}
|
||||
void h_iter_to_end(heap_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->target->count - 1;
|
||||
iter->start = h_empty(iter->target);
|
||||
iter->end = true;
|
||||
}
|
||||
bool h_iter_next(heap_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
iter->start = false;
|
||||
if (iter->cursor == iter->target->count - 1)
|
||||
iter->end = true;
|
||||
else
|
||||
iter->cursor++;
|
||||
return true;
|
||||
}
|
||||
bool h_iter_prev(heap_iter *iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
iter->end = false;
|
||||
if (iter->cursor == 0)
|
||||
iter->start = true;
|
||||
else
|
||||
iter->cursor--;
|
||||
return true;
|
||||
}
|
||||
size_t h_iter_value(heap_iter *iter)
|
||||
{
|
||||
if (h_empty(iter->target))
|
||||
return h_impl_default_value();
|
||||
return iter->target->buffer[iter->cursor];
|
||||
}
|
||||
size_t h_iter_index(heap_iter *iter) { return iter->cursor; }
|
||||
static bool h_impl_grow(heap *_heap_)
|
||||
{
|
||||
size_t new_capacity = _heap_->capacity * 2;
|
||||
size_t *new_buffer = realloc(_heap_->buffer, sizeof(size_t) * new_capacity);
|
||||
if (!new_buffer)
|
||||
return false;
|
||||
_heap_->buffer = new_buffer;
|
||||
_heap_->capacity = new_capacity;
|
||||
return true;
|
||||
}
|
||||
static size_t h_impl_p(size_t index)
|
||||
{
|
||||
if (index == 0)
|
||||
return 0;
|
||||
return (index - 1) / 2;
|
||||
}
|
||||
static size_t h_impl_l(size_t index) { return 2 * index + 1; }
|
||||
static size_t h_impl_r(size_t index) { return 2 * index + 2; }
|
||||
static bool h_impl_float_up(heap *_heap_, size_t index)
|
||||
{
|
||||
size_t C = index;
|
||||
size_t child = _heap_->buffer[C];
|
||||
size_t parent = _heap_->buffer[h_impl_p(C)];
|
||||
int mod = _heap_->HO;
|
||||
while (C > 0 && _heap_->cmp(child, parent) * mod > 0)
|
||||
{
|
||||
size_t tmp = _heap_->buffer[C];
|
||||
_heap_->buffer[C] = _heap_->buffer[h_impl_p(C)];
|
||||
_heap_->buffer[h_impl_p(C)] = tmp;
|
||||
C = h_impl_p(C);
|
||||
child = _heap_->buffer[C];
|
||||
parent = _heap_->buffer[h_impl_p(C)];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static bool h_impl_float_down(heap *_heap_, size_t index)
|
||||
{
|
||||
int mod = _heap_->HO;
|
||||
while (index < _heap_->count)
|
||||
{
|
||||
size_t L = h_impl_l(index);
|
||||
size_t R = h_impl_r(index);
|
||||
size_t C = index;
|
||||
if (L < _heap_->count && _heap_->cmp(_heap_->buffer[L], _heap_->buffer[C]) * mod > 0)
|
||||
{
|
||||
C = L;
|
||||
}
|
||||
if (R < _heap_->count && _heap_->cmp(_heap_->buffer[R], _heap_->buffer[C]) * mod > 0)
|
||||
{
|
||||
C = R;
|
||||
}
|
||||
if (C != index)
|
||||
{
|
||||
size_t tmp = _heap_->buffer[index];
|
||||
_heap_->buffer[index] = _heap_->buffer[C];
|
||||
_heap_->buffer[C] = tmp;
|
||||
index = C;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static heap_iter h_impl_it_start(heap *_heap_)
|
||||
{
|
||||
heap_iter iter;
|
||||
h_iter_init(&iter, _heap_);
|
||||
h_iter_to_start(&iter);
|
||||
return iter;
|
||||
}
|
||||
static heap_iter h_impl_it_end(heap *_heap_)
|
||||
{
|
||||
heap_iter iter;
|
||||
h_iter_init(&iter, _heap_);
|
||||
h_iter_to_end(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
#include "cmc/linkedlist.h"
|
||||
|
||||
typedef struct linkedlist_s
|
||||
{
|
||||
struct linkedlist_node_s *head;
|
||||
struct linkedlist_node_s *tail;
|
||||
size_t count;
|
||||
struct linkedlist_iter_s (*it_start)(struct linkedlist_s *);
|
||||
struct linkedlist_iter_s (*it_end)(struct linkedlist_s *);
|
||||
} linkedlist, *linkedlist_ptr;
|
||||
typedef struct linkedlist_node_s
|
||||
{
|
||||
size_t data;
|
||||
struct linkedlist_node_s *next;
|
||||
struct linkedlist_node_s *prev;
|
||||
} linkedlist_node, *linkedlist_node_ptr;
|
||||
typedef struct linkedlist_iter_s
|
||||
{
|
||||
struct linkedlist_s *target;
|
||||
struct linkedlist_node_s *cursor;
|
||||
size_t index;
|
||||
bool start;
|
||||
bool end;
|
||||
} linkedlist_iter, *linkedlist_iter_ptr;
|
||||
linkedlist *ll_new(void);
|
||||
void ll_clear(linkedlist *_list_);
|
||||
void ll_free(linkedlist *_list_);
|
||||
bool ll_push_front(linkedlist *_list_, size_t element);
|
||||
bool ll_push(linkedlist *_list_, size_t element, size_t index);
|
||||
bool ll_push_back(linkedlist *_list_, size_t element);
|
||||
bool ll_pop_front(linkedlist *_list_);
|
||||
bool ll_pop(linkedlist *_list_, size_t index);
|
||||
bool ll_pop_back(linkedlist *_list_);
|
||||
bool ll_push_if(linkedlist *_list_, size_t element, size_t index, bool condition);
|
||||
bool ll_pop_if(linkedlist *_list_, size_t index, bool condition);
|
||||
size_t ll_front(linkedlist *_list_);
|
||||
size_t ll_get(linkedlist *_list_, size_t index);
|
||||
size_t *ll_get_ref(linkedlist *_list_, size_t index);
|
||||
size_t ll_back(linkedlist *_list_);
|
||||
bool ll_contains(linkedlist *_list_, size_t element, int (*comparator)(size_t, size_t));
|
||||
bool ll_empty(linkedlist *_list_);
|
||||
size_t ll_count(linkedlist *_list_);
|
||||
linkedlist_node *ll_new_node(size_t element);
|
||||
void ll_free_node(linkedlist_node *_node_);
|
||||
linkedlist_node *ll_head(linkedlist *_list_);
|
||||
linkedlist_node *ll_get_node(linkedlist *_list_, size_t index);
|
||||
linkedlist_node *ll_tail(linkedlist *_list_);
|
||||
bool ll_insert_after(linkedlist *_owner_, linkedlist_node *_node_, size_t element);
|
||||
bool ll_insert_before(linkedlist *_owner_, linkedlist_node *_node_, size_t element);
|
||||
bool ll_remove_after(linkedlist *_owner_, linkedlist_node *_node_);
|
||||
bool ll_remove_current(linkedlist *_owner_, linkedlist_node *_node_);
|
||||
bool ll_remove_before(linkedlist *_owner_, linkedlist_node *_node_);
|
||||
linkedlist_node *ll_next_node(linkedlist_node *_node_);
|
||||
linkedlist_node *ll_prev_node(linkedlist_node *_node_);
|
||||
linkedlist_iter *ll_iter_new(linkedlist *target);
|
||||
void ll_iter_free(linkedlist_iter *iter);
|
||||
void ll_iter_init(linkedlist_iter *iter, linkedlist *target);
|
||||
bool ll_iter_start(linkedlist_iter *iter);
|
||||
bool ll_iter_end(linkedlist_iter *iter);
|
||||
void ll_iter_to_start(linkedlist_iter *iter);
|
||||
void ll_iter_to_end(linkedlist_iter *iter);
|
||||
bool ll_iter_next(linkedlist_iter *iter);
|
||||
bool ll_iter_prev(linkedlist_iter *iter);
|
||||
size_t ll_iter_value(linkedlist_iter *iter);
|
||||
size_t *ll_iter_rvalue(linkedlist_iter *iter);
|
||||
size_t ll_iter_index(linkedlist_iter *iter);
|
||||
linkedlist_node *ll_iter_node(linkedlist_iter *iter);
|
||||
static inline size_t ll_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
static linkedlist_iter ll_impl_it_start(linkedlist *_list_);
|
||||
static linkedlist_iter ll_impl_it_end(linkedlist *_list_);
|
||||
linkedlist *ll_new(void)
|
||||
{
|
||||
linkedlist *_list_ = malloc(sizeof(linkedlist));
|
||||
if (!_list_)
|
||||
return NULL;
|
||||
_list_->count = 0;
|
||||
_list_->head = NULL;
|
||||
_list_->tail = NULL;
|
||||
_list_->it_start = ll_impl_it_start;
|
||||
_list_->it_end = ll_impl_it_end;
|
||||
return _list_;
|
||||
}
|
||||
void ll_clear(linkedlist *_list_)
|
||||
{
|
||||
linkedlist_node *scan = _list_->head;
|
||||
while (_list_->head != NULL)
|
||||
{
|
||||
_list_->head = _list_->head->next;
|
||||
free(scan);
|
||||
scan = _list_->head;
|
||||
}
|
||||
_list_->count = 0;
|
||||
_list_->head = NULL;
|
||||
_list_->tail = NULL;
|
||||
}
|
||||
void ll_free(linkedlist *_list_)
|
||||
{
|
||||
ll_clear(_list_);
|
||||
free(_list_);
|
||||
}
|
||||
bool ll_push_front(linkedlist *_list_, size_t element)
|
||||
{
|
||||
linkedlist_node *_node_ = ll_new_node(element);
|
||||
if (!_node_)
|
||||
return false;
|
||||
if (ll_empty(_list_))
|
||||
{
|
||||
_list_->head = _node_;
|
||||
_list_->tail = _node_;
|
||||
}
|
||||
else
|
||||
{
|
||||
_node_->next = _list_->head;
|
||||
_list_->head->prev = _node_;
|
||||
_list_->head = _node_;
|
||||
}
|
||||
_list_->count++;
|
||||
return true;
|
||||
}
|
||||
bool ll_push(linkedlist *_list_, size_t element, size_t index)
|
||||
{
|
||||
if (index > _list_->count)
|
||||
return false;
|
||||
if (index == 0)
|
||||
{
|
||||
return ll_push_front(_list_, element);
|
||||
}
|
||||
else if (index == _list_->count)
|
||||
{
|
||||
return ll_push_back(_list_, element);
|
||||
}
|
||||
linkedlist_node *_node_ = ll_new_node(element);
|
||||
if (!_node_)
|
||||
return false;
|
||||
linkedlist_node *scan = ll_get_node(_list_, index - 1);
|
||||
_node_->next = scan->next;
|
||||
_node_->prev = scan;
|
||||
_node_->next->prev = _node_;
|
||||
_node_->prev->next = _node_;
|
||||
_list_->count++;
|
||||
return true;
|
||||
}
|
||||
bool ll_push_back(linkedlist *_list_, size_t element)
|
||||
{
|
||||
linkedlist_node *_node_ = ll_new_node(element);
|
||||
if (!_node_)
|
||||
return false;
|
||||
if (ll_empty(_list_))
|
||||
{
|
||||
_list_->head = _node_;
|
||||
_list_->tail = _node_;
|
||||
}
|
||||
else
|
||||
{
|
||||
_node_->prev = _list_->tail;
|
||||
_list_->tail->next = _node_;
|
||||
_list_->tail = _node_;
|
||||
}
|
||||
_list_->count++;
|
||||
return true;
|
||||
}
|
||||
bool ll_pop_front(linkedlist *_list_)
|
||||
{
|
||||
if (ll_empty(_list_))
|
||||
return false;
|
||||
linkedlist_node *_node_ = _list_->head;
|
||||
_list_->head = _list_->head->next;
|
||||
free(_node_);
|
||||
if (_list_->head == NULL)
|
||||
_list_->tail = NULL;
|
||||
else
|
||||
_list_->head->prev = NULL;
|
||||
_list_->count--;
|
||||
return true;
|
||||
}
|
||||
bool ll_pop(linkedlist *_list_, size_t index)
|
||||
{
|
||||
if (ll_empty(_list_))
|
||||
return false;
|
||||
if (index >= _list_->count)
|
||||
return false;
|
||||
if (index == 0)
|
||||
{
|
||||
return ll_pop_front(_list_);
|
||||
}
|
||||
else if (index == _list_->count - 1)
|
||||
{
|
||||
return ll_pop_back(_list_);
|
||||
}
|
||||
linkedlist_node *_node_ = ll_get_node(_list_, index);
|
||||
if (!_node_)
|
||||
return false;
|
||||
_node_->next->prev = _node_->prev;
|
||||
_node_->prev->next = _node_->next;
|
||||
free(_node_);
|
||||
_list_->count--;
|
||||
return true;
|
||||
}
|
||||
bool ll_pop_back(linkedlist *_list_)
|
||||
{
|
||||
if (ll_empty(_list_))
|
||||
return false;
|
||||
linkedlist_node *_node_ = _list_->tail;
|
||||
_list_->tail = _list_->tail->prev;
|
||||
free(_node_);
|
||||
if (_list_->tail == NULL)
|
||||
_list_->head = NULL;
|
||||
else
|
||||
_list_->tail->next = NULL;
|
||||
_list_->count--;
|
||||
return true;
|
||||
}
|
||||
bool ll_push_if(linkedlist *_list_, size_t element, size_t index, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return ll_push(_list_, element, index);
|
||||
return false;
|
||||
}
|
||||
bool ll_pop_if(linkedlist *_list_, size_t index, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return ll_pop(_list_, index);
|
||||
return false;
|
||||
}
|
||||
size_t ll_front(linkedlist *_list_)
|
||||
{
|
||||
if (ll_empty(_list_))
|
||||
return ll_impl_default_value();
|
||||
return _list_->head->data;
|
||||
}
|
||||
size_t ll_get(linkedlist *_list_, size_t index)
|
||||
{
|
||||
if (index >= _list_->count || ll_empty(_list_))
|
||||
return ll_impl_default_value();
|
||||
linkedlist_node *scan = ll_get_node(_list_, index);
|
||||
if (scan == NULL)
|
||||
return ll_impl_default_value();
|
||||
return scan->data;
|
||||
}
|
||||
size_t *ll_get_ref(linkedlist *_list_, size_t index)
|
||||
{
|
||||
if (index >= _list_->count)
|
||||
return NULL;
|
||||
if (ll_empty(_list_))
|
||||
return NULL;
|
||||
linkedlist_node *scan = ll_get_node(_list_, index);
|
||||
if (scan == NULL)
|
||||
return NULL;
|
||||
return &(scan->data);
|
||||
}
|
||||
size_t ll_back(linkedlist *_list_)
|
||||
{
|
||||
if (ll_empty(_list_))
|
||||
return ll_impl_default_value();
|
||||
return _list_->tail->data;
|
||||
}
|
||||
bool ll_contains(linkedlist *_list_, size_t element, int (*comparator)(size_t, size_t))
|
||||
{
|
||||
linkedlist_node *scan = _list_->head;
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (comparator(scan->data, element) == 0)
|
||||
return true;
|
||||
scan = scan->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool ll_empty(linkedlist *_list_) { return _list_->count == 0; }
|
||||
size_t ll_count(linkedlist *_list_) { return _list_->count; }
|
||||
linkedlist_node *ll_new_node(size_t element)
|
||||
{
|
||||
linkedlist_node *_node_ = malloc(sizeof(linkedlist_node));
|
||||
if (!_node_)
|
||||
return NULL;
|
||||
_node_->data = element;
|
||||
_node_->next = NULL;
|
||||
_node_->prev = NULL;
|
||||
return _node_;
|
||||
}
|
||||
void ll_free_node(linkedlist_node *_node_) { free(_node_); }
|
||||
linkedlist_node *ll_head(linkedlist *_list_) { return _list_->head; }
|
||||
linkedlist_node *ll_get_node(linkedlist *_list_, size_t index)
|
||||
{
|
||||
if (index >= _list_->count)
|
||||
return NULL;
|
||||
if (ll_empty(_list_))
|
||||
return NULL;
|
||||
linkedlist_node *_node_ = NULL;
|
||||
if (index <= _list_->count / 2)
|
||||
{
|
||||
_node_ = _list_->head;
|
||||
for (size_t i = 0; i < index; i++)
|
||||
{
|
||||
_node_ = _node_->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_node_ = _list_->tail;
|
||||
for (size_t i = _list_->count - 1; i > index; i--)
|
||||
{
|
||||
_node_ = _node_->prev;
|
||||
}
|
||||
}
|
||||
return _node_;
|
||||
}
|
||||
linkedlist_node *ll_tail(linkedlist *_list_) { return _list_->tail; }
|
||||
bool ll_insert_after(linkedlist *_owner_, linkedlist_node *_node_, size_t element)
|
||||
{
|
||||
linkedlist_node *new_node = ll_new_node(element);
|
||||
if (!new_node)
|
||||
return false;
|
||||
new_node->next = _node_->next;
|
||||
if (_node_->next != NULL)
|
||||
_node_->next->prev = new_node;
|
||||
else
|
||||
_owner_->tail = new_node;
|
||||
new_node->prev = _node_;
|
||||
_node_->next = new_node;
|
||||
_owner_->count++;
|
||||
return true;
|
||||
}
|
||||
bool ll_insert_before(linkedlist *_owner_, linkedlist_node *_node_, size_t element)
|
||||
{
|
||||
linkedlist_node *new_node = ll_new_node(element);
|
||||
if (!new_node)
|
||||
return false;
|
||||
new_node->prev = _node_->prev;
|
||||
if (_node_->prev != NULL)
|
||||
_node_->prev->next = new_node;
|
||||
else
|
||||
_owner_->head = new_node;
|
||||
new_node->next = _node_;
|
||||
_node_->prev = new_node;
|
||||
_owner_->count++;
|
||||
return true;
|
||||
}
|
||||
bool ll_remove_after(linkedlist *_owner_, linkedlist_node *_node_)
|
||||
{
|
||||
if (_node_->next == NULL)
|
||||
return false;
|
||||
linkedlist_node *tmp = _node_->next;
|
||||
if (tmp->next != NULL)
|
||||
{
|
||||
_node_->next = _node_->next->next;
|
||||
_node_->next->prev = _node_;
|
||||
}
|
||||
else
|
||||
_owner_->tail = _node_;
|
||||
free(tmp);
|
||||
_owner_->count--;
|
||||
return true;
|
||||
}
|
||||
bool ll_remove_current(linkedlist *_owner_, linkedlist_node *_node_)
|
||||
{
|
||||
if (_node_->prev != NULL)
|
||||
_node_->prev->next = _node_->next;
|
||||
else
|
||||
_owner_->head = _node_->next;
|
||||
if (_node_->next != NULL)
|
||||
_node_->next->prev = _node_->prev;
|
||||
else
|
||||
_owner_->tail = _node_->prev;
|
||||
free(_node_);
|
||||
_owner_->count--;
|
||||
return true;
|
||||
}
|
||||
bool ll_remove_before(linkedlist *_owner_, linkedlist_node *_node_)
|
||||
{
|
||||
if (_node_->prev == NULL)
|
||||
return false;
|
||||
linkedlist_node *tmp = _node_->prev;
|
||||
if (tmp->prev != NULL)
|
||||
{
|
||||
_node_->prev = _node_->prev->prev;
|
||||
_node_->prev->next = _node_;
|
||||
}
|
||||
else
|
||||
_owner_->head = _node_;
|
||||
free(tmp);
|
||||
_owner_->count--;
|
||||
return true;
|
||||
}
|
||||
linkedlist_node *ll_next_node(linkedlist_node *_node_) { return _node_->next; }
|
||||
linkedlist_node *ll_prev_node(linkedlist_node *_node_) { return _node_->prev; }
|
||||
linkedlist_iter *ll_iter_new(linkedlist *target)
|
||||
{
|
||||
linkedlist_iter *iter = malloc(sizeof(linkedlist_iter));
|
||||
if (!iter)
|
||||
return NULL;
|
||||
ll_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void ll_iter_free(linkedlist_iter *iter) { free(iter); }
|
||||
void ll_iter_init(linkedlist_iter *iter, linkedlist *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->cursor = target->head;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = ll_empty(target);
|
||||
}
|
||||
bool ll_iter_start(linkedlist_iter *iter) { return ll_empty(iter->target) || iter->start; }
|
||||
bool ll_iter_end(linkedlist_iter *iter) { return ll_empty(iter->target) || iter->end; }
|
||||
void ll_iter_to_start(linkedlist_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->target->head;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = ll_empty(iter->target);
|
||||
}
|
||||
void ll_iter_to_end(linkedlist_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->target->tail;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = ll_empty(iter->target);
|
||||
iter->end = true;
|
||||
}
|
||||
bool ll_iter_next(linkedlist_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
iter->start = ll_empty(iter->target);
|
||||
if (iter->cursor->next == NULL)
|
||||
iter->end = true;
|
||||
else
|
||||
{
|
||||
iter->cursor = iter->cursor->next;
|
||||
iter->index++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool ll_iter_prev(linkedlist_iter *iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
iter->end = ll_empty(iter->target);
|
||||
if (iter->cursor->prev == NULL)
|
||||
iter->start = true;
|
||||
else
|
||||
{
|
||||
iter->cursor = iter->cursor->prev;
|
||||
iter->index--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
size_t ll_iter_value(linkedlist_iter *iter)
|
||||
{
|
||||
if (ll_empty(iter->target))
|
||||
return ll_impl_default_value();
|
||||
return iter->cursor->data;
|
||||
}
|
||||
size_t *ll_iter_rvalue(linkedlist_iter *iter)
|
||||
{
|
||||
if (ll_empty(iter->target))
|
||||
return NULL;
|
||||
return &(iter->cursor->data);
|
||||
}
|
||||
size_t ll_iter_index(linkedlist_iter *iter) { return iter->index; }
|
||||
linkedlist_node *ll_iter_node(linkedlist_iter *iter) { return iter->cursor; }
|
||||
static linkedlist_iter ll_impl_it_start(linkedlist *_list_)
|
||||
{
|
||||
linkedlist_iter iter;
|
||||
ll_iter_init(&iter, _list_);
|
||||
ll_iter_to_start(&iter);
|
||||
return iter;
|
||||
}
|
||||
static linkedlist_iter ll_impl_it_end(linkedlist *_list_)
|
||||
{
|
||||
linkedlist_iter iter;
|
||||
ll_iter_init(&iter, _list_);
|
||||
ll_iter_to_end(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,422 @@
|
||||
#include "cmc/list.h"
|
||||
|
||||
typedef struct list_s
|
||||
{
|
||||
size_t *buffer;
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
struct list_iter_s (*it_start)(struct list_s *);
|
||||
struct list_iter_s (*it_end)(struct list_s *);
|
||||
} list, *list_ptr;
|
||||
typedef struct list_iter_s
|
||||
{
|
||||
struct list_s *target;
|
||||
size_t cursor;
|
||||
bool start;
|
||||
bool end;
|
||||
} list_iter, *list_iter_ptr;
|
||||
list *l_new(size_t capacity);
|
||||
list *l_new_from(size_t *elements, size_t size);
|
||||
void l_clear(list *_list_);
|
||||
void l_free(list *_list_);
|
||||
bool l_push_front(list *_list_, size_t element);
|
||||
bool l_push(list *_list_, size_t element, size_t index);
|
||||
bool l_push_back(list *_list_, size_t element);
|
||||
bool l_pop_front(list *_list_);
|
||||
bool l_pop(list *_list_, size_t index);
|
||||
bool l_pop_back(list *_list_);
|
||||
bool l_push_if(list *_list_, size_t element, size_t index, bool condition);
|
||||
bool l_pop_if(list *_list_, size_t index, bool condition);
|
||||
bool l_prepend(list *_list_, size_t *elements, size_t size);
|
||||
bool l_insert(list *_list_, size_t *elements, size_t size, size_t index);
|
||||
bool l_append(list *_list_, size_t *elements, size_t size);
|
||||
bool l_remove(list *_list_, size_t from, size_t to);
|
||||
list *l_extract(list *_list_, size_t from, size_t to);
|
||||
size_t l_front(list *_list_);
|
||||
size_t l_get(list *_list_, size_t index);
|
||||
size_t *l_get_ref(list *_list_, size_t index);
|
||||
size_t l_back(list *_list_);
|
||||
size_t l_indexof(list *_list_, size_t element, int (*comparator)(size_t, size_t), bool from_start);
|
||||
bool l_contains(list *_list_, size_t element, int (*comparator)(size_t, size_t));
|
||||
bool l_empty(list *_list_);
|
||||
bool l_full(list *_list_);
|
||||
size_t l_count(list *_list_);
|
||||
bool l_fits(list *_list_, size_t size);
|
||||
size_t l_capacity(list *_list_);
|
||||
list_iter *l_iter_new(list *target);
|
||||
void l_iter_free(list_iter *iter);
|
||||
void l_iter_init(list_iter *iter, list *target);
|
||||
bool l_iter_start(list_iter *iter);
|
||||
bool l_iter_end(list_iter *iter);
|
||||
void l_iter_to_start(list_iter *iter);
|
||||
void l_iter_to_end(list_iter *iter);
|
||||
bool l_iter_next(list_iter *iter);
|
||||
bool l_iter_prev(list_iter *iter);
|
||||
size_t l_iter_value(list_iter *iter);
|
||||
size_t *l_iter_rvalue(list_iter *iter);
|
||||
size_t l_iter_index(list_iter *iter);
|
||||
static inline size_t l_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
|
||||
static bool l_impl_grow(list *_list_, size_t required);
|
||||
static list_iter l_impl_it_start(list *_list_);
|
||||
static list_iter l_impl_it_end(list *_list_);
|
||||
list *l_new(size_t capacity)
|
||||
{
|
||||
if (capacity < 1)
|
||||
return NULL;
|
||||
list *_list_ = malloc(sizeof(list));
|
||||
if (!_list_)
|
||||
return NULL;
|
||||
_list_->buffer = malloc(capacity * sizeof(size_t));
|
||||
if (!_list_->buffer)
|
||||
{
|
||||
free(_list_);
|
||||
return NULL;
|
||||
}
|
||||
memset(_list_->buffer, 0, capacity * sizeof(size_t));
|
||||
_list_->capacity = capacity;
|
||||
_list_->count = 0;
|
||||
_list_->it_start = l_impl_it_start;
|
||||
_list_->it_end = l_impl_it_end;
|
||||
return _list_;
|
||||
}
|
||||
list *l_new_from(size_t *elements, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
list *_list_ = l_new(size + size / 2);
|
||||
if (!_list_)
|
||||
return NULL;
|
||||
memcpy(_list_->buffer, elements, size * sizeof(size_t));
|
||||
_list_->count = size;
|
||||
return _list_;
|
||||
}
|
||||
void l_clear(list *_list_)
|
||||
{
|
||||
memset(_list_->buffer, 0, sizeof(size_t) * _list_->capacity);
|
||||
_list_->count = 0;
|
||||
}
|
||||
void l_free(list *_list_)
|
||||
{
|
||||
free(_list_->buffer);
|
||||
free(_list_);
|
||||
}
|
||||
bool l_push_front(list *_list_, size_t element)
|
||||
{
|
||||
if (l_full(_list_))
|
||||
{
|
||||
if (!l_impl_grow(_list_, _list_->count + 1))
|
||||
return false;
|
||||
}
|
||||
if (!l_empty(_list_))
|
||||
{
|
||||
memmove(_list_->buffer + 1, _list_->buffer, _list_->count * sizeof(size_t));
|
||||
}
|
||||
_list_->buffer[0] = element;
|
||||
_list_->count++;
|
||||
return true;
|
||||
}
|
||||
bool l_push(list *_list_, size_t element, size_t index)
|
||||
{
|
||||
if (index > _list_->count)
|
||||
return false;
|
||||
if (index == 0)
|
||||
{
|
||||
return l_push_front(_list_, element);
|
||||
}
|
||||
else if (index == _list_->count)
|
||||
{
|
||||
return l_push_back(_list_, element);
|
||||
}
|
||||
if (l_full(_list_))
|
||||
{
|
||||
if (!l_impl_grow(_list_, _list_->count + 1))
|
||||
return false;
|
||||
}
|
||||
memmove(_list_->buffer + index + 1, _list_->buffer + index, (_list_->count - index) * sizeof(size_t));
|
||||
_list_->buffer[index] = element;
|
||||
_list_->count++;
|
||||
return true;
|
||||
}
|
||||
bool l_push_back(list *_list_, size_t element)
|
||||
{
|
||||
if (l_full(_list_))
|
||||
{
|
||||
if (!l_impl_grow(_list_, _list_->count + 1))
|
||||
return false;
|
||||
}
|
||||
_list_->buffer[_list_->count++] = element;
|
||||
return true;
|
||||
}
|
||||
bool l_pop_front(list *_list_)
|
||||
{
|
||||
if (l_empty(_list_))
|
||||
return false;
|
||||
memmove(_list_->buffer, _list_->buffer + 1, _list_->count * sizeof(size_t));
|
||||
_list_->buffer[--_list_->count] = l_impl_default_value();
|
||||
return true;
|
||||
}
|
||||
bool l_pop(list *_list_, size_t index)
|
||||
{
|
||||
if (l_empty(_list_))
|
||||
return false;
|
||||
if (index >= _list_->count)
|
||||
return false;
|
||||
if (index == 0)
|
||||
{
|
||||
return l_pop_front(_list_);
|
||||
}
|
||||
else if (index == _list_->count - 1)
|
||||
{
|
||||
return l_pop_back(_list_);
|
||||
}
|
||||
memmove(_list_->buffer + index, _list_->buffer + index + 1, (_list_->count - index) * sizeof(size_t));
|
||||
_list_->buffer[--_list_->count] = l_impl_default_value();
|
||||
return true;
|
||||
}
|
||||
bool l_pop_back(list *_list_)
|
||||
{
|
||||
if (l_empty(_list_))
|
||||
return false;
|
||||
_list_->buffer[--_list_->count] = l_impl_default_value();
|
||||
return true;
|
||||
}
|
||||
bool l_push_if(list *_list_, size_t element, size_t index, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return l_push(_list_, element, index);
|
||||
return false;
|
||||
}
|
||||
bool l_pop_if(list *_list_, size_t index, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return l_pop(_list_, index);
|
||||
return false;
|
||||
}
|
||||
bool l_prepend(list *_list_, size_t *elements, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return false;
|
||||
if (!l_fits(_list_, size))
|
||||
{
|
||||
if (!l_impl_grow(_list_, _list_->count + size))
|
||||
return false;
|
||||
}
|
||||
memmove(_list_->buffer + size, _list_->buffer, _list_->count * sizeof(size_t));
|
||||
memcpy(_list_->buffer, elements, size * sizeof(size_t));
|
||||
_list_->count += size;
|
||||
return true;
|
||||
}
|
||||
bool l_insert(list *_list_, size_t *elements, size_t size, size_t index)
|
||||
{
|
||||
if (size == 0 || index > _list_->count)
|
||||
return false;
|
||||
if (index == 0)
|
||||
return l_prepend(_list_, elements, size);
|
||||
else if (index == _list_->count)
|
||||
return l_append(_list_, elements, size);
|
||||
else
|
||||
{
|
||||
if (!l_fits(_list_, size))
|
||||
{
|
||||
if (!l_impl_grow(_list_, _list_->count + size))
|
||||
return false;
|
||||
}
|
||||
memmove(_list_->buffer + index + size, _list_->buffer + index, (_list_->count - index) * sizeof(size_t));
|
||||
memcpy(_list_->buffer + index, elements, size * sizeof(size_t));
|
||||
_list_->count += size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool l_append(list *_list_, size_t *elements, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return false;
|
||||
if (!l_fits(_list_, size))
|
||||
{
|
||||
if (!l_impl_grow(_list_, _list_->count + size))
|
||||
return false;
|
||||
}
|
||||
memcpy(_list_->buffer + _list_->count, elements, size * sizeof(size_t));
|
||||
_list_->count += size;
|
||||
return true;
|
||||
}
|
||||
bool l_remove(list *_list_, size_t from, size_t to)
|
||||
{
|
||||
if (from > to || to >= _list_->count)
|
||||
return false;
|
||||
size_t length = (to - from + 1);
|
||||
memmove(_list_->buffer + from, _list_->buffer + to + 1, (_list_->count - to - 1) * sizeof(size_t));
|
||||
memset(_list_->buffer + _list_->count - length, 0, length * sizeof(size_t));
|
||||
_list_->count -= to - from + 1;
|
||||
return true;
|
||||
}
|
||||
list *l_extract(list *_list_, size_t from, size_t to)
|
||||
{
|
||||
if (from > to || to >= _list_->count)
|
||||
return false;
|
||||
size_t length = to - from + 1;
|
||||
list *result = l_new_from(_list_->buffer + from, length);
|
||||
if (!result)
|
||||
return NULL;
|
||||
memmove(_list_->buffer + from, _list_->buffer + to + 1, (_list_->count - to - 1) * sizeof(size_t));
|
||||
memset(_list_->buffer + _list_->count - length, 0, length * sizeof(size_t));
|
||||
_list_->count -= length;
|
||||
return result;
|
||||
}
|
||||
size_t l_front(list *_list_)
|
||||
{
|
||||
if (l_empty(_list_))
|
||||
return l_impl_default_value();
|
||||
return _list_->buffer[0];
|
||||
}
|
||||
size_t l_get(list *_list_, size_t index)
|
||||
{
|
||||
if (index >= _list_->count || l_empty(_list_))
|
||||
return l_impl_default_value();
|
||||
return _list_->buffer[index];
|
||||
}
|
||||
size_t *l_get_ref(list *_list_, size_t index)
|
||||
{
|
||||
if (index >= _list_->count)
|
||||
return NULL;
|
||||
if (l_empty(_list_))
|
||||
return NULL;
|
||||
return &(_list_->buffer[index]);
|
||||
}
|
||||
size_t l_back(list *_list_)
|
||||
{
|
||||
if (l_empty(_list_))
|
||||
return l_impl_default_value();
|
||||
return _list_->buffer[_list_->count - 1];
|
||||
}
|
||||
size_t l_indexof(list *_list_, size_t element, int (*comparator)(size_t, size_t), bool from_start)
|
||||
{
|
||||
if (from_start)
|
||||
{
|
||||
for (size_t i = 0; i < _list_->count; i++)
|
||||
{
|
||||
if (comparator(_list_->buffer[i], element) == 0)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = _list_->count; i > 0; i--)
|
||||
{
|
||||
if (comparator(_list_->buffer[i - 1], element) == 0)
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
return _list_->count;
|
||||
}
|
||||
bool l_contains(list *_list_, size_t element, int (*comparator)(size_t, size_t))
|
||||
{
|
||||
for (size_t i = 0; i < _list_->count; i++)
|
||||
{
|
||||
if (comparator(_list_->buffer[i], element) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool l_empty(list *_list_) { return _list_->count == 0; }
|
||||
bool l_full(list *_list_) { return _list_->count >= _list_->capacity; }
|
||||
size_t l_count(list *_list_) { return _list_->count; }
|
||||
bool l_fits(list *_list_, size_t size) { return _list_->count + size <= _list_->capacity; }
|
||||
size_t l_capacity(list *_list_) { return _list_->capacity; }
|
||||
list_iter *l_iter_new(list *target)
|
||||
{
|
||||
list_iter *iter = malloc(sizeof(list_iter));
|
||||
if (!iter)
|
||||
return NULL;
|
||||
l_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void l_iter_free(list_iter *iter) { free(iter); }
|
||||
void l_iter_init(list_iter *iter, list *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->cursor = 0;
|
||||
iter->start = true;
|
||||
iter->end = l_empty(target);
|
||||
}
|
||||
bool l_iter_start(list_iter *iter) { return l_empty(iter->target) || iter->start; }
|
||||
bool l_iter_end(list_iter *iter) { return l_empty(iter->target) || iter->end; }
|
||||
void l_iter_to_start(list_iter *iter)
|
||||
{
|
||||
iter->cursor = 0;
|
||||
iter->start = true;
|
||||
iter->end = l_empty(iter->target);
|
||||
}
|
||||
void l_iter_to_end(list_iter *iter)
|
||||
{
|
||||
iter->start = l_empty(iter->target);
|
||||
iter->cursor = l_empty(iter->target) ? 0 : iter->target->count - 1;
|
||||
iter->end = true;
|
||||
}
|
||||
bool l_iter_next(list_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
iter->start = l_empty(iter->target);
|
||||
if (iter->cursor == iter->target->count - 1)
|
||||
iter->end = true;
|
||||
else
|
||||
iter->cursor++;
|
||||
return true;
|
||||
}
|
||||
bool l_iter_prev(list_iter *iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
iter->end = l_empty(iter->target);
|
||||
if (iter->cursor == 0)
|
||||
iter->start = true;
|
||||
else
|
||||
iter->cursor--;
|
||||
return true;
|
||||
}
|
||||
size_t l_iter_value(list_iter *iter)
|
||||
{
|
||||
if (l_empty(iter->target))
|
||||
return l_impl_default_value();
|
||||
return iter->target->buffer[iter->cursor];
|
||||
}
|
||||
size_t *l_iter_rvalue(list_iter *iter)
|
||||
{
|
||||
if (l_empty(iter->target))
|
||||
return NULL;
|
||||
return &(iter->target->buffer[iter->cursor]);
|
||||
}
|
||||
size_t l_iter_index(list_iter *iter) { return iter->cursor; }
|
||||
static bool l_impl_grow(list *_list_, size_t required)
|
||||
{
|
||||
size_t new_capacity = _list_->capacity * 2;
|
||||
if (new_capacity < required)
|
||||
new_capacity = required;
|
||||
size_t *new_buffer = realloc(_list_->buffer, sizeof(size_t) * new_capacity);
|
||||
if (!new_buffer)
|
||||
return false;
|
||||
_list_->buffer = new_buffer;
|
||||
_list_->capacity = new_capacity;
|
||||
return true;
|
||||
}
|
||||
static list_iter l_impl_it_start(list *_list_)
|
||||
{
|
||||
list_iter iter;
|
||||
l_iter_init(&iter, _list_);
|
||||
l_iter_to_start(&iter);
|
||||
return iter;
|
||||
}
|
||||
static list_iter l_impl_it_end(list *_list_)
|
||||
{
|
||||
list_iter iter;
|
||||
l_iter_init(&iter, _list_);
|
||||
l_iter_to_end(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
#include "cmc/queue.h"
|
||||
|
||||
typedef struct queue_s
|
||||
{
|
||||
size_t *buffer;
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
size_t front;
|
||||
size_t rear;
|
||||
struct queue_iter_s (*it_start)(struct queue_s *);
|
||||
struct queue_iter_s (*it_end)(struct queue_s *);
|
||||
} queue, *queue_ptr;
|
||||
typedef struct queue_iter_s
|
||||
{
|
||||
struct queue_s *target;
|
||||
size_t cursor;
|
||||
size_t index;
|
||||
bool start;
|
||||
bool end;
|
||||
} queue_iter, *queue_iter_ptr;
|
||||
queue *q_new(size_t capacity);
|
||||
void q_clear(queue *_queue_);
|
||||
void q_free(queue *_queue_);
|
||||
bool q_enqueue(queue *_queue_, size_t element);
|
||||
bool q_dequeue(queue *_queue_);
|
||||
bool q_enqueue_if(queue *_queue_, size_t element, bool condition);
|
||||
bool q_dequeue_if(queue *_queue_, bool condition);
|
||||
size_t q_peek(queue *_queue_);
|
||||
bool q_contains(queue *_queue_, size_t element, int (*comparator)(size_t, size_t));
|
||||
bool q_empty(queue *_queue_);
|
||||
bool q_full(queue *_queue_);
|
||||
size_t q_count(queue *_queue_);
|
||||
size_t q_capacity(queue *_queue_);
|
||||
queue_iter *q_iter_new(queue *target);
|
||||
void q_iter_free(queue_iter *iter);
|
||||
void q_iter_init(queue_iter *iter, queue *target);
|
||||
bool q_iter_start(queue_iter *iter);
|
||||
bool q_iter_end(queue_iter *iter);
|
||||
void q_iter_to_start(queue_iter *iter);
|
||||
void q_iter_to_end(queue_iter *iter);
|
||||
bool q_iter_next(queue_iter *iter);
|
||||
bool q_iter_prev(queue_iter *iter);
|
||||
size_t q_iter_value(queue_iter *iter);
|
||||
size_t *q_iter_rvalue(queue_iter *iter);
|
||||
size_t q_iter_index(queue_iter *iter);
|
||||
static inline size_t q_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
static bool q_impl_grow(queue *_queue_);
|
||||
static queue_iter q_impl_it_start(queue *_queue_);
|
||||
static queue_iter q_impl_it_end(queue *_queue_);
|
||||
queue *q_new(size_t capacity)
|
||||
{
|
||||
if (capacity < 1)
|
||||
return NULL;
|
||||
queue *_queue_ = malloc(sizeof(queue));
|
||||
if (!_queue_)
|
||||
return NULL;
|
||||
_queue_->buffer = malloc(sizeof(size_t) * capacity);
|
||||
if (!_queue_->buffer)
|
||||
{
|
||||
free(_queue_);
|
||||
return NULL;
|
||||
}
|
||||
memset(_queue_->buffer, 0, sizeof(size_t) * capacity);
|
||||
_queue_->capacity = capacity;
|
||||
_queue_->count = 0;
|
||||
_queue_->front = 0;
|
||||
_queue_->rear = 0;
|
||||
_queue_->it_start = q_impl_it_start;
|
||||
_queue_->it_end = q_impl_it_end;
|
||||
return _queue_;
|
||||
}
|
||||
void q_clear(queue *_queue_)
|
||||
{
|
||||
memset(_queue_->buffer, 0, sizeof(size_t) * _queue_->capacity);
|
||||
_queue_->count = 0;
|
||||
_queue_->front = 0;
|
||||
_queue_->rear = 0;
|
||||
}
|
||||
void q_free(queue *_queue_)
|
||||
{
|
||||
free(_queue_->buffer);
|
||||
free(_queue_);
|
||||
}
|
||||
bool q_enqueue(queue *_queue_, size_t element)
|
||||
{
|
||||
if (q_full(_queue_))
|
||||
{
|
||||
if (!q_impl_grow(_queue_))
|
||||
return false;
|
||||
}
|
||||
_queue_->buffer[_queue_->rear] = element;
|
||||
_queue_->rear = (_queue_->rear == _queue_->capacity - 1) ? 0 : _queue_->rear + 1;
|
||||
_queue_->count++;
|
||||
return true;
|
||||
}
|
||||
bool q_dequeue(queue *_queue_)
|
||||
{
|
||||
if (q_empty(_queue_))
|
||||
return false;
|
||||
_queue_->buffer[_queue_->front] = q_impl_default_value();
|
||||
_queue_->front = (_queue_->front == _queue_->capacity - 1) ? 0 : _queue_->front + 1;
|
||||
_queue_->count--;
|
||||
return true;
|
||||
}
|
||||
bool q_enqueue_if(queue *_queue_, size_t element, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return q_enqueue(_queue_, element);
|
||||
return false;
|
||||
}
|
||||
bool q_dequeue_if(queue *_queue_, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return q_dequeue(_queue_);
|
||||
return false;
|
||||
}
|
||||
size_t q_peek(queue *_queue_)
|
||||
{
|
||||
if (q_empty(_queue_))
|
||||
return q_impl_default_value();
|
||||
return _queue_->buffer[_queue_->front];
|
||||
}
|
||||
bool q_contains(queue *_queue_, size_t element, int (*comparator)(size_t, size_t))
|
||||
{
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->count, j++)
|
||||
{
|
||||
if (comparator(_queue_->buffer[i], element) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool q_empty(queue *_queue_) { return _queue_->count == 0; }
|
||||
bool q_full(queue *_queue_) { return _queue_->count >= _queue_->capacity; }
|
||||
size_t q_count(queue *_queue_) { return _queue_->count; }
|
||||
size_t q_capacity(queue *_queue_) { return _queue_->capacity; }
|
||||
queue_iter *q_iter_new(queue *target)
|
||||
{
|
||||
queue_iter *iter = malloc(sizeof(queue_iter));
|
||||
if (!iter)
|
||||
return NULL;
|
||||
q_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void q_iter_free(queue_iter *iter) { free(iter); }
|
||||
void q_iter_init(queue_iter *iter, queue *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->cursor = target->front;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = q_empty(target);
|
||||
}
|
||||
bool q_iter_start(queue_iter *iter) { return q_empty(iter->target) || iter->start; }
|
||||
bool q_iter_end(queue_iter *iter) { return q_empty(iter->target) || iter->end; }
|
||||
void q_iter_to_start(queue_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->target->front;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = q_empty(iter->target);
|
||||
}
|
||||
void q_iter_to_end(queue_iter *iter)
|
||||
{
|
||||
if (q_empty(iter->target))
|
||||
iter->cursor = 0;
|
||||
else
|
||||
iter->cursor = (iter->target->rear == 0) ? iter->target->capacity - 1 : iter->target->rear - 1;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = q_empty(iter->target);
|
||||
iter->end = true;
|
||||
}
|
||||
bool q_iter_next(queue_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
iter->start = q_empty(iter->target);
|
||||
if (iter->index == iter->target->count - 1)
|
||||
iter->end = true;
|
||||
else
|
||||
{
|
||||
iter->cursor = (iter->cursor + 1) % (iter->target->capacity);
|
||||
iter->index++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool q_iter_prev(queue_iter *iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
iter->end = q_empty(iter->target);
|
||||
if (iter->index == 0)
|
||||
iter->start = true;
|
||||
else
|
||||
{
|
||||
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1;
|
||||
iter->index--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
size_t q_iter_value(queue_iter *iter)
|
||||
{
|
||||
if (q_empty(iter->target))
|
||||
return q_impl_default_value();
|
||||
return iter->target->buffer[iter->cursor];
|
||||
}
|
||||
size_t *q_iter_rvalue(queue_iter *iter)
|
||||
{
|
||||
if (q_empty(iter->target))
|
||||
return NULL;
|
||||
return &(iter->target->buffer[iter->cursor]);
|
||||
}
|
||||
size_t q_iter_index(queue_iter *iter) { return iter->index; }
|
||||
static bool q_impl_grow(queue *_queue_)
|
||||
{
|
||||
size_t new_capacity = _queue_->capacity * 2;
|
||||
size_t *new_buffer = malloc(sizeof(size_t) * new_capacity);
|
||||
if (!new_buffer)
|
||||
return false;
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->capacity, j++)
|
||||
{
|
||||
new_buffer[j] = _queue_->buffer[i];
|
||||
}
|
||||
free(_queue_->buffer);
|
||||
_queue_->buffer = new_buffer;
|
||||
_queue_->capacity = new_capacity;
|
||||
_queue_->front = 0;
|
||||
_queue_->rear = _queue_->count;
|
||||
return true;
|
||||
}
|
||||
static queue_iter q_impl_it_start(queue *_queue_)
|
||||
{
|
||||
queue_iter iter;
|
||||
q_iter_init(&iter, _queue_);
|
||||
q_iter_to_start(&iter);
|
||||
return iter;
|
||||
}
|
||||
static queue_iter q_impl_it_end(queue *_queue_)
|
||||
{
|
||||
queue_iter iter;
|
||||
q_iter_init(&iter, _queue_);
|
||||
q_iter_to_end(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
#include "cmc/stack.h"
|
||||
|
||||
typedef struct stack_s
|
||||
{
|
||||
size_t *buffer;
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
struct stack_iter_s (*it_start)(struct stack_s *);
|
||||
struct stack_iter_s (*it_end)(struct stack_s *);
|
||||
} stack, *stack_ptr;
|
||||
typedef struct stack_iter_s
|
||||
{
|
||||
struct stack_s *target;
|
||||
size_t cursor;
|
||||
bool start;
|
||||
bool end;
|
||||
} stack_iter, *stack_iter_ptr;
|
||||
stack *s_new(size_t capacity);
|
||||
void s_clear(stack *_stack_);
|
||||
void s_free(stack *_stack_);
|
||||
bool s_push(stack *_stack_, size_t element);
|
||||
bool s_pop(stack *_stack_);
|
||||
bool s_push_if(stack *_stack_, size_t element, bool condition);
|
||||
bool s_pop_if(stack *_stack_, bool condition);
|
||||
size_t s_top(stack *_stack_);
|
||||
bool s_contains(stack *_stack_, size_t element, int (*comparator)(size_t, size_t));
|
||||
bool s_empty(stack *_stack_);
|
||||
bool s_full(stack *_stack_);
|
||||
size_t s_count(stack *_stack_);
|
||||
size_t s_capacity(stack *_stack_);
|
||||
stack_iter *s_iter_new(stack *target);
|
||||
void s_iter_free(stack_iter *iter);
|
||||
void s_iter_init(stack_iter *iter, stack *target);
|
||||
bool s_iter_start(stack_iter *iter);
|
||||
bool s_iter_end(stack_iter *iter);
|
||||
void s_iter_to_start(stack_iter *iter);
|
||||
void s_iter_to_end(stack_iter *iter);
|
||||
bool s_iter_next(stack_iter *iter);
|
||||
bool s_iter_prev(stack_iter *iter);
|
||||
size_t s_iter_value(stack_iter *iter);
|
||||
size_t *s_iter_rvalue(stack_iter *iter);
|
||||
size_t s_iter_index(stack_iter *iter);
|
||||
static inline size_t s_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
static bool s_impl_grow(stack *_stack_);
|
||||
static stack_iter s_impl_it_start(stack *_stack_);
|
||||
static stack_iter s_impl_it_end(stack *_stack_);
|
||||
stack *s_new(size_t capacity)
|
||||
{
|
||||
if (capacity < 1)
|
||||
return NULL;
|
||||
stack *_stack_ = malloc(sizeof(stack));
|
||||
if (!_stack_)
|
||||
return NULL;
|
||||
_stack_->buffer = malloc(sizeof(size_t) * capacity);
|
||||
if (!_stack_->buffer)
|
||||
{
|
||||
free(_stack_);
|
||||
return NULL;
|
||||
}
|
||||
memset(_stack_->buffer, 0, sizeof(size_t) * capacity);
|
||||
_stack_->capacity = capacity;
|
||||
_stack_->count = 0;
|
||||
_stack_->it_start = s_impl_it_start;
|
||||
_stack_->it_end = s_impl_it_end;
|
||||
return _stack_;
|
||||
}
|
||||
void s_clear(stack *_stack_)
|
||||
{
|
||||
memset(_stack_->buffer, 0, sizeof(size_t) * _stack_->capacity);
|
||||
_stack_->count = 0;
|
||||
}
|
||||
void s_free(stack *_stack_)
|
||||
{
|
||||
free(_stack_->buffer);
|
||||
free(_stack_);
|
||||
}
|
||||
bool s_push(stack *_stack_, size_t element)
|
||||
{
|
||||
if (s_full(_stack_))
|
||||
{
|
||||
if (!s_impl_grow(_stack_))
|
||||
return false;
|
||||
}
|
||||
_stack_->buffer[_stack_->count++] = element;
|
||||
return true;
|
||||
}
|
||||
bool s_pop(stack *_stack_)
|
||||
{
|
||||
if (s_empty(_stack_))
|
||||
return false;
|
||||
_stack_->buffer[--_stack_->count] = s_impl_default_value();
|
||||
return true;
|
||||
}
|
||||
bool s_push_if(stack *_stack_, size_t element, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return s_push(_stack_, element);
|
||||
return false;
|
||||
}
|
||||
bool s_pop_if(stack *_stack_, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return s_pop(_stack_);
|
||||
return false;
|
||||
}
|
||||
size_t s_top(stack *_stack_)
|
||||
{
|
||||
if (s_empty(_stack_))
|
||||
return s_impl_default_value();
|
||||
return _stack_->buffer[_stack_->count - 1];
|
||||
}
|
||||
bool s_contains(stack *_stack_, size_t element, int (*comparator)(size_t, size_t))
|
||||
{
|
||||
for (size_t i = 0; i < _stack_->count; i++)
|
||||
{
|
||||
if (comparator(_stack_->buffer[i], element) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool s_empty(stack *_stack_) { return _stack_->count == 0; }
|
||||
bool s_full(stack *_stack_) { return _stack_->count >= _stack_->capacity; }
|
||||
size_t s_count(stack *_stack_) { return _stack_->count; }
|
||||
size_t s_capacity(stack *_stack_) { return _stack_->capacity; }
|
||||
stack_iter *s_iter_new(stack *target)
|
||||
{
|
||||
stack_iter *iter = malloc(sizeof(stack_iter));
|
||||
if (!iter)
|
||||
return NULL;
|
||||
s_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void s_iter_free(stack_iter *iter) { free(iter); }
|
||||
void s_iter_init(stack_iter *iter, stack *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->cursor = iter->target->count - 1;
|
||||
iter->start = true;
|
||||
iter->end = s_empty(target);
|
||||
}
|
||||
bool s_iter_start(stack_iter *iter) { return s_empty(iter->target) || iter->start; }
|
||||
bool s_iter_end(stack_iter *iter) { return s_empty(iter->target) || iter->end; }
|
||||
void s_iter_to_start(stack_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->target->count - 1;
|
||||
iter->start = true;
|
||||
iter->end = s_empty(iter->target);
|
||||
}
|
||||
void s_iter_to_end(stack_iter *iter)
|
||||
{
|
||||
iter->cursor = 0;
|
||||
iter->start = s_empty(iter->target);
|
||||
iter->end = true;
|
||||
}
|
||||
bool s_iter_next(stack_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
iter->start = s_empty(iter->target);
|
||||
if (iter->cursor == 0)
|
||||
iter->end = true;
|
||||
else
|
||||
iter->cursor--;
|
||||
return true;
|
||||
}
|
||||
bool s_iter_prev(stack_iter *iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
iter->end = s_empty(iter->target);
|
||||
if (iter->cursor == iter->target->count - 1)
|
||||
iter->start = true;
|
||||
else
|
||||
iter->cursor++;
|
||||
return true;
|
||||
}
|
||||
size_t s_iter_value(stack_iter *iter)
|
||||
{
|
||||
if (s_empty(iter->target))
|
||||
return s_impl_default_value();
|
||||
return iter->target->buffer[iter->cursor];
|
||||
}
|
||||
size_t *s_iter_rvalue(stack_iter *iter)
|
||||
{
|
||||
if (s_empty(iter->target))
|
||||
return NULL;
|
||||
return &(iter->target->buffer[iter->cursor]);
|
||||
}
|
||||
size_t s_iter_index(stack_iter *iter) { return iter->target->count - 1 - iter->cursor; }
|
||||
static bool s_impl_grow(stack *_stack_)
|
||||
{
|
||||
size_t new_capacity = _stack_->capacity * 2;
|
||||
size_t *new_buffer = realloc(_stack_->buffer, sizeof(size_t) * new_capacity);
|
||||
if (!new_buffer)
|
||||
return false;
|
||||
_stack_->buffer = new_buffer;
|
||||
_stack_->capacity = new_capacity;
|
||||
return true;
|
||||
}
|
||||
static stack_iter s_impl_it_start(stack *_stack_)
|
||||
{
|
||||
stack_iter iter;
|
||||
s_iter_init(&iter, _stack_);
|
||||
s_iter_to_start(&iter);
|
||||
return iter;
|
||||
}
|
||||
static stack_iter s_impl_it_end(stack *_stack_)
|
||||
{
|
||||
stack_iter iter;
|
||||
s_iter_init(&iter, _stack_);
|
||||
s_iter_to_end(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,597 @@
|
||||
#include "cmc/treemap.h"
|
||||
|
||||
typedef struct treemap_s
|
||||
{
|
||||
struct treemap_node_s *root;
|
||||
size_t count;
|
||||
int (*cmp)(size_t, size_t);
|
||||
struct treemap_iter_s (*it_start)(struct treemap_s *);
|
||||
struct treemap_iter_s (*it_end)(struct treemap_s *);
|
||||
} treemap, *treemap_ptr;
|
||||
typedef struct treemap_node_s
|
||||
{
|
||||
size_t key;
|
||||
size_t value;
|
||||
unsigned char height;
|
||||
struct treemap_node_s *right;
|
||||
struct treemap_node_s *left;
|
||||
struct treemap_node_s *parent;
|
||||
} treemap_node, *treemap_node_ptr;
|
||||
typedef struct treemap_iter_s
|
||||
{
|
||||
struct treemap_s *target;
|
||||
struct treemap_node_s *cursor;
|
||||
struct treemap_node_s *first;
|
||||
struct treemap_node_s *last;
|
||||
size_t index;
|
||||
bool start;
|
||||
bool end;
|
||||
} treemap_iter, *treemap_iter_ptr;
|
||||
treemap *tm_new(int (*compare)(size_t, size_t));
|
||||
void tm_clear(treemap *_map_);
|
||||
void tm_free(treemap *_map_);
|
||||
bool tm_insert(treemap *_map_, size_t key, size_t value);
|
||||
bool tm_remove(treemap *_map_, size_t key, size_t *value);
|
||||
bool tm_insert_if(treemap *_map_, size_t key, size_t value, bool condition);
|
||||
bool tm_remove_if(treemap *_map_, size_t key, size_t *value, bool condition);
|
||||
bool tm_max(treemap *_map_, size_t *key, size_t *value);
|
||||
bool tm_min(treemap *_map_, size_t *key, size_t *value);
|
||||
size_t tm_get(treemap *_map_, size_t key);
|
||||
size_t *tm_get_ref(treemap *_map_, size_t key);
|
||||
bool tm_contains(treemap *_map_, size_t key);
|
||||
bool tm_empty(treemap *_map_);
|
||||
size_t tm_count(treemap *_map_);
|
||||
treemap_iter *tm_iter_new(treemap *target);
|
||||
void tm_iter_free(treemap_iter *iter);
|
||||
void tm_iter_init(treemap_iter *iter, treemap *target);
|
||||
bool tm_iter_start(treemap_iter *iter);
|
||||
bool tm_iter_end(treemap_iter *iter);
|
||||
void tm_iter_to_start(treemap_iter *iter);
|
||||
void tm_iter_to_end(treemap_iter *iter);
|
||||
bool tm_iter_next(treemap_iter *iter);
|
||||
bool tm_iter_prev(treemap_iter *iter);
|
||||
size_t tm_iter_key(treemap_iter *iter);
|
||||
size_t tm_iter_value(treemap_iter *iter);
|
||||
size_t *tm_iter_rvalue(treemap_iter *iter);
|
||||
size_t tm_iter_index(treemap_iter *iter);
|
||||
static inline size_t tm_impl_default_key(void)
|
||||
{
|
||||
size_t _empty_key_;
|
||||
memset(&_empty_key_, 0, sizeof(size_t));
|
||||
return _empty_key_;
|
||||
}
|
||||
static inline size_t tm_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
static treemap_node *tm_impl_new_node(size_t key, size_t value);
|
||||
static treemap_node *tm_impl_get_node(treemap *_map_, size_t key);
|
||||
static unsigned char tm_impl_h(treemap_node *node);
|
||||
static unsigned char tm_impl_hupdate(treemap_node *node);
|
||||
static void tm_impl_rotate_right(treemap_node **Z);
|
||||
static void tm_impl_rotate_left(treemap_node **Z);
|
||||
static void tm_impl_rebalance(treemap *_map_, treemap_node *node);
|
||||
static treemap_iter tm_impl_it_start(treemap *_map_);
|
||||
static treemap_iter tm_impl_it_end(treemap *_map_);
|
||||
treemap *tm_new(int (*compare)(size_t, size_t))
|
||||
{
|
||||
treemap *_map_ = malloc(sizeof(treemap));
|
||||
if (!_map_)
|
||||
return NULL;
|
||||
_map_->count = 0;
|
||||
_map_->root = NULL;
|
||||
_map_->cmp = compare;
|
||||
_map_->it_start = tm_impl_it_start;
|
||||
_map_->it_end = tm_impl_it_end;
|
||||
return _map_;
|
||||
}
|
||||
void tm_clear(treemap *_map_)
|
||||
{
|
||||
treemap_node *scan = _map_->root;
|
||||
treemap_node *up = NULL;
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (scan->left != NULL)
|
||||
{
|
||||
treemap_node *left = scan->left;
|
||||
scan->left = up;
|
||||
up = scan;
|
||||
scan = left;
|
||||
}
|
||||
else if (scan->right != NULL)
|
||||
{
|
||||
treemap_node *right = scan->right;
|
||||
scan->left = up;
|
||||
scan->right = NULL;
|
||||
up = scan;
|
||||
scan = right;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (up == NULL)
|
||||
{
|
||||
free(scan);
|
||||
scan = NULL;
|
||||
}
|
||||
while (up != NULL)
|
||||
{
|
||||
free(scan);
|
||||
if (up->right != NULL)
|
||||
{
|
||||
scan = up->right;
|
||||
up->right = NULL;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
scan = up;
|
||||
up = up->left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_map_->count = 0;
|
||||
_map_->root = NULL;
|
||||
}
|
||||
void tm_free(treemap *_map_)
|
||||
{
|
||||
tm_clear(_map_);
|
||||
free(_map_);
|
||||
}
|
||||
bool tm_insert(treemap *_map_, size_t key, size_t value)
|
||||
{
|
||||
if (tm_empty(_map_))
|
||||
{
|
||||
_map_->root = tm_impl_new_node(key, value);
|
||||
if (!_map_->root)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
treemap_node *scan = _map_->root;
|
||||
treemap_node *parent = scan;
|
||||
while (scan != NULL)
|
||||
{
|
||||
parent = scan;
|
||||
if (_map_->cmp(scan->key, key) > 0)
|
||||
scan = scan->left;
|
||||
else if (_map_->cmp(scan->key, key) < 0)
|
||||
scan = scan->right;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
treemap_node *node;
|
||||
if (_map_->cmp(parent->key, key) > 0)
|
||||
{
|
||||
parent->left = tm_impl_new_node(key, value);
|
||||
if (!parent->left)
|
||||
return false;
|
||||
parent->left->parent = parent;
|
||||
node = parent->left;
|
||||
}
|
||||
else
|
||||
{
|
||||
parent->right = tm_impl_new_node(key, value);
|
||||
if (!parent->right)
|
||||
return false;
|
||||
parent->right->parent = parent;
|
||||
node = parent->right;
|
||||
}
|
||||
tm_impl_rebalance(_map_, node);
|
||||
}
|
||||
_map_->count++;
|
||||
return true;
|
||||
}
|
||||
bool tm_remove(treemap *_map_, size_t key, size_t *value)
|
||||
{
|
||||
treemap_node *node = tm_impl_get_node(_map_, key);
|
||||
if (!node)
|
||||
return false;
|
||||
*value = node->value;
|
||||
treemap_node *temp = NULL, *unbalanced = NULL;
|
||||
bool is_root = node->parent == NULL;
|
||||
if (node->left == NULL && node->right == NULL)
|
||||
{
|
||||
if (is_root)
|
||||
_map_->root = NULL;
|
||||
else
|
||||
{
|
||||
unbalanced = node->parent;
|
||||
if (node->parent->right == node)
|
||||
node->parent->right = NULL;
|
||||
else
|
||||
node->parent->left = NULL;
|
||||
}
|
||||
free(node);
|
||||
}
|
||||
else if (node->left == NULL)
|
||||
{
|
||||
if (is_root)
|
||||
{
|
||||
_map_->root = node->right;
|
||||
_map_->root->parent = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
unbalanced = node->parent;
|
||||
node->right->parent = node->parent;
|
||||
if (node->parent->right == node)
|
||||
node->parent->right = node->right;
|
||||
else
|
||||
node->parent->left = node->right;
|
||||
}
|
||||
free(node);
|
||||
}
|
||||
else if (node->right == NULL)
|
||||
{
|
||||
if (is_root)
|
||||
{
|
||||
_map_->root = node->left;
|
||||
_map_->root->parent = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
unbalanced = node->parent;
|
||||
node->left->parent = node->parent;
|
||||
if (node->parent->right == node)
|
||||
node->parent->right = node->left;
|
||||
else
|
||||
node->parent->left = node->left;
|
||||
}
|
||||
free(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = node->right;
|
||||
while (temp->left != NULL)
|
||||
temp = temp->left;
|
||||
size_t temp_key = temp->key;
|
||||
size_t temp_val = temp->value;
|
||||
unbalanced = temp->parent;
|
||||
if (temp->left == NULL && temp->right == NULL)
|
||||
{
|
||||
if (temp->parent->right == temp)
|
||||
temp->parent->right = NULL;
|
||||
else
|
||||
temp->parent->left = NULL;
|
||||
}
|
||||
else if (temp->left == NULL)
|
||||
{
|
||||
temp->right->parent = temp->parent;
|
||||
if (temp->parent->right == temp)
|
||||
temp->parent->right = temp->right;
|
||||
else
|
||||
temp->parent->left = temp->right;
|
||||
}
|
||||
else if (temp->right == NULL)
|
||||
{
|
||||
temp->left->parent = temp->parent;
|
||||
if (temp->parent->right == temp)
|
||||
temp->parent->right = temp->left;
|
||||
else
|
||||
temp->parent->left = temp->left;
|
||||
}
|
||||
free(temp);
|
||||
node->key = temp_key;
|
||||
node->value = temp_val;
|
||||
}
|
||||
if (unbalanced != NULL)
|
||||
tm_impl_rebalance(_map_, unbalanced);
|
||||
_map_->count--;
|
||||
if (_map_->count == 0)
|
||||
_map_->root = NULL;
|
||||
return true;
|
||||
}
|
||||
bool tm_insert_if(treemap *_map_, size_t key, size_t value, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return tm_insert(_map_, key, value);
|
||||
return false;
|
||||
}
|
||||
bool tm_remove_if(treemap *_map_, size_t key, size_t *value, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return tm_remove(_map_, key, value);
|
||||
return false;
|
||||
}
|
||||
bool tm_max(treemap *_map_, size_t *key, size_t *value)
|
||||
{
|
||||
if (tm_empty(_map_))
|
||||
return false;
|
||||
treemap_node *scan = _map_->root;
|
||||
while (scan->right != NULL)
|
||||
scan = scan->right;
|
||||
*key = scan->key;
|
||||
*value = scan->value;
|
||||
return true;
|
||||
}
|
||||
bool tm_min(treemap *_map_, size_t *key, size_t *value)
|
||||
{
|
||||
if (tm_empty(_map_))
|
||||
return false;
|
||||
treemap_node *scan = _map_->root;
|
||||
while (scan->left != NULL)
|
||||
scan = scan->left;
|
||||
*key = scan->key;
|
||||
*value = scan->value;
|
||||
return true;
|
||||
}
|
||||
size_t tm_get(treemap *_map_, size_t key)
|
||||
{
|
||||
treemap_node *node = tm_impl_get_node(_map_, key);
|
||||
if (!node)
|
||||
return tm_impl_default_value();
|
||||
return node->value;
|
||||
}
|
||||
size_t *tm_get_ref(treemap *_map_, size_t key)
|
||||
{
|
||||
treemap_node *node = tm_impl_get_node(_map_, key);
|
||||
if (!node)
|
||||
return NULL;
|
||||
return &(node->value);
|
||||
}
|
||||
bool tm_contains(treemap *_map_, size_t key)
|
||||
{
|
||||
treemap_node *scan = _map_->root;
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (_map_->cmp(scan->key, key) > 0)
|
||||
scan = scan->left;
|
||||
else if (_map_->cmp(scan->key, key) < 0)
|
||||
scan = scan->right;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool tm_empty(treemap *_map_) { return _map_->count == 0; }
|
||||
size_t tm_count(treemap *_map_) { return _map_->count; }
|
||||
treemap_iter *tm_iter_new(treemap *target)
|
||||
{
|
||||
treemap_iter *iter = malloc(sizeof(treemap_iter));
|
||||
if (!iter)
|
||||
return NULL;
|
||||
tm_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void tm_iter_free(treemap_iter *iter) { free(iter); }
|
||||
void tm_iter_init(treemap_iter *iter, treemap *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = tm_empty(target);
|
||||
iter->cursor = target->root;
|
||||
while (iter->cursor->left != NULL)
|
||||
iter->cursor = iter->cursor->left;
|
||||
iter->first = iter->cursor;
|
||||
iter->last = target->root;
|
||||
while (iter->last->right != NULL)
|
||||
iter->last = iter->last->right;
|
||||
}
|
||||
bool tm_iter_start(treemap_iter *iter) { return tm_empty(iter->target) || iter->start; }
|
||||
bool tm_iter_end(treemap_iter *iter) { return tm_empty(iter->target) || iter->end; }
|
||||
void tm_iter_to_start(treemap_iter *iter)
|
||||
{
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = tm_empty(iter->target);
|
||||
iter->cursor = iter->first;
|
||||
}
|
||||
void tm_iter_to_end(treemap_iter *iter)
|
||||
{
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = tm_empty(iter->target);
|
||||
iter->end = true;
|
||||
iter->cursor = iter->last;
|
||||
}
|
||||
bool tm_iter_next(treemap_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
iter->start = false;
|
||||
if (iter->cursor->right != NULL)
|
||||
{
|
||||
iter->cursor = iter->cursor->right;
|
||||
while (iter->cursor->left != NULL)
|
||||
iter->cursor = iter->cursor->left;
|
||||
iter->index++;
|
||||
return true;
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
if (iter->cursor == iter->last)
|
||||
{
|
||||
iter->end = true;
|
||||
return true;
|
||||
}
|
||||
if (iter->cursor->parent->left == iter->cursor)
|
||||
{
|
||||
iter->cursor = iter->cursor->parent;
|
||||
iter->index++;
|
||||
return true;
|
||||
}
|
||||
iter->cursor = iter->cursor->parent;
|
||||
}
|
||||
}
|
||||
bool tm_iter_prev(treemap_iter *iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
iter->end = false;
|
||||
if (iter->cursor->left != NULL)
|
||||
{
|
||||
iter->cursor = iter->cursor->left;
|
||||
while (iter->cursor->right != NULL)
|
||||
iter->cursor = iter->cursor->right;
|
||||
iter->index--;
|
||||
return true;
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
if (iter->cursor == iter->first)
|
||||
{
|
||||
iter->start = true;
|
||||
return true;
|
||||
}
|
||||
if (iter->cursor->parent->right == iter->cursor)
|
||||
{
|
||||
iter->cursor = iter->cursor->parent;
|
||||
iter->index--;
|
||||
return true;
|
||||
}
|
||||
iter->cursor = iter->cursor->parent;
|
||||
}
|
||||
}
|
||||
size_t tm_iter_key(treemap_iter *iter)
|
||||
{
|
||||
if (tm_empty(iter->target))
|
||||
return tm_impl_default_key();
|
||||
return iter->cursor->key;
|
||||
}
|
||||
size_t tm_iter_value(treemap_iter *iter)
|
||||
{
|
||||
if (tm_empty(iter->target))
|
||||
return tm_impl_default_value();
|
||||
return iter->cursor->value;
|
||||
}
|
||||
size_t *tm_iter_rvalue(treemap_iter *iter)
|
||||
{
|
||||
if (tm_empty(iter->target))
|
||||
return NULL;
|
||||
return &(iter->cursor->value);
|
||||
}
|
||||
size_t tm_iter_index(treemap_iter *iter) { return iter->index; }
|
||||
static treemap_node *tm_impl_new_node(size_t key, size_t value)
|
||||
{
|
||||
treemap_node *node = malloc(sizeof(treemap_node));
|
||||
if (!node)
|
||||
return NULL;
|
||||
node->key = key;
|
||||
node->value = value;
|
||||
node->right = NULL;
|
||||
node->left = NULL;
|
||||
node->parent = NULL;
|
||||
node->height = 0;
|
||||
return node;
|
||||
}
|
||||
static treemap_node *tm_impl_get_node(treemap *_map_, size_t key)
|
||||
{
|
||||
if (tm_empty(_map_))
|
||||
return NULL;
|
||||
treemap_node *scan = _map_->root;
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (_map_->cmp(scan->key, key) > 0)
|
||||
scan = scan->left;
|
||||
else if (_map_->cmp(scan->key, key) < 0)
|
||||
scan = scan->right;
|
||||
else
|
||||
return scan;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
static unsigned char tm_impl_h(treemap_node *node)
|
||||
{
|
||||
if (node == NULL)
|
||||
return 0;
|
||||
return node->height;
|
||||
}
|
||||
static unsigned char tm_impl_hupdate(treemap_node *node)
|
||||
{
|
||||
if (node == NULL)
|
||||
return 0;
|
||||
unsigned char h_l = tm_impl_h(node->left);
|
||||
unsigned char h_r = tm_impl_h(node->right);
|
||||
return 1 + (h_l > h_r ? h_l : h_r);
|
||||
}
|
||||
static void tm_impl_rotate_right(treemap_node **Z)
|
||||
{
|
||||
treemap_node *root = *Z;
|
||||
treemap_node *new_root = root->left;
|
||||
if (root->parent != NULL)
|
||||
{
|
||||
if (root->parent->left == root)
|
||||
root->parent->left = new_root;
|
||||
else
|
||||
root->parent->right = new_root;
|
||||
}
|
||||
new_root->parent = root->parent;
|
||||
root->parent = new_root;
|
||||
root->left = new_root->right;
|
||||
if (root->left)
|
||||
root->left->parent = root;
|
||||
new_root->right = root;
|
||||
root->height = tm_impl_hupdate(root);
|
||||
new_root->height = tm_impl_hupdate(new_root);
|
||||
*Z = new_root;
|
||||
}
|
||||
static void tm_impl_rotate_left(treemap_node **Z)
|
||||
{
|
||||
treemap_node *root = *Z;
|
||||
treemap_node *new_root = root->right;
|
||||
if (root->parent != NULL)
|
||||
{
|
||||
if (root->parent->right == root)
|
||||
root->parent->right = new_root;
|
||||
else
|
||||
root->parent->left = new_root;
|
||||
}
|
||||
new_root->parent = root->parent;
|
||||
root->parent = new_root;
|
||||
root->right = new_root->left;
|
||||
if (root->right)
|
||||
root->right->parent = root;
|
||||
new_root->left = root;
|
||||
root->height = tm_impl_hupdate(root);
|
||||
new_root->height = tm_impl_hupdate(new_root);
|
||||
*Z = new_root;
|
||||
}
|
||||
static void tm_impl_rebalance(treemap *_map_, treemap_node *node)
|
||||
{
|
||||
treemap_node *scan = node, *child = NULL;
|
||||
int balance;
|
||||
bool is_root = false;
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (scan->parent == NULL)
|
||||
is_root = true;
|
||||
scan->height = tm_impl_hupdate(scan);
|
||||
balance = tm_impl_h(scan->right) - tm_impl_h(scan->left);
|
||||
if (balance >= 2)
|
||||
{
|
||||
child = scan->right;
|
||||
if (tm_impl_h(child->right) < tm_impl_h(child->left))
|
||||
tm_impl_rotate_right(&(scan->right));
|
||||
tm_impl_rotate_left(&scan);
|
||||
}
|
||||
else if (balance <= -2)
|
||||
{
|
||||
child = scan->left;
|
||||
if (tm_impl_h(child->left) < tm_impl_h(child->right))
|
||||
tm_impl_rotate_left(&(scan->left));
|
||||
tm_impl_rotate_right(&scan);
|
||||
}
|
||||
if (is_root)
|
||||
{
|
||||
_map_->root = scan;
|
||||
is_root = false;
|
||||
}
|
||||
scan = scan->parent;
|
||||
}
|
||||
}
|
||||
static treemap_iter tm_impl_it_start(treemap *_map_)
|
||||
{
|
||||
treemap_iter iter;
|
||||
tm_iter_init(&iter, _map_);
|
||||
return iter;
|
||||
}
|
||||
static treemap_iter tm_impl_it_end(treemap *_map_)
|
||||
{
|
||||
treemap_iter iter;
|
||||
tm_iter_init(&iter, _map_);
|
||||
tm_iter_to_end(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,688 @@
|
||||
#include "cmc/treeset.h"
|
||||
|
||||
typedef struct treeset_s
|
||||
{
|
||||
struct treeset_node_s *root;
|
||||
size_t count;
|
||||
int (*cmp)(size_t, size_t);
|
||||
struct treeset_iter_s (*it_start)(struct treeset_s *);
|
||||
struct treeset_iter_s (*it_end)(struct treeset_s *);
|
||||
} treeset, *treeset_ptr;
|
||||
typedef struct treeset_node_s
|
||||
{
|
||||
size_t value;
|
||||
unsigned char height;
|
||||
struct treeset_node_s *right;
|
||||
struct treeset_node_s *left;
|
||||
struct treeset_node_s *parent;
|
||||
} treeset_node, *treeset_node_ptr;
|
||||
typedef struct treeset_iter_s
|
||||
{
|
||||
struct treeset_s *target;
|
||||
struct treeset_node_s *cursor;
|
||||
struct treeset_node_s *first;
|
||||
struct treeset_node_s *last;
|
||||
size_t index;
|
||||
bool start;
|
||||
bool end;
|
||||
} treeset_iter, *treeset_iter_ptr;
|
||||
treeset *ts_new(int (*compare)(size_t, size_t));
|
||||
void ts_clear(treeset *_set_);
|
||||
void ts_free(treeset *_set_);
|
||||
bool ts_insert(treeset *_set_, size_t element);
|
||||
bool ts_remove(treeset *_set_, size_t element);
|
||||
bool ts_insert_if(treeset *_set_, size_t element, bool condition);
|
||||
bool ts_remove_if(treeset *_set_, size_t element, bool condition);
|
||||
bool ts_max(treeset *_set_, size_t *value);
|
||||
bool ts_min(treeset *_set_, size_t *value);
|
||||
bool ts_contains(treeset *_set_, size_t element);
|
||||
bool ts_empty(treeset *_set_);
|
||||
size_t ts_count(treeset *_set_);
|
||||
treeset *ts_union(treeset *_set1_, treeset *_set2_);
|
||||
treeset *ts_intersection(treeset *_set1_, treeset *_set2_);
|
||||
treeset *ts_difference(treeset *_set1_, treeset *_set2_);
|
||||
treeset *ts_symmetric_difference(treeset *_set1_, treeset *_set2_);
|
||||
bool ts_is_subset(treeset *_set1_, treeset *_set2_);
|
||||
bool ts_is_superset(treeset *_set1_, treeset *_set2_);
|
||||
bool ts_is_proper_subset(treeset *_set1_, treeset *_set2_);
|
||||
bool ts_is_proper_superset(treeset *_set1_, treeset *_set2_);
|
||||
bool ts_is_disjointset(treeset *_set1_, treeset *_set2_);
|
||||
treeset_iter *ts_iter_new(treeset *target);
|
||||
void ts_iter_free(treeset_iter *iter);
|
||||
void ts_iter_init(treeset_iter *iter, treeset *target);
|
||||
bool ts_iter_start(treeset_iter *iter);
|
||||
bool ts_iter_end(treeset_iter *iter);
|
||||
void ts_iter_to_start(treeset_iter *iter);
|
||||
void ts_iter_to_end(treeset_iter *iter);
|
||||
bool ts_iter_next(treeset_iter *iter);
|
||||
bool ts_iter_prev(treeset_iter *iter);
|
||||
size_t ts_iter_value(treeset_iter *iter);
|
||||
size_t ts_iter_index(treeset_iter *iter);
|
||||
static inline size_t ts_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
static treeset_node *ts_impl_new_node(size_t element);
|
||||
static treeset_node *ts_impl_get_node(treeset *_set_, size_t element);
|
||||
static unsigned char ts_impl_h(treeset_node *node);
|
||||
static unsigned char ts_impl_hupdate(treeset_node *node);
|
||||
static void ts_impl_rotate_right(treeset_node **Z);
|
||||
static void ts_impl_rotate_left(treeset_node **Z);
|
||||
static void ts_impl_rebalance(treeset *_set_, treeset_node *node);
|
||||
static treeset_iter ts_impl_it_start(treeset *_set_);
|
||||
static treeset_iter ts_impl_it_end(treeset *_set_);
|
||||
treeset *ts_new(int (*compare)(size_t, size_t))
|
||||
{
|
||||
treeset *_set_ = malloc(sizeof(treeset));
|
||||
if (!_set_)
|
||||
return NULL;
|
||||
_set_->count = 0;
|
||||
_set_->root = NULL;
|
||||
_set_->cmp = compare;
|
||||
_set_->it_start = ts_impl_it_start;
|
||||
_set_->it_end = ts_impl_it_end;
|
||||
return _set_;
|
||||
}
|
||||
void ts_clear(treeset *_set_)
|
||||
{
|
||||
treeset_node *scan = _set_->root;
|
||||
treeset_node *up = NULL;
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (scan->left != NULL)
|
||||
{
|
||||
treeset_node *left = scan->left;
|
||||
scan->left = up;
|
||||
up = scan;
|
||||
scan = left;
|
||||
}
|
||||
else if (scan->right != NULL)
|
||||
{
|
||||
treeset_node *right = scan->right;
|
||||
scan->left = up;
|
||||
scan->right = NULL;
|
||||
up = scan;
|
||||
scan = right;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (up == NULL)
|
||||
{
|
||||
free(scan);
|
||||
scan = NULL;
|
||||
}
|
||||
while (up != NULL)
|
||||
{
|
||||
free(scan);
|
||||
if (up->right != NULL)
|
||||
{
|
||||
scan = up->right;
|
||||
up->right = NULL;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
scan = up;
|
||||
up = up->left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_set_->count = 0;
|
||||
_set_->root = NULL;
|
||||
}
|
||||
void ts_free(treeset *_set_)
|
||||
{
|
||||
ts_clear(_set_);
|
||||
free(_set_);
|
||||
}
|
||||
bool ts_insert(treeset *_set_, size_t element)
|
||||
{
|
||||
if (ts_empty(_set_))
|
||||
{
|
||||
_set_->root = ts_impl_new_node(element);
|
||||
if (!_set_->root)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
treeset_node *scan = _set_->root;
|
||||
treeset_node *parent = scan;
|
||||
while (scan != NULL)
|
||||
{
|
||||
parent = scan;
|
||||
if (_set_->cmp(scan->value, element) > 0)
|
||||
scan = scan->left;
|
||||
else if (_set_->cmp(scan->value, element) < 0)
|
||||
scan = scan->right;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
treeset_node *node;
|
||||
if (_set_->cmp(parent->value, element) > 0)
|
||||
{
|
||||
parent->left = ts_impl_new_node(element);
|
||||
if (!parent->left)
|
||||
return false;
|
||||
parent->left->parent = parent;
|
||||
node = parent->left;
|
||||
}
|
||||
else
|
||||
{
|
||||
parent->right = ts_impl_new_node(element);
|
||||
if (!parent->right)
|
||||
return false;
|
||||
parent->right->parent = parent;
|
||||
node = parent->right;
|
||||
}
|
||||
ts_impl_rebalance(_set_, node);
|
||||
}
|
||||
_set_->count++;
|
||||
return true;
|
||||
}
|
||||
bool ts_remove(treeset *_set_, size_t element)
|
||||
{
|
||||
treeset_node *node = ts_impl_get_node(_set_, element);
|
||||
if (!node)
|
||||
return false;
|
||||
treeset_node *temp = NULL, *unbalanced = NULL;
|
||||
bool is_root = node->parent == NULL;
|
||||
if (node->left == NULL && node->right == NULL)
|
||||
{
|
||||
if (is_root)
|
||||
_set_->root = NULL;
|
||||
else
|
||||
{
|
||||
unbalanced = node->parent;
|
||||
if (node->parent->right == node)
|
||||
node->parent->right = NULL;
|
||||
else
|
||||
node->parent->left = NULL;
|
||||
}
|
||||
free(node);
|
||||
}
|
||||
else if (node->left == NULL)
|
||||
{
|
||||
if (is_root)
|
||||
{
|
||||
_set_->root = node->right;
|
||||
_set_->root->parent = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
unbalanced = node->parent;
|
||||
node->right->parent = node->parent;
|
||||
if (node->parent->right == node)
|
||||
node->parent->right = node->right;
|
||||
else
|
||||
node->parent->left = node->right;
|
||||
}
|
||||
free(node);
|
||||
}
|
||||
else if (node->right == NULL)
|
||||
{
|
||||
if (is_root)
|
||||
{
|
||||
_set_->root = node->left;
|
||||
_set_->root->parent = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
unbalanced = node->parent;
|
||||
node->left->parent = node->parent;
|
||||
if (node->parent->right == node)
|
||||
node->parent->right = node->left;
|
||||
else
|
||||
node->parent->left = node->left;
|
||||
}
|
||||
free(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = node->right;
|
||||
while (temp->left != NULL)
|
||||
temp = temp->left;
|
||||
size_t temp_value = temp->value;
|
||||
unbalanced = temp->parent;
|
||||
if (temp->left == NULL && temp->right == NULL)
|
||||
{
|
||||
if (temp->parent->right == temp)
|
||||
temp->parent->right = NULL;
|
||||
else
|
||||
temp->parent->left = NULL;
|
||||
}
|
||||
else if (temp->left == NULL)
|
||||
{
|
||||
temp->right->parent = temp->parent;
|
||||
if (temp->parent->right == temp)
|
||||
temp->parent->right = temp->right;
|
||||
else
|
||||
temp->parent->left = temp->right;
|
||||
}
|
||||
else if (temp->right == NULL)
|
||||
{
|
||||
temp->left->parent = temp->parent;
|
||||
if (temp->parent->right == temp)
|
||||
temp->parent->right = temp->left;
|
||||
else
|
||||
temp->parent->left = temp->left;
|
||||
}
|
||||
free(temp);
|
||||
node->value = temp_value;
|
||||
}
|
||||
if (unbalanced != NULL)
|
||||
ts_impl_rebalance(_set_, unbalanced);
|
||||
_set_->count--;
|
||||
if (_set_->count == 0)
|
||||
_set_->root = NULL;
|
||||
return true;
|
||||
}
|
||||
bool ts_insert_if(treeset *_set_, size_t element, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return ts_insert(_set_, element);
|
||||
return false;
|
||||
}
|
||||
bool ts_remove_if(treeset *_set_, size_t element, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return ts_remove(_set_, element);
|
||||
return false;
|
||||
}
|
||||
bool ts_max(treeset *_set_, size_t *value)
|
||||
{
|
||||
if (ts_empty(_set_))
|
||||
return false;
|
||||
treeset_node *scan = _set_->root;
|
||||
while (scan->right != NULL)
|
||||
scan = scan->right;
|
||||
*value = scan->value;
|
||||
return true;
|
||||
}
|
||||
bool ts_min(treeset *_set_, size_t *value)
|
||||
{
|
||||
if (ts_empty(_set_))
|
||||
return false;
|
||||
treeset_node *scan = _set_->root;
|
||||
while (scan->left != NULL)
|
||||
scan = scan->left;
|
||||
*value = scan->value;
|
||||
return true;
|
||||
}
|
||||
bool ts_contains(treeset *_set_, size_t element)
|
||||
{
|
||||
treeset_node *scan = _set_->root;
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (_set_->cmp(scan->value, element) > 0)
|
||||
scan = scan->left;
|
||||
else if (_set_->cmp(scan->value, element) < 0)
|
||||
scan = scan->right;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool ts_empty(treeset *_set_) { return _set_->count == 0; }
|
||||
size_t ts_count(treeset *_set_) { return _set_->count; }
|
||||
treeset *ts_union(treeset *_set1_, treeset *_set2_)
|
||||
{
|
||||
treeset *_set_r_ = ts_new(_set1_->cmp);
|
||||
if (!_set_r_)
|
||||
return false;
|
||||
treeset_iter iter1, iter2;
|
||||
ts_iter_init(&iter1, _set1_);
|
||||
ts_iter_init(&iter2, _set2_);
|
||||
for (ts_iter_to_start(&iter1); !ts_iter_end(&iter1); ts_iter_next(&iter1))
|
||||
{
|
||||
ts_insert(_set_r_, ts_iter_value(&iter1));
|
||||
}
|
||||
for (ts_iter_to_start(&iter2); !ts_iter_end(&iter2); ts_iter_next(&iter2))
|
||||
{
|
||||
ts_insert(_set_r_, ts_iter_value(&iter2));
|
||||
}
|
||||
return _set_r_;
|
||||
}
|
||||
treeset *ts_intersection(treeset *_set1_, treeset *_set2_)
|
||||
{
|
||||
treeset *_set_r_ = ts_new(_set1_->cmp);
|
||||
if (!_set_r_)
|
||||
return false;
|
||||
treeset *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_;
|
||||
treeset *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_;
|
||||
treeset_iter iter;
|
||||
ts_iter_init(&iter, _set_A_);
|
||||
for (ts_iter_to_start(&iter); !ts_iter_end(&iter); ts_iter_next(&iter))
|
||||
{
|
||||
size_t value = ts_iter_value(&iter);
|
||||
if (ts_impl_get_node(_set_B_, value) != NULL)
|
||||
ts_insert(_set_r_, value);
|
||||
}
|
||||
return _set_r_;
|
||||
}
|
||||
treeset *ts_difference(treeset *_set1_, treeset *_set2_)
|
||||
{
|
||||
treeset *_set_r_ = ts_new(_set1_->cmp);
|
||||
if (!_set_r_)
|
||||
return false;
|
||||
treeset_iter iter;
|
||||
ts_iter_init(&iter, _set1_);
|
||||
for (ts_iter_to_start(&iter); !ts_iter_end(&iter); ts_iter_next(&iter))
|
||||
{
|
||||
size_t value = ts_iter_value(&iter);
|
||||
if (ts_impl_get_node(_set2_, value) == NULL)
|
||||
ts_insert(_set_r_, value);
|
||||
}
|
||||
return _set_r_;
|
||||
}
|
||||
treeset *ts_symmetric_difference(treeset *_set1_, treeset *_set2_)
|
||||
{
|
||||
treeset *_set_r_ = ts_new(_set1_->cmp);
|
||||
if (!_set_r_)
|
||||
return false;
|
||||
treeset_iter iter1, iter2;
|
||||
ts_iter_init(&iter1, _set1_);
|
||||
ts_iter_init(&iter2, _set2_);
|
||||
for (ts_iter_to_start(&iter1); !ts_iter_end(&iter1); ts_iter_next(&iter1))
|
||||
{
|
||||
size_t value = ts_iter_value(&iter1);
|
||||
if (ts_impl_get_node(_set2_, value) == NULL)
|
||||
ts_insert(_set_r_, value);
|
||||
}
|
||||
for (ts_iter_to_start(&iter2); !ts_iter_end(&iter2); ts_iter_next(&iter2))
|
||||
{
|
||||
size_t value = ts_iter_value(&iter2);
|
||||
if (ts_impl_get_node(_set1_, value) == NULL)
|
||||
ts_insert(_set_r_, value);
|
||||
}
|
||||
return _set_r_;
|
||||
}
|
||||
bool ts_is_subset(treeset *_set1_, treeset *_set2_)
|
||||
{
|
||||
if (ts_count(_set1_) > ts_count(_set2_))
|
||||
return false;
|
||||
if (ts_empty(_set1_))
|
||||
return true;
|
||||
treeset_iter iter;
|
||||
ts_iter_init(&iter, _set1_);
|
||||
for (ts_iter_to_start(&iter); !ts_iter_end(&iter); ts_iter_next(&iter))
|
||||
{
|
||||
size_t value = ts_iter_value(&iter);
|
||||
if (!ts_contains(_set2_, value))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool ts_is_superset(treeset *_set1_, treeset *_set2_) { return ts_is_subset(_set2_, _set1_); }
|
||||
bool ts_is_proper_subset(treeset *_set1_, treeset *_set2_)
|
||||
{
|
||||
if (ts_count(_set1_) >= ts_count(_set2_))
|
||||
return false;
|
||||
if (ts_empty(_set1_))
|
||||
{
|
||||
if (!ts_empty(_set2_))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
treeset_iter iter;
|
||||
ts_iter_init(&iter, _set1_);
|
||||
for (ts_iter_to_start(&iter); !ts_iter_end(&iter); ts_iter_next(&iter))
|
||||
{
|
||||
size_t value = ts_iter_value(&iter);
|
||||
if (!ts_contains(_set2_, value))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool ts_is_proper_superset(treeset *_set1_, treeset *_set2_) { return ts_is_proper_subset(_set2_, _set1_); }
|
||||
bool ts_is_disjointset(treeset *_set1_, treeset *_set2_)
|
||||
{
|
||||
if (ts_empty(_set1_))
|
||||
return true;
|
||||
treeset_iter iter;
|
||||
ts_iter_init(&iter, _set1_);
|
||||
for (ts_iter_to_start(&iter); !ts_iter_end(&iter); ts_iter_next(&iter))
|
||||
{
|
||||
size_t value = ts_iter_value(&iter);
|
||||
if (ts_contains(_set2_, value))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
treeset_iter *ts_iter_new(treeset *target)
|
||||
{
|
||||
treeset_iter *iter = malloc(sizeof(treeset_iter));
|
||||
if (!iter)
|
||||
return NULL;
|
||||
ts_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void ts_iter_free(treeset_iter *iter) { free(iter); }
|
||||
void ts_iter_init(treeset_iter *iter, treeset *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = ts_empty(target);
|
||||
iter->cursor = target->root;
|
||||
while (iter->cursor->left != NULL)
|
||||
iter->cursor = iter->cursor->left;
|
||||
iter->first = iter->cursor;
|
||||
iter->last = target->root;
|
||||
while (iter->last->right != NULL)
|
||||
iter->last = iter->last->right;
|
||||
}
|
||||
bool ts_iter_start(treeset_iter *iter) { return ts_empty(iter->target) || iter->start; }
|
||||
bool ts_iter_end(treeset_iter *iter) { return ts_empty(iter->target) || iter->end; }
|
||||
void ts_iter_to_start(treeset_iter *iter)
|
||||
{
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = ts_empty(iter->target);
|
||||
iter->cursor = iter->first;
|
||||
}
|
||||
void ts_iter_to_end(treeset_iter *iter)
|
||||
{
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = ts_empty(iter->target);
|
||||
iter->end = true;
|
||||
iter->cursor = iter->last;
|
||||
}
|
||||
bool ts_iter_next(treeset_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
iter->start = ts_empty(iter->target);
|
||||
if (iter->cursor->right != NULL)
|
||||
{
|
||||
iter->cursor = iter->cursor->right;
|
||||
while (iter->cursor->left != NULL)
|
||||
iter->cursor = iter->cursor->left;
|
||||
iter->index++;
|
||||
return true;
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
if (iter->cursor == iter->last)
|
||||
{
|
||||
iter->end = true;
|
||||
return true;
|
||||
}
|
||||
if (iter->cursor->parent->left == iter->cursor)
|
||||
{
|
||||
iter->cursor = iter->cursor->parent;
|
||||
iter->index++;
|
||||
return true;
|
||||
}
|
||||
iter->cursor = iter->cursor->parent;
|
||||
}
|
||||
}
|
||||
bool ts_iter_prev(treeset_iter *iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
iter->end = ts_empty(iter->target);
|
||||
if (iter->cursor->left != NULL)
|
||||
{
|
||||
iter->cursor = iter->cursor->left;
|
||||
while (iter->cursor->right != NULL)
|
||||
iter->cursor = iter->cursor->right;
|
||||
iter->index--;
|
||||
return true;
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
if (iter->cursor == iter->first)
|
||||
{
|
||||
iter->start = true;
|
||||
return true;
|
||||
}
|
||||
if (iter->cursor->parent->right == iter->cursor)
|
||||
{
|
||||
iter->cursor = iter->cursor->parent;
|
||||
iter->index--;
|
||||
return true;
|
||||
}
|
||||
iter->cursor = iter->cursor->parent;
|
||||
}
|
||||
}
|
||||
size_t ts_iter_value(treeset_iter *iter)
|
||||
{
|
||||
if (ts_empty(iter->target))
|
||||
return ts_impl_default_value();
|
||||
return iter->cursor->value;
|
||||
}
|
||||
size_t ts_iter_index(treeset_iter *iter) { return iter->index; }
|
||||
static treeset_node *ts_impl_new_node(size_t element)
|
||||
{
|
||||
treeset_node *node = malloc(sizeof(treeset_node));
|
||||
if (!node)
|
||||
return NULL;
|
||||
node->value = element;
|
||||
node->right = NULL;
|
||||
node->left = NULL;
|
||||
node->parent = NULL;
|
||||
node->height = 0;
|
||||
return node;
|
||||
}
|
||||
static treeset_node *ts_impl_get_node(treeset *_set_, size_t element)
|
||||
{
|
||||
if (ts_empty(_set_))
|
||||
return NULL;
|
||||
treeset_node *scan = _set_->root;
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (_set_->cmp(scan->value, element) > 0)
|
||||
scan = scan->left;
|
||||
else if (_set_->cmp(scan->value, element) < 0)
|
||||
scan = scan->right;
|
||||
else
|
||||
return scan;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
static unsigned char ts_impl_h(treeset_node *node)
|
||||
{
|
||||
if (node == NULL)
|
||||
return 0;
|
||||
return node->height;
|
||||
}
|
||||
static unsigned char ts_impl_hupdate(treeset_node *node)
|
||||
{
|
||||
if (node == NULL)
|
||||
return 0;
|
||||
unsigned char h_l = ts_impl_h(node->left);
|
||||
unsigned char h_r = ts_impl_h(node->right);
|
||||
return 1 + (h_l > h_r ? h_l : h_r);
|
||||
}
|
||||
static void ts_impl_rotate_right(treeset_node **Z)
|
||||
{
|
||||
treeset_node *root = *Z;
|
||||
treeset_node *new_root = root->left;
|
||||
if (root->parent != NULL)
|
||||
{
|
||||
if (root->parent->left == root)
|
||||
root->parent->left = new_root;
|
||||
else
|
||||
root->parent->right = new_root;
|
||||
}
|
||||
new_root->parent = root->parent;
|
||||
root->parent = new_root;
|
||||
root->left = new_root->right;
|
||||
if (root->left)
|
||||
root->left->parent = root;
|
||||
new_root->right = root;
|
||||
root->height = ts_impl_hupdate(root);
|
||||
new_root->height = ts_impl_hupdate(new_root);
|
||||
*Z = new_root;
|
||||
}
|
||||
static void ts_impl_rotate_left(treeset_node **Z)
|
||||
{
|
||||
treeset_node *root = *Z;
|
||||
treeset_node *new_root = root->right;
|
||||
if (root->parent != NULL)
|
||||
{
|
||||
if (root->parent->right == root)
|
||||
root->parent->right = new_root;
|
||||
else
|
||||
root->parent->left = new_root;
|
||||
}
|
||||
new_root->parent = root->parent;
|
||||
root->parent = new_root;
|
||||
root->right = new_root->left;
|
||||
if (root->right)
|
||||
root->right->parent = root;
|
||||
new_root->left = root;
|
||||
root->height = ts_impl_hupdate(root);
|
||||
new_root->height = ts_impl_hupdate(new_root);
|
||||
*Z = new_root;
|
||||
}
|
||||
static void ts_impl_rebalance(treeset *_set_, treeset_node *node)
|
||||
{
|
||||
treeset_node *scan = node, *child = NULL;
|
||||
int balance;
|
||||
bool is_root = false;
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (scan->parent == NULL)
|
||||
is_root = true;
|
||||
scan->height = ts_impl_hupdate(scan);
|
||||
balance = ts_impl_h(scan->right) - ts_impl_h(scan->left);
|
||||
if (balance >= 2)
|
||||
{
|
||||
child = scan->right;
|
||||
if (ts_impl_h(child->right) < ts_impl_h(child->left))
|
||||
ts_impl_rotate_right(&(scan->right));
|
||||
ts_impl_rotate_left(&scan);
|
||||
}
|
||||
else if (balance <= -2)
|
||||
{
|
||||
child = scan->left;
|
||||
if (ts_impl_h(child->left) < ts_impl_h(child->right))
|
||||
ts_impl_rotate_left(&(scan->left));
|
||||
ts_impl_rotate_right(&scan);
|
||||
}
|
||||
if (is_root)
|
||||
{
|
||||
_set_->root = scan;
|
||||
is_root = false;
|
||||
}
|
||||
scan = scan->parent;
|
||||
}
|
||||
}
|
||||
static treeset_iter ts_impl_it_start(treeset *_set_)
|
||||
{
|
||||
treeset_iter iter;
|
||||
ts_iter_init(&iter, _set_);
|
||||
return iter;
|
||||
}
|
||||
static treeset_iter ts_impl_it_end(treeset *_set_)
|
||||
{
|
||||
treeset_iter iter;
|
||||
ts_iter_init(&iter, _set_);
|
||||
ts_iter_to_end(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/deque.c"
|
||||
|
||||
CMC_CREATE_UNIT(deque_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
deque *d = d_new(1000000);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
bool passed = d->capacity == 1000000 && d->count == 0 && d->buffer;
|
||||
|
||||
cmc_assert_equals(size_t, 1000000, d->capacity);
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
cmc_assert_not_equals(ptr, NULL, d->buffer);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
d_free(d);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
deque *d = d_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, d);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(d == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
deque *d = d_new(UINT64_MAX);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, d);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(d == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
d_push_back(d, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, d_count(d));
|
||||
|
||||
d_clear(d);
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
cmc_assert_equals(size_t, 100, d_capacity(d));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(d_count(d) == 0 && d_capacity(d) == 100);
|
||||
|
||||
d_free(d);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
deque *d = d_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
d_push_back(d, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, d_count(d));
|
||||
cmc_assert_lesser_equals(size_t, d_capacity(d), d_count(d));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(d_count(d) == 50 && d_count(d) <= d_capacity(d));
|
||||
|
||||
d_free(d);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/hashmap.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(hashmap_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
hashmap *map = hm_new(943722, 0.6, cmp, hash);
|
||||
|
||||
bool passed = (map->capacity >= (943722 / 0.6)) && map->count == 0 && map->buffer;
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
cmc_assert_greater_equals(size_t, (943722 / 0.6), hm_capacity(map));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
hm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
hashmap *map = hm_new(0, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(map == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
hashmap *map = hm_new(UINT64_MAX, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(map == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
hm_insert(map, i, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, hm_count(map));
|
||||
|
||||
hm_clear(map);
|
||||
|
||||
cmc_assert_equals(size_t, 0, hm_count(map));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(hm_count(map) == 0);
|
||||
|
||||
hm_free(map);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/hashset.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(hashset_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
hashset *set = hs_new(943722, 0.6, cmp, hash);
|
||||
|
||||
bool passed = (set->capacity >= (943722 / 0.6)) && set->count == 0 && set->buffer;
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
cmc_assert(hs_capacity(set) > (943722 / 0.6));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
hs_free(set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
hashset *set = hs_new(0, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, set);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(set == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
hashset *set = hs_new(UINT64_MAX, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, set);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(set == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
hs_insert(set, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, hs_count(set));
|
||||
|
||||
hs_clear(set);
|
||||
|
||||
cmc_assert_equals(size_t, 0, hs_count(set));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(hs_count(set) == 0);
|
||||
|
||||
hs_free(set);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/heap.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(heap_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
heap *h = h_new(1000000, MaxHeap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
bool passed = h->capacity == 1000000 && h->count == 0 && h->buffer;
|
||||
|
||||
cmc_assert_equals(size_t, 1000000, h->capacity);
|
||||
cmc_assert_equals(size_t, 0, h_count(h));
|
||||
cmc_assert_not_equals(ptr, NULL, h->buffer);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
h_free(h);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
heap *h = h_new(0, MaxHeap, cmp);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, h);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(h == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
heap *h = h_new(UINT64_MAX, MaxHeap, cmp);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, h);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(h == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
heap *h = h_new(100, MaxHeap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
h_insert(h, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, h_count(h));
|
||||
|
||||
h_clear(h);
|
||||
|
||||
cmc_assert_equals(size_t, 0, h_count(h));
|
||||
cmc_assert_equals(size_t, 100, h_capacity(h));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(h_count(h) == 0 && h_capacity(h) == 100);
|
||||
|
||||
h_free(h);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
heap *h = h_new(1, MaxHeap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
h_insert(h, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, h_count(h));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(h_count(h) == 50);
|
||||
|
||||
h_free(h);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/linkedlist.c"
|
||||
|
||||
CMC_CREATE_UNIT(linkedlist_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
linkedlist *ll = ll_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll);
|
||||
|
||||
bool passed = ll->count == 0 && ll->head == NULL && ll->tail == NULL;
|
||||
|
||||
cmc_assert_equals(size_t, 0, ll_count(ll));
|
||||
cmc_assert_equals(ptr, NULL, ll->head);
|
||||
cmc_assert_equals(ptr, NULL, ll->tail);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
ll_free(ll);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
linkedlist *ll = ll_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
ll_push_back(ll, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, ll_count(ll));
|
||||
|
||||
ll_clear(ll);
|
||||
|
||||
cmc_assert_equals(size_t, 0, ll_count(ll));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(ll_count(ll) == 0);
|
||||
|
||||
ll_free(ll);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[edge_case:count = 0], {
|
||||
linkedlist *ll = ll_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll);
|
||||
|
||||
ll_clear(ll);
|
||||
|
||||
cmc_assert_equals(size_t, 0, ll_count(ll));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(ll_count(ll) == 0);
|
||||
|
||||
ll_free(ll);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[count], {
|
||||
linkedlist *ll = ll_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll);
|
||||
|
||||
ll_push_front(ll, 1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll->head);
|
||||
cmc_assert_not_equals(ptr, NULL, ll->tail);
|
||||
cmc_assert_equals(size_t, 1, ll_count(ll));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(ll->head && ll->tail && ll_count(ll) == 1);
|
||||
|
||||
ll_free(ll);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[item_preservation], {
|
||||
linkedlist *ll = ll_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll);
|
||||
|
||||
for (size_t i = 0; i < 200; i++)
|
||||
ll_push_front(ll, i);
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < ll_count(ll); i++)
|
||||
{
|
||||
passed = passed && ll_get(ll, i) == (ll_count(ll) - i - 1);
|
||||
|
||||
cmc_assert_equals(size_t, ll_get(ll, i), ll_count(ll) - i - 1);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed && ll_count(ll) == 200);
|
||||
|
||||
ll_free(ll);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,420 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/list.c"
|
||||
|
||||
CMC_CREATE_UNIT(list_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
list *l = l_new(1000000);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
bool passed = l->capacity == 1000000 && l->count == 0 && l->buffer;
|
||||
|
||||
cmc_assert_equals(size_t, 1000000, l->capacity);
|
||||
cmc_assert_equals(size_t, 0, l_count(l));
|
||||
cmc_assert_not_equals(ptr, NULL, l->buffer);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
list *l = l_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, l);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
list *l = l_new(UINT64_MAX);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, l);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new_from[count item_preservation], {
|
||||
size_t v[5];
|
||||
|
||||
for (size_t i = 0; i < 5; i++)
|
||||
{
|
||||
v[i] = i;
|
||||
}
|
||||
|
||||
list *l = l_new_from(v, 5);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < 5; i++)
|
||||
{
|
||||
cmc_assert_equals(size_t, i, l_get(l, i));
|
||||
|
||||
passed = passed && l_get(l, i) == i;
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed && l_count(l) == 5);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new_from[edge_case:size = 1], {
|
||||
size_t a = 10;
|
||||
|
||||
size_t *values = &a;
|
||||
|
||||
list *l = l_new_from(values, 1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 1);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
l_push_back(l, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, l_count(l));
|
||||
|
||||
l_clear(l);
|
||||
|
||||
cmc_assert_equals(size_t, 0, l_count(l));
|
||||
cmc_assert_equals(size_t, 100, l_capacity(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0 && l_capacity(l) == 100);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
list *l = l_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
l_push_back(l, i);
|
||||
|
||||
cmc_assert_equals(size_t, 100, l_count(l));
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
{
|
||||
passed = passed && l_get(l, i) == i;
|
||||
cmc_assert_equals(size_t, i, l_get(l, i));
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[count], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_front(l, i));
|
||||
|
||||
cmc_assert_equals(size_t, 250, l_count(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 250);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[capacity], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_front(l, i));
|
||||
|
||||
cmc_assert_lesser_equals(size_t, l_capacity(l), l_count(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) <= l_capacity(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[item_preservation], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_front(l, i));
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
{
|
||||
passed = passed && l_get(l, i) == (l_count(l) - i - 1);
|
||||
|
||||
cmc_assert_equals(size_t, l_get(l, i), l_count(l) - i - 1);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[count], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
cmc_assert(l_push_back(l, 0));
|
||||
cmc_assert(l_push_back(l, 249));
|
||||
|
||||
for (size_t i = 1; i < 249; i++)
|
||||
cmc_assert(l_push(l, i, l_count(l) - 1));
|
||||
|
||||
cmc_assert_equals(size_t, 250, l_count(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 250);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[capacity], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
cmc_assert(l_push_back(l, 0));
|
||||
cmc_assert(l_push_back(l, 249));
|
||||
|
||||
for (size_t i = 1; i < 249; i++)
|
||||
cmc_assert(l_push(l, i, l_count(l) - 1));
|
||||
|
||||
cmc_assert_lesser_equals(size_t, l_capacity(l), l_count(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) <= l_capacity(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[item_preservation], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
cmc_assert(l_push_back(l, 0));
|
||||
cmc_assert(l_push_back(l, 249));
|
||||
|
||||
for (size_t i = 1; i < 249; i++)
|
||||
cmc_assert(l_push(l, i, l_count(l) - 1));
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
{
|
||||
passed = passed && l_get(l, i) == i;
|
||||
|
||||
cmc_assert_equals(size_t, l_get(l, i), i);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_back[count], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_back(l, i));
|
||||
|
||||
cmc_assert_equals(size_t, 250, l_count(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 250);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_back[capacity], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_back(l, i));
|
||||
|
||||
cmc_assert_lesser_equals(size_t, l_capacity(l), l_count(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) <= l_capacity(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_back[item_preservation], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_back(l, i));
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
{
|
||||
passed = passed && l_get(l, i) == i;
|
||||
|
||||
cmc_assert_equals(size_t, l_get(l, i), i);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[count], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
l_push_back(l, i);
|
||||
|
||||
cmc_assert(l_pop_front(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 250 - 1);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[item_preservation], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
l_push_back(l, i);
|
||||
|
||||
bool passed = l_pop_front(l);
|
||||
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
{
|
||||
passed = passed && l_get(l, i) == i + 1;
|
||||
|
||||
cmc_assert_equals(size_t, l_get(l, i), i + 1);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[edge_case:count = 0], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(!l_pop_front(l));
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[edge_case:count = 1], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 10));
|
||||
cmc_assert(l_pop_front(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[buffer_clear], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 1));
|
||||
cmc_assert(l_push_front(l, 2));
|
||||
|
||||
bool passed = l_pop_front(l) && l->buffer[1] == 0;
|
||||
|
||||
cmc_assert_equals(size_t, 0, l->buffer[1]);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed && l_count(l) == 1);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[edge_case:count = 0], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(!l_pop(l, 1));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(!l_pop(l, 1));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[edge_case:count = 1], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 1));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_pop(l, 0));
|
||||
|
||||
cmc_assert_equals(size_t, 0, l->buffer[0]);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[buffer_clear], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 1));
|
||||
cmc_assert(l_push_back(l, 2));
|
||||
cmc_assert(l_push_back(l, 3));
|
||||
cmc_assert(l_pop(l, 1));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(0 == l->buffer[2]);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_back[edge_case:count = 0], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(!l_pop_back(l));
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_back[edge_case:count = 1], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 10));
|
||||
cmc_assert(l_pop_back(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
})
|
||||
@@ -0,0 +1,73 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/queue.c"
|
||||
|
||||
CMC_CREATE_UNIT(queue_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
queue *q = q_new(1000000);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
bool passed = q->capacity == 1000000 && q->count == 0 && q->buffer;
|
||||
|
||||
cmc_assert_equals(size_t, 1000000, q->capacity);
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
cmc_assert_not_equals(ptr, NULL, q->buffer);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
queue *q = q_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, q);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(q == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
queue *q = q_new(UINT64_MAX);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, q);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(q == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
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));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(q_count(q) == 0 && q_capacity(q) == 100);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
queue *q = q_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
q_enqueue(q, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, q_count(q));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(q_count(q) == 50);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,335 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/stack.c"
|
||||
|
||||
CMC_CREATE_UNIT(stack_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
stack *s = s_new(1000000);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
bool passed = s->capacity == 1000000 && s->count == 0 && s->buffer;
|
||||
|
||||
cmc_assert_equals(size_t, 1000000, s->capacity);
|
||||
cmc_assert_equals(size_t, 0, s_count(s));
|
||||
cmc_assert_not_equals(ptr, NULL, s->buffer);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
stack *s = s_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, s);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
stack *s = s_new(UINT64_MAX);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, s);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, s_count(s));
|
||||
|
||||
s_clear(s);
|
||||
|
||||
cmc_assert_equals(size_t, 0, s_count(s));
|
||||
cmc_assert_equals(size_t, 100, s_capacity(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_count(s) == 0 && s_capacity(s) == 100);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
stack *s = s_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, s_count(s));
|
||||
cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_count(s) == 50 && s_count(s) <= s_capacity(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[count], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert_equals(size_t, 250, s_count(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_count(s) == 250);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[capacity], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_count(s) <= s_capacity(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[item_preservation], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
{
|
||||
passed = s->buffer[i] == i;
|
||||
|
||||
cmc_assert_equals(size_t, i, s->buffer[i]);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[count], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert(s_pop(s));
|
||||
|
||||
cmc_assert_equals(size_t, 249, s_count(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_count(s) == 249);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[capacity], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert(s_pop(s));
|
||||
|
||||
cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_count(s) <= s_capacity(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[item_preservation], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert(s_pop(s));
|
||||
cmc_assert(s_pop(s));
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
{
|
||||
passed = s->buffer[i] == i;
|
||||
|
||||
cmc_assert_equals(size_t, i, s->buffer[i]);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_if, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
s_push_if(s, i, i % 2 == 0);
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
{
|
||||
passed = passed && s->buffer[i] % 2 == 0;
|
||||
|
||||
cmc_assert(s->buffer[i] % 2 == 0);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_if, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
{
|
||||
s_push(s, i);
|
||||
s_pop_if(s, s_top(s) % 2 == 0);
|
||||
}
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
{
|
||||
passed = passed && !(s->buffer[i] % 2 == 0);
|
||||
|
||||
cmc_assert(!(s->buffer[i] % 2 == 0));
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(top, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert(s_pop(s));
|
||||
cmc_assert(s_pop(s));
|
||||
|
||||
cmc_assert_equals(size_t, 247, s_top(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(247 == s_top(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(top[edge_case:count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert(s_push(s, 1));
|
||||
|
||||
cmc_assert(s_pop(s));
|
||||
|
||||
cmc_assert_equals(size_t, s_impl_default_value(), s_top(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_impl_default_value() == s_top(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(top[edge_case:count = 1], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert(s_push(s, 10));
|
||||
cmc_assert_equals(size_t, 1, s_count(s));
|
||||
cmc_assert_equals(size_t, 10, s_top(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(10 == s_top(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(empty, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert(s_empty(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_empty(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(empty[after_io], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert(s_push(s, 10));
|
||||
cmc_assert(s_pop(s));
|
||||
cmc_assert(s_empty(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_empty(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(full, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < s_capacity(s); i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert(s_full(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_full(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(full[edge_case:capacity = 1], {
|
||||
stack *s = s_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert(s_push(s, 10));
|
||||
|
||||
cmc_assert(s_full(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_full(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/treemap.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(treemap_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
treemap *map = tm_new(cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(map);
|
||||
|
||||
tm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count], {
|
||||
treemap *map = tm_new(cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
tm_insert(map, i, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, tm_count(map));
|
||||
|
||||
tm_clear(map);
|
||||
|
||||
cmc_assert_equals(size_t, 0, tm_count(map));
|
||||
cmc_assert_equals(ptr, NULL, map->root);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(tm_count(map) == 0);
|
||||
|
||||
tm_free(map);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/treeset.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(treeset_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
treeset *set = ts_new(cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(set);
|
||||
|
||||
ts_free(set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count], {
|
||||
treeset *set = ts_new(cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
ts_insert(set, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, ts_count(set));
|
||||
|
||||
ts_clear(set);
|
||||
|
||||
cmc_assert_equals(size_t, 0, ts_count(set));
|
||||
cmc_assert_equals(ptr, NULL, set->root);
|
||||
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(ts_count(set) == 0);
|
||||
|
||||
ts_free(set);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
/* Utility file to be included in the unit tests */
|
||||
#ifndef CMC_UNIT_TEST_UTL__
|
||||
#define CMC_UNIT_TEST_UTL__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int cmp(size_t a, size_t b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
size_t hash(size_t a)
|
||||
{
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
#endif /* CMC_UNIT_TEST_UTL__ */
|
||||
Reference in new issue
Block a user