You can't speak programming languages...
leoven / c-macro-collections Goto Github PK
View Code? Open in Web Editor NEWEasy to use, modular, header only, macro based, generic and type-safe Data Structures in C
License: MIT License
Easy to use, modular, header only, macro based, generic and type-safe Data Structures in C
License: MIT License
You can't speak programming languages...
struct cmc_collection {
enum cmc_collection_type type; // DEQUE, HASHMAP, LIST, STACK, etc
const char *key_type;
const char *val_type;
};
A cmc_collection
is the common interface to all data structures so that you can differentiate them when storing them on void pointers
Currently, bitset always uses a power of 2 size. If you want to only use 100 bits, all operations are based on 128 and might be incorrect. Operations on the last word must always be checked if all of its bits are being used.
Trying to use this library in a 32bit Cortex M0 microcontroller. Including macro_collections.h is overkill and gives compile error for stuff that I don't even need (multithreading, etc.)
I have produced a simple header file - for instance, macro_defs.h - where only the global macros are defined. Then it is just a matter of including the needed header files in your code, like:
#include "cmc_list.h"
#include "ext_cmc_list.h"
#include "utl_futils.h"
#include "macro_defs.h"
The existing macro_collections.h can include this file as the very last and we have the same functionality as before
Includes testing
cmc log functions from log.h, cmc_log_trace for example, are defined as:
#define cmc_log_trace(fmt, ...) cmc_log(CMC_LOG_TRACE, __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__)
##__VA_ARGS__
is supported by most compilers, but still non-standard, -pedantic
issues a warning about it.
C23 solves the problem by introducing the __VA_OPT__
preprocessor. So this is the C23 solution:
#define cmc_log_trace(fmt, ...) cmc_log(CMC_LOG_TRACE, __FILE__, __func__, __LINE__, fmt __VA_OPT__(,) __VA_ARGS__)
Full C23 support is yet to be available, so not a high priority.
Detect the version via __STDC_VERSION__
, and use the standard solution if C23 or later.
This library is constantly receiving new updates that are disruptive and I believe that by now all examples no longer compile. This will eventually be fixed but only when all collections have the functions in the scope defined by the TODO file and the unit tests are complete.
HashBidiMap iterators are still not implemented properly. Currently you can only iterate over the keys. Decide whether:
See which approach is most compatible with CMC_FOREACH
and have a similar look to the other iterators.
I'm working with sprites on a game. I'll create, destroy and loop the sprites over the frame a bunch of times, and sort them only at the end, before rendering. SortedList is not suited for this since it might sort the list automatically unnecessarily. I would much rather have a list.h and manually sort at the appropriate time.
have a sort function for list.h
self
or _list_
and the function nameCan I suggest we parse the deallocator to the "new" function and hold it in the container, thus avoiding having to parse it to every "pop", "remove" and "clear" function.
The library should:
Thanks for working on C-Macro-Collections!
you can easily make a new list with
#define V struct my_struct
#define PFX my_struct
#define SNAME my_struct_list
#include <cmc/ds/list.h>
since cmc/ds/list.h includes the #include "cmc/list/code.h"
, you can't just place the above snippet on a header, because it would define each function multiple times.
In order to share declarations, you need to do something like this
file.c
#define V struct my_struct
#define PFX my_struct
#define SNAME my_struct_list
#include <ds/cmc/list/code.h>
#include <ds/cor/undef.h>
file.h
#define V struct my_struct
#define PFX my_struct
#define SNAME my_struct_list
#include <ds/cmc/list/struct.h>
#include <ds/cmc/list/header.h>
#include <ds/cor/undef.h>
I think it would be much better if we could do this
file.c
#define V struct my_struct
#define PFX my_struct
#define SNAME my_struct_list
#include <ds/cmc/list/code.h>
// code includes undef.h
file.h
#define V struct my_struct
#define PFX my_struct
#define SNAME my_struct_list
#include <ds/cmc/list.h>
What do you think? It would be a breaking change, I can open a PR if you agree it's a good change.
Maybe this? I prefer the above
file.c
#define V struct my_struct
#define PFX my_struct
#define SNAME my_struct_list
#define SOURCE
#include <ds/cmc/list.h>
file.h
#define V struct my_struct
#define PFX my_struct
#define SNAME my_struct_list
#include <ds/cmc/list.h>
I think SNAME, the name of the collection, is a reasonable PFX. So maybe if PFX is not set, we could assume SNAME=PFX?
#ifndef PFX
#define PFX SNAME
#endif // PFX
With the release of 1.8, examples and benchmarks are once again outdated.
Line 299, I think it should be
memmove(list->buffer, list->buffer + 1, (list->count - 1) * sizeof(V));
Line 311, I think it should be
memmove(list->buffer + index, list->buffer + index + 1, (list->count - index - 1) * sizeof(V));
I also suggest calling PFX##_pop_at(list, 0) inside PFX##_pop_front.
Also, all of the pop functions should be calling deallocators
cmc_string is used by to_string
functions and it is currently not ideal. How to replace it?
char *
FILE *
Thanks for working on C-Macro-Collections!
I think it would be less typing if we moved everything out of cmc folder. We could then avoid adding a bunch of -I flags on our build systems. It's also pointless to have a src/ folder, since there's no include/ folder.
Remove the src folder, and remove the cmc/cmc/ folder, moving everything inside of it out one level.
Instead of
src/
cmc/
cor/
cmc/
list/
code.h
list.h
Do something like
cmc/
cor/
list/
code.h
list.h
We would then do something like -I.
and include like this
#include <cmc/list.h>
#include <cmc/list/code.h>
At this point of the project if feels like the ext collections are growing quite big and the idea of having half of the collections in one folder and the other half in another is quite unnecessary. So eventually merge all collections into the cmc folder and leave dev and sac.
Tests should be based on heap allocated of char *
and not size_t
to test against NULL
pointers and memory leaks.
Basic implementation and tests
Compiling on windows/mingw requires each symbol to be exported, with something like __declspec(dllexport)
, libraries usually have something like this, example from PHYSFS
#if defined(PHYSFS_DECL)
/* do nothing. */
#elif defined(PHYSFS_STATIC)
#define PHYSFS_DECL /**/
#elif defined(_WIN32) || defined(__OS2__)
#define PHYSFS_DECL __declspec(dllexport)
#elif defined(__SUNPRO_C)
#define PHYSFS_DECL __global
#elif ((__GNUC__ >= 3) && (!defined(__EMX__)) && (!defined(sun)))
#define PHYSFS_DECL __attribute__((visibility("default")))
#else
#define PHYSFS_DECL
#endif
or at least expose a LIB_DECL, which can be defined by the consumer
prefix every function declaration on header.h with CMC_DECL, and have something like the above example on core.h
I have a localization system, I compile a human-readable format into a binary one, and load each string into a hashmap depending on the selected language. Since I know each string key ahead of time, I could hash them offline, and increase performance when loading new strings.
A way to insert an already hashed Key into a hashmap/hashset
ftable->free
and free the elementCMC_EXT_INIT just adds two new functions, they should be there by default and save everyone the hassle. Unused functions can be easily stripped from release builds.
remove CMC_EXT_INIT, have _init
functions by default.
I always use CMC_EXT_INIT
. So I generate a collection like this
#define V struct timeline
#define PFX timeline_list
#define SNAME timeline_list
#define CMC_EXT_INIT
#include <lib/ds/list/code.h>
#include <lib/ds/list/ext/code.h>
#include <lib/ds/cor/undef.h>
which is very verbose, I also need a copy of this on the header in order to share declarations.
Ditch the ext/ folder, e.gĀ· merge everything inside list/ext/code.h into list/code.h, list/header.h etc... and activate the feature with a macro. Like this
#define V struct timeline
#define PFX timeline_list
#define SNAME timeline_list
#define CMC_EXT_INIT
#include <lib/ds/list/code.h>
#include <lib/ds/cor/undef.h>
What is worth being an extension or included by default is another discussion, but for this particular case of CMC_EXT_INIT #37
Currently, if you want to add an element then get it's reference, you need to first call _push_back
, then _get_ref(_count(list) - 1)
, _back
returns a copy, so we can't use that. This is quite verbose.
it would be useful if we had an _push_back_ref
, function, which is like _push_back
, but it returns the pointer instead of a bool.
Maybe a _back_ref
Not sure if expanding the API surface is worth it, but it might be worth considering.
Compiling without CMC_CALLBACKS support, generates the following warning with -pedantic
:
In file included from /cmc/list.h:84:
/cmc/list/struct.h:43:20: warning: extra ';' inside a struct [-Wextra-semi]
CMC_CALLBACKS_DECL;
Without CMC_CALLBACKS, CMC_CALLBACKS_DECL is expanded to nothing, so CMC_CALLBACKS_DECL;
indeed produces a stray semicolon,
Perhaps suppress the warning somehow with #pragmas, or something like this
struct {
...
#ifdef CMC_CALLBACKS
cmc_callback callbacks:
#endif
}
Thanks for working on CMC!
some functions do not modify the collection, like the _count
functions, these should have the collection parameter marked as const
functions like _count
, _get
(except for sorted lists), _index_of
, _contains
should have the collection marked as const
Not a breaking change as C auto casts to const
CMC_SAC
makes a collection to have a fixed buffer size, possibly avoiding allocations, but the _new()
function allocates the struct anyway. This can be good if the buffer size is huge and wouldn't fit on the stack.
malloc
, free
, etc. in the code whe CMC_SAC
is defined_new()
and _init()
Compiling the utl_futils.h header on a 32bit Cortex M0 ARM gives overflow warnings for hash math, since 64bit integer math is apparently not supported.
Steps to reproduce the behavior:
Somehow this 64bit math should not be included in this case.
[build] [1/2 50% :: 0.097] Building C object console/CMakeFiles/console.dir/console.c.obj
[build] /home/rafa/repos/own/pico/pico-lipophot4c/src/lib/C-Macro-Collections/include/c_macro_collections/utl_futils.h: In function 'cmc_str_hash_java':
[build] /home/rafa/repos/own/pico/pico-lipophot4c/src/lib/C-Macro-Collections/include/c_macro_collections/utl_futils.h:413:28: warning: conversion from 'long long unsigned int' to 'size_t' {aka 'unsigned int'} changes value from '1125899906842597' to '4294967269' [-Woverflow]
[build] 413 | size_t hash = UINT64_C(1125899906842597); // prime
[build] | ^~~~~~~~~~~~~~~~
[build] In file included from /home/rafa/repos/own/pico/pico-lipophot4c/src/console/console.c:16:
[build] /home/rafa/repos/own/pico/pico-lipophot4c/src/lib/C-Macro-Collections/include/c_macro_collections/utl_futils.h: In function 'cmc_str_hash_murmur3':
[build] /home/rafa/repos/own/pico/pico-lipophot4c/src/lib/C-Macro-Collections/include/c_macro_collections/utl_futils.h:428:13: warning: right shift count >= width of type [-Wshift-count-overflow]
[build] 428 | x ^= (x >> 33);
[build] | ^~
[build] /home/rafa/repos/own/pico/pico-lipophot4c/src/lib/C-Macro-Collections/include/c_macro_collections/utl_futils.h:430:13: warning: right shift count >= width of type [-Wshift-count-overflow]
[build] 430 | x ^= (x >> 33);
[build] | ^~
[build] /home/rafa/repos/own/pico/pico-lipophot4c/src/lib/C-Macro-Collections/include/c_macro_collections/utl_futils.h:432:13: warning: right shift count >= width of type [-Wshift-count-overflow]
[build] 432 | x ^= (x >> 33);
[build] | ^~
[build] /home/rafa/repos/own/pico/pico-lipophot4c/src/lib/C-Macro-Collections/include/c_macro_collections/utl_futils.h: In function 'cmc_str_hash_murmur3_variant':
[build] /home/rafa/repos/own/pico/pico-lipophot4c/src/lib/C-Macro-Collections/include/c_macro_collections/utl_futils.h:447:13: warning: right shift count >= width of type [-Wshift-count-overflow]
[build] 447 | x ^= (x >> 33);
[build] | ^~
[build] /home/rafa/repos/own/pico/pico-lipophot4c/src/console/console.c: In function 'console_init':
[build] /home/rafa/repos/own/pico/pico-lipophot4c/src/console/console.c:52:80: warning: initialization of '_Bool (*)(FILE *, int)' from incompatible pointer type '_Bool (*)(FILE *, int32_t)' {aka '_Bool (*)(FILE *, long int)'} [-Wincompatible-pointer-types]
[build] 52 | struct int_list *list = intl_new_custom(32, &(struct int_list_fval){.str = cmc_i32_str, NULL}, &custom_allocator, NULL);
...and that needs to change.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
š Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ššš
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ā¤ļø Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.