19 files changed
+866
-103
No files matched your search
@@ -1,5 +1,12 @@
|
|||||||
# RELEASE.MAJOR.MINOR
|
# RELEASE.MAJOR.MINOR
|
||||||
|
|
||||||
|
1.7.1
|
||||||
|
- Added new assert macro cmc_assert_sorted
|
||||||
|
- Fixed some include guards for hashtables
|
||||||
|
- Moved the cmc string format to each file
|
||||||
|
- Renamed some list functions (sequence input/output)
|
||||||
|
- Renamed list and linkedlist functions push and pop to push_at and pop_at
|
||||||
|
|
||||||
1.7.0
|
1.7.0
|
||||||
- Removed FMOD (function modifier)
|
- Removed FMOD (function modifier)
|
||||||
- Added CMC prefix to all macros defined within the library
|
- Added CMC prefix to all macros defined within the library
|
||||||
|
|||||||
@@ -1,11 +1,22 @@
|
|||||||
# C-Macro-Collections
|
# C Macro Collections
|
||||||
|
|
||||||
Header only, macro generated, generic and type-safe Collections in C.
|
<p align="center">
|
||||||
|
<img src="https://leoven.github.io/C-Macro-Collections/images/logo.png" alt="C Macro Collections Logo" width="300"/>
|
||||||
|
</p>
|
||||||
|
|
||||||

|
<p align="center">Header only, macro generated, generic and type-safe Collections in C.</p>
|
||||||

|
|
||||||
[](https://travis-ci.org/LeoVen/C-Macro-Collections)
|
<p align="center">
|
||||||
[](https://codecov.io/gh/LeoVen/C-Macro-Collections)
|
<a href="https://github.com/LeoVen/C-Macro-Collections"><img src="https://img.shields.io/badge/GitHub-C%20Macro%20Collections-lightgrey.svg?logo=github" alt="LinkToRepo"/></a>
|
||||||
|
<a href="https://leoven.github.io/C-Macro-Collections/"><img style="color: #ffffff;" src="https://img.shields.io/badge/Read%20the%20Docs-5A5A5A.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHN0eWxlPSIiPjxyZWN0IGlkPSJiYWNrZ3JvdW5kcmVjdCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgeD0iMCIgeT0iMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJub25lIi8%2BPHRpdGxlPmljbi9kb2MtdGV4dDwvdGl0bGU%2BPGcgY2xhc3M9ImN1cnJlbnRMYXllciIgc3R5bGU9IiI%2BPHRpdGxlPkxheWVyIDE8L3RpdGxlPjxwYXRoIGQ9Ik01IDFoNC4yNDRhMiAyIDAgMCAxIDEuNDM0LjYwNmwyLjc1NiAyLjgzNEEyIDIgMCAwIDEgMTQgNS44MzVWMTJhMyAzIDAgMCAxLTMgM0g1YTMgMyAwIDAgMS0zLTNWNGEzIDMgMCAwIDEgMy0zem0wIDJhMSAxIDAgMCAwLTEgMXY4YTEgMSAwIDAgMCAxIDFoNmExIDEgMCAwIDAgMS0xVjUuODM1TDkuMjQ0IDNINXptMS41IDdoM2EuNS41IDAgMSAxIDAgMWgtM2EuNS41IDAgMSAxIDAtMXptMC0yaDJhLjUuNSAwIDAgMSAwIDFoLTJhLjUuNSAwIDAgMSAwLTF6TTggMmwzIDEuOTk1TDEzIDdIOWExIDEgMCAwIDEtMS0xVjJ6IiBpZD0iYSIgY2xhc3M9IiIgZmlsbD0iI2ZmZmZmZiIgZmlsbC1vcGFjaXR5PSIxIi8%2BPC9nPjwvc3ZnPg%3D%3D" alt="LinkToDocs"/></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/LeoVen/C-Macro-Collections/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License"/></a>
|
||||||
|
<a href="#"><img src="https://img.shields.io/badge/Version-v1.7.1-orange.svg" alt="Version"/></a>
|
||||||
|
<a href="https://travis-ci.org/LeoVen/C-Macro-Collections"><img src="https://travis-ci.org/LeoVen/C-Macro-Collections.svg?branch=master" alt="travis-ci"/></a>
|
||||||
|
<a href="https://codecov.io/gh/LeoVen/C-Macro-Collections"><img src="https://codecov.io/gh/LeoVen/C-Macro-Collections/branch/master/graph/badge.svg" alt="codecov"/></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
@@ -13,8 +24,8 @@ Header only, macro generated, generic and type-safe Collections in C.
|
|||||||
* Available Collections
|
* Available Collections
|
||||||
* Overall To-Do
|
* Overall To-Do
|
||||||
* Design Decisions
|
* Design Decisions
|
||||||
* What to Use
|
* What to use
|
||||||
* How to Use
|
* How to use
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
@@ -31,28 +42,14 @@ Header only, macro generated, generic and type-safe Collections in C.
|
|||||||
|
|
||||||
## Available Collections
|
## Available Collections
|
||||||
|
|
||||||
* Main C Macro Collections Library
|
* Linear Collections
|
||||||
* Deque
|
* List, LinkedList, Deque, Stack, Queue
|
||||||
* HashMap
|
* Sets
|
||||||
* HashSet
|
* HashSet, TreeSet, MultiSet
|
||||||
* Heap
|
* Maps
|
||||||
* LinkedList
|
* HashMap, TreeMap, MultiMap
|
||||||
* List
|
* Heaps
|
||||||
* Queue
|
* Heap, IntervalHeap
|
||||||
* Stack
|
|
||||||
* TreeMap
|
|
||||||
* TreeSet
|
|
||||||
* Extra Collections Library
|
|
||||||
* IntervalHeap
|
|
||||||
* MultiMap
|
|
||||||
* MultiSet
|
|
||||||
* Statically Allocated Collections Library
|
|
||||||
* Queue
|
|
||||||
* Stack
|
|
||||||
* Development Collections Library
|
|
||||||
* Deque
|
|
||||||
|
|
||||||
Check out **Documentation.md** for more information about each collection. The documentation is still being written.
|
|
||||||
|
|
||||||
## Overall To-Do
|
## Overall To-Do
|
||||||
|
|
||||||
@@ -117,21 +114,21 @@ Every collection is separated by two parts:
|
|||||||
|
|
||||||
All collections have three main macros:
|
All collections have three main macros:
|
||||||
|
|
||||||
* `SNAME_GENERATE` - Generates `SNAME_GENERATE_HEADER` and `SNAME_GENERATE_SOURCE`.
|
* `CMC_GENERATE_SNAME` - Generates `CMC_GENERATE_SNAME_HEADER` and `CMC_GENERATE_SNAME_SOURCE`.
|
||||||
|
|
||||||
Or you can generate each part individually:
|
Or you can generate each part individually:
|
||||||
|
|
||||||
* `SNAME_GENERATE_HEADER` - Generates all struct definitions and function definitions.
|
* `CMC_GENERATE_SNAME_HEADER` - Generates all struct definitions and function definitions.
|
||||||
* `SNAME_GENERATE_SOURCE` - Generates all function implementations.
|
* `CMC_GENERATE_SNAME_SOURCE` - Generates all function implementations.
|
||||||
|
|
||||||
### For Each
|
### For Each
|
||||||
|
|
||||||
There are 2 for-each macros:
|
There are 2 for-each macros:
|
||||||
|
|
||||||
* `FOR_EACH` - Starts at the start of the collection towards the end.
|
* `CMC_FOR_EACH` - Starts at the start of the collection towards the end.
|
||||||
* `FOR_EACH_REV` - Starts at the end of the collection towards the start.
|
* `CMC_FOR_EACH_REV` - Starts at the end of the collection towards the start.
|
||||||
|
|
||||||
Check out the **Documentation.md** to know exactly what represents the *end* and the *start* of each collection.
|
Check out the documentation to know more.
|
||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ TODO
|
|||||||
[~] - Needs to be reviewed
|
[~] - Needs to be reviewed
|
||||||
|
|
||||||
[ ] Future possible Collections
|
[ ] Future possible Collections
|
||||||
[ ] Add TreeHashMap
|
|
||||||
[ ] Add SortedList
|
[ ] Add SortedList
|
||||||
[ ] Add BiDiMap
|
[ ] Add BiDiMap
|
||||||
[ ] Add Trie (or any variant)
|
[ ] Add Trie (or any variant)
|
||||||
|
|
||||||
[/] Documentation
|
[/] Documentation
|
||||||
|
[/] Tests
|
||||||
[X] Remove PUBLIC and PRIVATE
|
[X] Remove PUBLIC and PRIVATE
|
||||||
[X] Extra Collections
|
[X] Extra Collections
|
||||||
[X] Add MultiSet
|
[X] Add MultiSet
|
||||||
@@ -57,9 +57,14 @@ TODO
|
|||||||
[ ] Stack
|
[ ] Stack
|
||||||
[ ] TreeMap
|
[ ] TreeMap
|
||||||
[ ] TreeSet
|
[ ] TreeSet
|
||||||
[~] Utility
|
[X] Utility
|
||||||
[~] assert.h
|
[X] assert.h
|
||||||
[X] foreach.h
|
[X] foreach.h
|
||||||
[~] log.h
|
[X] log.h
|
||||||
[~] test.h
|
[X] test.h
|
||||||
[X] timer.h
|
[X] timer.h
|
||||||
|
|
||||||
|
[ ] Optimizations
|
||||||
|
[ ] Hashtable insertion can avoid a call to impl_get_entry to check if a key already exists
|
||||||
|
[ ] Use binary search to find optimum hashtable prime size inside impl_calculate_size
|
||||||
|
|
||||||
+5
-1
@@ -31,12 +31,16 @@
|
|||||||
#ifndef CMC_DEQUE_H
|
#ifndef CMC_DEQUE_H
|
||||||
#define CMC_DEQUE_H
|
#define CMC_DEQUE_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../utl/cmc_string.h"
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
|
/* to_string format */
|
||||||
|
static const char *cmc_string_fmt_deque = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
|
||||||
|
|
||||||
#define CMC_GENERATE_DEQUE(PFX, SNAME, V) \
|
#define CMC_GENERATE_DEQUE(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_DEQUE_HEADER(PFX, SNAME, V) \
|
CMC_GENERATE_DEQUE_HEADER(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_DEQUE_SOURCE(PFX, SNAME, V)
|
CMC_GENERATE_DEQUE_SOURCE(PFX, SNAME, V)
|
||||||
@@ -403,7 +407,7 @@
|
|||||||
size_t i, j, k; \
|
size_t i, j, k; \
|
||||||
for (i = _deque1_->front, j = _deque2_->front, k = 0; k < PFX##_count(_deque1_); k++) \
|
for (i = _deque1_->front, j = _deque2_->front, k = 0; k < PFX##_count(_deque1_); k++) \
|
||||||
{ \
|
{ \
|
||||||
if (comparator(_deque1_->buffer[i], _deque2_->buffer[j]) == 0) \
|
if (comparator(_deque1_->buffer[i], _deque2_->buffer[j]) != 0) \
|
||||||
return false; \
|
return false; \
|
||||||
\
|
\
|
||||||
i = (i + 1) % _deque1_->capacity; \
|
i = (i + 1) % _deque1_->capacity; \
|
||||||
|
|||||||
+14
-5
@@ -19,21 +19,30 @@
|
|||||||
#ifndef CMC_HASHMAP_H
|
#ifndef CMC_HASHMAP_H
|
||||||
#define CMC_HASHMAP_H
|
#define CMC_HASHMAP_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../utl/cmc_string.h"
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
#ifndef CMC_HASH_TABLE_SETUP
|
/* to_string format */
|
||||||
#define CMC_HASH_TABLE_SETUP
|
static const char *cmc_string_fmt_hashmap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
|
||||||
|
|
||||||
typedef enum cmc_entry_state_e
|
#ifndef CMC_IMPL_HASHTABLE_STATE
|
||||||
|
#define CMC_IMPL_HASHTABLE_STATE
|
||||||
|
|
||||||
|
enum cmc_entry_state_e
|
||||||
{
|
{
|
||||||
CMC_ES_DELETED = -1,
|
CMC_ES_DELETED = -1,
|
||||||
CMC_ES_EMPTY = 0,
|
CMC_ES_EMPTY = 0,
|
||||||
CMC_ES_FILLED = 1
|
CMC_ES_FILLED = 1
|
||||||
} cmc_entry_state;
|
};
|
||||||
|
|
||||||
|
#endif /* CMC_IMPL_HASHTABLE_STATE */
|
||||||
|
|
||||||
|
#ifndef CMC_IMPL_HASHTABLE_SETUP
|
||||||
|
#define CMC_IMPL_HASHTABLE_SETUP
|
||||||
|
|
||||||
static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||||
3067, 6143, 12289, 24571, 49157,
|
3067, 6143, 12289, 24571, 49157,
|
||||||
@@ -67,7 +76,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
|||||||
6917529027641081903,
|
6917529027641081903,
|
||||||
13835058055282163729llu};
|
13835058055282163729llu};
|
||||||
|
|
||||||
#endif /* CMC_HASH_TABLE_SETUP */
|
#endif /* CMC_IMPL_HASHTABLE_SETUP */
|
||||||
|
|
||||||
#define CMC_GENERATE_HASHMAP(PFX, SNAME, K, V) \
|
#define CMC_GENERATE_HASHMAP(PFX, SNAME, K, V) \
|
||||||
CMC_GENERATE_HASHMAP_HEADER(PFX, SNAME, K, V) \
|
CMC_GENERATE_HASHMAP_HEADER(PFX, SNAME, K, V) \
|
||||||
|
|||||||
+14
-5
@@ -18,21 +18,30 @@
|
|||||||
#ifndef CMC_HASHSET_H
|
#ifndef CMC_HASHSET_H
|
||||||
#define CMC_HASHSET_H
|
#define CMC_HASHSET_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../utl/cmc_string.h"
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
#ifndef CMC_HASH_TABLE_SETUP
|
/* to_string format */
|
||||||
#define CMC_HASH_TABLE_SETUP
|
static const char *cmc_string_fmt_hashset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
|
||||||
|
|
||||||
typedef enum cmc_entry_state_e
|
#ifndef CMC_IMPL_HASHTABLE_STATE
|
||||||
|
#define CMC_IMPL_HASHTABLE_STATE
|
||||||
|
|
||||||
|
enum cmc_entry_state_e
|
||||||
{
|
{
|
||||||
CMC_ES_DELETED = -1,
|
CMC_ES_DELETED = -1,
|
||||||
CMC_ES_EMPTY = 0,
|
CMC_ES_EMPTY = 0,
|
||||||
CMC_ES_FILLED = 1
|
CMC_ES_FILLED = 1
|
||||||
} cmc_entry_state;
|
};
|
||||||
|
|
||||||
|
#endif /* CMC_IMPL_HASHTABLE_STATE */
|
||||||
|
|
||||||
|
#ifndef CMC_IMPL_HASHTABLE_SETUP
|
||||||
|
#define CMC_IMPL_HASHTABLE_SETUP
|
||||||
|
|
||||||
static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||||
3067, 6143, 12289, 24571, 49157,
|
3067, 6143, 12289, 24571, 49157,
|
||||||
@@ -66,7 +75,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
|||||||
6917529027641081903,
|
6917529027641081903,
|
||||||
13835058055282163729llu};
|
13835058055282163729llu};
|
||||||
|
|
||||||
#endif /* CMC_HASH_TABLE_SETUP */
|
#endif /* CMC_IMPL_HASHTABLE_SETUP */
|
||||||
|
|
||||||
#define CMC_GENERATE_HASHSET(PFX, SNAME, V) \
|
#define CMC_GENERATE_HASHSET(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_HASHSET_HEADER(PFX, SNAME, V) \
|
CMC_GENERATE_HASHSET_HEADER(PFX, SNAME, V) \
|
||||||
|
|||||||
@@ -30,12 +30,16 @@
|
|||||||
#ifndef CMC_HEAP_H
|
#ifndef CMC_HEAP_H
|
||||||
#define CMC_HEAP_H
|
#define CMC_HEAP_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../utl/cmc_string.h"
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
|
/* to_string format */
|
||||||
|
static const char *cmc_string_fmt_heap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", type:%s, cmp:%p }";
|
||||||
|
|
||||||
typedef enum cmc_heap_order_e
|
typedef enum cmc_heap_order_e
|
||||||
{
|
{
|
||||||
cmc_max_heap = 1,
|
cmc_max_heap = 1,
|
||||||
|
|||||||
+10
-6
@@ -28,12 +28,16 @@
|
|||||||
#ifndef CMC_LINKEDLIST_H
|
#ifndef CMC_LINKEDLIST_H
|
||||||
#define CMC_LINKEDLIST_H
|
#define CMC_LINKEDLIST_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../utl/cmc_string.h"
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
|
/* to_string format */
|
||||||
|
static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", head:%p, tail:%p }";
|
||||||
|
|
||||||
#define CMC_GENERATE_LINKEDLIST(PFX, SNAME, V) \
|
#define CMC_GENERATE_LINKEDLIST(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_LINKEDLIST_HEADER(PFX, SNAME, V) \
|
CMC_GENERATE_LINKEDLIST_HEADER(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_LINKEDLIST_SOURCE(PFX, SNAME, V)
|
CMC_GENERATE_LINKEDLIST_SOURCE(PFX, SNAME, V)
|
||||||
@@ -108,10 +112,10 @@
|
|||||||
void PFX##_free(SNAME *_list_, void (*deallocator)(V)); \
|
void PFX##_free(SNAME *_list_, void (*deallocator)(V)); \
|
||||||
/* Collection Input and Output */ \
|
/* Collection Input and Output */ \
|
||||||
bool PFX##_push_front(SNAME *_list_, V element); \
|
bool PFX##_push_front(SNAME *_list_, V element); \
|
||||||
bool PFX##_push(SNAME *_list_, V element, size_t index); \
|
bool PFX##_push_at(SNAME *_list_, V element, size_t index); \
|
||||||
bool PFX##_push_back(SNAME *_list_, V element); \
|
bool PFX##_push_back(SNAME *_list_, V element); \
|
||||||
bool PFX##_pop_front(SNAME *_list_); \
|
bool PFX##_pop_front(SNAME *_list_); \
|
||||||
bool PFX##_pop(SNAME *_list_, size_t index); \
|
bool PFX##_pop_at(SNAME *_list_, size_t index); \
|
||||||
bool PFX##_pop_back(SNAME *_list_); \
|
bool PFX##_pop_back(SNAME *_list_); \
|
||||||
/* Conditional Input and Output */ \
|
/* Conditional Input and Output */ \
|
||||||
bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition); \
|
bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition); \
|
||||||
@@ -259,7 +263,7 @@
|
|||||||
return true; \
|
return true; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
bool PFX##_push(SNAME *_list_, V element, size_t index) \
|
bool PFX##_push_at(SNAME *_list_, V element, size_t index) \
|
||||||
{ \
|
{ \
|
||||||
if (index > _list_->count) \
|
if (index > _list_->count) \
|
||||||
return false; \
|
return false; \
|
||||||
@@ -334,7 +338,7 @@
|
|||||||
return true; \
|
return true; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
bool PFX##_pop(SNAME *_list_, size_t index) \
|
bool PFX##_pop_at(SNAME *_list_, size_t index) \
|
||||||
{ \
|
{ \
|
||||||
if (PFX##_empty(_list_)) \
|
if (PFX##_empty(_list_)) \
|
||||||
return false; \
|
return false; \
|
||||||
@@ -389,7 +393,7 @@
|
|||||||
bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition) \
|
bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition) \
|
||||||
{ \
|
{ \
|
||||||
if (condition) \
|
if (condition) \
|
||||||
return PFX##_push(_list_, element, index); \
|
return PFX##_push_at(_list_, element, index); \
|
||||||
\
|
\
|
||||||
return false; \
|
return false; \
|
||||||
} \
|
} \
|
||||||
@@ -397,7 +401,7 @@
|
|||||||
bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition) \
|
bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition) \
|
||||||
{ \
|
{ \
|
||||||
if (condition) \
|
if (condition) \
|
||||||
return PFX##_pop(_list_, index); \
|
return PFX##_pop_at(_list_, index); \
|
||||||
\
|
\
|
||||||
return false; \
|
return false; \
|
||||||
} \
|
} \
|
||||||
|
|||||||
+27
-20
@@ -43,12 +43,16 @@
|
|||||||
#ifndef CMC_LIST_H
|
#ifndef CMC_LIST_H
|
||||||
#define CMC_LIST_H
|
#define CMC_LIST_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../utl/cmc_string.h"
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
|
/* to_string format */
|
||||||
|
static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
|
||||||
|
|
||||||
#define CMC_GENERATE_LIST(PFX, SNAME, V) \
|
#define CMC_GENERATE_LIST(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_LIST_HEADER(PFX, SNAME, V) \
|
CMC_GENERATE_LIST_HEADER(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_LIST_SOURCE(PFX, SNAME, V)
|
CMC_GENERATE_LIST_SOURCE(PFX, SNAME, V)
|
||||||
@@ -107,20 +111,20 @@
|
|||||||
void PFX##_free(SNAME *_list_, void (*deallocator)(V)); \
|
void PFX##_free(SNAME *_list_, void (*deallocator)(V)); \
|
||||||
/* Collection Input and Output */ \
|
/* Collection Input and Output */ \
|
||||||
bool PFX##_push_front(SNAME *_list_, V element); \
|
bool PFX##_push_front(SNAME *_list_, V element); \
|
||||||
bool PFX##_push(SNAME *_list_, V element, size_t index); \
|
bool PFX##_push_at(SNAME *_list_, V element, size_t index); \
|
||||||
bool PFX##_push_back(SNAME *_list_, V element); \
|
bool PFX##_push_back(SNAME *_list_, V element); \
|
||||||
bool PFX##_pop_front(SNAME *_list_); \
|
bool PFX##_pop_front(SNAME *_list_); \
|
||||||
bool PFX##_pop(SNAME *_list_, size_t index); \
|
bool PFX##_pop_at(SNAME *_list_, size_t index); \
|
||||||
bool PFX##_pop_back(SNAME *_list_); \
|
bool PFX##_pop_back(SNAME *_list_); \
|
||||||
/* Conditional Input and Output */ \
|
/* Conditional Input and Output */ \
|
||||||
bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition); \
|
bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition); \
|
||||||
bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition); \
|
bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition); \
|
||||||
/* Collection Range Input and Output */ \
|
/* Collection Sequence Input and Output */ \
|
||||||
bool PFX##_prepend(SNAME *_list_, V *elements, size_t size); \
|
bool PFX##_seq_push_front(SNAME *_list_, V *elements, size_t size); \
|
||||||
bool PFX##_insert(SNAME *_list_, V *elements, size_t size, size_t index); \
|
bool PFX##_seq_push_at(SNAME *_list_, V *elements, size_t size, size_t index); \
|
||||||
bool PFX##_append(SNAME *_list_, V *elements, size_t size); \
|
bool PFX##_seq_push_back(SNAME *_list_, V *elements, size_t size); \
|
||||||
bool PFX##_remove(SNAME *_list_, size_t from, size_t to); \
|
bool PFX##_seq_pop_at(SNAME *_list_, size_t from, size_t to); \
|
||||||
SNAME *PFX##_extract(SNAME *_list_, size_t from, size_t to); \
|
SNAME *PFX##_seq_sublist(SNAME *_list_, size_t from, size_t to); \
|
||||||
/* Element Access */ \
|
/* Element Access */ \
|
||||||
V PFX##_front(SNAME *_list_); \
|
V PFX##_front(SNAME *_list_); \
|
||||||
V PFX##_get(SNAME *_list_, size_t index); \
|
V PFX##_get(SNAME *_list_, size_t index); \
|
||||||
@@ -270,7 +274,7 @@
|
|||||||
return true; \
|
return true; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
bool PFX##_push(SNAME *_list_, V element, size_t index) \
|
bool PFX##_push_at(SNAME *_list_, V element, size_t index) \
|
||||||
{ \
|
{ \
|
||||||
if (index > _list_->count) \
|
if (index > _list_->count) \
|
||||||
return false; \
|
return false; \
|
||||||
@@ -324,7 +328,7 @@
|
|||||||
return true; \
|
return true; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
bool PFX##_pop(SNAME *_list_, size_t index) \
|
bool PFX##_pop_at(SNAME *_list_, size_t index) \
|
||||||
{ \
|
{ \
|
||||||
if (PFX##_empty(_list_)) \
|
if (PFX##_empty(_list_)) \
|
||||||
return false; \
|
return false; \
|
||||||
@@ -361,7 +365,7 @@
|
|||||||
bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition) \
|
bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition) \
|
||||||
{ \
|
{ \
|
||||||
if (condition) \
|
if (condition) \
|
||||||
return PFX##_push(_list_, element, index); \
|
return PFX##_push_at(_list_, element, index); \
|
||||||
\
|
\
|
||||||
return false; \
|
return false; \
|
||||||
} \
|
} \
|
||||||
@@ -369,12 +373,12 @@
|
|||||||
bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition) \
|
bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition) \
|
||||||
{ \
|
{ \
|
||||||
if (condition) \
|
if (condition) \
|
||||||
return PFX##_pop(_list_, index); \
|
return PFX##_pop_at(_list_, index); \
|
||||||
\
|
\
|
||||||
return false; \
|
return false; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
bool PFX##_prepend(SNAME *_list_, V *elements, size_t size) \
|
bool PFX##_seq_push_front(SNAME *_list_, V *elements, size_t size) \
|
||||||
{ \
|
{ \
|
||||||
if (size == 0) \
|
if (size == 0) \
|
||||||
return false; \
|
return false; \
|
||||||
@@ -394,15 +398,15 @@
|
|||||||
return true; \
|
return true; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
bool PFX##_insert(SNAME *_list_, V *elements, size_t size, size_t index) \
|
bool PFX##_seq_push_at(SNAME *_list_, V *elements, size_t size, size_t index) \
|
||||||
{ \
|
{ \
|
||||||
if (size == 0 || index > _list_->count) \
|
if (size == 0 || index > _list_->count) \
|
||||||
return false; \
|
return false; \
|
||||||
\
|
\
|
||||||
if (index == 0) \
|
if (index == 0) \
|
||||||
return PFX##_prepend(_list_, elements, size); \
|
return PFX##_seq_push_front(_list_, elements, size); \
|
||||||
else if (index == _list_->count) \
|
else if (index == _list_->count) \
|
||||||
return PFX##_append(_list_, elements, size); \
|
return PFX##_seq_push_back(_list_, elements, size); \
|
||||||
else \
|
else \
|
||||||
{ \
|
{ \
|
||||||
if (!PFX##_fits(_list_, size)) \
|
if (!PFX##_fits(_list_, size)) \
|
||||||
@@ -421,7 +425,7 @@
|
|||||||
return true; \
|
return true; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
bool PFX##_append(SNAME *_list_, V *elements, size_t size) \
|
bool PFX##_seq_push_back(SNAME *_list_, V *elements, size_t size) \
|
||||||
{ \
|
{ \
|
||||||
if (size == 0) \
|
if (size == 0) \
|
||||||
return false; \
|
return false; \
|
||||||
@@ -439,7 +443,7 @@
|
|||||||
return true; \
|
return true; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
bool PFX##_remove(SNAME *_list_, size_t from, size_t to) \
|
bool PFX##_seq_pop_at(SNAME *_list_, size_t from, size_t to) \
|
||||||
{ \
|
{ \
|
||||||
if (from > to || to >= _list_->count) \
|
if (from > to || to >= _list_->count) \
|
||||||
return false; \
|
return false; \
|
||||||
@@ -455,23 +459,26 @@
|
|||||||
return true; \
|
return true; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
SNAME *PFX##_extract(SNAME *_list_, size_t from, size_t to) \
|
SNAME *PFX##_seq_sublist(SNAME *_list_, size_t from, size_t to) \
|
||||||
{ \
|
{ \
|
||||||
if (from > to || to >= _list_->count) \
|
if (from > to || to >= _list_->count) \
|
||||||
return false; \
|
return false; \
|
||||||
\
|
\
|
||||||
size_t length = to - from + 1; \
|
size_t length = to - from + 1; \
|
||||||
\
|
\
|
||||||
SNAME *result = PFX##_new_from(_list_->buffer + from, length); \
|
SNAME *result = PFX##_new(length); \
|
||||||
\
|
\
|
||||||
if (!result) \
|
if (!result) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
\
|
\
|
||||||
|
memcpy(result->buffer, _list_->buffer, _list_->count * sizeof(V)); \
|
||||||
|
\
|
||||||
memmove(_list_->buffer + from, _list_->buffer + to + 1, (_list_->count - to - 1) * sizeof(V)); \
|
memmove(_list_->buffer + from, _list_->buffer + to + 1, (_list_->count - to - 1) * sizeof(V)); \
|
||||||
\
|
\
|
||||||
memset(_list_->buffer + _list_->count - length, 0, length * sizeof(V)); \
|
memset(_list_->buffer + _list_->count - length, 0, length * sizeof(V)); \
|
||||||
\
|
\
|
||||||
_list_->count -= length; \
|
_list_->count -= length; \
|
||||||
|
result->count = length; \
|
||||||
\
|
\
|
||||||
return result; \
|
return result; \
|
||||||
} \
|
} \
|
||||||
|
|||||||
@@ -43,12 +43,16 @@
|
|||||||
#ifndef CMC_QUEUE_H
|
#ifndef CMC_QUEUE_H
|
||||||
#define CMC_QUEUE_H
|
#define CMC_QUEUE_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../utl/cmc_string.h"
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
|
/* to_string format */
|
||||||
|
static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
|
||||||
|
|
||||||
#define CMC_GENERATE_QUEUE(PFX, SNAME, V) \
|
#define CMC_GENERATE_QUEUE(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_QUEUE_HEADER(PFX, SNAME, V) \
|
CMC_GENERATE_QUEUE_HEADER(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V)
|
CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V)
|
||||||
|
|||||||
@@ -28,12 +28,16 @@
|
|||||||
#ifndef CMC_STACK_H
|
#ifndef CMC_STACK_H
|
||||||
#define CMC_STACK_H
|
#define CMC_STACK_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../utl/cmc_string.h"
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
|
/* to_string format */
|
||||||
|
static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
|
||||||
|
|
||||||
#define CMC_GENERATE_STACK(PFX, SNAME, V) \
|
#define CMC_GENERATE_STACK(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_STACK_HEADER(PFX, SNAME, V) \
|
CMC_GENERATE_STACK_HEADER(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V)
|
CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V)
|
||||||
|
|||||||
@@ -19,12 +19,16 @@
|
|||||||
#ifndef CMC_TREEMAP_H
|
#ifndef CMC_TREEMAP_H
|
||||||
#define CMC_TREEMAP_H
|
#define CMC_TREEMAP_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../utl/cmc_string.h"
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
|
/* to_string format */
|
||||||
|
static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
|
||||||
|
|
||||||
#define CMC_GENERATE_TREEMAP(PFX, SNAME, K, V) \
|
#define CMC_GENERATE_TREEMAP(PFX, SNAME, K, V) \
|
||||||
CMC_GENERATE_TREEMAP_HEADER(PFX, SNAME, K, V) \
|
CMC_GENERATE_TREEMAP_HEADER(PFX, SNAME, K, V) \
|
||||||
CMC_GENERATE_TREEMAP_SOURCE(PFX, SNAME, K, V)
|
CMC_GENERATE_TREEMAP_SOURCE(PFX, SNAME, K, V)
|
||||||
|
|||||||
@@ -19,12 +19,16 @@
|
|||||||
#ifndef CMC_TREESET_H
|
#ifndef CMC_TREESET_H
|
||||||
#define CMC_TREESET_H
|
#define CMC_TREESET_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../utl/cmc_string.h"
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
|
/* to_string format */
|
||||||
|
static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
|
||||||
|
|
||||||
#define CMC_GENERATE_TREESET(PFX, SNAME, V) \
|
#define CMC_GENERATE_TREESET(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_TREESET_HEADER(PFX, SNAME, V) \
|
CMC_GENERATE_TREESET_HEADER(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_TREESET_SOURCE(PFX, SNAME, V)
|
CMC_GENERATE_TREESET_SOURCE(PFX, SNAME, V)
|
||||||
|
|||||||
@@ -21,12 +21,16 @@
|
|||||||
#ifndef CMC_INTERVALHEAP_H
|
#ifndef CMC_INTERVALHEAP_H
|
||||||
#define CMC_INTERVALHEAP_H
|
#define CMC_INTERVALHEAP_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../utl/cmc_string.h"
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
|
/* to_string format */
|
||||||
|
static const char *cmc_string_fmt_intervalheap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", size:%" PRIuMAX ", count:%" PRIuMAX ", cmp:%p }";
|
||||||
|
|
||||||
#define CMC_GENERATE_INTERVALHEAP(PFX, SNAME, V) \
|
#define CMC_GENERATE_INTERVALHEAP(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_INTERVALHEAP_HEADER(PFX, SNAME, V) \
|
CMC_GENERATE_INTERVALHEAP_HEADER(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_INTERVALHEAP_SOURCE(PFX, SNAME, V)
|
CMC_GENERATE_INTERVALHEAP_SOURCE(PFX, SNAME, V)
|
||||||
|
|||||||
+7
-3
@@ -43,14 +43,18 @@
|
|||||||
#ifndef CMC_MULTIMAP_H
|
#ifndef CMC_MULTIMAP_H
|
||||||
#define CMC_MULTIMAP_H
|
#define CMC_MULTIMAP_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../utl/cmc_string.h"
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
#ifndef CMC_HASH_TABLE_SETUP
|
/* to_string format */
|
||||||
#define CMC_HASH_TABLE_SETUP
|
static const char *cmc_string_fmt_multimap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
|
||||||
|
|
||||||
|
#ifndef CMC_IMPL_HASHTABLE_SETUP
|
||||||
|
#define CMC_IMPL_HASHTABLE_SETUP
|
||||||
|
|
||||||
static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||||
3067, 6143, 12289, 24571, 49157,
|
3067, 6143, 12289, 24571, 49157,
|
||||||
@@ -84,7 +88,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
|||||||
6917529027641081903,
|
6917529027641081903,
|
||||||
13835058055282163729llu};
|
13835058055282163729llu};
|
||||||
|
|
||||||
#endif /* CMC_HASH_TABLE_SETUP */
|
#endif /* CMC_IMPL_HASHTABLE_SETUP */
|
||||||
|
|
||||||
#define CMC_GENERATE_MULTIMAP(PFX, SNAME, K, V) \
|
#define CMC_GENERATE_MULTIMAP(PFX, SNAME, K, V) \
|
||||||
CMC_GENERATE_MULTIMAP_HEADER(PFX, SNAME, K, V) \
|
CMC_GENERATE_MULTIMAP_HEADER(PFX, SNAME, K, V) \
|
||||||
|
|||||||
+14
-5
@@ -21,21 +21,30 @@
|
|||||||
#ifndef CMC_MULTISET_H
|
#ifndef CMC_MULTISET_H
|
||||||
#define CMC_MULTISET_H
|
#define CMC_MULTISET_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../utl/cmc_string.h"
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
#ifndef CMC_HASH_TABLE_SETUP
|
/* to_string format */
|
||||||
#define CMC_HASH_TABLE_SETUP
|
static const char *cmc_string_fmt_multiset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", cardinality:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
|
||||||
|
|
||||||
typedef enum cmc_entry_state_e
|
#ifndef CMC_IMPL_HASHTABLE_STATE
|
||||||
|
#define CMC_IMPL_HASHTABLE_STATE
|
||||||
|
|
||||||
|
enum cmc_entry_state_e
|
||||||
{
|
{
|
||||||
CMC_ES_DELETED = -1,
|
CMC_ES_DELETED = -1,
|
||||||
CMC_ES_EMPTY = 0,
|
CMC_ES_EMPTY = 0,
|
||||||
CMC_ES_FILLED = 1
|
CMC_ES_FILLED = 1
|
||||||
} cmc_entry_state;
|
};
|
||||||
|
|
||||||
|
#endif /* CMC_IMPL_HASHTABLE_STATE */
|
||||||
|
|
||||||
|
#ifndef CMC_IMPL_HASHTABLE_SETUP
|
||||||
|
#define CMC_IMPL_HASHTABLE_SETUP
|
||||||
|
|
||||||
static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||||
3067, 6143, 12289, 24571, 49157,
|
3067, 6143, 12289, 24571, 49157,
|
||||||
@@ -69,7 +78,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
|||||||
6917529027641081903,
|
6917529027641081903,
|
||||||
13835058055282163729llu};
|
13835058055282163729llu};
|
||||||
|
|
||||||
#endif /* CMC_HASH_TABLE_SETUP */
|
#endif /* CMC_IMPL_HASHTABLE_SETUP */
|
||||||
|
|
||||||
#define CMC_GENERATE_MULTISET(PFX, SNAME, V) \
|
#define CMC_GENERATE_MULTISET(PFX, SNAME, V) \
|
||||||
CMC_GENERATE_MULTISET_HEADER(PFX, SNAME, V) \
|
CMC_GENERATE_MULTISET_HEADER(PFX, SNAME, V) \
|
||||||
|
|||||||
@@ -0,0 +1,657 @@
|
|||||||
|
/**
|
||||||
|
* list.h
|
||||||
|
*
|
||||||
|
* Creation Date: 17/09/2019
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* THIS IS ONLY A PREVIEW
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CMC_SORTEDLIST_H
|
||||||
|
#define CMC_SORTEDLIST_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "../utl/cmc_string.h"
|
||||||
|
|
||||||
|
/* to_string format */
|
||||||
|
static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", is_sorted:%s, cmp:%p }";
|
||||||
|
|
||||||
|
#define CMC_GENERATE_SORTEDLIST(PFX, SNAME, V) \
|
||||||
|
CMC_GENERATE_SORTEDLIST_HEADER(PFX, SNAME, V) \
|
||||||
|
CMC_GENERATE_SORTEDLIST_SOURCE(PFX, SNAME, V)
|
||||||
|
|
||||||
|
#define CMC_WRAPGEN_SORTEDLIST_HEADER(PFX, SNAME, K, V) \
|
||||||
|
CMC_GENERATE_SORTEDLIST_HEADER(PFX, SNAME, V)
|
||||||
|
|
||||||
|
#define CMC_WRAPGEN_SORTEDLIST_SOURCE(PFX, SNAME, K, V) \
|
||||||
|
CMC_GENERATE_SORTEDLIST_SOURCE(PFX, SNAME, V)
|
||||||
|
|
||||||
|
/* HEADER ********************************************************************/
|
||||||
|
#define CMC_GENERATE_SORTEDLIST_HEADER(PFX, SNAME, V) \
|
||||||
|
\
|
||||||
|
/* List Structure */ \
|
||||||
|
typedef struct SNAME##_s \
|
||||||
|
{ \
|
||||||
|
/* Dynamic array of elements */ \
|
||||||
|
V *buffer; \
|
||||||
|
\
|
||||||
|
/* Current array capacity */ \
|
||||||
|
size_t capacity; \
|
||||||
|
\
|
||||||
|
/* Current amount of elements */ \
|
||||||
|
size_t count; \
|
||||||
|
\
|
||||||
|
/* Flag if the list is sorted or not, used by lazy evaluation */ \
|
||||||
|
bool is_sorted; \
|
||||||
|
\
|
||||||
|
/* Element comparison function */ \
|
||||||
|
int (*cmp)(V, V); \
|
||||||
|
\
|
||||||
|
/* Function that returns an iterator to the start of the list */ \
|
||||||
|
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||||
|
\
|
||||||
|
/* Function that returns an iterator to the end of the list */ \
|
||||||
|
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||||
|
\
|
||||||
|
} SNAME, *SNAME##_ptr; \
|
||||||
|
\
|
||||||
|
/* List Iterator */ \
|
||||||
|
typedef struct SNAME##_iter_s \
|
||||||
|
{ \
|
||||||
|
/* Target list */ \
|
||||||
|
struct SNAME##_s *target; \
|
||||||
|
\
|
||||||
|
/* Cursor's position (index) */ \
|
||||||
|
size_t cursor; \
|
||||||
|
\
|
||||||
|
/* If the iterator has reached the start of the iteration */ \
|
||||||
|
bool start; \
|
||||||
|
\
|
||||||
|
/* If the iterator has reached the end of the iteration */ \
|
||||||
|
bool end; \
|
||||||
|
\
|
||||||
|
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||||
|
\
|
||||||
|
/* Collection Functions */ \
|
||||||
|
/* Collection Allocation and Deallocation */ \
|
||||||
|
SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)); \
|
||||||
|
void PFX##_clear(SNAME *_list_, void (*deallocator)(V)); \
|
||||||
|
void PFX##_free(SNAME *_list_, void (*deallocator)(V)); \
|
||||||
|
/* Collection Input and Output */ \
|
||||||
|
bool PFX##_insert(SNAME *_list_, V element); \
|
||||||
|
bool PFX##_remove(SNAME *_list_, size_t index); \
|
||||||
|
/* Conditional Input and Output */ \
|
||||||
|
bool PFX##_insert_if(SNAME *_list_, V element, bool condition); \
|
||||||
|
bool PFX##_remove_if(SNAME *_list_, size_t index, bool condition); \
|
||||||
|
/* Element Access */ \
|
||||||
|
bool PFX##_max(SNAME *_list_, V *result); \
|
||||||
|
bool PFX##_min(SNAME *_list_, V *result); \
|
||||||
|
V PFX##_get(SNAME *_list_, size_t index); \
|
||||||
|
size_t PFX##_indexof(SNAME *_list_, V element, bool from_start); \
|
||||||
|
/* Collection State */ \
|
||||||
|
bool PFX##_contains(SNAME *_list_, V element); \
|
||||||
|
bool PFX##_empty(SNAME *_list_); \
|
||||||
|
bool PFX##_full(SNAME *_list_); \
|
||||||
|
size_t PFX##_count(SNAME *_list_); \
|
||||||
|
size_t PFX##_capacity(SNAME *_list_); \
|
||||||
|
/* Collection Utility */ \
|
||||||
|
void PFX##_sort(SNAME *_list_); \
|
||||||
|
SNAME *PFX##_copy_of(SNAME *_list_, V (*copy_func)(V)); \
|
||||||
|
bool PFX##_equals(SNAME *_list1_, SNAME *_list2_); \
|
||||||
|
cmc_string PFX##_to_string(SNAME *_list_); \
|
||||||
|
\
|
||||||
|
/* Iterator Functions */ \
|
||||||
|
/* Iterator Allocation and Deallocation */ \
|
||||||
|
SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||||
|
void PFX##_iter_free(SNAME##_iter *iter); \
|
||||||
|
/* Iterator Initialization */ \
|
||||||
|
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||||
|
/* Iterator State */ \
|
||||||
|
bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||||
|
bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||||
|
/* Iterator Movement */ \
|
||||||
|
void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||||
|
void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||||
|
bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||||
|
bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||||
|
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
|
||||||
|
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
|
||||||
|
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
|
||||||
|
/* Iterator Access */ \
|
||||||
|
V PFX##_iter_value(SNAME##_iter *iter); \
|
||||||
|
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 CMC_GENERATE_SORTEDLIST_SOURCE(PFX, SNAME, V) \
|
||||||
|
\
|
||||||
|
/* Implementation Detail Functions */ \
|
||||||
|
static bool PFX##_impl_grow(SNAME *_list_, size_t required); \
|
||||||
|
static size_t PFX##_impl_binary_search_first(SNAME *_list_, V value); \
|
||||||
|
static size_t PFX##_impl_binary_search_last(SNAME *_list_, V value); \
|
||||||
|
void PFX##_impl_sort_quicksort(V *array, int (*cmp)(V, V), size_t low, size_t high); \
|
||||||
|
void PFX##_impl_sort_insertion(V *array, int (*cmp)(V, V), size_t low, size_t high); \
|
||||||
|
static SNAME##_iter PFX##_impl_it_start(SNAME *_list_); \
|
||||||
|
static SNAME##_iter PFX##_impl_it_end(SNAME *_list_); \
|
||||||
|
\
|
||||||
|
SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)) \
|
||||||
|
{ \
|
||||||
|
if (capacity < 1) \
|
||||||
|
return NULL; \
|
||||||
|
\
|
||||||
|
SNAME *_list_ = malloc(sizeof(SNAME)); \
|
||||||
|
\
|
||||||
|
if (!_list_) \
|
||||||
|
return NULL; \
|
||||||
|
\
|
||||||
|
_list_->buffer = malloc(capacity * sizeof(V)); \
|
||||||
|
\
|
||||||
|
if (!_list_->buffer) \
|
||||||
|
{ \
|
||||||
|
free(_list_); \
|
||||||
|
return NULL; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
memset(_list_->buffer, 0, capacity * sizeof(V)); \
|
||||||
|
\
|
||||||
|
_list_->capacity = capacity; \
|
||||||
|
_list_->count = 0; \
|
||||||
|
_list_->cmp = compare; \
|
||||||
|
_list_->is_sorted = false; \
|
||||||
|
\
|
||||||
|
_list_->it_start = PFX##_impl_it_start; \
|
||||||
|
_list_->it_end = PFX##_impl_it_end; \
|
||||||
|
\
|
||||||
|
return _list_; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void PFX##_clear(SNAME *_list_, void (*deallocator)(V)) \
|
||||||
|
{ \
|
||||||
|
if (deallocator) \
|
||||||
|
{ \
|
||||||
|
for (size_t i = 0; i < _list_->count; i++) \
|
||||||
|
deallocator(_list_->buffer[i]); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
memset(_list_->buffer, 0, sizeof(V) * _list_->capacity); \
|
||||||
|
\
|
||||||
|
_list_->count = 0; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void PFX##_free(SNAME *_list_, void (*deallocator)(V)) \
|
||||||
|
{ \
|
||||||
|
if (deallocator) \
|
||||||
|
{ \
|
||||||
|
for (size_t i = 0; i < _list_->count; i++) \
|
||||||
|
deallocator(_list_->buffer[i]); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
free(_list_->buffer); \
|
||||||
|
free(_list_); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool PFX##_insert(SNAME *_list_, V element) \
|
||||||
|
{ \
|
||||||
|
if (PFX##_full(_list_)) \
|
||||||
|
{ \
|
||||||
|
if (!PFX##_impl_grow(_list_, _list_->count + 1)) \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
_list_->buffer[_list_->count++] = element; \
|
||||||
|
\
|
||||||
|
_list_->is_sorted = false; \
|
||||||
|
\
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool PFX##_remove(SNAME *_list_, size_t index) \
|
||||||
|
{ \
|
||||||
|
if (index >= PFX##_count(_list_)) \
|
||||||
|
return false; \
|
||||||
|
\
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool PFX##_min(SNAME *_list_, V *result) \
|
||||||
|
{ \
|
||||||
|
if (PFX##_empty(_list_)) \
|
||||||
|
return false; \
|
||||||
|
\
|
||||||
|
PFX##_sort(_list_); \
|
||||||
|
\
|
||||||
|
*result = _list_->buffer[0]; \
|
||||||
|
\
|
||||||
|
return true; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool PFX##_max(SNAME *_list_, V *result) \
|
||||||
|
{ \
|
||||||
|
if (PFX##_empty(_list_)) \
|
||||||
|
return false; \
|
||||||
|
\
|
||||||
|
PFX##_sort(_list_); \
|
||||||
|
\
|
||||||
|
*result = _list_->buffer[_list_->count - 1]; \
|
||||||
|
\
|
||||||
|
return true; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
V PFX##_get(SNAME *_list_, size_t index) \
|
||||||
|
{ \
|
||||||
|
if (index >= _list_->count || PFX##_empty(_list_)) \
|
||||||
|
return PFX##_impl_default_value(); \
|
||||||
|
\
|
||||||
|
return _list_->buffer[index]; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
size_t PFX##_indexof(SNAME *_list_, V element, bool from_start) \
|
||||||
|
{ \
|
||||||
|
if (PFX##_empty(_list_)) \
|
||||||
|
return _list_->count; \
|
||||||
|
\
|
||||||
|
PFX##_sort(_list_); \
|
||||||
|
\
|
||||||
|
/* TODO Do a binary search */ \
|
||||||
|
\
|
||||||
|
/* Not found */ \
|
||||||
|
return _list_->count; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool PFX##_contains(SNAME *_list_, V element) \
|
||||||
|
{ \
|
||||||
|
if (PFX##_empty(_list_)) \
|
||||||
|
return false; \
|
||||||
|
\
|
||||||
|
PFX##_sort(_list_); \
|
||||||
|
\
|
||||||
|
/* TODO Do a binary search */ \
|
||||||
|
\
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool PFX##_empty(SNAME *_list_) \
|
||||||
|
{ \
|
||||||
|
return _list_->count == 0; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool PFX##_full(SNAME *_list_) \
|
||||||
|
{ \
|
||||||
|
return _list_->count >= _list_->capacity; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
size_t PFX##_count(SNAME *_list_) \
|
||||||
|
{ \
|
||||||
|
return _list_->count; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
size_t PFX##_capacity(SNAME *_list_) \
|
||||||
|
{ \
|
||||||
|
return _list_->capacity; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void PFX##_sort(SNAME *_list_) \
|
||||||
|
{ \
|
||||||
|
if (!_list_->is_sorted && _list_->count > 1) \
|
||||||
|
{ \
|
||||||
|
PFX##_impl_sort_quicksort(_list_->buffer, _list_->cmp, 0, _list_->count - 1); \
|
||||||
|
\
|
||||||
|
_list_->is_sorted = true; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
SNAME *PFX##_copy_of(SNAME *_list_, V (*copy_func)(V)) \
|
||||||
|
{ \
|
||||||
|
SNAME *result = PFX##_new(_list_->capacity, _list_->cmp); \
|
||||||
|
\
|
||||||
|
if (!result) \
|
||||||
|
return NULL; \
|
||||||
|
\
|
||||||
|
if (copy_func) \
|
||||||
|
{ \
|
||||||
|
for (size_t i = 0; i < _list_->count; i++) \
|
||||||
|
result->buffer[i] = copy_func(_list_->buffer[i]); \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
memcpy(result->buffer, _list_->buffer, sizeof(V) * _list_->count); \
|
||||||
|
\
|
||||||
|
result->count = _list_->count; \
|
||||||
|
\
|
||||||
|
return result; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool PFX##_equals(SNAME *_list1_, SNAME *_list2_) \
|
||||||
|
{ \
|
||||||
|
if (PFX##_count(_list1_) != PFX##_count(_list2_)) \
|
||||||
|
return false; \
|
||||||
|
\
|
||||||
|
for (size_t i = 0; i < PFX##_count(_list1_); i++) \
|
||||||
|
{ \
|
||||||
|
if (_list1_->cmp(_list1_->buffer[i], _list2_->buffer[i]) != 0) \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
cmc_string PFX##_to_string(SNAME *_list_) \
|
||||||
|
{ \
|
||||||
|
cmc_string str; \
|
||||||
|
SNAME *l_ = _list_; \
|
||||||
|
const char *name = #SNAME; \
|
||||||
|
\
|
||||||
|
snprintf(str.s, cmc_string_len, cmc_string_fmt_sortedlist, \
|
||||||
|
name, l_, l_->buffer, l_->capacity, l_->count, \
|
||||||
|
l_->is_sorted ? "true" : "false", l_->cmp); \
|
||||||
|
\
|
||||||
|
return str; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||||
|
{ \
|
||||||
|
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||||
|
\
|
||||||
|
if (!iter) \
|
||||||
|
return NULL; \
|
||||||
|
\
|
||||||
|
PFX##_iter_init(iter, target); \
|
||||||
|
\
|
||||||
|
return iter; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void PFX##_iter_free(SNAME##_iter *iter) \
|
||||||
|
{ \
|
||||||
|
free(iter); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||||
|
{ \
|
||||||
|
PFX##_sort(target); \
|
||||||
|
\
|
||||||
|
iter->target = target; \
|
||||||
|
iter->cursor = 0; \
|
||||||
|
iter->start = true; \
|
||||||
|
iter->end = PFX##_empty(target); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||||
|
{ \
|
||||||
|
return PFX##_empty(iter->target) || iter->start; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||||
|
{ \
|
||||||
|
return PFX##_empty(iter->target) || iter->end; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||||
|
{ \
|
||||||
|
if (!PFX##_empty(iter->target)) \
|
||||||
|
{ \
|
||||||
|
iter->cursor = 0; \
|
||||||
|
iter->start = true; \
|
||||||
|
iter->end = PFX##_empty(iter->target); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||||
|
{ \
|
||||||
|
if (!PFX##_empty(iter->target)) \
|
||||||
|
{ \
|
||||||
|
iter->start = PFX##_empty(iter->target); \
|
||||||
|
iter->cursor = PFX##_empty(iter->target) ? 0 : iter->target->count - 1; \
|
||||||
|
iter->end = true; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||||
|
{ \
|
||||||
|
if (iter->end) \
|
||||||
|
return false; \
|
||||||
|
\
|
||||||
|
if (iter->cursor + 1 == PFX##_count(iter->target)) \
|
||||||
|
{ \
|
||||||
|
iter->end = true; \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
iter->start = PFX##_empty(iter->target); \
|
||||||
|
\
|
||||||
|
iter->cursor++; \
|
||||||
|
\
|
||||||
|
return true; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||||
|
{ \
|
||||||
|
if (iter->start) \
|
||||||
|
return false; \
|
||||||
|
\
|
||||||
|
if (iter->cursor == 0) \
|
||||||
|
{ \
|
||||||
|
iter->start = true; \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
iter->end = PFX##_empty(iter->target); \
|
||||||
|
\
|
||||||
|
iter->cursor--; \
|
||||||
|
\
|
||||||
|
return true; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Returns true only if the iterator moved */ \
|
||||||
|
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
|
||||||
|
{ \
|
||||||
|
if (iter->end) \
|
||||||
|
return false; \
|
||||||
|
\
|
||||||
|
if (iter->cursor + 1 == iter->target->count) \
|
||||||
|
{ \
|
||||||
|
iter->end = true; \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (steps == 0 || iter->cursor + steps >= PFX##_count(iter->target)) \
|
||||||
|
return false; \
|
||||||
|
\
|
||||||
|
iter->start = PFX##_empty(iter->target); \
|
||||||
|
\
|
||||||
|
iter->cursor += steps; \
|
||||||
|
\
|
||||||
|
return true; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Returns true only if the iterator moved */ \
|
||||||
|
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
|
||||||
|
{ \
|
||||||
|
if (iter->start) \
|
||||||
|
return false; \
|
||||||
|
\
|
||||||
|
if (iter->cursor == 0) \
|
||||||
|
{ \
|
||||||
|
iter->start = true; \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (steps == 0 || iter->cursor < steps) \
|
||||||
|
return false; \
|
||||||
|
\
|
||||||
|
iter->end = PFX##_empty(iter->target); \
|
||||||
|
\
|
||||||
|
iter->cursor -= steps; \
|
||||||
|
\
|
||||||
|
return true; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Returns true only if the iterator was able to be positioned at the given index */ \
|
||||||
|
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
|
||||||
|
{ \
|
||||||
|
if (index >= PFX##_count(iter->target)) \
|
||||||
|
return false; \
|
||||||
|
\
|
||||||
|
if (iter->cursor > index) \
|
||||||
|
return PFX##_iter_rewind(iter, iter->cursor - index); \
|
||||||
|
else if (iter->cursor < index) \
|
||||||
|
return PFX##_iter_advance(iter, index - iter->cursor); \
|
||||||
|
\
|
||||||
|
return true; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
V PFX##_iter_value(SNAME##_iter *iter) \
|
||||||
|
{ \
|
||||||
|
if (PFX##_empty(iter->target)) \
|
||||||
|
return PFX##_impl_default_value(); \
|
||||||
|
\
|
||||||
|
return iter->target->buffer[iter->cursor]; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||||
|
{ \
|
||||||
|
return iter->cursor; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static bool PFX##_impl_grow(SNAME *_list_, size_t required) \
|
||||||
|
{ \
|
||||||
|
size_t new_capacity = _list_->capacity * 2; \
|
||||||
|
\
|
||||||
|
if (new_capacity < required) \
|
||||||
|
new_capacity = required; \
|
||||||
|
\
|
||||||
|
V *new_buffer = realloc(_list_->buffer, sizeof(V) * new_capacity); \
|
||||||
|
\
|
||||||
|
if (!new_buffer) \
|
||||||
|
return false; \
|
||||||
|
\
|
||||||
|
_list_->buffer = new_buffer; \
|
||||||
|
_list_->capacity = new_capacity; \
|
||||||
|
\
|
||||||
|
return true; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static size_t PFX##_impl_binary_search_first(SNAME *_list_, V value) \
|
||||||
|
{ \
|
||||||
|
/* TODO */ \
|
||||||
|
\
|
||||||
|
/* Not found */ \
|
||||||
|
return _list_->count; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static size_t PFX##_impl_binary_search_last(SNAME *_list_, V value) \
|
||||||
|
{ \
|
||||||
|
/* TODO */ \
|
||||||
|
\
|
||||||
|
/* Not found */ \
|
||||||
|
return _list_->count; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Characteristics of this quicksort implementation: */ \
|
||||||
|
/* - Hybrid: uses insertion sort for small arrays */ \
|
||||||
|
/* - Partition: Lomuto's Method (can be optimized and use Hoare's Method) */ \
|
||||||
|
/* - Tail recursion: minimize recursion depth */ \
|
||||||
|
void PFX##_impl_sort_quicksort(V *array, int (*cmp)(V, V), size_t low, size_t high) \
|
||||||
|
{ \
|
||||||
|
while (low < high) \
|
||||||
|
{ \
|
||||||
|
/* Quicksort performs poorly for smaller arrays so let insertion */ \
|
||||||
|
/* sort do the job */ \
|
||||||
|
if (high - low < 10) \
|
||||||
|
{ \
|
||||||
|
PFX##_impl_sort_insertion(array, cmp, low, high); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
/* Partition */ \
|
||||||
|
V pivot = array[high]; \
|
||||||
|
\
|
||||||
|
size_t pindex = low; \
|
||||||
|
\
|
||||||
|
for (size_t i = low; i < high; i++) \
|
||||||
|
{ \
|
||||||
|
if (cmp(array[i], pivot) <= 0) \
|
||||||
|
{ \
|
||||||
|
V _tmp_ = array[i]; \
|
||||||
|
array[i] = array[pindex]; \
|
||||||
|
array[pindex] = _tmp_; \
|
||||||
|
\
|
||||||
|
pindex++; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
V _tmp_ = array[pindex]; \
|
||||||
|
array[pindex] = array[high]; \
|
||||||
|
array[high] = _tmp_; \
|
||||||
|
\
|
||||||
|
if (pindex - low < high - pindex) \
|
||||||
|
{ \
|
||||||
|
PFX##_impl_sort_quicksort(array, cmp, low, pindex - 1); \
|
||||||
|
\
|
||||||
|
low = pindex + 1; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
PFX##_impl_sort_quicksort(array, cmp, pindex + 1, high); \
|
||||||
|
\
|
||||||
|
high = pindex - 1; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void PFX##_impl_sort_insertion(V *array, int (*cmp)(V, V), size_t low, size_t high) \
|
||||||
|
{ \
|
||||||
|
for (size_t i = low + 1; i <= high; i++) \
|
||||||
|
{ \
|
||||||
|
V _tmp_ = array[i]; \
|
||||||
|
size_t j = i; \
|
||||||
|
\
|
||||||
|
while (j > low && cmp(array[j - 1], _tmp_) > 0) \
|
||||||
|
{ \
|
||||||
|
array[j] = array[j - 1]; \
|
||||||
|
j--; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
array[j] = _tmp_; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static SNAME##_iter PFX##_impl_it_start(SNAME *_list_) \
|
||||||
|
{ \
|
||||||
|
SNAME##_iter iter; \
|
||||||
|
\
|
||||||
|
PFX##_iter_init(&iter, _list_); \
|
||||||
|
PFX##_iter_to_start(&iter); \
|
||||||
|
\
|
||||||
|
return iter; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static SNAME##_iter PFX##_impl_it_end(SNAME *_list_) \
|
||||||
|
{ \
|
||||||
|
SNAME##_iter iter; \
|
||||||
|
\
|
||||||
|
PFX##_iter_init(&iter, _list_); \
|
||||||
|
PFX##_iter_to_end(&iter); \
|
||||||
|
\
|
||||||
|
return iter; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CMC_SORTEDLIST_H */
|
||||||
@@ -40,6 +40,9 @@
|
|||||||
* - ptr
|
* - ptr
|
||||||
* - bool (only for equals and not_equals)
|
* - bool (only for equals and not_equals)
|
||||||
*
|
*
|
||||||
|
* Specialized assertions:
|
||||||
|
*
|
||||||
|
* - cmc_assert_sorted
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CMC_ASSERT_H
|
#ifndef CMC_ASSERT_H
|
||||||
@@ -158,6 +161,46 @@ static bool cmc_assert_state = true;
|
|||||||
CMC_ASSERT_GLUE(dtype, not_in_range) \
|
CMC_ASSERT_GLUE(dtype, not_in_range) \
|
||||||
(lower_bound, upper_bound, actual)
|
(lower_bound, upper_bound, actual)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dtype : The type of the array
|
||||||
|
* array : Array to be checked if it is sorted
|
||||||
|
* comparator : A function that has two 'dtype' arguments and returns -1 if the
|
||||||
|
* first is less then the second, 0 if both are equal or 1 if the
|
||||||
|
* first is greater then the second.
|
||||||
|
* from : First index to compare (inclusive)
|
||||||
|
* to : Last index to compare (inclusive)
|
||||||
|
*
|
||||||
|
* This macro can be used for any data type.
|
||||||
|
*/
|
||||||
|
#define cmc_assert_sorted(dtype, array, comparator, from, to) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
const char *str = #array; \
|
||||||
|
dtype *arr__ = array; \
|
||||||
|
size_t from__ = from; \
|
||||||
|
size_t to__ = to; \
|
||||||
|
int (*cmp__)(dtype, dtype) = comparator; \
|
||||||
|
\
|
||||||
|
size_t iprev__ = from__; \
|
||||||
|
\
|
||||||
|
for (size_t i__ = from__ + 1; i__ <= to__; i__++) \
|
||||||
|
{ \
|
||||||
|
if (cmp__(arr__[iprev__], arr__[i__]) > 0) \
|
||||||
|
{ \
|
||||||
|
cmc_assert_state = false; \
|
||||||
|
\
|
||||||
|
fprintf(stderr, \
|
||||||
|
"Assertion Failed at %s:%s:%u for { %s }: Not sorted when comparing indexes %" PRIuMAX " and %" PRIuMAX "\n", \
|
||||||
|
__FILE__, __func__, __LINE__, str, iprev__, i__); \
|
||||||
|
\
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
iprev__ = i__; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define cmc_assert_equals_int8_t(expected, actual) \
|
#define cmc_assert_equals_int8_t(expected, actual) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
|
|||||||
+1
-17
@@ -13,8 +13,8 @@
|
|||||||
#ifndef CMC_STRING_H
|
#ifndef CMC_STRING_H
|
||||||
#define CMC_STRING_H
|
#define CMC_STRING_H
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
static const size_t cmc_string_len = 200;
|
static const size_t cmc_string_len = 200;
|
||||||
|
|
||||||
@@ -23,20 +23,4 @@ typedef struct cmc_string_s
|
|||||||
char s[200];
|
char s[200];
|
||||||
} cmc_string;
|
} cmc_string;
|
||||||
|
|
||||||
/* to_string formats */
|
|
||||||
static const char *cmc_string_fmt_deque = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
|
|
||||||
static const char *cmc_string_fmt_hashmap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
|
|
||||||
static const char *cmc_string_fmt_hashset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
|
|
||||||
static const char *cmc_string_fmt_heap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", type:%s, cmp:%p }";
|
|
||||||
static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", head:%p, tail:%p }";
|
|
||||||
static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
|
|
||||||
static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
|
|
||||||
static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
|
|
||||||
static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
|
|
||||||
static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
|
|
||||||
|
|
||||||
static const char *cmc_string_fmt_intervalheap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", size:%" PRIuMAX ", count:%" PRIuMAX ", cmp:%p }";
|
|
||||||
static const char *cmc_string_fmt_multimap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
|
|
||||||
static const char *cmc_string_fmt_multiset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", cardinality:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";;
|
|
||||||
|
|
||||||
#endif /* CMC_STRING_H */
|
#endif /* CMC_STRING_H */
|
||||||
Reference in new issue
Block a user