Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d75237ba66 | ||
|
|
9909877771 | ||
|
|
64ef1f3aba | ||
|
|
d670e1a6bb | ||
|
|
7082a4dc24 | ||
|
|
e6c9314c91 | ||
|
|
3dccd4484e | ||
|
|
170ed98701 | ||
|
|
54fa2c8635 | ||
|
|
bc83fe43e5 | ||
|
|
18710567f2 | ||
|
|
9a98ed5cb6 | ||
|
|
35a98fd3b5 | ||
|
|
cd74fdf234 | ||
|
|
6cccbfc73a | ||
|
|
e59308a9a3 | ||
|
|
85a3be4ae3 | ||
|
|
d873693fe7 | ||
|
|
2df967d5c2 | ||
|
|
20989a7ab5 | ||
|
|
8e114d6fe4 | ||
|
|
479ad2d4ba | ||
|
|
d05bb49f5d | ||
|
|
fc9755379d | ||
|
|
a85db0c383 | ||
|
|
d19ec5bf49 | ||
|
|
ba72e4ebbf | ||
|
|
5936e25ce4 | ||
|
|
d82dc196e0 | ||
|
|
c174b368e8 | ||
|
|
81e3515f40 | ||
|
|
bffec6206b | ||
|
|
d269c23948 | ||
|
|
f2b2335080 | ||
|
|
5dded0d9aa | ||
|
|
33142c3a0d | ||
|
|
06e256f77a | ||
|
|
3f13cca666 | ||
|
|
73117708e5 | ||
|
|
f88b53dce5 | ||
|
|
3e609bab04 | ||
|
|
a6bf530c5f | ||
|
|
5d003b7678 | ||
|
|
a5cbc3f34a | ||
|
|
52e92e1ebf | ||
|
|
5307b6c097 | ||
|
|
dd4f4761de | ||
|
|
96f3533e46 | ||
|
|
774e1720b7 | ||
|
|
83f8eadce9 | ||
|
|
f8e75761ef | ||
|
|
cbb881df86 | ||
|
|
103e5304e8 | ||
|
|
e152ff0377 | ||
|
|
65f39ab22e | ||
|
|
df51c6dc64 | ||
|
|
b7c86ee01e | ||
|
|
992bb6a73a | ||
|
|
557dd3e0d5 | ||
|
|
c8d5b5440f | ||
|
|
0900e72070 | ||
|
|
dcdc64f974 | ||
|
|
58898adbcd | ||
|
|
ff2050466b | ||
|
|
dd209c05b9 | ||
|
|
12a4806b85 | ||
|
|
82575962ed | ||
|
|
1db2813aa3 | ||
|
|
c71613dcfe | ||
|
|
762d8a8e74 | ||
|
|
b7966f6b61 | ||
|
|
b1443533e0 | ||
|
|
6f12ac1d19 | ||
|
|
0295eea145 | ||
|
|
171402f99f | ||
|
|
3d57d35536 | ||
|
|
bacf2b9eec | ||
|
|
fd885bdb19 | ||
|
|
a497c07b0b | ||
|
|
ffd5f23406 | ||
|
|
97e3cc35c2 | ||
|
|
44d8363292 | ||
|
|
e540a95ad0 | ||
|
|
db63b0d515 | ||
|
|
7637c2fb58 | ||
|
|
5b40b43435 | ||
|
|
6ec277ec99 | ||
|
|
1befa63c9b | ||
|
|
3d3e052f23 | ||
|
|
aea816dcaf | ||
|
|
d258fb3eff | ||
|
|
1463d83b9f | ||
|
|
10c947d9d4 | ||
|
|
2da51ea6e9 | ||
|
|
d930c0a4ad | ||
|
|
d0e7cc41bf | ||
|
|
8c610adee5 | ||
|
|
a1e791d1e9 | ||
|
|
264249fb8b | ||
|
|
e2b00d7c73 | ||
|
|
ff3964e2eb | ||
|
|
2ed95bfe16 | ||
|
|
958936319f | ||
|
|
39fca33958 | ||
|
|
eb4cbe863e | ||
|
|
d146ea6a63 | ||
|
|
f4b2ba8322 | ||
|
|
acb1aa8104 | ||
|
|
03f7a75e54 | ||
|
|
2dc71cc5fd | ||
|
|
4a92419bbe | ||
|
|
92699501f6 | ||
|
|
b49ed97be0 | ||
|
|
aec661edea | ||
|
|
675fa2cf85 | ||
|
|
b442d72ef7 | ||
|
|
2ff197c670 | ||
|
|
5c9a610823 | ||
|
|
8d871256ed | ||
|
|
3d59fb0d9a | ||
|
|
057d783158 | ||
|
|
ffb8a2a00a | ||
|
|
b32b93340c | ||
|
|
35a3f7c02a | ||
|
|
6de4c4092f | ||
|
|
c5de5e07d8 | ||
|
|
0176071011 | ||
|
|
3f2a641cdf | ||
|
|
20be2d8850 | ||
|
|
b37cd7dba7 | ||
|
|
e274a49ffd | ||
|
|
cba37abfae | ||
|
|
be198a7040 | ||
|
|
29d181c113 | ||
|
|
3d5914f389 | ||
|
|
c78c75d89a | ||
|
|
a4753be5ae | ||
|
|
3bda360196 | ||
|
|
2b4de98aee | ||
|
|
bbd887fd2c | ||
|
|
84a5add410 | ||
|
|
c999563ecd | ||
|
|
80c7cdbdd2 | ||
|
|
9c7b453732 | ||
|
|
45982c4b01 | ||
|
|
438704be37 | ||
|
|
1753ddc4d6 | ||
|
|
96178194b3 | ||
|
|
57fb2192be | ||
|
|
546a78be33 | ||
|
|
29acb67566 | ||
|
|
0afad9a825 | ||
|
|
c99b3de902 | ||
|
|
e8cf1d6b9a | ||
|
|
a9aa1e13ee | ||
|
|
f5857c8aab | ||
|
|
67856a98af | ||
|
|
c71de15cb0 | ||
|
|
73f15c1980 | ||
|
|
646df4f34e | ||
|
|
8489d0df97 | ||
|
|
86dfad860e | ||
|
|
c97a68029b | ||
|
|
08a4dfbe4c | ||
|
|
adcacf3cf9 | ||
|
|
7950b69136 | ||
|
|
5d75416948 | ||
|
|
2e96a00fde | ||
|
|
1f08bcf0f8 | ||
|
|
a3e2e75021 | ||
|
|
603bdd2941 | ||
|
|
6fb7a4f24b | ||
|
|
0c2d290835 | ||
|
|
210e05f7fc | ||
|
|
f4b443c33e | ||
|
|
52ffa09f73 | ||
|
|
52bb23bb6f | ||
|
|
2089af8fd3 | ||
|
|
778bc4072b | ||
|
|
2b2ebecae7 | ||
|
|
69cbd61915 | ||
|
|
4d41774345 | ||
|
|
ff6772aaa7 | ||
|
|
bbe9d43532 | ||
|
|
6549bea3e0 | ||
|
|
9d727589aa | ||
|
|
aede0547d3 | ||
|
|
55332d61fd | ||
|
|
83eeb5d6d0 | ||
|
|
5eaf796aab | ||
|
|
d46c40d3fa | ||
|
|
2461afa573 | ||
|
|
6acacf5efe | ||
|
|
075a74ea0c | ||
|
|
f9ddc43349 | ||
|
|
1c9a232a9d | ||
|
|
9c727a8d8c | ||
|
|
7c241c65de | ||
|
|
4f3823bfeb | ||
|
|
3f7b16c736 | ||
|
|
362fbb39d4 | ||
|
|
38fe24085f | ||
|
|
af3d5cb273 | ||
|
|
9200b742c5 | ||
|
|
f39c8ebaba | ||
|
|
bbb1831c5f | ||
|
|
ecae3d0e1e |
No files matched your search
@@ -7,6 +7,8 @@
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
depend
|
||||
*.depend
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
@@ -31,3 +33,6 @@
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
|
||||
# Others
|
||||
other/
|
||||
@@ -1,6 +1,6 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017, Patrick Pelissier
|
||||
Copyright (c) 2017-2018, Patrick Pelissier
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -2,6 +2,8 @@ PREFIX=/usr/local
|
||||
RM=rm -f
|
||||
MKDIR=mkdir -p
|
||||
|
||||
.PHONY: all test check doc clean distclean depend depend.png install
|
||||
|
||||
all:
|
||||
@echo "Nothing to be done."
|
||||
|
||||
@@ -18,7 +20,7 @@ clean:
|
||||
cd tests && $(MAKE) clean
|
||||
cd example && $(MAKE) clean
|
||||
cd bench && $(MAKE) clean
|
||||
$(RM) -f README.html
|
||||
$(RM) -f README.html depend.dot
|
||||
|
||||
distclean:
|
||||
cd tests && $(MAKE) distclean
|
||||
@@ -26,6 +28,10 @@ distclean:
|
||||
depend:
|
||||
cd tests && $(MAKE) depend
|
||||
|
||||
depend.png:
|
||||
(echo "digraph g { " ; for i in *.h ; do list=$$(grep "include \"" $$i |cut -f2 -d\") ; for j in $$list ; do echo "\"$$i\" -> \"$$j\" ;" ; done ; done ; echo "}" )> depend.dot
|
||||
dot -Tpng depend.dot -o depend.png
|
||||
|
||||
install:
|
||||
$(MKDIR) $(DESTDIR)$(PREFIX)/include
|
||||
cp m-*.h $(DESTDIR)$(PREFIX)/include
|
||||
+37
-10
@@ -5,6 +5,8 @@ CPPFLAGS=-I..
|
||||
N=4
|
||||
BENCH_DEF=
|
||||
|
||||
.PHONY: all container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain
|
||||
|
||||
all: container queue mempool string plain
|
||||
|
||||
#########################################################################
|
||||
@@ -39,6 +41,7 @@ bench-mlib:
|
||||
@./bench-mlib.exe 42
|
||||
@./bench-mlib.exe 43
|
||||
@./bench-mlib.exe 50
|
||||
@./bench-mlib.exe 51
|
||||
|
||||
bench-mlib-mempool:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c -DUSE_MEMPOOL -pthread -o bench-mlib-mempool.exe
|
||||
@@ -50,6 +53,7 @@ bench-mlib-mempool:
|
||||
@./bench-mlib-mempool.exe 42
|
||||
@./bench-mlib-mempool.exe 43
|
||||
@./bench-mlib-mempool.exe 50
|
||||
@./bench-mlib-mempool.exe 51
|
||||
|
||||
bench-mlib-thread:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c -DMULTI_THREAD_MEASURE -pthread -o bench-mlib-thread.exe
|
||||
@@ -66,10 +70,13 @@ bench-stl:
|
||||
@./bench-stl.exe 42
|
||||
@./bench-stl.exe 43
|
||||
@./bench-stl.exe 50
|
||||
@./bench-stl.exe 51
|
||||
|
||||
# QT is supposed to be installed
|
||||
# QT shall point to the the directory containing the file .pc are stored
|
||||
bench-qt:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -fPIC `pkg-config --libs --cflags Qt5Core` bench-qt.cpp -o bench-qt.exe
|
||||
@if test -n "$${QT}" ; then $(MAKE) bench-qt0 ; else echo "Nothing to be done for QT." ; fi
|
||||
bench-qt0:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -fPIC `PKG_CONFIG_PATH="$${QT}" pkg-config --libs --cflags Qt5Core` bench-qt.cpp -o bench-qt.exe
|
||||
@./bench-qt.exe 10
|
||||
@./bench-qt.exe 20
|
||||
@./bench-qt.exe 30
|
||||
@@ -78,9 +85,11 @@ bench-qt:
|
||||
@./bench-qt.exe 42
|
||||
@./bench-qt.exe 50
|
||||
|
||||
#GLIB is supposed to be installed
|
||||
# GLIB shall point to the the directory containing the file .pc are stored
|
||||
bench-glib:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-glib.c -o bench-glib.exe `pkg-config --libs --cflags glib-2.0`
|
||||
@if test -n "$${GLIB}" ; then $(MAKE) bench-glib0 ; else echo "Nothing to be done for GLIB." ; fi
|
||||
bench-glib0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-glib.c -o bench-glib.exe `PKG_CONFIG_PATH="$${GLIB}" pkg-config --libs --cflags glib-2.0`
|
||||
@./bench-glib.exe 10
|
||||
@./bench-glib.exe 20
|
||||
@./bench-glib.exe 30
|
||||
@@ -164,7 +173,7 @@ bench-flathashmap:
|
||||
@if test -n "$${FLATHASHMAP}" ; then $(MAKE) bench-flathashmap0 ; else echo "Nothing to be done for FLATHASHMAP." ; fi
|
||||
|
||||
bench-flathashmap0:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${FLATHASHMAP}" bench-flathashmap.cpp -o bench-flathashmap.exe
|
||||
$(CXX) -std=c++14 $(CFLAGS) $(CPPFLAGS) -I "$${FLATHASHMAP}" bench-flathashmap.cpp -o bench-flathashmap.exe
|
||||
@./bench-flathashmap.exe 41
|
||||
@./bench-flathashmap.exe 42
|
||||
@./bench-flathashmap.exe 43
|
||||
@@ -222,7 +231,6 @@ bench-libsrt0:
|
||||
# The library shall be built.
|
||||
bench-liblfds:
|
||||
@if test -n "$${LIBLFDS}" ; then $(MAKE) bench-liblfds0 ; else echo "Nothing to be done for LIBLFDS." ; fi
|
||||
|
||||
bench-liblfds0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${LIBLFDS}/inc" -Wno-unknown-pragmas bench-liblfds.c -o bench-liblfds.exe $${LIBLFDS}/bin/liblfds711.so -lpthread
|
||||
@LD_LIBRARY_PATH="$${LIBLFDS}/bin:$${LD_LIBRARY_PATH}" ./bench-liblfds.exe 60
|
||||
@@ -232,17 +240,33 @@ bench-liblfds0:
|
||||
# The library shall be built.
|
||||
bench-concurrentqueue:
|
||||
@if test -n "$${CONCURRENTQUEUE}" ; then $(MAKE) bench-concurrentqueue0 ; else echo "Nothing to be done for CONCURRENTQUEUE." ; fi
|
||||
|
||||
bench-concurrentqueue0:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${CONCURRENTQUEUE}/" bench-concurrentqueue.cpp -o bench-concurrentqueue.exe -lpthread
|
||||
@./bench-concurrentqueue.exe 60
|
||||
|
||||
|
||||
# BOOST is assumed to be installed in the system
|
||||
# XXHASH shall point to the source directory of xxhash
|
||||
bench-xxhash:
|
||||
@if test -n "$${XXHASH}" ; then $(MAKE) bench-xxhash0 ; else echo "Nothing to be done for XXHASH." ; fi
|
||||
bench-xxhash0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${XXHASH}/" bench-xxhash.c "$${XXHASH}/libxxhash.a" -o bench-xxhash.exe
|
||||
@./bench-xxhash.exe 70
|
||||
|
||||
# BOOST shall point to the header location.
|
||||
bench-boost:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) bench-boost.cpp -o bench-boost.exe -lpthread
|
||||
@if test -n "$${BOOST}" ; then $(MAKE) bench-boost0 ; else echo "Nothing to be done for BOOST." ; fi
|
||||
bench-boost0:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp -o bench-boost.exe -lpthread
|
||||
@./bench-boost.exe 60
|
||||
|
||||
# NEDTRIES shall point to the header location.
|
||||
bench-nedtries:
|
||||
@if test -n "$${NEDTRIES}" ; then $(MAKE) bench-nedtries0 ; else echo "Nothing to be done for NEDTRIES." ; fi
|
||||
bench-nedtries0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${NEDTRIES}" bench-nedtries.c -o bench-nedtries.exe
|
||||
@./bench-nedtries.exe 40
|
||||
@./bench-nedtries.exe 45
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-plain:
|
||||
@@ -252,7 +276,9 @@ bench-plain:
|
||||
############################################################################
|
||||
|
||||
bench-mempool:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) pool.cc `pkg-config --libs --cflags glib-2.0` -lboost_system -o bench-mempool.exe
|
||||
@if test -n "$${BOOST}" ; then if test -n "$${GLIB}" ; then make bench-mempool0 BENCH_DEF="-DUSE_BOOST -DUSE_GLIB `pkg-config --libs --cflags glib-2.0` -lboost_system" ; else make bench-mempool0 BENCH_DEF="-DUSE_BOOST -lboost_system" ; fi ; else if test -n "$${GLIB}" ; then make bench-mempool0 BENCH_DEF="-DUSE_GLIB `pkg-config --libs --cflags glib-2.0`" ; else make bench-mempool0 ; fi ; fi
|
||||
bench-mempool0:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) pool.cc $(BENCH_DEF) -o bench-mempool.exe
|
||||
@./bench-mempool.exe
|
||||
|
||||
############################################################################
|
||||
@@ -280,6 +306,7 @@ bench-string-exe:
|
||||
|
||||
clean:
|
||||
rm -f *.o bench-*.exe bench-*.s *~ massif.out.*
|
||||
cd nucleotide && $(MAKE) clean
|
||||
|
||||
############################################################################
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dynamic.h"
|
||||
|
||||
@@ -29,26 +30,26 @@ static void test_array(size_t n)
|
||||
s += *(unsigned int*) vector_at(&a1, i) * *(unsigned int*) vector_at(&a2, i);
|
||||
}
|
||||
g_result = s;
|
||||
vector_destruct(&a1);
|
||||
vector_destruct(&a2);
|
||||
vector_destruct(&a1, NULL);
|
||||
vector_destruct(&a2, NULL);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static size_t hash_func (map *m, void *a)
|
||||
static size_t hash_func (void *a)
|
||||
{
|
||||
return hash_data(a, sizeof (unsigned long));
|
||||
}
|
||||
|
||||
static int equal_func(map *m, void *a, void *b)
|
||||
static int equal_func(void *a, void *b)
|
||||
{
|
||||
const unsigned long *pa = a;
|
||||
const unsigned long *pb = b;
|
||||
return *pa == *pb;
|
||||
}
|
||||
|
||||
static void set_func(map *m, void *a, void *b)
|
||||
static void set_func(void *a, void *b)
|
||||
{
|
||||
unsigned long *pa = a;
|
||||
const unsigned long *pb = b;
|
||||
@@ -86,20 +87,20 @@ test_dict(unsigned long n)
|
||||
|
||||
typedef char char_array_t[256];
|
||||
|
||||
static int char_equal (map *m, void *a, void *b)
|
||||
static int char_equal (void *a, void *b)
|
||||
{
|
||||
const char_array_t *pa = (const char_array_t *)a;
|
||||
const char_array_t *pb = (const char_array_t *)b;
|
||||
return strcmp(*pa,*pb)==0;
|
||||
}
|
||||
|
||||
static size_t char_hash(map *m, void *a)
|
||||
static size_t char_hash(void *a)
|
||||
{
|
||||
char_array_t *pa = (char_array_t *)a;
|
||||
return hash_string(*pa);
|
||||
}
|
||||
|
||||
static void char_set(map *m, void *a, void *b)
|
||||
static void char_set(void *a, void *b)
|
||||
{
|
||||
char_array_t *pa = (char_array_t *)a;
|
||||
const char_array_t *pb = (const char_array_t *)b;
|
||||
|
||||
+15
-2
@@ -177,9 +177,9 @@ static size_t char_hash(const char_array_t a) { return m_core_hash (a, strlen(a)
|
||||
#define CHAR_OPLIST (INIT(char_init), INIT_SET(char_set), SET(char_set), CLEAR(char_init), HASH(char_hash), EQUAL(char_equal_p))
|
||||
|
||||
#ifdef USE_MEMPOOL
|
||||
DICT_DEF2(dict_char, char_array_t, M_OPEXTEND(CHAR_OPLIST,MEMPOOL(dict_mpool2), MEMPOOL_LINKAGE(static)), char_array_t, CHAR_OPLIST)
|
||||
DICT_STOREHASH_DEF2(dict_char, char_array_t, M_OPEXTEND(CHAR_OPLIST,MEMPOOL(dict_mpool2), MEMPOOL_LINKAGE(static)), char_array_t, CHAR_OPLIST)
|
||||
#else
|
||||
DICT_DEF2(dict_char, char_array_t, CHAR_OPLIST, char_array_t, CHAR_OPLIST)
|
||||
DICT_STOREHASH_DEF2(dict_char, char_array_t, CHAR_OPLIST, char_array_t, CHAR_OPLIST)
|
||||
#endif
|
||||
|
||||
static void
|
||||
@@ -263,6 +263,17 @@ static void test_sort(size_t n)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_stable_sort(size_t n)
|
||||
{
|
||||
M_LET(a1, ARRAY_OPLIST(array_float)) {
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
array_float_push_back(a1, rand_get() );
|
||||
}
|
||||
array_float_special_stable_sort(a1);
|
||||
g_result = *array_float_get(a1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
BUFFER_DEF(buffer_uint, unsigned int, 0, BUFFER_QUEUE|BUFFER_BLOCKING)
|
||||
@@ -485,6 +496,8 @@ int main(int argc, const char *argv[])
|
||||
test_function("DictS time", 1000000, test_dict_str);
|
||||
if (n == 50)
|
||||
test_function("Sort time", 10000000, test_sort);
|
||||
if (n == 51)
|
||||
test_function("Stable Sort time", 10000000, test_stable_sort);
|
||||
if (n == 60)
|
||||
test_function("Buffer time", 1000000, test_buffer);
|
||||
if (n == 61)
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
#define NDEBUG
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "nedtrie.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct foo_s {
|
||||
NEDTRIE_ENTRY(foo_s) link;
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
} foo_t;
|
||||
typedef struct foo_tree_s foo_tree_t;
|
||||
NEDTRIE_HEAD(foo_tree_s, foo_s);
|
||||
|
||||
static inline size_t fookeyfunct(const foo_t *r)
|
||||
{
|
||||
return r->key;
|
||||
}
|
||||
|
||||
NEDTRIE_GENERATE(static, foo_tree_s, foo_s, link, fookeyfunct, NEDTRIE_NOBBLEZEROS(foo_tree_s))
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
{
|
||||
foo_tree_t footree;
|
||||
NEDTRIE_INIT(&footree);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
unsigned long val = rand_get();
|
||||
foo_t * p = malloc(sizeof(foo_t));
|
||||
if (p == NULL) abort();
|
||||
p->key = key;
|
||||
p->value = val;
|
||||
NEDTRIE_INSERT(foo_tree_s, &footree, p);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
foo_t key = { .key = rand_get() };
|
||||
foo_t *p = NEDTRIE_FIND(foo_tree_s, &footree, &key);
|
||||
if (p)
|
||||
s += p->value;
|
||||
}
|
||||
g_result = s;
|
||||
foo_t *r, *next;
|
||||
NEDTRIE_FOREACH_SAFE(r, foo_tree_s, &footree, next) {
|
||||
// Remove is needed, otherwise it segfault
|
||||
NEDTRIE_REMOVE(foo_tree_s, &footree, r);
|
||||
free(r);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_noalloc(unsigned long n)
|
||||
{
|
||||
foo_tree_t footree;
|
||||
NEDTRIE_INIT(&footree);
|
||||
|
||||
foo_t *tab = malloc(n*sizeof(foo_t));
|
||||
if (tab == NULL) abort();
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
unsigned long val = rand_get();
|
||||
tab[i].key = key;
|
||||
tab[i].value = val;
|
||||
NEDTRIE_INSERT(foo_tree_s, &footree, &tab[i]);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
foo_t key = { .key = rand_get() };
|
||||
foo_t *p = NEDTRIE_FIND(foo_tree_s, &footree, &key);
|
||||
if (p)
|
||||
s += p->value;
|
||||
}
|
||||
g_result = s;
|
||||
free(tab);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 40)
|
||||
test_function("Dict time", 1000000, test_dict);
|
||||
if (n == 45)
|
||||
test_function("Dict No Alloc time", 1000000, test_dict_noalloc);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#define NDEBUG
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -208,6 +208,16 @@ static void test_sort(size_t n)
|
||||
g_result = a1[0];
|
||||
}
|
||||
|
||||
static void test_stable_sort(size_t n)
|
||||
{
|
||||
vector<float> a1;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
}
|
||||
stable_sort(a1.begin(), a1.end());
|
||||
g_result = a1[0];
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
@@ -231,5 +241,7 @@ int main(int argc, const char *argv[])
|
||||
test_function("DictS(m) time", 1000000, test_dict_str2);
|
||||
if (n == 50)
|
||||
test_function("Sort time", 10000000, test_sort);
|
||||
if (n == 51)
|
||||
test_function("Stable Sort time", 10000000, test_stable_sort);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "xxhash.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static unsigned long *g_p;
|
||||
|
||||
static void test_hash_prepare(size_t n)
|
||||
{
|
||||
g_p = malloc (n * sizeof(unsigned long));
|
||||
if (g_p == NULL) abort();
|
||||
for(size_t i = 0; i < n ; i++)
|
||||
g_p[i] = ((rand_get()*RAND_MAX + rand_get())*RAND_MAX+rand_get())*RAND_MAX + rand_get();
|
||||
}
|
||||
|
||||
|
||||
static void test_hash_final(void)
|
||||
{
|
||||
free(g_p);
|
||||
}
|
||||
|
||||
static void test_hash(size_t n)
|
||||
{
|
||||
g_result = XXH64(g_p, sizeof(unsigned long)*n, 0);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 70) {
|
||||
n = (argc > 2) ? atoi(argv[2]) : 100000000;
|
||||
test_hash_prepare(n);
|
||||
test_function("XXHASH64 time", n, test_hash);
|
||||
test_hash_final();
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MLIB - TEST module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
CC=cc -std=c11
|
||||
CXX=c++ -std=c++11
|
||||
CFLAGS=-O2 -march=native -Wall
|
||||
CPPFLAGS=-I../..
|
||||
|
||||
all: k-nucleotide
|
||||
|
||||
k-nucleotide: k-nucleotide.exe data.txt
|
||||
./k-nucleotide.exe < data.txt
|
||||
|
||||
k-nucleotide.exe: nucleotide.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) nucleotide.c -o k-nucleotide.exe -lpthread
|
||||
|
||||
data.txt: fasta.exe
|
||||
./fasta.exe 25000000 > data.txt
|
||||
|
||||
fasta.exe: fasta.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -fopenmp fasta.c -o fasta.exe
|
||||
|
||||
clean:
|
||||
rm -f *.exe *~ *.o data.txt
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by Jeremy Zerfas
|
||||
// rewritten by Аноним Легионов, inspired by fasta Rust #2 program
|
||||
// use two OpenMP locks instead of one critical section
|
||||
// decouples IO activity from random number generation
|
||||
//
|
||||
// modified by Josh Goldfoot, adding use of a buffer for fasta_repeat
|
||||
|
||||
|
||||
// This controls the width of lines that are output by this program.
|
||||
#define MAXIMUM_LINE_WIDTH 60
|
||||
|
||||
// This program will generate the random nucleotide sequences in parallel which
|
||||
// are worked on in blocks of lines. The number of lines in those blocks is
|
||||
// controlled by this setting.
|
||||
#define LINES_PER_BLOCK 1024
|
||||
|
||||
#define CHARACTERS_PER_BLOCK (MAXIMUM_LINE_WIDTH*LINES_PER_BLOCK)
|
||||
|
||||
#define THREADS_TO_USE 4
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
// intptr_t should be the native integer type on most sane systems.
|
||||
typedef intptr_t intnative_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char letter;
|
||||
float probability;
|
||||
} nucleotide_info;
|
||||
|
||||
|
||||
// Repeatedly print string_To_Repeat until it has printed
|
||||
// number_Of_Characters_To_Create. The output is also wrapped to
|
||||
// MAXIMUM_LINE_WIDTH columns.
|
||||
static char* make_Sequence_Buffer(const char string_To_Repeat[])
|
||||
{
|
||||
const intnative_t string_To_Repeat_Length = strlen(string_To_Repeat);
|
||||
|
||||
// JG: Changed to that this writes a sequence to a buffer, which is used
|
||||
intnative_t number_Of_Characters_To_Create = string_To_Repeat_Length * MAXIMUM_LINE_WIDTH;
|
||||
char* buffer = (char*) malloc(number_Of_Characters_To_Create +
|
||||
number_Of_Characters_To_Create / MAXIMUM_LINE_WIDTH + 1);
|
||||
if (buffer == NULL)
|
||||
exit(-1);
|
||||
char* bufferOffset = buffer;
|
||||
|
||||
// Create an extended_String_To_Repeat which is a copy of string_To_Repeat
|
||||
// but extended with another copy of the first MAXIMUM_LINE_WIDTH characters
|
||||
// of string_To_Repeat appended to the end. Later on this allows us to
|
||||
// generate a line of output just by doing simple memory copies using an
|
||||
// appropriate offset into extended_String_To_Repeat.
|
||||
char extended_String_To_Repeat[string_To_Repeat_Length + MAXIMUM_LINE_WIDTH];
|
||||
for (intnative_t column = 0; column<string_To_Repeat_Length + MAXIMUM_LINE_WIDTH;
|
||||
column++)
|
||||
extended_String_To_Repeat[column] =
|
||||
string_To_Repeat[column%string_To_Repeat_Length];
|
||||
intnative_t offset = 0;
|
||||
|
||||
char line[MAXIMUM_LINE_WIDTH + 1];
|
||||
line[MAXIMUM_LINE_WIDTH] = '\n';
|
||||
|
||||
for (intnative_t current_Number_Of_Characters_To_Create =
|
||||
number_Of_Characters_To_Create;
|
||||
current_Number_Of_Characters_To_Create>0;)
|
||||
{
|
||||
// Figure out the length of the line we need to write. If it's less than
|
||||
// MAXIMUM_LINE_WIDTH then we also need to add a line feed in the right
|
||||
// spot too.
|
||||
intnative_t line_Length = MAXIMUM_LINE_WIDTH;
|
||||
if (current_Number_Of_Characters_To_Create<MAXIMUM_LINE_WIDTH)
|
||||
{
|
||||
line_Length = current_Number_Of_Characters_To_Create;
|
||||
line[line_Length] = '\n';
|
||||
}
|
||||
|
||||
memcpy(line, extended_String_To_Repeat + offset, line_Length);
|
||||
|
||||
// Update the offset, reducing it by string_To_Repeat_Length if
|
||||
// necessary.
|
||||
offset += line_Length;
|
||||
if (offset>string_To_Repeat_Length)
|
||||
offset -= string_To_Repeat_Length;
|
||||
|
||||
// "Output" that line to our buffer and update the
|
||||
// current_Number_Of_Characters_To_Create.
|
||||
memcpy(bufferOffset, line, line_Length + 1); // JG: used to be fwrite(line, line_Length + 1, 1, stdout);
|
||||
bufferOffset += line_Length + 1;
|
||||
current_Number_Of_Characters_To_Create -= line_Length;
|
||||
}
|
||||
*bufferOffset = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void repeat_And_Wrap_String(const char string_To_Repeat[], intnative_t number_Of_Characters_To_Create)
|
||||
{
|
||||
/* JG: fasta_repeat repeats every len(alu) * line-length = 287 * 61 = 17507 characters.
|
||||
So, calculate this once, then just print that buffer over and over. */
|
||||
char* sequence = make_Sequence_Buffer(string_To_Repeat);
|
||||
intnative_t sequenceLen = (intnative_t) strlen(sequence);
|
||||
intnative_t outputBytes = number_Of_Characters_To_Create + number_Of_Characters_To_Create / 60;
|
||||
while (outputBytes >= sequenceLen) {
|
||||
fwrite(sequence, sequenceLen, 1, stdout);
|
||||
outputBytes -= sequenceLen;
|
||||
}
|
||||
if (outputBytes > 0) {
|
||||
fwrite(sequence, outputBytes, 1, stdout);
|
||||
printf("\n");
|
||||
}
|
||||
free(sequence);
|
||||
}
|
||||
|
||||
|
||||
// Generate a pseudorandom number from 0 to max using a linear
|
||||
// congruential generator.
|
||||
#define IM 139968
|
||||
#define IA 3877
|
||||
#define IC 29573
|
||||
uint32_t seed = 42;
|
||||
|
||||
int rng_tid; //Thread ID
|
||||
int rng_tnum = 1; //Thread number
|
||||
intnative_t rng_cnt = 0;
|
||||
|
||||
#ifdef _OPENMP
|
||||
omp_lock_t rng_lock;
|
||||
#define RNG_LOCK_INIT() omp_init_lock(&rng_lock)
|
||||
#define RNG_LOCK() omp_set_lock(&rng_lock)
|
||||
#define RNG_FREE() omp_unset_lock(&rng_lock)
|
||||
#else
|
||||
#define RNG_LOCK_INIT() do{}while(0)
|
||||
#define RNG_LOCK() do{}while(0)
|
||||
#define RNG_FREE() do{}while(0)
|
||||
#endif
|
||||
|
||||
static void rng_init(void)
|
||||
{
|
||||
RNG_LOCK_INIT();
|
||||
rng_tid = 0;
|
||||
}
|
||||
|
||||
static intnative_t rng_gen_blk(uint32_t * buf, intnative_t len, int curr_tid)
|
||||
{
|
||||
intnative_t gen_cnt = -1;//Error by default
|
||||
RNG_LOCK();
|
||||
|
||||
if (rng_tid == curr_tid)
|
||||
{
|
||||
if (++rng_tid >= rng_tnum)
|
||||
{
|
||||
rng_tid = 0;
|
||||
}
|
||||
|
||||
gen_cnt = (len<rng_cnt) ? len : rng_cnt;
|
||||
rng_cnt -= gen_cnt;
|
||||
|
||||
len = gen_cnt;
|
||||
|
||||
while (0 != len--)
|
||||
{
|
||||
seed = (seed*IA + IC) % IM;
|
||||
*(buf++) = seed;//This is stupid actually!
|
||||
}
|
||||
}
|
||||
|
||||
RNG_FREE();
|
||||
return gen_cnt;
|
||||
}
|
||||
|
||||
int out_tid; //Thread ID
|
||||
int out_tnum = 1; //Thread number
|
||||
#ifdef _OPENMP
|
||||
omp_lock_t out_lock;
|
||||
#define OUT_LOCK_INIT() omp_init_lock(&out_lock)
|
||||
#define OUT_LOCK() omp_set_lock(&out_lock)
|
||||
#define OUT_FREE() omp_unset_lock(&out_lock)
|
||||
#else
|
||||
#define OUT_LOCK_INIT() do{}while(0)
|
||||
#define OUT_LOCK() do{}while(0)
|
||||
#define OUT_FREE() do{}while(0)
|
||||
#endif
|
||||
|
||||
static void out_init(void)
|
||||
{
|
||||
OUT_LOCK_INIT();
|
||||
rng_tid = 0;
|
||||
}
|
||||
|
||||
static intnative_t out_write(char * buf, intnative_t len, int curr_tid)
|
||||
{
|
||||
intnative_t wr_cnt = -1;//Error by default
|
||||
OUT_LOCK();
|
||||
|
||||
if (out_tid == curr_tid)
|
||||
{
|
||||
if (++out_tid >= out_tnum)
|
||||
{
|
||||
out_tid = 0;
|
||||
}
|
||||
wr_cnt = fwrite(buf, len, 1, stdout);
|
||||
}
|
||||
|
||||
OUT_FREE();
|
||||
return wr_cnt; //-1 - thread error, 0 - IO error, 1 - ОК
|
||||
}
|
||||
|
||||
static void generate_And_Wrap_Pseudorandom_DNA_Sequence(
|
||||
const nucleotide_info nucl_info[],
|
||||
const intnative_t nucl_num,
|
||||
const intnative_t char_num)
|
||||
{
|
||||
uint32_t cumul_p[nucl_num];
|
||||
float cumul_acc = 0.0;
|
||||
|
||||
for (intnative_t i = 0; i<nucl_num; i++)
|
||||
{
|
||||
cumul_acc += nucl_info[i].probability;
|
||||
cumul_p[i] = 1ul + (uint32_t)(cumul_acc*(float)IM); //Compensate rounding errors on test file
|
||||
}
|
||||
|
||||
#ifdef _OPENMP
|
||||
intnative_t tnum = omp_get_num_procs();
|
||||
if (tnum>THREADS_TO_USE) tnum = THREADS_TO_USE;
|
||||
omp_set_num_threads(tnum);
|
||||
rng_tnum = tnum;
|
||||
out_tnum = tnum;
|
||||
#endif
|
||||
rng_tid = 0;
|
||||
out_tid = 0;
|
||||
rng_cnt = char_num;
|
||||
|
||||
#pragma omp parallel
|
||||
{
|
||||
char block[CHARACTERS_PER_BLOCK + LINES_PER_BLOCK];
|
||||
char * line;
|
||||
uint32_t rnd[CHARACTERS_PER_BLOCK], r;
|
||||
intnative_t cnt, col, prid, nid, ncnt;
|
||||
int cur_tid;
|
||||
#ifdef _OPENMP
|
||||
cur_tid = omp_get_thread_num();
|
||||
#else
|
||||
cur_tid = 0;
|
||||
#endif
|
||||
while (1)
|
||||
{
|
||||
do
|
||||
{
|
||||
cnt = rng_gen_blk(rnd, CHARACTERS_PER_BLOCK, cur_tid);
|
||||
} while (-1 == cnt);
|
||||
|
||||
if (0 == cnt)
|
||||
{
|
||||
break;//Work finished!
|
||||
}
|
||||
|
||||
line = block;
|
||||
|
||||
for (col = 0, prid = 0; prid < cnt; prid++)
|
||||
{
|
||||
r = rnd[prid];
|
||||
|
||||
ncnt = 0;
|
||||
for (nid = 0; nid < nucl_num; nid++)
|
||||
{
|
||||
if (cumul_p[nid] <= r)
|
||||
{
|
||||
ncnt++;
|
||||
}
|
||||
}
|
||||
|
||||
*line++ = nucl_info[ncnt].letter;
|
||||
if (++col >= MAXIMUM_LINE_WIDTH)
|
||||
{
|
||||
col = 0;
|
||||
*line++ = '\n';
|
||||
}
|
||||
}
|
||||
//Check if we need to end the line
|
||||
if (0 != col)
|
||||
{
|
||||
//Last iteration didn't end the line, so finish the job.
|
||||
*line++ = '\n';
|
||||
}
|
||||
//Print results
|
||||
do
|
||||
{
|
||||
cnt = out_write(block, line - block, cur_tid);
|
||||
} while (-1 == cnt);
|
||||
//Check fot IO error
|
||||
if (0 == cnt)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
const intnative_t n = atoi(argv[1]);
|
||||
|
||||
fputs(">ONE Homo sapiens alu\n", stdout);
|
||||
const char homo_Sapiens_Alu[] =
|
||||
"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTC"
|
||||
"AGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCG"
|
||||
"TGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGG"
|
||||
"AGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
|
||||
repeat_And_Wrap_String(homo_Sapiens_Alu, 2 * n);
|
||||
|
||||
rng_init();
|
||||
out_init();
|
||||
|
||||
fputs(">TWO IUB ambiguity codes\n", stdout);
|
||||
nucleotide_info iub_Nucleotides_Information[] =
|
||||
{
|
||||
{ 'a', 0.27 },{ 'c', 0.12 },{ 'g', 0.12 },{ 't', 0.27 },{ 'B', 0.02 },
|
||||
{ 'D', 0.02 },{ 'H', 0.02 },{ 'K', 0.02 },{ 'M', 0.02 },{ 'N', 0.02 },
|
||||
{ 'R', 0.02 },{ 'S', 0.02 },{ 'V', 0.02 },{ 'W', 0.02 },{ 'Y', 0.02 }
|
||||
};
|
||||
generate_And_Wrap_Pseudorandom_DNA_Sequence(iub_Nucleotides_Information,
|
||||
sizeof(iub_Nucleotides_Information) / sizeof(nucleotide_info), 3 * n);
|
||||
|
||||
fputs(">THREE Homo sapiens frequency\n", stdout);
|
||||
nucleotide_info homo_Sapien_Nucleotides_Information[] =
|
||||
{
|
||||
{ 'a', 0.3029549426680 },{ 'c', 0.1979883004921 },
|
||||
{ 'g', 0.1975473066391 },{ 't', 0.3015094502008 }
|
||||
};
|
||||
generate_And_Wrap_Pseudorandom_DNA_Sequence(homo_Sapien_Nucleotides_Information,
|
||||
sizeof(homo_Sapien_Nucleotides_Information) / sizeof(nucleotide_info), 5 * n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// Original version Contributed by Jeremy Zerfas
|
||||
// M*LIB port contributed by Patrick Pélissier
|
||||
// gcc -O2 -march=native nucleotide.c -I../.. -std=c11 -lpthread -DNDEBUG
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "m-worker.h"
|
||||
#include "m-dict.h"
|
||||
|
||||
// This controls the maximum length for each set of oligonucleotide frequencies
|
||||
// and each oligonucleotide count output by this program.
|
||||
#define MAXIMUM_OUTPUT_LENGTH 4096
|
||||
|
||||
// Define Open Addressing dictionnary. Need to define how to handle out of bound data.
|
||||
static inline bool oor_equal_p(uint64_t k, unsigned char n)
|
||||
{
|
||||
return k == ~(uint64_t) n;
|
||||
}
|
||||
static inline void oor_set(uint64_t *k, unsigned char n)
|
||||
{
|
||||
*k = ~(uint64_t)n;
|
||||
}
|
||||
// Custom hash function.
|
||||
static inline size_t my_hash(uint64_t key)
|
||||
{
|
||||
return ((key) ^ (key)>>7);
|
||||
}
|
||||
// Define a dictionnary of uint64_t --> uint32_t
|
||||
DICT_OA_DEF2(dict_oligonucleotide,
|
||||
uint64_t, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
|
||||
uint32_t, M_DEFAULT_OPLIST)
|
||||
// Define oplist of dictionary
|
||||
#define OLIGONUCLEOTIDE_OPLIST DICT_OPLIST(dict_oligonucleotide, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(oor_hash), OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)), M_DEFAULT_OPLIST)
|
||||
|
||||
typedef struct {
|
||||
uint64_t key;
|
||||
uint32_t value;
|
||||
} element;
|
||||
|
||||
// Macro to convert a nucleotide character to a code. Note that upper and lower
|
||||
// case ASCII letters only differ in the fifth bit from the right and we only
|
||||
// need the three least significant bits to differentiate the letters 'A', 'C',
|
||||
// 'G', and 'T'. Spaces in this array/string will never be used as long as
|
||||
// characters other than 'A', 'C', 'G', and 'T' aren't used.
|
||||
#define CODE_FOR_NUCLEOTIDE(nucleotide) (" \0 \1\3 \2"[nucleotide & 0x7])
|
||||
|
||||
|
||||
// And one more macro to convert the codes back to nucleotide characters.
|
||||
#define NUCLEOTIDE_FOR_CODE(code) ("ACGT"[code & 0x3])
|
||||
|
||||
|
||||
// Function to use when sorting elements with qsort() later. Elements with
|
||||
// larger values will come first and in cases of identical values then elements
|
||||
// with smaller keys will come first.
|
||||
static int element_Compare(const void *a, const void *b)
|
||||
{
|
||||
const element * const left_Element = a;
|
||||
const element * const right_Element = b;
|
||||
// Sort based on element values.
|
||||
if(left_Element->value < right_Element->value) return 1;
|
||||
if(left_Element->value > right_Element->value) return -1;
|
||||
|
||||
// If we got here then both items have the same value so then sort based on
|
||||
// key.
|
||||
return left_Element->key > right_Element->key ? 1 : -1;
|
||||
}
|
||||
|
||||
|
||||
// Generate frequencies for all oligonucleotides in polynucleotide that are of
|
||||
// desired_Length_For_Oligonucleotides and then save it to output.
|
||||
static void
|
||||
generate_Frequencies_For_Desired_Length_Oligonucleotides(const char polynucleotide[],
|
||||
const int polynucleotide_Length,
|
||||
const int desired_Length_For_Oligonucleotides,
|
||||
char * const output)
|
||||
{
|
||||
assert (2*desired_Length_For_Oligonucleotides <= 64);
|
||||
|
||||
dict_oligonucleotide_t hash_Table;
|
||||
dict_oligonucleotide_init(hash_Table);
|
||||
|
||||
uint64_t key=0;
|
||||
const uint64_t mask=(1ULL<<(2*desired_Length_For_Oligonucleotides))-1;
|
||||
|
||||
// For the first several nucleotides we only need to append them to key in
|
||||
// preparation for the insertion of complete oligonucleotides to hash_Table.
|
||||
for(int i=0; i<desired_Length_For_Oligonucleotides-1; i++)
|
||||
key=(key<<2 & mask) | polynucleotide[i];
|
||||
|
||||
// Add all the complete oligonucleotides of
|
||||
// desired_Length_For_Oligonucleotides to hash_Table and update the count
|
||||
// for each oligonucleotide.
|
||||
for(int i=desired_Length_For_Oligonucleotides-1
|
||||
; i<polynucleotide_Length; i++){
|
||||
|
||||
key=(key<<2 & mask) | polynucleotide[i];
|
||||
|
||||
uint32_t *p = dict_oligonucleotide_get(hash_Table, key);
|
||||
if (p != NULL)
|
||||
(*p) ++;
|
||||
else {
|
||||
dict_oligonucleotide_set_at(hash_Table, key, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Create an array of elements from hash_Table.
|
||||
int elements_Array_Size=dict_oligonucleotide_size(hash_Table), i=0;
|
||||
element * elements_Array=malloc(elements_Array_Size*sizeof(element));
|
||||
if (!elements_Array) abort();
|
||||
for M_EACH(item, hash_Table, OLIGONUCLEOTIDE_OPLIST) {
|
||||
elements_Array[i++]=((element){item->key, item->value});
|
||||
}
|
||||
// Clear the hash table
|
||||
dict_oligonucleotide_clear(hash_Table);
|
||||
|
||||
// Sort elements_Array.
|
||||
qsort(elements_Array, elements_Array_Size, sizeof(element), element_Compare);
|
||||
|
||||
// Print the frequencies for each oligonucleotide.
|
||||
for(int output_Position=0, i=0; i<elements_Array_Size; i++) {
|
||||
|
||||
// Convert the key for the oligonucleotide to a string.
|
||||
char oligonucleotide[desired_Length_For_Oligonucleotides+1];
|
||||
for(int j=desired_Length_For_Oligonucleotides-1; j>-1; j--){
|
||||
oligonucleotide[j]=NUCLEOTIDE_FOR_CODE(elements_Array[i].key);
|
||||
elements_Array[i].key>>=2;
|
||||
}
|
||||
oligonucleotide[desired_Length_For_Oligonucleotides]='\0';
|
||||
|
||||
// Output the frequency for oligonucleotide to output.
|
||||
output_Position+=snprintf(output+output_Position
|
||||
, MAXIMUM_OUTPUT_LENGTH-output_Position, "%s %.3f\n", oligonucleotide
|
||||
, 100.0f*elements_Array[i].value
|
||||
/(polynucleotide_Length-desired_Length_For_Oligonucleotides+1));
|
||||
}
|
||||
|
||||
free(elements_Array);
|
||||
}
|
||||
|
||||
|
||||
// Generate a count for the number of times oligonucleotide appears in
|
||||
// polynucleotide and then save it to output.
|
||||
static void
|
||||
generate_Count_For_Oligonucleotide(const char * const polynucleotide,
|
||||
const int polynucleotide_Length,
|
||||
const char * const oligonucleotide,
|
||||
char * const output)
|
||||
{
|
||||
const int oligonucleotide_Length=strlen(oligonucleotide);
|
||||
assert (2*oligonucleotide_Length <= 64);
|
||||
|
||||
dict_oligonucleotide_t hash_Table;
|
||||
dict_oligonucleotide_init(hash_Table);
|
||||
|
||||
uint64_t key = 0;
|
||||
const uint64_t mask=(1ULL<<(2*oligonucleotide_Length))-1;
|
||||
|
||||
// For the first several nucleotides we only need to append them to key in
|
||||
// preparation for the insertion of complete oligonucleotides to hash_Table.
|
||||
for(int i=0; i<oligonucleotide_Length-1; i++)
|
||||
key=(key<<2 & mask) | polynucleotide[i];
|
||||
|
||||
// Add all the complete oligonucleotides of oligonucleotide_Length to
|
||||
// hash_Table and update the count for each oligonucleotide.
|
||||
for(int i=oligonucleotide_Length-1; i<polynucleotide_Length; i++){
|
||||
key=(key<<2 & mask) | polynucleotide[i];
|
||||
|
||||
uint32_t *p = dict_oligonucleotide_get(hash_Table, key);
|
||||
if (p != NULL)
|
||||
(*p) ++;
|
||||
else {
|
||||
dict_oligonucleotide_set_at(hash_Table, key, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the key for oligonucleotide.
|
||||
key=0;
|
||||
for(int i=0; i<oligonucleotide_Length; i++)
|
||||
key=(key<<2) | CODE_FOR_NUCLEOTIDE(oligonucleotide[i]);
|
||||
|
||||
// Output the count for oligonucleotide to output.
|
||||
uint32_t *p = dict_oligonucleotide_get(hash_Table, key);
|
||||
uintmax_t count= p== NULL ? 0 : *p;
|
||||
snprintf(output, MAXIMUM_OUTPUT_LENGTH, "%ju\t%s", count, oligonucleotide);
|
||||
|
||||
dict_oligonucleotide_clear(hash_Table);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
char buffer[MAXIMUM_OUTPUT_LENGTH];
|
||||
worker_t worker;
|
||||
|
||||
// Initialize the different worker threads by auto-detecting the number of cores of the system
|
||||
worker_init(worker, 0, 1, NULL);
|
||||
|
||||
// Find the start of the third polynucleotide.
|
||||
while(fgets(buffer, sizeof(buffer), stdin) && memcmp(">THREE", buffer
|
||||
, sizeof(">THREE")-1));
|
||||
|
||||
// Start with 1 MB of storage for reading in the polynucleotide and grow
|
||||
// geometrically.
|
||||
int polynucleotide_Capacity=1048576;
|
||||
int polynucleotide_Length=0;
|
||||
char * polynucleotide=malloc(polynucleotide_Capacity);
|
||||
if (!polynucleotide) abort();
|
||||
|
||||
// Start reading and encoding the third polynucleotide.
|
||||
while(fgets(buffer, sizeof(buffer), stdin) && buffer[0]!='>'){
|
||||
for(int i=0; buffer[i]!='\0'; i++)
|
||||
if(buffer[i]!='\n')
|
||||
polynucleotide[polynucleotide_Length++]
|
||||
=CODE_FOR_NUCLEOTIDE(buffer[i]);
|
||||
|
||||
// Make sure we still have enough memory allocated for any potential
|
||||
// nucleotides in the next line.
|
||||
if(polynucleotide_Capacity-polynucleotide_Length<sizeof(buffer)) {
|
||||
polynucleotide=realloc(polynucleotide, polynucleotide_Capacity*=2);
|
||||
if (!polynucleotide) abort();
|
||||
}
|
||||
}
|
||||
|
||||
char output_Buffer[7][MAXIMUM_OUTPUT_LENGTH];
|
||||
char (*output)[MAXIMUM_OUTPUT_LENGTH] = output_Buffer;
|
||||
|
||||
// Do the following functions in parallel.
|
||||
// Define a synchronization block
|
||||
worker_sync_t block;
|
||||
worker_start(block);
|
||||
|
||||
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
|
||||
generate_Count_For_Oligonucleotide(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
"GGTATTTTAATTTATAGT", output[6]);
|
||||
}, (/*no output*/));
|
||||
|
||||
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
|
||||
generate_Count_For_Oligonucleotide(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
"GGTATTTTAATT", output[5]);
|
||||
}, (/*no output*/));
|
||||
|
||||
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
|
||||
generate_Count_For_Oligonucleotide(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
"GGTATT", output[4]);
|
||||
}, (/*no output*/));
|
||||
|
||||
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
|
||||
generate_Count_For_Oligonucleotide(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
"GGTA", output[3]);
|
||||
}, (/*no output*/));
|
||||
|
||||
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
|
||||
generate_Count_For_Oligonucleotide(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
"GGT", output[2]);
|
||||
}, (/*no output*/));
|
||||
|
||||
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
|
||||
generate_Frequencies_For_Desired_Length_Oligonucleotides(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
2,
|
||||
output[1]);
|
||||
}, (/*no output*/));
|
||||
|
||||
generate_Frequencies_For_Desired_Length_Oligonucleotides(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
1,
|
||||
output[0]);
|
||||
worker_sync(block);
|
||||
|
||||
// Output the results to stdout.
|
||||
for(int i=0; i<7; i++)
|
||||
printf("%s\n", output_Buffer[i]);
|
||||
|
||||
free(polynucleotide);
|
||||
worker_clear(worker);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+18
-5
@@ -51,9 +51,13 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#ifdef USE_BOOST
|
||||
#include <boost/pool/object_pool.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef USE_GLIB
|
||||
#include <glib.h>
|
||||
#endif
|
||||
|
||||
static const size_t PAGE_SIZE = 4096;
|
||||
|
||||
@@ -115,6 +119,8 @@ benchmark(std::string &&desc, std::function<void ()> cb)
|
||||
* Boost::pool
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
#ifdef USE_BOOST
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_boost_pool()
|
||||
@@ -166,6 +172,7 @@ benchmark_boost_pool_create_and_destroy()
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
@@ -220,6 +227,7 @@ benchmark_mallocfree_free()
|
||||
* GLib slices
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
#ifdef USE_GLIB
|
||||
template<class T>
|
||||
void
|
||||
benchmark_glib_slices()
|
||||
@@ -262,6 +270,7 @@ benchmark_glib_slices_free()
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
@@ -798,7 +807,7 @@ benchmark_mempool_small()
|
||||
mempool_small_init (p);
|
||||
mempool_small_t *ptr = &p; // C++ lambda !
|
||||
|
||||
benchmark(std::move(Small() + "mempool"), [=]() {
|
||||
benchmark(std::move(Small() + "M*LIB mempool"), [=]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(Small); ++i) {
|
||||
Small *o = mempool_small_alloc(*ptr);
|
||||
touch_obj(o);
|
||||
@@ -815,7 +824,7 @@ benchmark_mempool_big()
|
||||
mempool_big_init (p);
|
||||
mempool_big_t *ptr = &p; // C++ lambda !
|
||||
|
||||
benchmark(std::move(Big() + "mempool"), [=]() {
|
||||
benchmark(std::move(Big() + "M*LIB mempool"), [=]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(Big); ++i) {
|
||||
Big *o = mempool_big_alloc(*ptr);
|
||||
touch_obj(o);
|
||||
@@ -836,7 +845,7 @@ benchmark_mempool_mix_free()
|
||||
mempool_big_init (b);
|
||||
mempool_huge_init (h);
|
||||
|
||||
benchmark(std::move(std::string("mempool w/ free (Mix)")), [=]() {
|
||||
benchmark(std::move(std::string("M*LIB mempool w/ free (Mix)")), [=]() {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (__builtin_expect(!(i & 0xfff), 0)) {
|
||||
Huge *o = mempool_huge_alloc (*ptr_h);
|
||||
@@ -892,19 +901,23 @@ main()
|
||||
benchmark_mallocfree_free<Big>();
|
||||
std::cout << std::endl;
|
||||
|
||||
#ifdef USE_GLIB
|
||||
benchmark_glib_slices<Small>();
|
||||
benchmark_glib_slices_free<Small>();
|
||||
benchmark_glib_slices<Big>();
|
||||
benchmark_glib_slices_free<Big>();
|
||||
std::cout << std::endl;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_BOOST
|
||||
benchmark_boost_pool<Small>();
|
||||
benchmark_boost_pool_free<Small>();
|
||||
benchmark_boost_pool<Big>();
|
||||
benchmark_boost_pool_free<Big>();
|
||||
benchmark_boost_pool_create_and_destroy();
|
||||
std::cout << std::endl;
|
||||
|
||||
#endif
|
||||
|
||||
benchmark_ngx_pool<Small>();
|
||||
benchmark_ngx_pool<Big>();
|
||||
benchmark_ngx_pool_mix_free();
|
||||
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 150 KiB |
+7
-2
@@ -7,7 +7,8 @@ How to make a release?
|
||||
|
||||
2) Check that no memory leak is reported by valgrind:
|
||||
Run 'make valgrind' in tests folder on a system.
|
||||
|
||||
NOTE: valgrind seems completly lost in all the tests which spawn a lot of threads.
|
||||
|
||||
3) Check that no undefined behavior, nor data race, ... is reported by sanitizer:
|
||||
Run 'make sanitize' in tests folder on a system.
|
||||
This needs at least GCC 7
|
||||
@@ -22,7 +23,9 @@ How to make a release?
|
||||
5) Check that coverage is reasonnable.
|
||||
Run 'make coverage' and analyze result.
|
||||
|
||||
In case of problem, open a problem error.
|
||||
6) Publish the release
|
||||
|
||||
In case of problem, open a problem report.
|
||||
|
||||
List of primary systems
|
||||
=======================
|
||||
@@ -33,3 +36,5 @@ List of primary systems
|
||||
* clang 4 on linux/x86-64
|
||||
* g++ 7 on linux/x86-64
|
||||
* tcc on linux/x86-64
|
||||
* gcc 6 on windows/x86-64
|
||||
|
||||
+27
-14
@@ -5,11 +5,13 @@
|
||||
#include "m-mutex.h"
|
||||
|
||||
/* Global variable to stop scheduling */
|
||||
bool continue_threading_g;
|
||||
atomic_bool continue_threading_g;
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
/* Define a random big data structure */
|
||||
/* Define a custom random big data structure
|
||||
with its constructor and its destructor.
|
||||
*/
|
||||
|
||||
#define BIGDATA_SIZE 1000
|
||||
#define BIGDATA_NUM 10
|
||||
@@ -28,6 +30,7 @@ static void bigdata_init(bigdata_t d)
|
||||
{
|
||||
memset(d->bigdata, 0, BIGDATA_SIZE);
|
||||
d->ptr = malloc (BIGDATA_HEIGHT*BIGDATA_WIDTH);
|
||||
if (!d->ptr) abort();
|
||||
d->count = count_g++;
|
||||
printf ("Init image %d\n", d->count);
|
||||
}
|
||||
@@ -38,19 +41,25 @@ static void bigdata_clear(bigdata_t d)
|
||||
free(d->ptr);
|
||||
}
|
||||
|
||||
/* Let's register the oplist of our custom type globally */
|
||||
#define M_OPL_bigdata_t() (INIT(bigdata_init), CLEAR(bigdata_clear))
|
||||
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
/* Perform some random works on this big data */
|
||||
/* Perform some random works on this custom type */
|
||||
|
||||
static void perform_acquisition(bigdata_t p)
|
||||
{
|
||||
printf ("Acquiring image %d\n", p->count);
|
||||
// Let's say that rand is our acquisition function.
|
||||
for(int i = 0 ; i < BIGDATA_SIZE;i++)
|
||||
p->bigdata[i] = rand();
|
||||
for(int i = 0 ; i < BIGDATA_WIDTH*BIGDATA_HEIGHT;i++)
|
||||
p->ptr[i] = rand();
|
||||
// Let's stop arbitrary after 20 acquisitions
|
||||
if (p->count == 20)
|
||||
continue_threading_g = false;
|
||||
atomic_store(&continue_threading_g, false);
|
||||
}
|
||||
|
||||
static void perform_computation2(bigdata_t p)
|
||||
@@ -69,7 +78,7 @@ static void perform_computation3(bigdata_t p)
|
||||
|
||||
static void perform_computation4(bigdata_t p)
|
||||
{
|
||||
printf ("Computation 4 on image %d\n", p->count);
|
||||
printf ("Reduction on image %d\n", p->count);
|
||||
unsigned long s = 0;
|
||||
for(int i = 0 ; i < BIGDATA_WIDTH*BIGDATA_HEIGHT;i++)
|
||||
s += p->ptr[i];
|
||||
@@ -81,11 +90,12 @@ static void perform_computation4(bigdata_t p)
|
||||
/**************************************************************/
|
||||
|
||||
/* Let's define a shared pointer interface around the bigdata structure */
|
||||
SHARED_PTR_DEF(shared_bigdata, bigdata_t, (INIT(bigdata_init), CLEAR(bigdata_clear)))
|
||||
SHARED_PTR_DEF(shared_bigdata, bigdata_t)
|
||||
|
||||
/* Let's define the communication queue between the thread:
|
||||
* - size of queue is 10,
|
||||
* - it is a queue BUFFER_QUEUE,
|
||||
* - it store shared pointer to our bigdata_t,
|
||||
* - we change the semantics of _push / _pop into buffer as push a new item and pop it as a move (ideal semantics for shared_ptr interface).
|
||||
*/
|
||||
#define MY_QUEUE_SIZE 10
|
||||
@@ -94,11 +104,11 @@ BUFFER_DEF(buffer_bigdata, shared_bigdata_t, MY_QUEUE_SIZE,
|
||||
|
||||
/* Let's build a Thread synchros tree:
|
||||
*
|
||||
* Thread1 perform the simulation acquisition of the data.
|
||||
* Thread2 & Thread3 perform independet computation.
|
||||
* Thread1 perform the simulated acquisition of the data.
|
||||
* Thread2 & Thread3 perform independent computation.
|
||||
* Thread4 finalizes the computation :
|
||||
*
|
||||
* Thread1 ---> Thread 2
|
||||
* Thread1 ---> Thread 2 +
|
||||
* +-> Thread 3 --> Thread 4
|
||||
*/
|
||||
buffer_bigdata_t buf_t1tot2;
|
||||
@@ -123,7 +133,7 @@ static void clearbuf(void)
|
||||
static void thread1 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (continue_threading_g) {
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_init_new (ptr);
|
||||
perform_acquisition(*shared_bigdata_ref(ptr));
|
||||
@@ -135,7 +145,7 @@ static void thread1 (void *arg)
|
||||
static void thread2 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (continue_threading_g) {
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
buffer_bigdata_pop(&ptr, buf_t1tot2); // NOTE: Pop has been configured to init ptr
|
||||
perform_computation2(*shared_bigdata_ref(ptr));
|
||||
@@ -145,7 +155,7 @@ static void thread2 (void *arg)
|
||||
static void thread3 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (continue_threading_g) {
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
buffer_bigdata_pop(&ptr, buf_t1tot3); // NOTE: Pop has been configured to init ptr
|
||||
perform_computation3(*shared_bigdata_ref(ptr));
|
||||
@@ -156,7 +166,7 @@ static void thread3 (void *arg)
|
||||
static void thread4 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (continue_threading_g) {
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
buffer_bigdata_pop(&ptr, buf_t3tot4); // NOTE: Pop has been configured to init ptr
|
||||
perform_computation4(*shared_bigdata_ref(ptr));
|
||||
@@ -164,11 +174,12 @@ static void thread4 (void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
initbuf();
|
||||
continue_threading_g = true;
|
||||
atomic_init(&continue_threading_g, true);
|
||||
m_thread_create(t1, thread1, NULL);
|
||||
m_thread_create(t2, thread2, NULL);
|
||||
m_thread_create(t3, thread3, NULL);
|
||||
@@ -184,6 +195,8 @@ static void clear(void)
|
||||
clearbuf();
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ int main(void)
|
||||
list_string_get_str (tmpstr, grow, false);
|
||||
|
||||
// print out
|
||||
printf("Number of elements = %lu\n", (unsigned long) list_string_size(grow));
|
||||
printf("Number of elements = %zu\n", list_string_size(grow));
|
||||
printf("Final string = %s\n", string_get_cstr(tmpstr));
|
||||
|
||||
// Let's iterate over each element of the list
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - ALGO module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define different kind of algorithms named 'name' over the container
|
||||
which oplist is 'cont_oplist'
|
||||
which oplist is 'cont_oplist' as static inline functions.
|
||||
USAGE:
|
||||
ALGO_DEF(algogName, containerOplist) */
|
||||
#define ALGO_DEF(name, cont_oplist) \
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
/* Map a function or a macro to all elements of a container.
|
||||
USAGE:
|
||||
ALGO_MAP(container, containerOplist, func[, extra arguments of function]) */
|
||||
ALGO_MAP(container, containerOplist, function[, extra arguments of function]) */
|
||||
#define ALGO_MAP(container, cont_oplist, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ALGOI_MAP(container, cont_oplist, __VA_ARGS__), \
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
/* Extract a subset of a container to fill in another container.
|
||||
USAGE:
|
||||
ALGO_EXTRACT(contDst, contDstOplist, contSrc, contSrcOplist, func
|
||||
ALGO_EXTRACT(contDst, contDstOplist, contSrc, contSrcOplist, function
|
||||
[, extra arguments of function]) */
|
||||
// TODO: without 'func' parameter, extract all.
|
||||
#define ALGO_EXTRACT(contD, contDop, contS, contSop, ...) \
|
||||
@@ -81,7 +81,9 @@
|
||||
|
||||
#define ALGOI_DEF(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
static inline void M_C(name, _find) (it_t it, container_t l, const type_t data) \
|
||||
/* TODO: Add a specialization if container is sorted */ \
|
||||
static inline void \
|
||||
M_C(name, _find) (it_t it, container_t l, const type_t data) \
|
||||
{ \
|
||||
for (M_GET_IT_FIRST cont_oplist (it, l); \
|
||||
!M_GET_IT_END_P cont_oplist (it) ; \
|
||||
@@ -91,17 +93,20 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline bool M_C(name, _contains) (container_t l, const type_t data) \
|
||||
static inline bool \
|
||||
M_C(name, _contains) (container_t l, const type_t data) \
|
||||
{ \
|
||||
it_t it; \
|
||||
M_C(name,_find)(it, l, data); \
|
||||
return !M_GET_IT_END_P cont_oplist (it); \
|
||||
} \
|
||||
\
|
||||
/* NOTE: If PREVIOUS & IT_LAST exist, then go backwards */ \
|
||||
/* For the definition of _find_last, if the methods \
|
||||
PREVIOUS & IT_LAST are defined, then search backwards */ \
|
||||
M_IF(M_AND(M_TEST_METHOD_P(PREVIOUS, cont_oplist), M_TEST_METHOD_P(IT_LAST, cont_oplist))) \
|
||||
( \
|
||||
static inline void M_C(name, _find_last) (it_t it, container_t l, const type_t data) \
|
||||
static inline void \
|
||||
M_C(name, _find_last) (it_t it, container_t l, const type_t data) \
|
||||
{ \
|
||||
for (M_GET_IT_LAST cont_oplist (it, l); \
|
||||
!M_GET_IT_END_P cont_oplist (it) ; \
|
||||
@@ -111,7 +116,8 @@
|
||||
} \
|
||||
} \
|
||||
, \
|
||||
static inline void M_C(name, _find_last) (it_t it, container_t l, const type_t data) \
|
||||
static inline void \
|
||||
M_C(name, _find_last) (it_t it, container_t l, const type_t data) \
|
||||
{ \
|
||||
M_GET_IT_END cont_oplist (it, l); \
|
||||
it_t it2; \
|
||||
@@ -124,7 +130,8 @@
|
||||
} \
|
||||
) /* End of alternative of _find_last */ \
|
||||
\
|
||||
static inline size_t M_C(name, _count) (container_t l, const type_t data) \
|
||||
static inline size_t \
|
||||
M_C(name, _count) (container_t l, const type_t data) \
|
||||
{ \
|
||||
it_t it; \
|
||||
size_t count = 0; \
|
||||
@@ -137,43 +144,43 @@
|
||||
return count; \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _map) (container_t l, \
|
||||
void (*f)(type_t const) ) \
|
||||
static inline void \
|
||||
M_C(name, _map) (container_t l, void (*f)(type_t const) ) \
|
||||
{ \
|
||||
for M_EACH(item, l, cont_oplist) { \
|
||||
f(*item); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _reduce) (type_t *dest, \
|
||||
container_t l, \
|
||||
void (*f)(type_t *, type_t const) ) \
|
||||
static inline void \
|
||||
M_C(name, _reduce) (type_t *dest, container_t l, void (*f)(type_t *, type_t const) ) \
|
||||
{ \
|
||||
bool initDone = false; \
|
||||
for M_EACH(item, l, cont_oplist) { \
|
||||
if (initDone) \
|
||||
if (initDone) { \
|
||||
f(dest, *item); \
|
||||
else { \
|
||||
} else { \
|
||||
M_GET_SET type_oplist (*dest, *item); \
|
||||
initDone = true; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _map_reduce) (type_t *dest, \
|
||||
container_t l, \
|
||||
void (*r)(type_t*, type_t const), \
|
||||
void (*m)(type_t*, type_t const) ) \
|
||||
static inline \
|
||||
void M_C(name, _map_reduce) (type_t *dest, \
|
||||
container_t l, \
|
||||
void (*redFunc)(type_t*, type_t const), \
|
||||
void (*mapFunc)(type_t*, type_t const) ) \
|
||||
{ \
|
||||
bool initDone = false; \
|
||||
type_t tmp; \
|
||||
M_GET_INIT type_oplist (tmp); \
|
||||
for M_EACH(item, l, cont_oplist) { \
|
||||
if (initDone) { \
|
||||
m(&tmp, *item); \
|
||||
r(dest, tmp); \
|
||||
mapFunc(&tmp, *item); \
|
||||
redFunc(dest, tmp); \
|
||||
} else { \
|
||||
m(dest, *item); \
|
||||
mapFunc(dest, *item); \
|
||||
initDone = true; \
|
||||
} \
|
||||
} \
|
||||
@@ -181,7 +188,8 @@
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(CMP, type_oplist)( \
|
||||
static inline type_t *M_C(name, _min) (const container_t l) \
|
||||
static inline type_t * \
|
||||
M_C(name, _min) (const container_t l) \
|
||||
{ \
|
||||
type_t *min = NULL; \
|
||||
for M_EACH(cref, l, cont_oplist) { \
|
||||
@@ -192,7 +200,8 @@
|
||||
return min; \
|
||||
} \
|
||||
\
|
||||
static inline type_t *M_C(name, _max) (const container_t l) \
|
||||
static inline type_t * \
|
||||
M_C(name, _max) (const container_t l) \
|
||||
{ \
|
||||
type_t *max = NULL; \
|
||||
for M_EACH(cref, l, cont_oplist) { \
|
||||
@@ -203,8 +212,9 @@
|
||||
return max; \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _minmax) (type_t **min_p, type_t **max_p, \
|
||||
const container_t l) \
|
||||
static inline void \
|
||||
M_C(name, _minmax) (type_t **min_p, type_t **max_p, \
|
||||
const container_t l) \
|
||||
{ \
|
||||
type_t *min = NULL; \
|
||||
type_t *max = NULL; \
|
||||
@@ -220,7 +230,8 @@
|
||||
*max_p = max; \
|
||||
} \
|
||||
\
|
||||
static inline bool M_C(name, _sort_p)(const container_t l) \
|
||||
static inline bool \
|
||||
M_C(name, _sort_p)(const container_t l) \
|
||||
{ \
|
||||
it_t it1; \
|
||||
it_t it2; \
|
||||
@@ -240,7 +251,8 @@
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(IT_REMOVE, cont_oplist)( \
|
||||
static inline void M_C(name, _uniq)(container_t l) \
|
||||
static inline void \
|
||||
M_C(name, _uniq)(container_t l) \
|
||||
{ \
|
||||
it_t it1; \
|
||||
it_t it2; \
|
||||
@@ -261,6 +273,7 @@
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
\
|
||||
/* Sort can be generated from 3 algorithms: */ \
|
||||
/* - a specialized version defined by the container */ \
|
||||
/* - an insertion sort (need 'previous' method) */ \
|
||||
@@ -417,6 +430,8 @@
|
||||
{ \
|
||||
it_t itSrc; \
|
||||
it_t itDst; \
|
||||
assert(M_C(name, _sort_p)(dst)); \
|
||||
assert(M_C(name, _sort_p)(src)); \
|
||||
M_GET_IT_FIRST cont_oplist (itSrc, src); \
|
||||
M_GET_IT_FIRST cont_oplist (itDst, dst); \
|
||||
while (!M_GET_IT_END_P cont_oplist (itSrc) \
|
||||
@@ -451,6 +466,8 @@
|
||||
{ \
|
||||
it_t itSrc; \
|
||||
it_t itDst; \
|
||||
assert(M_C(name, _sort_p)(dst)); \
|
||||
assert(M_C(name, _sort_p)(src)); \
|
||||
M_GET_IT_FIRST cont_oplist (itSrc, src); \
|
||||
M_GET_IT_FIRST cont_oplist (itDst, dst); \
|
||||
/* TODO: Not optimized at all for array ! O(n^2) */ \
|
||||
@@ -476,7 +493,6 @@
|
||||
, /* NO IT_REMOVE */ ), /* NO CMP */) \
|
||||
|
||||
|
||||
//TODO: const_iterator missing...
|
||||
//TODO: Algorithm missing
|
||||
// nth_element ( http://softwareengineering.stackexchange.com/questions/284767/kth-selection-routine-floyd-algorithm-489 )
|
||||
//, average, find_if, count_if, ...
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - dynamic ARRAY module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -378,6 +378,15 @@
|
||||
ARRAYI_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _pop_until)(array_t v, array_it_t pos) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
assert (v == pos->array); \
|
||||
M_ASSUME (pos->index <= v->size); \
|
||||
M_C(name, _resize)(v, pos->index); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const array_t v) \
|
||||
{ \
|
||||
@@ -622,14 +631,103 @@
|
||||
func_void = (int (*)(const void*, const void*))func_type; \
|
||||
qsort (l->ptr, l->size, sizeof(type), func_void); \
|
||||
} \
|
||||
,) /* IF CMP oplist */ \
|
||||
\
|
||||
M_IF_METHOD(SWAP, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _special_stable_sort_noalloc) (type tab[], size_t size, type tmp[]) \
|
||||
{ \
|
||||
size_t th = 4; \
|
||||
M_IF_DEBUG(type *org_tab = tab;) \
|
||||
assert (size > 1); \
|
||||
/* Let's select the threshold of the pass 1 to be sure \
|
||||
the final result is in tab.*/ \
|
||||
if (m_core_clz(size-1) & 1) \
|
||||
th += th; \
|
||||
\
|
||||
/* Pass 1: insertion sort (stable) */ \
|
||||
for(size_t k = 0 ; k < size; ) { \
|
||||
size_t max = size - k < 2*th ? size - k : th; \
|
||||
M_ASSUME(max >= th); \
|
||||
for(size_t i = 1; i < max; i++) { \
|
||||
size_t j = i; \
|
||||
while (j > 0 && M_GET_CMP oplist (tab[k+j-1], tab[k+j]) > 0) { \
|
||||
M_GET_SWAP oplist (tab[k+j-1], tab[k+j]); \
|
||||
j = j - 1; \
|
||||
} \
|
||||
} \
|
||||
k += max; \
|
||||
} \
|
||||
\
|
||||
/* N Pass of merge */ \
|
||||
while (th < size) { \
|
||||
type *dest = tmp; \
|
||||
/* Pass n: Merge */ \
|
||||
for(size_t k = 0 ; k < size; ) { \
|
||||
type *el1 = &tab[k]; \
|
||||
type *el2 = &tab[k+th]; \
|
||||
size_t n1 = th; \
|
||||
size_t n2 = size-k <= 3*th ? size-k-th : th; \
|
||||
assert (size-k > th); \
|
||||
assert (0 < n1 && n1 <= size); \
|
||||
assert (0 < n2 && n2 <= size); \
|
||||
k += n1+n2; \
|
||||
for (;;) { \
|
||||
if (M_GET_CMP oplist (*el1, *el2) <= 0) { \
|
||||
M_GET_SET oplist (*dest, *el1); \
|
||||
dest++; \
|
||||
el1++; \
|
||||
if (-- n1 == 0) { \
|
||||
if (n2 > 0) { \
|
||||
memcpy (dest, el2, n2 * sizeof (type)); \
|
||||
dest += n2; \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
} else { \
|
||||
M_GET_SET oplist (*dest, *el2); \
|
||||
dest++; \
|
||||
el2++; \
|
||||
if (-- n2 == 0) { \
|
||||
if (n1 > 0) { \
|
||||
memcpy (dest, el1, n1 * sizeof (type)); \
|
||||
dest += n1; \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
/* Swap t & tab */ \
|
||||
M_SWAP(type *, tab, tmp); \
|
||||
/* Increase th for next pass */ \
|
||||
th += th; \
|
||||
} \
|
||||
assert (org_tab == tab); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _special_stable_sort)(array_t l) \
|
||||
{ \
|
||||
if (M_UNLIKELY (l->size < 2)) \
|
||||
return; \
|
||||
type *temp = M_GET_REALLOC oplist (type, NULL, l->size); \
|
||||
if (temp == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (type) * l->size); \
|
||||
return ; \
|
||||
} \
|
||||
M_C(name, _special_stable_sort_noalloc)(l->ptr, l->size, temp); \
|
||||
M_GET_FREE oplist(temp); \
|
||||
} \
|
||||
,) /* IF SWAP method */ \
|
||||
\
|
||||
,) /* IF CMP oplist */ \
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, array_t array, \
|
||||
bool append) \
|
||||
{ \
|
||||
STRING_CONTRACT(str); \
|
||||
STRINGI_CONTRACT(str); \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
array_it_t it; \
|
||||
@@ -642,7 +740,7 @@
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
STRING_CONTRACT(str); \
|
||||
STRINGI_CONTRACT(str); \
|
||||
} \
|
||||
, /* no GET_STR */ ) \
|
||||
\
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin stdatomic wrapper for C++ compatibility
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -201,7 +201,7 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
#define atomic_fetch_and(ptr, val) atomic_fetch_op(ptr, val, &=)
|
||||
#define atomic_exchange(ptr, val) atomic_fetch_op(ptr, val, =)
|
||||
|
||||
#define ATOMIC_VAR_INIT(val) { val, 0, 0, 0, M_MUTEXI_INIT_VALUE }
|
||||
#define ATOMIC_VAR_INIT(val) { val, 0, 0, M_MUTEXI_INIT_VALUE }
|
||||
|
||||
#define atomic_init(ptr, val) \
|
||||
(m_mutex_init((ptr)->__lock), (ptr)->__val = val, (ptr)->__zero = 0)
|
||||
|
||||
+6
-6
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - BITSET module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -145,11 +145,11 @@ bitset_set_at(bitset_t v, size_t i, bool x)
|
||||
{
|
||||
BITSETI_CONTRACT(v);
|
||||
assert (i < v->size && v->ptr != NULL);
|
||||
size_t offset = i / BITSET_LIMB_BIT;
|
||||
size_t index = i % BITSET_LIMB_BIT;
|
||||
// This is a branchless version as x can only be 0 or 1.
|
||||
v->ptr[offset] &= ~(((bitset_limb)1)<<index);
|
||||
v->ptr[offset] |= ((bitset_limb)x)<<index;
|
||||
const size_t offset = i / BITSET_LIMB_BIT;
|
||||
const size_t index = i % BITSET_LIMB_BIT;
|
||||
// This is a branchless version as x can only be 0 or 1 with only one variable shift.
|
||||
const size_t mask = (bitset_limb)1<<index;
|
||||
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (-(bitset_limb)x));
|
||||
BITSETI_CONTRACT (v);
|
||||
}
|
||||
|
||||
|
||||
+304
-84
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Fixed size BUFFER & STACK interface
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -50,14 +50,14 @@ typedef enum {
|
||||
BUFFER_DEFERRED_POP = 64
|
||||
} buffer_policy_e;
|
||||
|
||||
/* Define a buffer.
|
||||
/* Define a lock based buffer.
|
||||
USAGE: BUFFER_DEF(name, type, size_of_buffer_or_0, policy[, oplist]) */
|
||||
#define BUFFER_DEF(name, type, m_size, ... ) \
|
||||
BUFFERI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, type, m_size,__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t)), \
|
||||
(name, type, m_size,__VA_ARGS__, M_C(name,_t))))
|
||||
|
||||
/* Define a queue for Many Producer Many Consummer
|
||||
/* Define a lock-free queue for Many Producer Many Consummer
|
||||
Much faster than queue of BUFFER_DEF in heavy communication scenario
|
||||
Size of created queue can only a power of 2.
|
||||
*/
|
||||
@@ -66,19 +66,18 @@ typedef enum {
|
||||
((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t)), \
|
||||
(name, type, __VA_ARGS__, M_C(name,_t))))
|
||||
|
||||
/* Define a wait-free queue for Single Producer Single Consummer
|
||||
Much faster than queue of BUFFER_DEF in heavy communication scenario
|
||||
Size of created queue can only a power of 2.
|
||||
*/
|
||||
#define QUEUE_SPSC_DEF(name, type, ...) \
|
||||
QUEUEI_SPSC_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t)), \
|
||||
(name, type, __VA_ARGS__, M_C(name,_t))))
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Define the exclusion size so that 2 atomic variables can be in
|
||||
separate cache line. This prevent false sharing to occur within the
|
||||
CPU cache. */
|
||||
#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
|
||||
# define BUFFERI_ALIGN_FOR_CACHELINE_EXCLUSION 128
|
||||
#else
|
||||
# define BUFFERI_ALIGN_FOR_CACHELINE_EXCLUSION 64
|
||||
#endif
|
||||
|
||||
#define BUFFERI_IF_CTE_SIZE(m_size) M_IF(M_BOOL(m_size))
|
||||
#define BUFFERI_SIZE(m_size) BUFFERI_IF_CTE_SIZE(m_size) (m_size, v->size)
|
||||
|
||||
@@ -92,8 +91,6 @@ typedef enum {
|
||||
|
||||
#define BUFFERI_PROTECTED_CONTRACT(buffer, size) do { \
|
||||
assert (atomic_load(&buffer->number[0]) <= BUFFERI_SIZE(size)); \
|
||||
assert (buffer->idx_prod <= BUFFERI_SIZE(size)); \
|
||||
assert (buffer->idx_cons <= BUFFERI_SIZE(size)); \
|
||||
} while (0)
|
||||
|
||||
#define BUFFERI_DEF(arg) BUFFERI_DEF2 arg
|
||||
@@ -101,35 +98,38 @@ typedef enum {
|
||||
#define BUFFERI_DEF2(name, type, m_size, policy, oplist, buffer_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
m_mutex_t mutex; \
|
||||
m_mutex_t mutexPush; \
|
||||
m_mutex_t mutexPop; \
|
||||
m_cond_t there_is_data; \
|
||||
m_cond_t there_is_room_for_data; \
|
||||
BUFFERI_IF_CTE_SIZE(m_size)( ,size_t size;) \
|
||||
size_t idx_prod, idx_cons, overwrite; \
|
||||
atomic_ulong number[1 + BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)]; \
|
||||
type *data; \
|
||||
BUFFERI_IF_CTE_SIZE(m_size)(type data[m_size], type *data); \
|
||||
} buffer_t[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(buffer_t v, size_t size) \
|
||||
{ \
|
||||
assert( size > 0); \
|
||||
BUFFERI_IF_CTE_SIZE(m_size)(assert(size == m_size), v->size = size); \
|
||||
v->idx_prod = v->idx_cons = v->overwrite = 0; \
|
||||
atomic_init (&v->number[0], 0UL); \
|
||||
if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
|
||||
atomic_init (&v->number[1], 0UL); \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_init(v->mutex); \
|
||||
m_mutex_init(v->mutexPush); \
|
||||
m_mutex_init(v->mutexPop); \
|
||||
m_cond_init(v->there_is_data); \
|
||||
m_cond_init(v->there_is_room_for_data); \
|
||||
} else \
|
||||
assert(BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING)); \
|
||||
v->data = M_GET_REALLOC oplist (type, NULL, BUFFERI_SIZE(m_size)); \
|
||||
if (v->data == NULL) { \
|
||||
M_MEMORY_FULL (BUFFERI_SIZE(m_size)*sizeof(type)); \
|
||||
return; \
|
||||
} \
|
||||
BUFFERI_IF_CTE_SIZE(m_size)( , \
|
||||
v->data = M_GET_REALLOC oplist (type, NULL, BUFFERI_SIZE(m_size)); \
|
||||
if (v->data == NULL) { \
|
||||
M_MEMORY_FULL (BUFFERI_SIZE(m_size)*sizeof(type)); \
|
||||
return; \
|
||||
} \
|
||||
) \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
for(size_t i = 0; i < size; i++) { \
|
||||
M_GET_INIT oplist(v->data[i]); \
|
||||
@@ -167,11 +167,14 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
{ \
|
||||
BUFFERI_CONTRACT(v,m_size); \
|
||||
M_C(name, _int_clear_obj)(v); \
|
||||
M_GET_FREE oplist (v->data); \
|
||||
v->data = NULL; \
|
||||
BUFFERI_IF_CTE_SIZE(m_size)( , \
|
||||
M_GET_FREE oplist (v->data); \
|
||||
v->data = NULL; \
|
||||
) \
|
||||
v->overwrite = 0; \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_clear(v->mutex); \
|
||||
m_mutex_clear(v->mutexPush); \
|
||||
m_mutex_clear(v->mutexPop); \
|
||||
m_cond_clear(v->there_is_data); \
|
||||
m_cond_clear(v->there_is_room_for_data); \
|
||||
} \
|
||||
@@ -181,8 +184,10 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_C(name, _clean)(buffer_t v) \
|
||||
{ \
|
||||
BUFFERI_CONTRACT(v,m_size); \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) \
|
||||
m_mutex_lock(v->mutex); \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_lock(v->mutexPush); \
|
||||
m_mutex_lock(v->mutexPop); \
|
||||
} \
|
||||
BUFFERI_PROTECTED_CONTRACT(v, m_size); \
|
||||
if (BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) \
|
||||
M_C(name, _int_clear_obj)(v); \
|
||||
@@ -191,8 +196,9 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
|
||||
atomic_store(&v->number[1], 0UL); \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
m_cond_signal(v->there_is_room_for_data); \
|
||||
m_mutex_unlock(v->mutex); \
|
||||
m_cond_broadcast(v->there_is_room_for_data); \
|
||||
m_mutex_unlock(v->mutexPop); \
|
||||
m_mutex_unlock(v->mutexPush); \
|
||||
} \
|
||||
BUFFERI_CONTRACT(v,m_size); \
|
||||
} \
|
||||
@@ -201,6 +207,10 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_C(name, _empty_p)(buffer_t v) \
|
||||
{ \
|
||||
BUFFERI_CONTRACT(v,m_size); \
|
||||
/* If the buffer has been configured with deferred pop \
|
||||
we considered the queue as empty when the number of \
|
||||
deferred pop has reached 0, not the number of items in the \
|
||||
buffer is 0. */ \
|
||||
if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \
|
||||
return atomic_load (&v->number[1]) == 0; \
|
||||
else \
|
||||
@@ -222,63 +232,80 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _push)(buffer_t v, type const data) \
|
||||
M_C(name, _push_blocking)(buffer_t v, type const data, bool blocking) \
|
||||
{ \
|
||||
BUFFERI_CONTRACT(v,m_size); \
|
||||
\
|
||||
/* BUFFER lock */ \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_lock(v->mutex); \
|
||||
m_mutex_lock(v->mutexPush); \
|
||||
while (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \
|
||||
&& M_C(name, _full_p)(v)) { \
|
||||
if (BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING_PUSH)) { \
|
||||
m_mutex_unlock(v->mutex); \
|
||||
if (!blocking) { \
|
||||
m_mutex_unlock(v->mutexPush); \
|
||||
return false; \
|
||||
} \
|
||||
m_cond_wait(v->there_is_room_for_data, v->mutex); \
|
||||
m_cond_wait(v->there_is_room_for_data, v->mutexPush); \
|
||||
} \
|
||||
} else if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \
|
||||
&& M_C(name, _full_p)(v)) \
|
||||
return false; \
|
||||
BUFFERI_PROTECTED_CONTRACT(v, m_size); \
|
||||
\
|
||||
size_t previousSize, idx = v->idx_prod; \
|
||||
/* INDEX computation if we have to overwrite the last element */ \
|
||||
if (M_UNLIKELY (BUFFERI_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \
|
||||
&& atomic_load (&v->number[0]) == BUFFERI_SIZE(m_size) )) { \
|
||||
&& M_C(name, _full_p)(v))) { \
|
||||
v->overwrite++; \
|
||||
/* Let's clear the last element to overwrite it */ \
|
||||
/* Let's overwrite the last element */ \
|
||||
/* Compute the index of the last push element */ \
|
||||
idx--; \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \
|
||||
v->idx_prod = (v->idx_prod - 1) % BUFFERI_SIZE(m_size); \
|
||||
idx = (idx == -1U) ? BUFFERI_SIZE(m_size)-1 : idx; \
|
||||
} \
|
||||
/* Update data in the buffer */ \
|
||||
M_GET_SET oplist (v->data[idx], data); \
|
||||
previousSize = BUFFERI_SIZE(m_size); \
|
||||
\
|
||||
} else { \
|
||||
\
|
||||
/* Add a new item in the buffer */ \
|
||||
/* PUSH data in the buffer */ \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_GET_SET oplist (v->data[idx], data); \
|
||||
} else { \
|
||||
(v->idx_prod) --; \
|
||||
M_GET_INIT_SET oplist(v->data[idx], data); \
|
||||
} \
|
||||
atomic_store (&v->number[0], atomic_load(&v->number[0]) - 1); \
|
||||
if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) \
|
||||
atomic_store (&v->number[1], atomic_load(&v->number[1]) - 1); \
|
||||
if (BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_GET_CLEAR oplist(v->data[v->idx_prod]); \
|
||||
\
|
||||
/* Increment production INDEX of the buffer */ \
|
||||
idx++; \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \
|
||||
idx = (idx == BUFFERI_SIZE(m_size)) ? 0 : idx; \
|
||||
} \
|
||||
v->idx_prod = idx; \
|
||||
\
|
||||
/* number[] is the only variable which can be modified by both \
|
||||
the consummer thread which has the pop lock and the producer \
|
||||
thread which has the push lock. As such, it has to be handled \
|
||||
like an atomic variable. */ \
|
||||
/* Increment number of elements of the buffer */ \
|
||||
previousSize = atomic_fetch_add (&v->number[0], 1UL); \
|
||||
if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \
|
||||
previousSize = atomic_fetch_add (&v->number[1], 1UL); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* PUSH data */ \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_GET_SET oplist (v->data[v->idx_prod], data); \
|
||||
} else { \
|
||||
M_GET_INIT_SET oplist(v->data[v->idx_prod], data); \
|
||||
} \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \
|
||||
v->idx_prod = (v->idx_prod +1) % BUFFERI_SIZE(m_size); \
|
||||
} else { \
|
||||
(v->idx_prod) ++; \
|
||||
} \
|
||||
atomic_store (&v->number[0], atomic_load(&v->number[0]) + 1); \
|
||||
if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) \
|
||||
atomic_store (&v->number[1], atomic_load(&v->number[1]) + 1); \
|
||||
\
|
||||
/* BUFFER unlock */ \
|
||||
/* BUFFER unlock */ \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
m_cond_signal(v->there_is_data); \
|
||||
m_mutex_unlock(v->mutex); \
|
||||
m_mutex_unlock(v->mutexPush); \
|
||||
/* If the number of items in the buffer was 0, some consummer \
|
||||
may be waiting. Signal to them the availibility of the data \
|
||||
We cannot only signal one thread. */ \
|
||||
if (previousSize == 0) { \
|
||||
m_mutex_lock(v->mutexPop); \
|
||||
m_cond_broadcast(v->there_is_data); \
|
||||
m_mutex_unlock(v->mutexPop); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
BUFFERI_CONTRACT(v,m_size); \
|
||||
@@ -286,34 +313,36 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _pop)(type *data, buffer_t v) \
|
||||
M_C(name, _pop_blocking)(type *data, buffer_t v, bool blocking) \
|
||||
{ \
|
||||
BUFFERI_CONTRACT(v,m_size); \
|
||||
assert (data != NULL); \
|
||||
\
|
||||
/* BUFFER lock */ \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
m_mutex_lock(v->mutex); \
|
||||
m_mutex_lock(v->mutexPop); \
|
||||
while (M_C(name, _empty_p)(v)) { \
|
||||
if (BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING_POP)) { \
|
||||
m_mutex_unlock(v->mutex); \
|
||||
if (!blocking) { \
|
||||
m_mutex_unlock(v->mutexPop); \
|
||||
return false; \
|
||||
} \
|
||||
m_cond_wait(v->there_is_data, v->mutex); \
|
||||
m_cond_wait(v->there_is_data, v->mutexPop); \
|
||||
} \
|
||||
} else if (M_C(name, _empty_p)(v)) \
|
||||
return false; \
|
||||
BUFFERI_PROTECTED_CONTRACT(v, m_size); \
|
||||
\
|
||||
/* POP data */ \
|
||||
/* POP data from the buffer and update INDEX */ \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \
|
||||
/* FIFO queue */ \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_GET_SET oplist (*data, v->data[v->idx_cons]); \
|
||||
} else { \
|
||||
M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_cons]); \
|
||||
} \
|
||||
v->idx_cons = (v->idx_cons +1) % BUFFERI_SIZE(m_size); \
|
||||
v->idx_cons = (v->idx_cons == BUFFERI_SIZE(m_size)-1) ? 0 : (v->idx_cons + 1); \
|
||||
} else { \
|
||||
/* STACK queue */ \
|
||||
v->idx_prod --; \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_GET_SET oplist (*data, v->data[v->idx_prod]); \
|
||||
@@ -321,20 +350,52 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_prod]); \
|
||||
} \
|
||||
} \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) \
|
||||
atomic_store (&v->number[0], atomic_load(&v->number[0]) - 1); \
|
||||
else \
|
||||
atomic_store (&v->number[1], atomic_load(&v->number[1]) - 1); \
|
||||
\
|
||||
/* number[] is the only variable which can be modified by both \
|
||||
the consummer thread which has the pop lock and the producer \
|
||||
thread which has the push lock. As such, it has to be handled \
|
||||
like an atomic variable. */ \
|
||||
/* Decrement number of elements in the buffer */ \
|
||||
size_t previousSize; \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \
|
||||
previousSize = atomic_fetch_sub (&v->number[0], 1UL); \
|
||||
} else { \
|
||||
atomic_fetch_sub (&v->number[1], 1UL); \
|
||||
} \
|
||||
\
|
||||
/* BUFFER unlock */ \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \
|
||||
m_cond_signal(v->there_is_room_for_data); \
|
||||
m_mutex_unlock(v->mutex); \
|
||||
m_mutex_unlock(v->mutexPop); \
|
||||
/* If the number of items in the buffer was the max, some producer \
|
||||
may be waiting. Signal to them the availibility of the free room \
|
||||
We cannot only signal one thread. */ \
|
||||
if ((!BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) \
|
||||
&& previousSize == BUFFERI_SIZE(m_size)) { \
|
||||
m_mutex_lock(v->mutexPush); \
|
||||
m_cond_broadcast(v->there_is_room_for_data); \
|
||||
m_mutex_unlock(v->mutexPush); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
BUFFERI_CONTRACT(v,m_size); \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _push)(buffer_t v, type const data) \
|
||||
{ \
|
||||
return M_C(name, _push_blocking)(v, data, \
|
||||
!BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING_PUSH)); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _pop)(type *data, buffer_t v) \
|
||||
{ \
|
||||
return M_C(name, _pop_blocking)(data, v, \
|
||||
!BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING_POP)); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _overwrite)(const buffer_t v) \
|
||||
{ \
|
||||
@@ -351,8 +412,15 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
static inline void \
|
||||
M_C(name, _pop_release)(buffer_t v) \
|
||||
{ \
|
||||
if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) \
|
||||
atomic_store (&v->number[0], atomic_load(&v->number[0]) - 1); \
|
||||
/* Decrement the effective number of elements in the buffer */ \
|
||||
if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \
|
||||
size_t previousSize = atomic_fetch_sub (&v->number[0], 1UL); \
|
||||
if (previousSize == BUFFERI_SIZE(m_size)) { \
|
||||
m_mutex_lock(v->mutexPush); \
|
||||
m_cond_broadcast(v->there_is_room_for_data); \
|
||||
m_mutex_unlock(v->mutexPush); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
|
||||
|
||||
@@ -369,12 +437,20 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
*/
|
||||
#define QUEUEI_MPMC_DEF(arg) QUEUEI_MPMC_DEF2 arg
|
||||
|
||||
#define QUEUEI_MPMC_CONTRACT(v) do { \
|
||||
#ifdef NDEBUG
|
||||
# define QUEUEI_MPMC_CONTRACT(v) /* nothing */
|
||||
#else
|
||||
# define QUEUEI_MPMC_CONTRACT(v) do { \
|
||||
assert (v != 0); \
|
||||
assert (v->Tab != NULL); \
|
||||
/* ProdIdx >= ConsoIdx, but due to atomic constraints, we can't check it reliabely */ \
|
||||
unsigned long long _r = atomic_load(&v->ConsoIdx); \
|
||||
unsigned long long _w = atomic_load(&v->ProdIdx); \
|
||||
assert (_r <= _w); \
|
||||
_r = atomic_load(&v->ConsoIdx); \
|
||||
assert (_r > _w || _w-_r <= v->size); \
|
||||
assert (M_POWEROF2_P(v->size)); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define QUEUEI_MPMC_DEF2(name, type, policy, oplist, buffer_t) \
|
||||
\
|
||||
@@ -385,14 +461,14 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
typedef struct M_C(name, _el_s) { \
|
||||
atomic_ullong seq; /* Can only increase. */ \
|
||||
type x; \
|
||||
char align[BUFFERI_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(atomic_ullong)+sizeof(type) ? BUFFERI_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(atomic_ullong)-sizeof(type) : 1]; \
|
||||
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(atomic_ullong)+sizeof(type) ? M_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(atomic_ullong)-sizeof(type) : 1]; \
|
||||
} M_C(name, _el_t); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
atomic_ullong ProdIdx; /* Can only increase */ \
|
||||
char align1[BUFFERI_ALIGN_FOR_CACHELINE_EXCLUSION]; \
|
||||
char align1[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
|
||||
atomic_ullong ConsoIdx; /* can only increase */ \
|
||||
char align2[BUFFERI_ALIGN_FOR_CACHELINE_EXCLUSION]; \
|
||||
char align2[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
|
||||
M_C(name, _el_t) *Tab; \
|
||||
unsigned int size; \
|
||||
} buffer_t[1]; \
|
||||
@@ -426,6 +502,7 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
M_C(name, _pop)(type *ptr, buffer_t table) \
|
||||
{ \
|
||||
QUEUEI_MPMC_CONTRACT(table); \
|
||||
assert (ptr != NULL); \
|
||||
unsigned long long iC = atomic_load(&table->ConsoIdx); \
|
||||
const unsigned int i = (iC & (table->size -1)); \
|
||||
const unsigned long long seq = atomic_load(&table->Tab[i].seq); \
|
||||
@@ -512,19 +589,162 @@ M_C(name, _init)(buffer_t v, size_t size) \
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(buffer_t v) \
|
||||
{ \
|
||||
QUEUEI_MPMC_CONTRACT(v); \
|
||||
return M_C(name, _size) (v) == 0; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _full_p)(buffer_t v) \
|
||||
{ \
|
||||
QUEUEI_MPMC_CONTRACT(v); \
|
||||
return M_C(name, _size)(v) == v->size; \
|
||||
} \
|
||||
|
||||
|
||||
|
||||
/* Definition of a a QUEUE for Single Produccer / Single Consummer
|
||||
for high bandwidth scenario:
|
||||
* wait-free,
|
||||
* quite fast
|
||||
* no blocking calls.
|
||||
* only queue (no stack)
|
||||
* size of queue is always a power of 2
|
||||
* no overwriting.
|
||||
*/
|
||||
#define QUEUEI_SPSC_DEF(arg) QUEUEI_SPSC_DEF2 arg
|
||||
|
||||
#define QUEUEI_SPSC_CONTRACT(table) do { \
|
||||
assert (table != NULL); \
|
||||
unsigned long long _r = atomic_load(&table->consoIdx); \
|
||||
unsigned long long _w = atomic_load(&table->prodIdx); \
|
||||
assert (_r <= _w); \
|
||||
_r = atomic_load(&table->consoIdx); \
|
||||
assert (_r > _w || _w-_r <= table->size); \
|
||||
assert (M_POWEROF2_P(table->size)); \
|
||||
} while (0)
|
||||
|
||||
#define QUEUEI_SPSC_DEF2(name, type, policy, oplist, buffer_t) \
|
||||
\
|
||||
/* Not sure if the alignment constraint is needed */ \
|
||||
typedef struct M_C(name, _el_s) { \
|
||||
type x; \
|
||||
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(type) ? M_ALIGN_FOR_CACHELINE_EXCLUSION -sizeof(type) : 1]; \
|
||||
} M_C(name, _el_t); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
atomic_ullong consoIdx; \
|
||||
size_t size; \
|
||||
M_C(name, _el_t) *Tab; \
|
||||
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(atomic_ullong) +sizeof(size_t) +sizeof(void*) ? M_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(atomic_ullong) -sizeof(size_t)-sizeof(void*): 1]; \
|
||||
atomic_ullong prodIdx; \
|
||||
} buffer_t[1]; \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _push)(buffer_t table, type x) \
|
||||
{ \
|
||||
QUEUEI_SPSC_CONTRACT(table); \
|
||||
unsigned long long r = atomic_load(&table->consoIdx); \
|
||||
unsigned long long w = atomic_load(&table->prodIdx); \
|
||||
if (w-r == table->size) \
|
||||
return false; \
|
||||
size_t i = w & (table->size -1); \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_GET_SET oplist (table->Tab[i].x, x); \
|
||||
} else { \
|
||||
M_GET_INIT_SET oplist (table->Tab[i].x, x); \
|
||||
} \
|
||||
atomic_store(&table->prodIdx, w+1); \
|
||||
QUEUEI_SPSC_CONTRACT(table); \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _pop)(type *ptr, buffer_t table) \
|
||||
{ \
|
||||
QUEUEI_SPSC_CONTRACT(table); \
|
||||
assert (ptr != NULL); \
|
||||
unsigned long long w = atomic_load(&table->prodIdx); \
|
||||
unsigned long long r = atomic_load(&table->consoIdx); \
|
||||
if (w-r == 0) \
|
||||
return false; \
|
||||
size_t i = r & (table->size -1); \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
M_GET_SET oplist (*ptr , table->Tab[i].x); \
|
||||
} else { \
|
||||
M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \
|
||||
} \
|
||||
atomic_store(&table->consoIdx, r+1); \
|
||||
QUEUEI_SPSC_CONTRACT(table); \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(buffer_t table) \
|
||||
{ \
|
||||
QUEUEI_SPSC_CONTRACT(table); \
|
||||
unsigned long long r = atomic_load(&table->consoIdx); \
|
||||
unsigned long long w = atomic_load(&table->prodIdx); \
|
||||
return w-r; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(buffer_t v) \
|
||||
{ \
|
||||
return M_C(name, _size) (v) == 0; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _full_p)(buffer_t v) \
|
||||
{ \
|
||||
return M_C(name, _size)(v) == v->size; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(buffer_t buffer, size_t size) \
|
||||
{ \
|
||||
assert (buffer != NULL); \
|
||||
assert( M_POWEROF2_P(size)); \
|
||||
assert(((policy) & (BUFFER_STACK|BUFFER_THREAD_UNSAFE|BUFFER_PUSH_OVERWRITE)) == 0); \
|
||||
atomic_init(&buffer->prodIdx, (unsigned long long) size); \
|
||||
atomic_init(&buffer->consoIdx, (unsigned long long) size); \
|
||||
buffer->size = size; \
|
||||
buffer->Tab = M_GET_REALLOC oplist (M_C(name, _el_t), NULL, size); \
|
||||
if (buffer->Tab == NULL) { \
|
||||
M_MEMORY_FULL (size*sizeof(M_C(name, _el_t) )); \
|
||||
return; \
|
||||
} \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
for(size_t j = 0; j < size; j++) { \
|
||||
M_GET_INIT oplist (buffer->Tab[j].x); \
|
||||
} \
|
||||
} \
|
||||
QUEUEI_SPSC_CONTRACT(buffer); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(buffer_t buffer) \
|
||||
{ \
|
||||
QUEUEI_SPSC_CONTRACT(buffer); \
|
||||
if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \
|
||||
for(unsigned int j = 0; j < buffer->size; j++) { \
|
||||
M_GET_CLEAR oplist (buffer->Tab[j].x); \
|
||||
} \
|
||||
} else { \
|
||||
unsigned long long iP = atomic_load(&buffer->prodIdx); \
|
||||
unsigned int i = iP & (buffer->size -1); \
|
||||
unsigned long long iC = atomic_load(&buffer->consoIdx); \
|
||||
unsigned int j = iC & (buffer->size -1); \
|
||||
while (i != j) { \
|
||||
M_GET_CLEAR oplist(buffer->Tab[j].x); \
|
||||
j++; \
|
||||
if (j >= buffer->size) \
|
||||
j = 0; \
|
||||
} \
|
||||
} \
|
||||
M_GET_FREE oplist (buffer->Tab); \
|
||||
buffer->Tab = NULL; /* safer */ \
|
||||
} \
|
||||
\
|
||||
|
||||
|
||||
// NOTE: SET & INIT_SET are deliberatly missing. TBC if it the right way.
|
||||
// NOTE: There is no oplist defined for this container.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Extended Pre-processing macros module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -42,7 +42,7 @@
|
||||
#if !defined(NDEBUG)
|
||||
# define M_ASSUME(x) assert(x)
|
||||
#elif defined(__GNUC__) \
|
||||
&& (__GNUC__ * 100 + __GNUC_MINOR__) >= 480
|
||||
&& (__GNUC__ * 100 + __GNUC_MINOR__) >= 408
|
||||
# define M_ASSUME(x) \
|
||||
(! __builtin_constant_p (!!(x) || !(x)) || (x) ? \
|
||||
(void) 0 : __builtin_unreachable())
|
||||
@@ -62,6 +62,14 @@
|
||||
# define M_UNLIKELY(cond) (cond)
|
||||
#endif
|
||||
|
||||
/* Define the exclusion size so that 2 atomic variables can be in
|
||||
separate cache line. This prevents false sharing to occur within the
|
||||
CPU cache. */
|
||||
#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
|
||||
# define M_ALIGN_FOR_CACHELINE_EXCLUSION 128
|
||||
#else
|
||||
# define M_ALIGN_FOR_CACHELINE_EXCLUSION 64
|
||||
#endif
|
||||
|
||||
/***************************************************************/
|
||||
/****************** Preprocessing Times Macro ******************/
|
||||
@@ -967,6 +975,19 @@
|
||||
#define M_IF_DEFAULT1(value, ...) \
|
||||
__VA_ARGS__ M_IF_NARGS_EQ1(__VA_ARGS__)(M_DEFERRED_COMMA value, )
|
||||
|
||||
/* Helper macro to redefine a function with a default values:
|
||||
Give the number of expected arguments, the value list of the
|
||||
default argument, and the arguments.
|
||||
It will complete the arguments with the value of the default
|
||||
argument to complete up to 'expected' arguments.
|
||||
Example:
|
||||
#define f(...) f(M_DEFAULT_ARGS(4, (0, 1, NULL), __VA_ARGS__))
|
||||
*/
|
||||
#define M_DEFAULT_ARGS2(expected, value, ...) \
|
||||
__VA_ARGS__ M_IF(M_NOTEQUAL(M_NARGS(__VA_ARGS__), expected))(M_DEFERRED_COMMA, ) \
|
||||
M_ID M_INVERT(M_KEEP(M_SUB(expected, M_NARGS(__VA_ARGS__)), M_ID M_INVERT value))
|
||||
#define M_DEFAULT_ARGS_EVAL(...) __VA_ARGS__
|
||||
#define M_DEFAULT_ARGS( ...) M_DEFAULT_ARGS_EVAL(M_DEFAULT_ARGS2(__VA_ARGS__))
|
||||
|
||||
/* NOTEQUAL(val1,val2) with val from [0 to 30[
|
||||
Return 1 or 0 if val1=val2
|
||||
@@ -1142,9 +1163,9 @@
|
||||
|
||||
/* Swap two types */
|
||||
#define M_SWAP(type, x, y) do { \
|
||||
type tmp = (x); \
|
||||
(x) = (y); \
|
||||
(y) = tmp; \
|
||||
type _tmp = (x); \
|
||||
(x) = (y); \
|
||||
(y) = _tmp; \
|
||||
} while (0)
|
||||
|
||||
/* Check if 'n' is assignable to an object of type 'type'.
|
||||
@@ -1181,6 +1202,8 @@
|
||||
#define M_TYPE_FROM_FIELD(type, ptr, field_type, field) \
|
||||
((type *)(void*)( (char *)M_ASSIGN_CAST(field_type*, (ptr)) - offsetof(type, field) ))
|
||||
|
||||
#define M_CTYPE_FROM_FIELD(type, ptr, field_type, field) \
|
||||
((const type *)(const void*)( (const char *)M_ASSIGN_CAST(const field_type*, (ptr)) - offsetof(const type, field) ))
|
||||
|
||||
|
||||
/************************************************************/
|
||||
@@ -1427,6 +1450,8 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_SUBTYPE_SUBTYPE(a) ,a,
|
||||
#define M_OPLIST_OPLIST(a) ,a,
|
||||
#define M_SORT_SORT(a) ,a,
|
||||
#define M_GET_KEY_GET_KEY(a) ,a,
|
||||
#define M_SET_KEY_SET_KEY(a) ,a,
|
||||
#define M_UPDATE_UPDATE(a) ,a,
|
||||
#define M_IT_TYPE_IT_TYPE(a) ,a,
|
||||
#define M_IT_FIRST_IT_FIRST(a) ,a,
|
||||
@@ -1490,6 +1515,8 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_GET_SUBTYPE(...) M_GET_METHOD(SUBTYPE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_OPLIST(...) M_GET_METHOD(OPLIST, (), __VA_ARGS__)
|
||||
#define M_GET_SORT(...) M_GET_METHOD(SORT, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_GET_KEY(...) M_GET_METHOD(GET_KEY, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SET_KEY(...) M_GET_METHOD(SET_KEY, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_TYPE(...) M_GET_METHOD(IT_TYPE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_FIRST(...) M_GET_METHOD(IT_FIRST, M_NO_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_IT_LAST(...) M_GET_METHOD(IT_LAST, M_NO_DEFAULT, __VA_ARGS__)
|
||||
@@ -1549,22 +1576,28 @@ m_core_hash (const void *str, size_t length)
|
||||
#define M_MEMSET_DEFAULT(a) (memset(&(a), 0, sizeof (a)))
|
||||
#define M_MEMCMP1_DEFAULT(a,b) (memcmp(&(a), &(b), sizeof (a)) == 0)
|
||||
#define M_MEMCMP2_DEFAULT(a,b) (memcmp(&(a), &(b), sizeof (a)))
|
||||
#define M_SWAP_DEFAULT(el1, el2) do { \
|
||||
char _tmp[sizeof (el1)]; \
|
||||
memcpy(&_tmp, &(el1), sizeof (el1)); \
|
||||
memcpy(&(el1), &(el2), sizeof (el1)); \
|
||||
memcpy(&(el2), &_tmp, sizeof (el1)); \
|
||||
} while (0)
|
||||
|
||||
/* NOTE: Theses operators are to be used with the '[1]' tricks
|
||||
if the variable is defined as a parameter of a function
|
||||
(sizeof (a) is not portable). */
|
||||
#define M_MOVE_A1_DEFAULT(a,b) (M_MEMCPY_A1_DEFAULT(a, b), M_MEMSET_A1_DEFAULT(b))
|
||||
#define M_MEMCPY_A1_DEFAULT(a,b) (memcpy(&(a), &(b), sizeof (a[0])))
|
||||
#define M_MEMSET_A1_DEFAULT(a) (memset(&(a), 0, sizeof (a[0])))
|
||||
#define M_MEMCMP1_A1_DEFAULT(a,b) (memcmp(&(a), &(b), sizeof (a[0])) == 0)
|
||||
#define M_MEMCMP2_A1_DEFAULT(a,b) (memcmp(&(a), &(b), sizeof (a[0])))
|
||||
#define M_HASH_A1_DEFAULT(a) (m_core_hash((const void*) &(a), sizeof (a[0])) )
|
||||
#define M_MEMCPY_A1_DEFAULT(a,b) (memcpy(&(a[0]), &(b[0]), sizeof (a[0])))
|
||||
#define M_MEMSET_A1_DEFAULT(a) (memset(&(a[0]), 0, sizeof (a[0])))
|
||||
#define M_MEMCMP1_A1_DEFAULT(a,b) (memcmp(&(a[0]), &(b[0]), sizeof (a[0])) == 0)
|
||||
#define M_MEMCMP2_A1_DEFAULT(a,b) (memcmp(&(a[0]), &(b[0]), sizeof (a[0])))
|
||||
#define M_HASH_A1_DEFAULT(a) (m_core_hash((const void*) &(a[0]), sizeof (a[0])) )
|
||||
|
||||
/* Default oplist for plain structure */
|
||||
#define M_POD_OPLIST \
|
||||
(INIT(M_MEMSET_DEFAULT), INIT_SET(M_MEMCPY_DEFAULT), SET(M_MEMCPY_DEFAULT), \
|
||||
CLEAR(M_NOTHING_DEFAULT), EQUAL(M_MEMCMP1_DEFAULT), CMP(M_MEMCMP2_DEFAULT), \
|
||||
HASH(M_HASH_DEFAULT))
|
||||
HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT))
|
||||
|
||||
/* Default oplist for a structure defined with an array of size 1 */
|
||||
#define M_A1_OPLIST \
|
||||
@@ -1577,7 +1610,7 @@ m_core_hash (const void *str, size_t length)
|
||||
(INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \
|
||||
CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \
|
||||
INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \
|
||||
HASH(M_HASH_DEFAULT) )
|
||||
HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT) )
|
||||
|
||||
#define M_CLASSIC_OPLIST(name) ( \
|
||||
INIT(M_C(name, _init)), \
|
||||
@@ -1688,7 +1721,7 @@ m_core_hash (const void *str, size_t length)
|
||||
/* Check if a a symbol composed of M_OPL_##a() is defined as an oplist, and returns it
|
||||
otherwise return M_DEFAULT_OPLIST.
|
||||
In short, if a global oplist is defined for the argument, it returns it
|
||||
otherwise it returns the argument.
|
||||
otherwise it returns the default oplist.
|
||||
Global oplist is limited to typedef types.
|
||||
*/
|
||||
#define M_GLOBAL_OPLIST_OR_DEF(a) \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - DEQUE module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -46,6 +46,14 @@
|
||||
|
||||
#define DEQUEUI_DEFAULT_SIZE 8
|
||||
|
||||
/* C++ doesn't support flexible array within a structure.
|
||||
Let's define at least one element. */
|
||||
#ifdef __cplusplus
|
||||
# define DEQUEI_MIN_ARRAY_SIZE 1
|
||||
#else
|
||||
# define DEQUEI_MIN_ARRAY_SIZE
|
||||
#endif
|
||||
|
||||
#define DEQUEI_CONTRACT(d) do { \
|
||||
assert ((d) != NULL); \
|
||||
assert ((d)->default_size >= DEQUEUI_DEFAULT_SIZE); \
|
||||
@@ -66,7 +74,7 @@
|
||||
typedef struct M_C(name, _node_s) { \
|
||||
ILIST_INTERFACE(M_C(name, _node_list), struct M_C(name, _node_s)); \
|
||||
size_t size; \
|
||||
type data[]; \
|
||||
type data[DEQUEI_MIN_ARRAY_SIZE]; \
|
||||
} node_t; \
|
||||
\
|
||||
ILIST_DEF(M_C(name, _node_list), node_t, (DEL(M_GET_FREE oplist)) ) \
|
||||
@@ -92,23 +100,25 @@
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
static inline deque_node_t* \
|
||||
static inline M_C(name, _node_t)* \
|
||||
M_C(name, _int_new_node)(deque_t d) \
|
||||
{ \
|
||||
const size_t def = d->default_size; \
|
||||
if (M_UNLIKELY (def >SIZE_MAX / sizeof (type) - sizeof(deque_node_t))) { \
|
||||
M_MEMORY_FULL(sizeof(deque_node_t)+def * sizeof(type)); \
|
||||
size_t def = d->default_size; \
|
||||
if (M_UNLIKELY (def >SIZE_MAX / sizeof (type) - sizeof(M_C(name, _node_t)))) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _node_t))+def * sizeof(type)); \
|
||||
return NULL; \
|
||||
} \
|
||||
deque_node_t*n = (deque_node_t*) (void*) \
|
||||
M_C(name, _node_t)*n = (M_C(name, _node_t)*) (void*) \
|
||||
M_GET_REALLOC oplist (char, NULL, \
|
||||
sizeof(deque_node_t)+def * sizeof(type) ); \
|
||||
sizeof(M_C(name, _node_t)) + def * sizeof(type) ); \
|
||||
if (n==NULL) { \
|
||||
M_MEMORY_FULL(sizeof(deque_node_t)+def * sizeof(type)); \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _node_t))+def * sizeof(type)); \
|
||||
return NULL; \
|
||||
} \
|
||||
n->size = def; \
|
||||
deque_node_list_init_field(n); \
|
||||
M_C(name, _node_list_init_field)(n); \
|
||||
/* Do not increase it too much if there are few items */ \
|
||||
def = M_MIN(def, d->count); \
|
||||
d->default_size = M_GET_INC_ALLOC oplist (def); \
|
||||
return n; \
|
||||
} \
|
||||
@@ -119,9 +129,9 @@
|
||||
M_C(name, _node_list_init)(d->list); \
|
||||
d->default_size = DEQUEUI_DEFAULT_SIZE; \
|
||||
d->count = 0; \
|
||||
deque_node_t *n = M_C(name, _int_new_node)(d); \
|
||||
M_C(name, _node_t) *n = M_C(name, _int_new_node)(d); \
|
||||
if (n == NULL) return; \
|
||||
deque_node_list_push_back(d->list, n); \
|
||||
M_C(name, _node_list_push_back)(d->list, n); \
|
||||
d->front->node = n; \
|
||||
d->front->index = DEQUEUI_DEFAULT_SIZE/2; \
|
||||
d->back->node = n; \
|
||||
@@ -134,11 +144,11 @@
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_C(name, _node_list_it_t) it; \
|
||||
deque_node_t *min_node = NULL; \
|
||||
M_C(name, _node_t) *min_node = NULL; \
|
||||
for(M_C(name, _node_list_it)(it, d->list) ; \
|
||||
!M_C(name, _node_list_end_p)(it) ; \
|
||||
M_C(name, _node_list_next)(it) ){ \
|
||||
deque_node_t *n = M_C(name, _node_list_ref)(it); \
|
||||
M_C(name, _node_t) *n = M_C(name, _node_list_ref)(it); \
|
||||
size_t min = n == d->front->node ? d->back->index + 1 : 0; \
|
||||
size_t max = n == d->back->node ? d->back->index + 1: n->size; \
|
||||
for(size_t i = min; i < max; i++) { \
|
||||
@@ -172,7 +182,7 @@
|
||||
M_C(name, _push_back_raw)(deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
deque_node_t *n = d->back->node; \
|
||||
M_C(name, _node_t) *n = d->back->node; \
|
||||
size_t index = d->back->index; \
|
||||
if (M_UNLIKELY (n->size <= index)) { \
|
||||
n = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
@@ -215,7 +225,7 @@
|
||||
M_C(name, _push_front_raw)(deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
deque_node_t *n = d->front->node; \
|
||||
M_C(name, _node_t) *n = d->front->node; \
|
||||
size_t index = d->front->index; \
|
||||
index --; \
|
||||
/* If overflow */ \
|
||||
@@ -260,11 +270,20 @@
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
assert(d->count > 0); \
|
||||
deque_node_t *n = d->back->node; \
|
||||
M_C(name, _node_t) *n = d->back->node; \
|
||||
size_t index = d->back->index; \
|
||||
index --; \
|
||||
if (M_UNLIKELY (n->size <= index)) { \
|
||||
n = deque_node_list_previous_obj(d->list, n); \
|
||||
/* If there is a next node, \
|
||||
pop the back node and push it back to the front. This \
|
||||
reduce the used memory if the deque is used as a FIFO queue.*/ \
|
||||
M_C(name, _node_t) *next = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
if (next != NULL) { \
|
||||
next = M_C(name, _node_list_pop_back)(d->list); \
|
||||
assert (next != n); \
|
||||
M_C(name, _node_list_push_front)(d->list, next); \
|
||||
} \
|
||||
n = M_C(name, _node_list_previous_obj)(d->list, n); \
|
||||
assert (n != NULL); \
|
||||
d->back->node = n; \
|
||||
index = n->size-1; \
|
||||
@@ -286,10 +305,19 @@
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
assert(d->count > 0); \
|
||||
deque_node_t *n = d->front->node; \
|
||||
M_C(name, _node_t) *n = d->front->node; \
|
||||
size_t index = d->front->index; \
|
||||
if (M_UNLIKELY (n->size <= index)) { \
|
||||
n = deque_node_list_next_obj(d->list, n); \
|
||||
/* If there is a previous node, \
|
||||
pop the front node and push it back to the back. This \
|
||||
reduce the used memory if the deque is used as a FIFO queue.*/ \
|
||||
M_C(name,_node_t) *prev = M_C(name, _node_list_previous_obj)(d->list, n); \
|
||||
if (prev != NULL) { \
|
||||
prev = M_C(name, _node_list_pop_front)(d->list); \
|
||||
assert (prev != n); \
|
||||
M_C(name, _node_list_push_back)(d->list, prev); \
|
||||
} \
|
||||
n = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
assert (n != NULL); \
|
||||
d->front->node = n; \
|
||||
index = 0; \
|
||||
@@ -312,9 +340,9 @@
|
||||
DEQUEI_CONTRACT(d); \
|
||||
assert (d->count > 0); \
|
||||
size_t i = d->back->index; \
|
||||
deque_node_t *n = d->back->node; \
|
||||
M_C(name, _node_t) *n = d->back->node; \
|
||||
if (M_UNLIKELY (i == 0)) { \
|
||||
n = deque_node_list_previous_obj(d->list, n); \
|
||||
n = M_C(name, _node_list_previous_obj)(d->list, n); \
|
||||
assert (n != NULL); \
|
||||
i = n->size; \
|
||||
} \
|
||||
@@ -327,9 +355,9 @@
|
||||
DEQUEI_CONTRACT(d); \
|
||||
assert (d->count > 0); \
|
||||
size_t i = d->front->index; \
|
||||
deque_node_t *n = d->front->node; \
|
||||
M_C(name, _node_t) *n = d->front->node; \
|
||||
if (M_UNLIKELY (n->size <= i)) { \
|
||||
n = deque_node_list_next_obj(d->list, n); \
|
||||
n = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
assert (n != NULL); \
|
||||
i = 0; \
|
||||
} \
|
||||
@@ -369,7 +397,7 @@
|
||||
it->index = d->back->index - 1; \
|
||||
it->deque = d; \
|
||||
if (M_UNLIKELY (it->index >= it->node->size)) { \
|
||||
it->node = deque_node_list_previous_obj(d->list, it->node); \
|
||||
it->node = M_C(name, _node_list_previous_obj)(d->list, it->node); \
|
||||
assert (it->node != NULL); \
|
||||
it->index = it->node->size-1; \
|
||||
} \
|
||||
@@ -409,10 +437,10 @@
|
||||
M_C(name, _next)(it_t it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
deque_node_t *n = it->node; \
|
||||
M_C(name, _node_t) *n = it->node; \
|
||||
it->index ++; \
|
||||
if (M_UNLIKELY (it->index >= n->size)) { \
|
||||
n = deque_node_list_next_obj(it->deque->list, n); \
|
||||
n = M_C(name, _node_list_next_obj)(it->deque->list, n); \
|
||||
if (M_UNLIKELY (n == NULL)) { \
|
||||
/* Point to 'end' (can't undo it) */ \
|
||||
it->node = it->deque->back->node; \
|
||||
@@ -428,10 +456,10 @@
|
||||
M_C(name, _previous)(it_t it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
deque_node_t *n = it->node; \
|
||||
M_C(name, _node_t) *n = it->node; \
|
||||
it->index --; \
|
||||
if (M_UNLIKELY (it->index >= n->size)) { \
|
||||
n = deque_node_list_previous_obj(it->deque->list, n); \
|
||||
n = M_C(name, _node_list_previous_obj)(it->deque->list, n); \
|
||||
if (M_UNLIKELY (n == NULL)) { \
|
||||
/* Point to 'end' (can't undo it) */ \
|
||||
it->node = it->deque->back->node; \
|
||||
@@ -487,10 +515,10 @@
|
||||
M_C(name, _node_list_init)(d->list); \
|
||||
d->default_size = DEQUEUI_DEFAULT_SIZE + src->count; \
|
||||
d->count = src->count; \
|
||||
deque_node_t *n = M_C(name, _int_new_node)(d); \
|
||||
M_C(name, _node_t) *n = M_C(name, _int_new_node)(d); \
|
||||
if (n == NULL) return; \
|
||||
d->default_size /= 2; \
|
||||
deque_node_list_push_back(d->list, n); \
|
||||
M_C(name, _node_list_push_back)(d->list, n); \
|
||||
d->front->node = n; \
|
||||
d->front->index = DEQUEUI_DEFAULT_SIZE/2; \
|
||||
d->back->node = n; \
|
||||
@@ -541,7 +569,7 @@
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
DEQUEI_CONTRACT(e); \
|
||||
deque_node_list_swap (d->list, e->list); \
|
||||
M_C(name, _node_list_swap) (d->list, e->list); \
|
||||
M_SWAP(node_t *, d->front->node, e->front->node); \
|
||||
M_SWAP(node_t *, d->back->node, e->back->node); \
|
||||
M_SWAP(size_t, d->front->index, e->front->index); \
|
||||
@@ -564,7 +592,7 @@
|
||||
for(M_C(name, _node_list_it)(it, d->list) ; \
|
||||
!M_C(name, _node_list_end_p)(it) ; \
|
||||
M_C(name, _node_list_next)(it) ){ \
|
||||
deque_node_t *n = M_C(name, _node_list_ref)(it); \
|
||||
M_C(name, _node_t) *n = M_C(name, _node_list_ref)(it); \
|
||||
if (index0 + key < count + n->size) { \
|
||||
return &n->data[index0 + key - count]; \
|
||||
} \
|
||||
@@ -645,7 +673,7 @@
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, deque_t deque, bool append) \
|
||||
{ \
|
||||
STRING_CONTRACT(str); \
|
||||
STRINGI_CONTRACT(str); \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
it_t it; \
|
||||
@@ -658,7 +686,7 @@
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
STRING_CONTRACT(str); \
|
||||
STRINGI_CONTRACT(str); \
|
||||
} \
|
||||
, /* no GET_STR */ ) \
|
||||
\
|
||||
@@ -669,10 +697,13 @@
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
assert (file != NULL); \
|
||||
fputc ('[', file); \
|
||||
for (size_t i = 0; i < deque->size; i++) { \
|
||||
const type *item = M_C(name, _cget)(deque, i); \
|
||||
it_t it; \
|
||||
for (M_C(name, _it)(it, deque) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
M_C(name, _next)(it)) { \
|
||||
const type *item = M_C(name, _cref)(it); \
|
||||
M_GET_OUT_STR oplist (file, *item); \
|
||||
if (i != deque->size-1) \
|
||||
if (!M_C(name, _last_p)(it)) \
|
||||
fputc (M_GET_SEPARATOR oplist, file); \
|
||||
} \
|
||||
fputc (']', file); \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - DICTIONARY Module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -49,9 +49,32 @@
|
||||
ARRAY_DEF(M_C(name, _array_list_pair), M_C(name, _list_pair_t), \
|
||||
LIST_OPLIST(M_C(name, _list_pair), TUPLE_OPLIST(M_C(name, _pair), key_oplist, value_oplist))) \
|
||||
\
|
||||
DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, 0, M_C(name, _t), M_C(name, _it_t))
|
||||
DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, 0, 0, M_C(name, _t), M_C(name, _it_t))
|
||||
|
||||
|
||||
/* Define a dictionary with the key key_type to the value value_type.
|
||||
which stores the computed hash value (avoiding the need of recomputing it).
|
||||
USAGE: DICT_STOREHASH_DEF2(name, key_type, key_oplist, value_type, value_oplist)
|
||||
*/
|
||||
#define DICT_STOREHASH_DEF2(name, key_type, key_oplist, value_type, value_oplist) \
|
||||
\
|
||||
TUPLE_DEF2(M_C(name, _pair), (hash, size_t, M_DEFAULT_OPLIST), (key, key_type, key_oplist), (value, value_type, value_oplist)) \
|
||||
\
|
||||
M_IF_METHOD(MEMPOOL, key_oplist) \
|
||||
( \
|
||||
LIST_DEF(M_C(name, _list_pair), M_C(name, _pair_t), \
|
||||
M_OPEXTEND(TUPLE_OPLIST(M_C(name, _pair), key_oplist, value_oplist), \
|
||||
MEMPOOL(M_GET_MEMPOOL key_oplist), MEMPOOL_LINKAGE(M_GET_MEMPOOL_LINKAGE key_oplist))) \
|
||||
, \
|
||||
LIST_DEF(M_C(name, _list_pair), M_C(name, _pair_t), \
|
||||
TUPLE_OPLIST(M_C(name, _pair), M_DEFAULT_OPLIST, key_oplist, value_oplist)) \
|
||||
) \
|
||||
\
|
||||
ARRAY_DEF(M_C(name, _array_list_pair), M_C(name, _list_pair_t), \
|
||||
LIST_OPLIST(M_C(name, _list_pair), TUPLE_OPLIST(M_C(name, _pair), M_DEFAULT_OPLIST, key_oplist, value_oplist))) \
|
||||
\
|
||||
DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, 0, 1, M_C(name, _t), M_C(name, _it_t))
|
||||
|
||||
/* Define the oplist of a dictionnary.
|
||||
USAGE: DICT_OPLIST(name[, oplist of the key type, oplist of the value type]) */
|
||||
#define DICT_OPLIST(...) \
|
||||
@@ -82,7 +105,7 @@
|
||||
DICTI_FUNC_DEF2(name, key_type, key_oplist, key_type, \
|
||||
(INIT(M_EMPTY_DEFAULT), INIT_SET(M_EMPTY_DEFAULT), SET(M_EMPTY_DEFAULT), CLEAR(M_EMPTY_DEFAULT), \
|
||||
EQUAL(M_EMPTY_DEFAULT), GET_STR(M_EMPTY_DEFAULT), OUT_STR(M_EMPTY_DEFAULT), IN_STR(M_TRUE_DEFAULT)), \
|
||||
1, M_C(name, _t), M_C(name, _it_t))
|
||||
1, 0, M_C(name, _t), M_C(name, _it_t))
|
||||
|
||||
|
||||
/* Define the oplist of a dictionnary.
|
||||
@@ -105,7 +128,7 @@
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Define a chained dictionnary */
|
||||
#define DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, dict_t, dict_it_t) \
|
||||
#define DICTI_FUNC_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, isStoreHash, dict_t, dict_it_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
size_t used, lower_limit, upper_limit; \
|
||||
@@ -218,14 +241,15 @@
|
||||
{ \
|
||||
DICTI_CONTRACT(name, map); \
|
||||
size_t hash = M_GET_HASH key_oplist (key); \
|
||||
hash = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \
|
||||
size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \
|
||||
const M_C(name, _list_pair_t) *list_ptr = \
|
||||
M_C(name, _array_list_pair_cget)(map->table, hash); \
|
||||
M_C(name, _array_list_pair_cget)(map->table, i); \
|
||||
M_C(name, _list_pair_it_t) it; \
|
||||
for(M_C(name, _list_pair_it)(it, *list_ptr); \
|
||||
!M_C(name, _list_pair_end_p)(it); \
|
||||
M_C(name, _list_pair_next)(it)) { \
|
||||
M_C(name, _pair_t) *ref = M_C(name, _list_pair_ref)(it); \
|
||||
M_IF(isStoreHash)(if ((*ref)->hash != hash) { continue; }, ) \
|
||||
if (M_GET_EQUAL key_oplist ((*ref)->key, key)) \
|
||||
return &(*ref)->M_IF(isSet)(key, value); \
|
||||
} \
|
||||
@@ -253,7 +277,7 @@
|
||||
M_C(name, _list_pair_it)(it, *list); \
|
||||
while (!M_C(name, _list_pair_end_p)(it)) { \
|
||||
M_C(name, _pair_ptr) pair = *M_C(name, _list_pair_ref)(it); \
|
||||
size_t hash = M_GET_HASH key_oplist (pair->key); \
|
||||
size_t hash = M_IF(isStoreHash)(pair->hash, M_GET_HASH key_oplist (pair->key)); \
|
||||
if ((hash & (new_size-1)) >= old_size) { \
|
||||
assert( (hash & (new_size-1)) == (i + old_size)); \
|
||||
M_C(name, _list_pair_t) *new_list = \
|
||||
@@ -300,21 +324,24 @@
|
||||
DICTI_CONTRACT(name, map); \
|
||||
\
|
||||
size_t hash = M_GET_HASH key_oplist(key); \
|
||||
hash = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \
|
||||
size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \
|
||||
M_C(name, _list_pair_t) *list_ptr = \
|
||||
M_C(name, _array_list_pair_get)(map->table, hash); \
|
||||
M_C(name, _array_list_pair_get)(map->table, i); \
|
||||
M_C(name, _list_pair_it_t) it; \
|
||||
for(M_C(name, _list_pair_it)(it, *list_ptr); \
|
||||
!M_C(name, _list_pair_end_p)(it); \
|
||||
M_C(name, _list_pair_next)(it)) { \
|
||||
M_C(name, _pair_ptr) ref = *M_C(name, _list_pair_ref)(it); \
|
||||
M_IF(isStoreHash)(if (ref->hash != hash) continue;, ) \
|
||||
if (M_GET_EQUAL key_oplist(ref->key, key)) { \
|
||||
M_GET_SET value_oplist(ref->value, value); \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
M_C(name, _pair_init_set2)(*M_C(name, _list_pair_push_raw)(*list_ptr), \
|
||||
key M_IF(isSet)(, M_DEFERRED_COMMA value)); \
|
||||
M_IF(isStoreHash)(hash M_DEFERRED_COMMA,) \
|
||||
key \
|
||||
M_IF(isSet)(, M_DEFERRED_COMMA value)); \
|
||||
map->used ++; \
|
||||
if (M_UNLIKELY (map->used > map->upper_limit) ) \
|
||||
M_C(name,_int_resize_up)(map); \
|
||||
@@ -328,14 +355,15 @@
|
||||
\
|
||||
bool ret = false; \
|
||||
size_t hash = M_GET_HASH key_oplist(key); \
|
||||
hash = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \
|
||||
size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \
|
||||
M_C(name, _list_pair_t) *list_ptr = \
|
||||
M_C(name, _array_list_pair_get)(map->table, hash); \
|
||||
M_C(name, _array_list_pair_get)(map->table, i); \
|
||||
M_C(name, _list_pair_it_t) it; \
|
||||
for(M_C(name, _list_pair_it)(it, *list_ptr); \
|
||||
!M_C(name, _list_pair_end_p)(it); \
|
||||
M_C(name, _list_pair_next)(it)) { \
|
||||
M_C(name, _pair_ptr) ref = *M_C(name, _list_pair_ref)(it); \
|
||||
M_IF(isStoreHash)(if (ref->hash != hash) continue;, ) \
|
||||
if (M_GET_EQUAL key_oplist(ref->key, key)) { \
|
||||
M_C(name, _list_pair_remove)(*list_ptr, it); \
|
||||
map->used --; \
|
||||
@@ -469,14 +497,14 @@
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, dict_t dict, const bool append) \
|
||||
{ \
|
||||
STRING_CONTRACT (str); \
|
||||
STRINGI_CONTRACT (str); \
|
||||
DICTI_CONTRACT(name, dict); \
|
||||
(append ? string_cat_str : string_set_str) (str, "{"); \
|
||||
dict_it_t it; \
|
||||
for (M_C(name, _it)(it, dict) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
M_C(name, _next)(it)){ \
|
||||
const struct M_C(name, _pair_s) *item = \
|
||||
const struct M_C(name, _pair_s) *item = \
|
||||
M_C(name, _cref)(it); \
|
||||
M_GET_GET_STR key_oplist (str, item->key, true); \
|
||||
string_push_back (str, ':'); \
|
||||
@@ -485,7 +513,7 @@
|
||||
string_push_back (str, ','); \
|
||||
} \
|
||||
string_push_back (str, '}'); \
|
||||
STRING_CONTRACT(str); \
|
||||
STRINGI_CONTRACT(str); \
|
||||
} \
|
||||
, /* no GET_STR */ ) \
|
||||
\
|
||||
@@ -583,7 +611,10 @@
|
||||
#define DICTI_INITIAL_SIZE 16
|
||||
|
||||
#define DICTI_CONTRACT(name, map) do { \
|
||||
assert(map != NULL); \
|
||||
assert(map->used <= map->upper_limit); \
|
||||
assert(map->upper_limit >= DICTI_UPPER_BOUND(DICTI_INITIAL_SIZE)); \
|
||||
assert(map->used >= map->lower_limit); \
|
||||
assert(M_POWEROF2_P(M_C(name, _array_list_pair_size)(map->table))); \
|
||||
} while (0)
|
||||
|
||||
|
||||
+128
-44
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - GENINT module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -31,43 +31,72 @@
|
||||
/* GENINT is a container of integers with the following properties:
|
||||
|
||||
- it stores integer from [0..N) (N is fixed).
|
||||
- an integer can have only one occurence in the container
|
||||
(makeing the container a kind of permutation of [0..N) )
|
||||
- you can atomically push in / pop out integer from this container.
|
||||
- an integer can have only one occurrence in the container.
|
||||
- you can atomically push in / pop out integer from this container
|
||||
provided that they were not already in the container.
|
||||
- there are no order (like FIFO or stack)
|
||||
|
||||
This can be used to map integers to index of ressources in a table.
|
||||
This can be used to map integers to index of resources in a table.
|
||||
At most we can support N = GENINT_LIMBSIZE * GENINT_LIMBSIZE >= 4096
|
||||
due to the master trick. For the typical usage of this container
|
||||
(mapping hardware or software limited resources), this should be
|
||||
enough.
|
||||
*/
|
||||
|
||||
typedef unsigned long genint_limb_t;
|
||||
// TO DO: We may want a specialization with constant N value.
|
||||
|
||||
// Define the limb size
|
||||
typedef unsigned long long genint_limb_t;
|
||||
|
||||
typedef struct genint_s {
|
||||
size_t n;
|
||||
atomic_ulong *data;
|
||||
unsigned int n; // size of the container
|
||||
unsigned int max; // number of allocated limb - 1
|
||||
genint_limb_t mask0; // mask of the last limb
|
||||
genint_limb_t mask_master; // mask of master
|
||||
atomic_ullong master; // master bitfield (which informs if a limb is full or not)
|
||||
atomic_ullong *data; // the bitfield which informs if an integer
|
||||
} genint_t[1];
|
||||
|
||||
#define GENINT_LIMBSIZE (sizeof(genint_limb_t) * CHAR_BIT)
|
||||
|
||||
#define GENINT_CONTRACT(s) do { \
|
||||
assert (s != NULL); \
|
||||
assert (s->n > 0); \
|
||||
assert (s->data != NULL); \
|
||||
#define GENINT_CONTRACT(s) do { \
|
||||
assert (s != NULL); \
|
||||
assert (s->n > 0 && s->n <= GENINT_LIMBSIZE * GENINT_LIMBSIZE); \
|
||||
assert ((s->max+1) * GENINT_LIMBSIZE >= s->n); \
|
||||
assert (s->data != NULL); \
|
||||
} while (0)
|
||||
|
||||
#define GENINT_ONE ((genint_limb_t)1)
|
||||
#define GENINT_ONE ((genint_limb_t)1)
|
||||
|
||||
#define GENINT_ABA_CPT 32
|
||||
#define GENINT_ABA_CPT_T uint32_t
|
||||
|
||||
#define GENINT_MASTER_SET(master, i) \
|
||||
((((master)& (~((GENINT_ONE<< GENINT_ABA_CPT)-1))) | (GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
|
||||
|((GENINT_ABA_CPT_T)((master) + 1)))
|
||||
|
||||
#define GENINT_MASTER_RESET(master, i) \
|
||||
(((master) & (~((GENINT_ONE<< GENINT_ABA_CPT)-1)) & ~(GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
|
||||
|((GENINT_ABA_CPT_T)((master) + 1)))
|
||||
|
||||
static inline void genint_init(genint_t s, size_t n)
|
||||
{
|
||||
assert (s != NULL && n > 0);
|
||||
assert (s != NULL && n > 0 && n <= GENINT_LIMBSIZE * (GENINT_LIMBSIZE - GENINT_ABA_CPT));
|
||||
const size_t alloc = (n + GENINT_LIMBSIZE - 1) / GENINT_LIMBSIZE;
|
||||
atomic_ulong *ptr = M_MEMORY_REALLOC (atomic_ulong, NULL, alloc);
|
||||
s->n = n;
|
||||
s->data = ptr;
|
||||
const size_t index = n % GENINT_LIMBSIZE;
|
||||
atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, alloc);
|
||||
if (M_UNLIKELY (ptr == NULL)) {
|
||||
M_MEMORY_FULL(alloc);
|
||||
return;
|
||||
}
|
||||
s->n = n;
|
||||
s->data = ptr;
|
||||
s->max = alloc-1;
|
||||
s->mask0 = (index == 0) ? -GENINT_ONE : ~((GENINT_ONE<<(GENINT_LIMBSIZE-index))-1);
|
||||
s->mask_master = (((GENINT_ONE << alloc) - 1) << (GENINT_LIMBSIZE-alloc)) >> GENINT_ABA_CPT;
|
||||
atomic_init (&s->master, (genint_limb_t)0);
|
||||
for(size_t i = 0; i < alloc; i++)
|
||||
atomic_init(&s->data[i], 0UL);
|
||||
atomic_init(&s->data[i], (genint_limb_t)0);
|
||||
GENINT_CONTRACT(s);
|
||||
}
|
||||
|
||||
@@ -78,47 +107,102 @@ static inline void genint_clear(genint_t s)
|
||||
s->data = NULL;
|
||||
}
|
||||
|
||||
static inline size_t genint_size(genint_t s)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
return s->n;
|
||||
}
|
||||
|
||||
// Typical case: one CAS per pop.
|
||||
static inline size_t genint_pop(genint_t s)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
const size_t max = (s->n + GENINT_LIMBSIZE - 1) / GENINT_LIMBSIZE;
|
||||
const size_t index = s->n % GENINT_LIMBSIZE;
|
||||
const genint_limb_t mask0 = (index == 0) ? -GENINT_ONE : (GENINT_ONE<<index)-1;
|
||||
// O(n) approach, but with a really low constant factor
|
||||
for(size_t i = 0; i < max; i++)
|
||||
{
|
||||
const size_t mask = (i+1 == max) ? mask0 : -GENINT_ONE;
|
||||
unsigned int bit;
|
||||
genint_limb_t next, org = atomic_load(&s->data[i]);
|
||||
do {
|
||||
if (org == mask)
|
||||
goto next_element;
|
||||
// At least one bit is free in the limb
|
||||
bit = GENINT_LIMBSIZE - m_core_clz(org);
|
||||
assert ((org & (GENINT_ONE<<bit)) == 0);
|
||||
// Set & reserve the integer as being used.
|
||||
next = org | (GENINT_ONE << bit);
|
||||
} while (!atomic_compare_exchange_weak (&s->data[i], &org, next));
|
||||
// Return the new number
|
||||
GENINT_CONTRACT(s);
|
||||
return i * GENINT_LIMBSIZE + bit;
|
||||
next_element: (void)1;
|
||||
// First read master to see which limb is not full.
|
||||
genint_limb_t master = atomic_load(&s->master);
|
||||
// While master is not full
|
||||
while ((master >> GENINT_ABA_CPT) != s->mask_master) {
|
||||
// Let's get the index i of the first not full limb according to master.
|
||||
unsigned int i = m_core_clz(~master);
|
||||
// Let's compute the mask of this limb representing the limb as being full
|
||||
genint_limb_t mask = s->mask0;
|
||||
mask = (i == s->max) ? mask : -GENINT_ONE;
|
||||
unsigned int bit;
|
||||
// Let's load this limb,
|
||||
genint_limb_t next, org = atomic_load(&s->data[i]);
|
||||
do {
|
||||
// If it is now full, we have been preempted by another.
|
||||
if (M_UNLIKELY (org == mask))
|
||||
goto next_element;
|
||||
// At least one bit is free in the limb. Find one.
|
||||
bit = GENINT_LIMBSIZE - 1 - m_core_clz(~org);
|
||||
assert ((org & (GENINT_ONE<<bit)) == 0);
|
||||
assert (i * GENINT_LIMBSIZE + GENINT_LIMBSIZE - 1 - bit < s->n);
|
||||
// Set the integer as being used.
|
||||
next = org | (GENINT_ONE << bit);
|
||||
// Try to reserve the integer
|
||||
} while (!atomic_compare_exchange_weak (&s->data[i], &org, next));
|
||||
// We have reserved the integer.
|
||||
// If the limb is now full, try to update master
|
||||
if (M_UNLIKELY(next == mask)) {
|
||||
while (true) {
|
||||
genint_limb_t newMaster;
|
||||
if (next == mask) {
|
||||
newMaster = GENINT_MASTER_SET(master, i);
|
||||
} else {
|
||||
newMaster = GENINT_MASTER_RESET(master, i);
|
||||
}
|
||||
if (atomic_compare_exchange_weak (&s->master, &master, newMaster))
|
||||
break;
|
||||
// Fail to update. Reload limb to check if it is still full.
|
||||
next = atomic_load(&s->data[i]);
|
||||
}
|
||||
}
|
||||
// Return the new number
|
||||
GENINT_CONTRACT(s);
|
||||
return i * GENINT_LIMBSIZE + GENINT_LIMBSIZE - 1 - bit;
|
||||
next_element:
|
||||
// Reload master
|
||||
master = atomic_load(&s->master);
|
||||
}
|
||||
GENINT_CONTRACT(s);
|
||||
return -(size_t)1; // No more ressource available
|
||||
return -(size_t)1; // No more resource available
|
||||
}
|
||||
|
||||
// Typical usage: one CAS per push
|
||||
static inline void genint_push(genint_t s, size_t n)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
assert (n < s->n);
|
||||
size_t i = n / GENINT_LIMBSIZE;
|
||||
size_t bit = n % GENINT_LIMBSIZE;
|
||||
const size_t i = n / GENINT_LIMBSIZE;
|
||||
const size_t bit = GENINT_LIMBSIZE - 1 - (n % GENINT_LIMBSIZE);
|
||||
genint_limb_t master = atomic_load(&s->master);
|
||||
// Load the limb
|
||||
genint_limb_t next, org = atomic_load(&s->data[i]);
|
||||
do {
|
||||
assert ((org & (GENINT_ONE<<bit)) != 0);
|
||||
assert ((org & (GENINT_ONE << bit)) != 0);
|
||||
// Reset it
|
||||
next = org & (~(GENINT_ONE << bit));
|
||||
// Try to unreserve it.
|
||||
} while (!atomic_compare_exchange_weak (&s->data[i], &org, next));
|
||||
// if the limb was marked as full by master
|
||||
genint_limb_t mask = s->mask0;
|
||||
mask = (i == s->max) ? mask : -GENINT_ONE;
|
||||
if (M_UNLIKELY (next != mask)) {
|
||||
// Let's compute the mask of this limb representing the limb as being full
|
||||
// Let's try to update master to say that this limb is not full
|
||||
while (true) {
|
||||
genint_limb_t newMaster;
|
||||
if (next == mask) {
|
||||
newMaster = GENINT_MASTER_SET(master, i);
|
||||
} else {
|
||||
newMaster = GENINT_MASTER_RESET(master, i);
|
||||
}
|
||||
if (atomic_compare_exchange_weak (&s->master, &master, newMaster))
|
||||
break;
|
||||
// Fail to update. Reload limb to check if it is still full.
|
||||
next = atomic_load(&s->data[i]);
|
||||
}
|
||||
}
|
||||
GENINT_CONTRACT(s);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Intrusive List module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+10
-10
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - INTRUSIVE SHARED PTR Module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -75,7 +75,7 @@
|
||||
typedef type *M_C(name,_t); \
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
static inline type * \
|
||||
static inline M_C(name,_t) \
|
||||
M_C(name, _init)(type *ptr) \
|
||||
{ \
|
||||
if (M_LIKELY (ptr != NULL)) \
|
||||
@@ -83,8 +83,8 @@
|
||||
return ptr; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _init_set)(type *shared) \
|
||||
static inline M_C(name,_t) \
|
||||
M_C(name, _init_set)(M_C(name,_t) shared) \
|
||||
{ \
|
||||
if (M_LIKELY (shared != NULL)) { \
|
||||
int n = atomic_fetch_add(&(shared->M_C(name, _cpt)), 1); \
|
||||
@@ -94,14 +94,14 @@
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set2)(type ** ptr, type *shared) \
|
||||
M_C(name, _init_set2)(M_C(name,_t) *ptr, M_C(name,_t) shared) \
|
||||
{ \
|
||||
assert (ptr != NULL); \
|
||||
*ptr = M_C(name, _init_set)(shared); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _init_new)(void) \
|
||||
static inline M_C(name,_t) \
|
||||
M_C(name, _init_new)(void) \
|
||||
{ \
|
||||
type *ptr = M_GET_NEW oplist (type); \
|
||||
if (ptr == NULL) { \
|
||||
@@ -114,7 +114,7 @@
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(type *shared) \
|
||||
M_C(name, _clear)(M_C(name,_t) shared) \
|
||||
{ \
|
||||
if (shared != NULL) { \
|
||||
if (atomic_fetch_sub(&(shared->M_C(name, _cpt)), 1) == 1) { \
|
||||
@@ -125,14 +125,14 @@
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(type **shared) \
|
||||
M_C(name, _clean)(M_C(name,_t) *shared) \
|
||||
{ \
|
||||
M_C(name, _clear)(*shared); \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(type ** ptr, type *shared) \
|
||||
M_C(name, _set)(M_C(name,_t) *ptr, M_C(name,_t)shared) \
|
||||
{ \
|
||||
assert (ptr != NULL); \
|
||||
if (M_LIKELY (*ptr != shared)) { \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - LIST module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -27,13 +27,20 @@
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define a list of a given type.
|
||||
/* Define a singly linked list of a given type.
|
||||
USAGE: LIST_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define LIST_DEF(name, ...) \
|
||||
LISTI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t), M_C(name, _it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name, _it_t) )))
|
||||
|
||||
/* Define a dual-push singly linked list of a given type.
|
||||
USAGE: LIST_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define LIST_DUAL_PUSH_DEF(name, ...) \
|
||||
LISTI_DUAL_PUSH_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t), M_C(name, _it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name, _it_t) )))
|
||||
|
||||
/* Define the oplist of a list of type.
|
||||
USAGE: LIST_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define LIST_OPLIST(...) \
|
||||
@@ -84,21 +91,8 @@
|
||||
|
||||
#define LISTI_DEF(arg) LISTI_DEF2 arg
|
||||
|
||||
#define LISTI_DEF2(name, type, oplist, list_t, list_it_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
struct M_C(name, _s) *next; \
|
||||
type data; \
|
||||
} *list_t[1]; \
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
struct M_C(name, _s) *previous; \
|
||||
list_t l; \
|
||||
} list_it_t[1]; \
|
||||
\
|
||||
/* Define alloc functions. If MEMPOOL, we need to define it */ \
|
||||
/* Define allocation functions. If MEMPOOL, we need to define it */
|
||||
#define LISTI_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \
|
||||
M_IF_METHOD(MEMPOOL, oplist)( \
|
||||
\
|
||||
MEMPOOL_DEF(M_C(name, _mempool), struct M_C(name, _s)) \
|
||||
@@ -118,24 +112,43 @@
|
||||
static inline void M_C(name,_int_del)(struct M_C(name, _s) *ptr) { \
|
||||
M_GET_DEL oplist (ptr); \
|
||||
} \
|
||||
) \
|
||||
\
|
||||
LISTI_DEF3(name, type, oplist, list_t, list_it_t) \
|
||||
) \
|
||||
|
||||
#define LISTI_DEF2(name, type, oplist, list_t, list_it_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
struct M_C(name, _s) *next; \
|
||||
type data; \
|
||||
} *list_t[1]; \
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
struct M_C(name, _s) *previous; \
|
||||
struct M_C(name, _s) *current; \
|
||||
} list_it_t[1]; \
|
||||
\
|
||||
LISTI_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \
|
||||
LISTI_DEF3(name, type, oplist, list_t, list_it_t) \
|
||||
LISTI_ITBASE_DEF(name, type, oplist, list_t, list_it_t)
|
||||
|
||||
#define LISTI_CONTRACT(v) do { \
|
||||
assert (v != NULL); \
|
||||
} while (0)
|
||||
|
||||
#define LISTI_DEF3(name, type, oplist, list_t, list_it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(list_t v) \
|
||||
{ \
|
||||
assert( v != NULL); \
|
||||
assert (v != NULL); \
|
||||
*v = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(list_t v) \
|
||||
{ \
|
||||
assert (v != NULL); \
|
||||
LISTI_CONTRACT(v); \
|
||||
struct M_C(name, _s) *it = *v; \
|
||||
*v = NULL; \
|
||||
while (it != NULL) { \
|
||||
@@ -144,6 +157,7 @@
|
||||
M_C(name,_int_del)(it); \
|
||||
it = next; \
|
||||
} \
|
||||
LISTI_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -155,14 +169,15 @@
|
||||
static inline const type * \
|
||||
M_C(name, _back)(const list_t v) \
|
||||
{ \
|
||||
assert(v != NULL && *v != NULL); \
|
||||
LISTI_CONTRACT(v); \
|
||||
assert(*v != NULL); \
|
||||
return M_CONST_CAST(type, &((*v)->data)); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_raw)(list_t v) \
|
||||
{ \
|
||||
assert (v != NULL); \
|
||||
LISTI_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next; \
|
||||
next = M_C(name, _int_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
@@ -172,6 +187,7 @@
|
||||
type *ret = &next->data; \
|
||||
next->next = *v; \
|
||||
*v = next; \
|
||||
LISTI_CONTRACT(v); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
@@ -197,7 +213,8 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_back)(type *data, list_t v) \
|
||||
{ \
|
||||
assert(v != NULL && *v != NULL); \
|
||||
LISTI_CONTRACT(v); \
|
||||
assert(*v != NULL); \
|
||||
if (data != NULL) { \
|
||||
M_GET_SET oplist(*data, (*v)->data); \
|
||||
} \
|
||||
@@ -205,96 +222,102 @@
|
||||
struct M_C(name, _s) *tofree = *v; \
|
||||
*v = (*v)->next; \
|
||||
M_C(name,_int_del)(tofree); \
|
||||
LISTI_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const list_t v) \
|
||||
{ \
|
||||
assert (v!= NULL); \
|
||||
LISTI_CONTRACT(v); \
|
||||
return *v == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(list_t l, list_t v) \
|
||||
{ \
|
||||
assert (v != NULL && l != NULL); \
|
||||
LISTI_CONTRACT(l); \
|
||||
LISTI_CONTRACT(v); \
|
||||
struct M_C(name, _s) *tmp = *l; \
|
||||
*l = *v; \
|
||||
*v = tmp; \
|
||||
LISTI_CONTRACT(l); \
|
||||
LISTI_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(list_it_t l, const list_t v) \
|
||||
M_C(name, _it)(list_it_t it, const list_t v) \
|
||||
{ \
|
||||
assert (v != NULL && l[0].l != NULL); \
|
||||
l[0].l[0] = *v; \
|
||||
l[0].previous = NULL; \
|
||||
LISTI_CONTRACT(v); \
|
||||
assert (it != NULL); \
|
||||
it->current = *v; \
|
||||
it->previous = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(list_it_t it1, const list_it_t it2) \
|
||||
{ \
|
||||
assert (it1 != NULL && it2 != NULL); \
|
||||
it1[0].l[0] = it2[0].l[0]; \
|
||||
it1[0].previous = it2[0].previous; \
|
||||
it1->current = it2->current; \
|
||||
it1->previous = it2->previous; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_end)(list_it_t it1, const list_t v) \
|
||||
{ \
|
||||
assert (it1 != NULL && v != NULL); \
|
||||
LISTI_CONTRACT(v); \
|
||||
assert (it1 != NULL); \
|
||||
(void)v; /* unused */ \
|
||||
it1[0].l[0] = NULL; \
|
||||
it1[0].previous = NULL; \
|
||||
it1->current = NULL; \
|
||||
it1->previous = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const list_it_t v) \
|
||||
M_C(name, _end_p)(const list_it_t it) \
|
||||
{ \
|
||||
assert (v!= NULL); \
|
||||
return v[0].l[0] == NULL; \
|
||||
assert (it != NULL); \
|
||||
return it->current == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _last_p)(const list_it_t v) \
|
||||
M_C(name, _last_p)(const list_it_t it) \
|
||||
{ \
|
||||
assert (v!= NULL); \
|
||||
return v[0].l[0] == NULL || v[0].l[0]->next == NULL; \
|
||||
assert (it != NULL); \
|
||||
return it->current == NULL || it->current->next == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _next)(list_it_t tail) \
|
||||
M_C(name, _next)(list_it_t it) \
|
||||
{ \
|
||||
assert(tail != NULL && tail[0].l[0] != NULL); \
|
||||
tail[0].previous = tail[0].l[0]; \
|
||||
tail[0].l[0] = tail[0].l[0]->next; \
|
||||
assert(it != NULL && it->current != NULL); \
|
||||
it->previous = it->current; \
|
||||
it->current = it->current->next; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_equal_p)(const list_it_t it1, const list_it_t it2) \
|
||||
{ \
|
||||
assert(it1 != NULL && it2 != NULL); \
|
||||
return it1[0].l[0] == it2[0].l[0]; \
|
||||
return it1->current == it2->current; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(const list_it_t v) \
|
||||
M_C(name, _ref)(const list_it_t it) \
|
||||
{ \
|
||||
assert(v != NULL && v[0].l[0] != NULL); \
|
||||
return &(v[0].l[0]->data); \
|
||||
assert(it != NULL && it->current != NULL); \
|
||||
return &(it->current->data); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
M_C(name, _cref)(const list_it_t v) \
|
||||
M_C(name, _cref)(const list_it_t it) \
|
||||
{ \
|
||||
assert(v != NULL && v[0].l[0] != NULL); \
|
||||
return M_CONST_CAST(type, &(v[0].l[0]->data)); \
|
||||
assert(it != NULL && it->current != NULL); \
|
||||
return M_CONST_CAST(type, &(it->current->data)); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const list_t list) \
|
||||
{ \
|
||||
assert (list != NULL); \
|
||||
LISTI_CONTRACT(list); \
|
||||
size_t size = 0; \
|
||||
struct M_C(name, _s) *it = *list; \
|
||||
while (it != NULL) { \
|
||||
@@ -305,22 +328,22 @@
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _sublist_p)(const list_t list, \
|
||||
const list_it_t sublist) \
|
||||
M_C(name, _sublist_p)(const list_t list, const list_it_t itsub) \
|
||||
{ \
|
||||
assert (list != NULL && sublist != NULL); \
|
||||
LISTI_CONTRACT(list); \
|
||||
assert (itsub != NULL); \
|
||||
struct M_C(name, _s) *it = *list; \
|
||||
while (it != NULL) { \
|
||||
if (it == sublist[0].l[0]) return true; \
|
||||
if (it == itsub->current) return true; \
|
||||
it = it->next; \
|
||||
} \
|
||||
return (sublist[0].l[0] == NULL); \
|
||||
return (itsub->current == NULL); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _get)(const list_t list, size_t i) \
|
||||
{ \
|
||||
assert (list != NULL); \
|
||||
LISTI_CONTRACT(list); \
|
||||
struct M_C(name, _s) *it = *list; \
|
||||
/* FIXME: How to avoid the double iteration over the list? */ \
|
||||
size_t len = M_C(name,_size)(list); \
|
||||
@@ -341,50 +364,53 @@
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _insert)(list_t list, \
|
||||
list_it_t insertion_point, \
|
||||
M_C(name, _insert)(list_t list, list_it_t insertion_point, \
|
||||
type const x) \
|
||||
{ \
|
||||
assert (list != NULL && insertion_point != NULL); \
|
||||
LISTI_CONTRACT(list); \
|
||||
assert (insertion_point != NULL); \
|
||||
assert(M_C(name, _sublist_p)(list, insertion_point)); \
|
||||
struct M_C(name, _s) *next; \
|
||||
next = M_C(name, _int_new)(); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
M_GET_INIT_SET oplist(next->data, x); \
|
||||
if (M_UNLIKELY (insertion_point[0].l[0] == NULL)) { \
|
||||
struct M_C(name, _s) *current = insertion_point->current; \
|
||||
if (M_UNLIKELY (current == NULL)) { \
|
||||
next->next = *list; \
|
||||
*list = next; \
|
||||
} else { \
|
||||
next->next = insertion_point[0].l[0]->next; \
|
||||
insertion_point[0].l[0]->next = next; \
|
||||
next->next = current->next; \
|
||||
current->next = next; \
|
||||
} \
|
||||
LISTI_CONTRACT(list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _remove)(list_t list, \
|
||||
list_it_t removing_point) \
|
||||
M_C(name, _remove)(list_t list, list_it_t removing_point) \
|
||||
{ \
|
||||
assert (list != NULL && removing_point != NULL); \
|
||||
assert(removing_point[0].l[0] != NULL); \
|
||||
LISTI_CONTRACT(list); \
|
||||
assert (removing_point != NULL); \
|
||||
assert (removing_point->current != NULL); \
|
||||
assert(M_C(name, _sublist_p)(list, removing_point)); \
|
||||
struct M_C(name, _s) *next = removing_point[0].l[0]->next; \
|
||||
struct M_C(name, _s) *next = removing_point->current->next; \
|
||||
if (M_UNLIKELY (removing_point->previous == NULL)) { \
|
||||
*list = next; \
|
||||
} else { \
|
||||
removing_point->previous->next = next; \
|
||||
} \
|
||||
M_GET_CLEAR oplist(removing_point[0].l[0]->data); \
|
||||
M_C(name,_int_del) (removing_point[0].l[0]); \
|
||||
removing_point[0].l[0] = next; \
|
||||
M_GET_CLEAR oplist(removing_point->current->data); \
|
||||
M_C(name,_int_del) (removing_point->current); \
|
||||
removing_point->current = next; \
|
||||
LISTI_CONTRACT(list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(list_t list, const list_t org) \
|
||||
{ \
|
||||
assert (list != NULL && org != NULL); \
|
||||
LISTI_CONTRACT(list); \
|
||||
LISTI_CONTRACT(org); \
|
||||
struct M_C(name, _s) *next, *it_org; \
|
||||
struct M_C(name, _s) **update_list; \
|
||||
if (list == org) return; \
|
||||
@@ -396,6 +422,7 @@
|
||||
*update_list = next; \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
/* FIXME: Partialy initialized list. What to do? */ \
|
||||
return; \
|
||||
} \
|
||||
update_list = &next->next; \
|
||||
@@ -408,7 +435,6 @@
|
||||
static inline void \
|
||||
M_C(name, _init_set)(list_t list, const list_t org) \
|
||||
{ \
|
||||
assert (list != NULL && org != NULL && list != org); \
|
||||
M_C(name, _init)(list); \
|
||||
M_C(name, _set)(list, org); \
|
||||
} \
|
||||
@@ -416,36 +442,38 @@
|
||||
static inline void \
|
||||
M_C(name, _init_move)(list_t list, list_t org) \
|
||||
{ \
|
||||
assert (list != NULL && org != NULL && list != org); \
|
||||
LISTI_CONTRACT(org); \
|
||||
assert (list != NULL && list != org); \
|
||||
*list = *org; \
|
||||
*org = NULL; \
|
||||
*org = NULL; /* safer */ \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(list_t list, list_t org) \
|
||||
{ \
|
||||
assert (list != NULL && org != NULL && list != org); \
|
||||
assert (list != org); \
|
||||
M_C(name, _clear)(list); \
|
||||
M_C(name, _init_move)(list, org); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice_back)(list_t nv, list_t ov, list_it_t it) \
|
||||
{ \
|
||||
assert (nv != NULL && ov != NULL && it != NULL && nv != ov); \
|
||||
assert(it[0].l[0] != NULL); \
|
||||
assert(M_C(name, _sublist_p)(ov, it)); \
|
||||
LISTI_CONTRACT(nv); \
|
||||
LISTI_CONTRACT(ov); \
|
||||
assert (it != NULL && nv != ov); \
|
||||
assert (it->current != NULL); \
|
||||
assert (M_C(name, _sublist_p)(ov, it)); \
|
||||
/* Remove it from ov */ \
|
||||
struct M_C(name, _s) *next = it[0].l[0]->next; \
|
||||
struct M_C(name, _s) *current = it[0].l[0]; \
|
||||
struct M_C(name, _s) *current = it->current; \
|
||||
struct M_C(name, _s) *next = current->next; \
|
||||
if (it->previous == NULL) { \
|
||||
*ov = next; \
|
||||
} else { \
|
||||
it->previous->next = next; \
|
||||
} \
|
||||
/* Update it to next element */ \
|
||||
it[0].l[0] = next; \
|
||||
it->current = next; \
|
||||
/* Move current in nv */ \
|
||||
current->next = *nv; \
|
||||
*nv = current; \
|
||||
@@ -454,7 +482,9 @@
|
||||
static inline void \
|
||||
M_C(name, _splice)(list_t list1, list_t list2) \
|
||||
{ \
|
||||
assert (list1 != NULL && list2 != NULL && list1 != list2); \
|
||||
LISTI_CONTRACT(list1); \
|
||||
LISTI_CONTRACT(list2); \
|
||||
assert (list1 != list2); \
|
||||
struct M_C(name, _s) **update_list = list1; \
|
||||
struct M_C(name, _s) *it = *list1; \
|
||||
while (it != NULL) { \
|
||||
@@ -468,7 +498,7 @@
|
||||
static inline void \
|
||||
M_C(name, _reverse)(list_t list) \
|
||||
{ \
|
||||
assert (list != NULL); \
|
||||
LISTI_CONTRACT(list); \
|
||||
struct M_C(name, _s) *previous = NULL, *it = *list, *next; \
|
||||
while (it != NULL) { \
|
||||
next = it->next; \
|
||||
@@ -478,7 +508,8 @@
|
||||
} \
|
||||
*list = previous; \
|
||||
} \
|
||||
\
|
||||
|
||||
#define LISTI_ITBASE_DEF(name, type, oplist, list_t, list_it_t) \
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, const list_t list, \
|
||||
@@ -586,5 +617,460 @@
|
||||
} \
|
||||
, /* no hash */ ) \
|
||||
|
||||
/* Dual Push singly linked list.
|
||||
Support Push Back / Push Front / Pop back in O(1).
|
||||
Doesn't support Pop front.
|
||||
This is done by keeping a pointer to both back & front
|
||||
*/
|
||||
#define LISTI_DUAL_PUSH_DEF(arg) LISTI_DUAL_PUSH_DEF2 arg
|
||||
|
||||
#define LISTI_DUAL_PUSH_DEF2(name, type, oplist, list_t, list_it_t) \
|
||||
\
|
||||
struct M_C(name, _s) { \
|
||||
struct M_C(name, _s) *next; \
|
||||
type data; \
|
||||
}; \
|
||||
\
|
||||
typedef struct { \
|
||||
struct M_C(name, _s) *front; \
|
||||
struct M_C(name, _s) *back; \
|
||||
} list_t[1]; \
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
struct M_C(name, _s) *previous; \
|
||||
struct M_C(name, _s) *current; \
|
||||
} list_it_t[1]; \
|
||||
\
|
||||
LISTI_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \
|
||||
LISTI_DUAL_PUSH_DEF3(name, type, oplist, list_t, list_it_t) \
|
||||
LISTI_ITBASE_DEF(name, type, oplist, list_t, list_it_t)
|
||||
|
||||
#define LISTI_DUAL_PUSH_CONTRACT(l) do { \
|
||||
assert (l != NULL); \
|
||||
assert ( (l->back == NULL && l->front == NULL) \
|
||||
|| (l->back != NULL && l->front != NULL)); \
|
||||
} while (0)
|
||||
|
||||
#define LISTI_DUAL_PUSH_DEF3(name, type, oplist, list_t, list_it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(list_t v) \
|
||||
{ \
|
||||
assert( v != NULL); \
|
||||
v->front = NULL; \
|
||||
v->back = NULL; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *it = v->back; \
|
||||
while (it != NULL) { \
|
||||
struct M_C(name, _s) *next = it->next; \
|
||||
M_GET_CLEAR oplist(it->data); \
|
||||
M_C(name,_int_del)(it); \
|
||||
it = next; \
|
||||
} \
|
||||
v->front = NULL; \
|
||||
v->back = NULL; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(list_t v) \
|
||||
{ \
|
||||
M_C(name, _clean)(v); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
M_C(name, _back)(const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
assert (v->back != NULL); \
|
||||
return M_CONST_CAST(type, &(v->back->data)); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_back_raw)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return NULL; \
|
||||
} \
|
||||
type *ret = &next->data; \
|
||||
next->next = v->back; \
|
||||
v->back = next; \
|
||||
/* Update front too if the list was empty */ \
|
||||
/* This C code shall generate branchless code */ \
|
||||
struct M_C(name, _s) *front = v->front; \
|
||||
front = (front == NULL) ? next : front; \
|
||||
v->front = front; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push_back)(list_t v, type const x) \
|
||||
{ \
|
||||
type *data = M_C(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return; \
|
||||
M_GET_INIT_SET oplist(*data, x); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_back_new)(list_t v) \
|
||||
{ \
|
||||
type *data = M_C(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return NULL; \
|
||||
M_GET_INIT oplist(*data); \
|
||||
return data; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _pop_back)(type *data, list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
assert (v->back != NULL); \
|
||||
struct M_C(name, _s) *tofree = v->back; \
|
||||
if (data != NULL) { \
|
||||
M_GET_SET oplist(*data, tofree->data); \
|
||||
} \
|
||||
M_GET_CLEAR oplist(tofree->data); \
|
||||
v->back = tofree->next; \
|
||||
M_C(name,_int_del)(tofree); \
|
||||
/* Update front too if the list became empty */ \
|
||||
/* This C code shall generate branchless code */ \
|
||||
struct M_C(name, _s) *front = v->front; \
|
||||
front = (front == tofree) ? NULL : front; \
|
||||
v->front = front; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
M_C(name, _front)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
assert (v->front != NULL); \
|
||||
return M_CONST_CAST(type, &(v->front->data)); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_front_raw)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return NULL; \
|
||||
} \
|
||||
type *ret = &next->data; \
|
||||
next->next = NULL; \
|
||||
if (M_LIKELY(v->front != NULL)) { \
|
||||
v->front->next = next; \
|
||||
} else { \
|
||||
/* Update back too as the list was empty */ \
|
||||
v->back = next; \
|
||||
} \
|
||||
v->front = next; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push_front)(list_t v, type const x) \
|
||||
{ \
|
||||
type *data = M_C(name, _push_front_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return; \
|
||||
M_GET_INIT_SET oplist(*data, x); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_front_new)(list_t v) \
|
||||
{ \
|
||||
type *data = M_C(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL)) \
|
||||
return NULL; \
|
||||
M_GET_INIT oplist(*data); \
|
||||
return data; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
return v->back == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(list_t l, list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(l); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_SWAP(struct M_C(name, _s) *, l->front, v->front); \
|
||||
M_SWAP(struct M_C(name, _s) *, l->back, v->back); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(list_it_t it, const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
assert (it != NULL); \
|
||||
it->current = v->back; \
|
||||
it->previous = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(list_it_t it1, const list_it_t it2) \
|
||||
{ \
|
||||
assert (it1 != NULL && it2 != NULL); \
|
||||
it1->current = it2->current; \
|
||||
it1->previous = it2->previous; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_end)(list_it_t it1, const list_t v) \
|
||||
{ \
|
||||
assert (it1 != NULL); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
(void)v; /* unused */ \
|
||||
it1->current = NULL; \
|
||||
it1->previous = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const list_it_t it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return it->current == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _last_p)(const list_it_t it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return it->current == NULL || it->current->next == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _next)(list_it_t it) \
|
||||
{ \
|
||||
assert(it != NULL && it->current != NULL); \
|
||||
it->previous = it->current; \
|
||||
it->current = it->current->next; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_equal_p)(const list_it_t it1, const list_it_t it2) \
|
||||
{ \
|
||||
assert(it1 != NULL && it2 != NULL); \
|
||||
return it1->current == it2->current; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(const list_it_t it) \
|
||||
{ \
|
||||
assert(it != NULL && it->current != NULL); \
|
||||
return &(it->current->data); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
M_C(name, _cref)(const list_it_t it) \
|
||||
{ \
|
||||
assert(it != NULL && it->current != NULL); \
|
||||
return M_CONST_CAST(type, &(it->current->data)); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
size_t size = 0; \
|
||||
struct M_C(name, _s) *it = v->back; \
|
||||
while (it != NULL) { \
|
||||
size ++; \
|
||||
it = it->next; \
|
||||
} \
|
||||
return size; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _insert)(list_t list, list_it_t insertion_point, \
|
||||
type const x) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
assert (insertion_point != NULL); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
M_GET_INIT_SET oplist(next->data, x); \
|
||||
if (M_UNLIKELY (insertion_point->current == NULL)) { \
|
||||
next->next = list->back; \
|
||||
list->back = next; \
|
||||
/* update front if list is empty */ \
|
||||
struct M_C(name, _s) *front = list->front; \
|
||||
front = (front == NULL) ? next : front; \
|
||||
list->front = front; \
|
||||
} else { \
|
||||
next->next = insertion_point->current->next; \
|
||||
insertion_point->current->next = next; \
|
||||
/* update front if current == front */ \
|
||||
struct M_C(name, _s) *front = list->front; \
|
||||
front = (front == insertion_point->current) ? next : front; \
|
||||
list->front = front; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _remove)(list_t list, list_it_t removing_point) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
assert (removing_point != NULL); \
|
||||
assert(removing_point->current != NULL); \
|
||||
struct M_C(name, _s) *next = removing_point->current->next; \
|
||||
struct M_C(name, _s) *previous = removing_point->previous; \
|
||||
if (M_UNLIKELY (previous == NULL)) { \
|
||||
list->back = next; \
|
||||
} else { \
|
||||
previous->next = next; \
|
||||
} \
|
||||
/* Update front */ \
|
||||
struct M_C(name, _s) *front = list->front; \
|
||||
front = (next == NULL) ? previous : front; \
|
||||
list->front = front; \
|
||||
/* Remove node */ \
|
||||
M_GET_CLEAR oplist(removing_point->current->data); \
|
||||
M_C(name,_int_del) (removing_point->current); \
|
||||
removing_point->current = next; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(list_t list, const list_t org) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(org); \
|
||||
struct M_C(name, _s) *next = NULL; \
|
||||
struct M_C(name, _s) *it_org; \
|
||||
struct M_C(name, _s) **update_list; \
|
||||
if (M_UNLIKELY (list == org)) return; \
|
||||
M_C(name, _clean)(list); \
|
||||
update_list = &list->back; \
|
||||
it_org = org->back; \
|
||||
while (it_org != NULL) { \
|
||||
next = M_C(name, _int_new)(); \
|
||||
*update_list = next; \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
update_list = &next->next; \
|
||||
M_GET_INIT_SET oplist(next->data, it_org->data); \
|
||||
it_org = it_org->next; \
|
||||
} \
|
||||
list->front = next; \
|
||||
*update_list = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(list_t list, const list_t org) \
|
||||
{ \
|
||||
assert (list != org); \
|
||||
M_C(name, _init)(list); \
|
||||
M_C(name, _set)(list, org); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(list_t list, list_t org) \
|
||||
{ \
|
||||
assert (list != org); \
|
||||
list->back = org->back; \
|
||||
list->front = org->front; \
|
||||
org->back = NULL; \
|
||||
org->front = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(list_t list, list_t org) \
|
||||
{ \
|
||||
M_C(name, _clear)(list); \
|
||||
M_C(name, _init_move)(list, org); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice_back)(list_t list1, list_t list2, list_it_t it) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
assert (list1 != list2); \
|
||||
assert(it->current != NULL); \
|
||||
/* First remove 'it' from list2 */ \
|
||||
struct M_C(name, _s) *current = it->current; \
|
||||
struct M_C(name, _s) *next = current->next; \
|
||||
if (it->previous == NULL) { \
|
||||
list2->back = next; \
|
||||
} else { \
|
||||
it->previous->next = next; \
|
||||
} \
|
||||
/* Update front */ \
|
||||
struct M_C(name, _s) *front = list2->front; \
|
||||
front = (next == NULL) ? it->previous : front; \
|
||||
list2->front = front; \
|
||||
/* Update it to next element */ \
|
||||
it->current = next; \
|
||||
/* Move current in nv */ \
|
||||
current->next = list1->back; \
|
||||
list1->back = current; \
|
||||
/* Update front too if the list was empty */ \
|
||||
/* This C code shall generate branchless code */ \
|
||||
front = list1->front; \
|
||||
front = (front == NULL) ? current : front; \
|
||||
list1->front = front; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice)(list_t list1, list_t list2) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
assert (list1 != list2); \
|
||||
if (M_LIKELY (list1->front != NULL)) { \
|
||||
list1->front->next = list2->back; \
|
||||
list1->front = list2->front; \
|
||||
} else { \
|
||||
/* list1 is empty */ \
|
||||
list1->back = list2->back; \
|
||||
list1->front = list2->front; \
|
||||
} \
|
||||
list2->back = NULL; \
|
||||
list2->front = NULL; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reverse)(list_t list) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
list->front = list->back; \
|
||||
struct M_C(name, _s) *previous = NULL, *it = list->back, *next; \
|
||||
while (it != NULL) { \
|
||||
next = it->next; \
|
||||
it->next = previous; \
|
||||
previous = it; \
|
||||
it = next; \
|
||||
} \
|
||||
list->back = previous; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
} \
|
||||
|
||||
#endif
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - MEMPOOL module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
/* Fast Fixed Size thread unsafe allocator.
|
||||
USAGE:
|
||||
MEMPOOL_DEF(uint, unsigned int)
|
||||
MEMPOOL_DEF(memppol_uint, unsigned int)
|
||||
...
|
||||
memppol_uint_t m;
|
||||
mempool_uint_init(m);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin Mutex & Thread wrapper
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -77,6 +77,16 @@ static inline void m_cond_clear(m_cond_t c)
|
||||
cnd_signal(c);
|
||||
}
|
||||
|
||||
static inline void m_cond_signal(m_cond_t c)
|
||||
{
|
||||
cnd_signal(c);
|
||||
}
|
||||
|
||||
static inline void m_cond_broadcast(m_cond_t c)
|
||||
{
|
||||
cnd_broadcast(c);
|
||||
}
|
||||
|
||||
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
|
||||
{
|
||||
cnd_wait(c, m);
|
||||
@@ -153,6 +163,8 @@ static inline void m_mutexi_lazy_lock (m_mutex_t m)
|
||||
assert (dwWaitResult == WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
// TODO: Use cond var described here
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682052(v=vs.85).aspx
|
||||
static inline void m_cond_init(m_cond_t c)
|
||||
{
|
||||
*c = CreateEvent (NULL, FALSE, FALSE, NULL);
|
||||
@@ -169,6 +181,11 @@ static inline void m_cond_signal(m_cond_t c)
|
||||
PulseEvent(*c);
|
||||
}
|
||||
|
||||
static inline void m_cond_broadcast(m_cond_t c)
|
||||
{
|
||||
PulseEvent(*c);
|
||||
}
|
||||
|
||||
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
|
||||
{
|
||||
DWORD dwWaitResult = SignalObjectAndWait(*m, *c, INFINITE,FALSE);
|
||||
@@ -245,6 +262,11 @@ static inline void m_cond_signal(m_cond_t c)
|
||||
pthread_cond_signal(c);
|
||||
}
|
||||
|
||||
static inline void m_cond_broadcast(m_cond_t c)
|
||||
{
|
||||
pthread_cond_broadcast(c);
|
||||
}
|
||||
|
||||
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
|
||||
{
|
||||
pthread_cond_wait(c, m);
|
||||
|
||||
+67
-4
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - dynamic priority queue module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -34,8 +34,8 @@
|
||||
USAGE: PRIOQUEUE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define PRIOQUEUE_DEF(name, ...) \
|
||||
PRIOQUEUEI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t))))
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), M_C(name,_t), M_C(name,_it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t))))
|
||||
|
||||
/* Define the oplist of an prioqueue of type.
|
||||
USAGE: PRIOQUEUE_OPLIST(name[, oplist of the type]) */
|
||||
@@ -66,7 +66,7 @@
|
||||
,OPLIST(oplist) \
|
||||
)
|
||||
|
||||
#define PRIOQUEUEI_DEF2(name, type, oplist, prioqueue_t) \
|
||||
#define PRIOQUEUEI_DEF2(name, type, oplist, prioqueue_t, it_t) \
|
||||
ARRAY_DEF(M_C(name, _array), type, oplist) \
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
@@ -75,6 +75,8 @@
|
||||
M_C(name, _array_t) array; \
|
||||
} prioqueue_t[1]; \
|
||||
\
|
||||
typedef M_C(name, _array_it_t) it_t; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(prioqueue_t p) \
|
||||
{ \
|
||||
@@ -205,6 +207,67 @@
|
||||
i = child; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const prioqueue_t v) \
|
||||
{ \
|
||||
M_C(name, _array_it)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, const prioqueue_t v) \
|
||||
{ \
|
||||
M_C(name, _array_it_last)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, const prioqueue_t v) \
|
||||
{ \
|
||||
M_C(name, _array_it_end)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t it, const it_t org) \
|
||||
{ \
|
||||
M_C(name, _array_it_set)(it, org); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_end_p)(it); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _last_p)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_last_p)(it); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_equal_p)(const it_t it1, \
|
||||
const it_t it2) \
|
||||
{ \
|
||||
return M_C(name, _array_it_equal_p)(it1, it2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _next)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _array_next)(it); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _previous)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _array_previous)(it); \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
M_C(name, _cref)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_cref)(it); \
|
||||
} \
|
||||
|
||||
|
||||
#endif
|
||||
+2
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - RED BLACK TREE module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -892,6 +892,7 @@ typedef enum {
|
||||
while (!M_C(name, _end_p)(it1)) { \
|
||||
const type *ref1 = M_C(name, _cref)(it1); \
|
||||
M_HASH_UP(hash, M_GET_HASH oplist (*ref1)); \
|
||||
M_C(name, _next)(it1); \
|
||||
} \
|
||||
return M_HASH_FINAL (hash); \
|
||||
} \
|
||||
|
||||
+199
-37
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SHARED PTR Module
|
||||
* M*LIB - SHARED Module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "m-core.h"
|
||||
#include "m-atomic.h"
|
||||
#include "m-genint.h"
|
||||
|
||||
/* Define the oplist of a shared pointer.
|
||||
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
|
||||
@@ -36,11 +37,28 @@
|
||||
_OPLIST(__VA_ARGS__ )))
|
||||
|
||||
/* Define shared pointer and its function.
|
||||
USAGE: SHARED_PTR_DEF(name[, oplist]) */
|
||||
USAGE: SHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_DEF(name, ...) \
|
||||
SHAREDI_PTR_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
|
||||
(name, __VA_ARGS__ )))
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), SHAREDI_ATOMIC_OPLIST ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST)))
|
||||
|
||||
/* Define relaxed shared pointer and its function (thread unsafe).
|
||||
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_RELAXED_DEF(name, ...) \
|
||||
SHAREDI_PTR_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__), SHAREDI_INTEGER_OPLIST ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_INTEGER_OPLIST)))
|
||||
|
||||
/* Define shared resource and its function.
|
||||
This is a bounded pool of resource shared by multiple owners.
|
||||
USAGE: SHARED_RESOURCE_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_RESOURCE_DEF(name, ...) \
|
||||
SHAREDI_RESOURCE_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
|
||||
(name, __VA_ARGS__)))
|
||||
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
@@ -64,11 +82,34 @@
|
||||
// deferred
|
||||
#define SHAREDI_PTR_DEF(arg) SHAREDI_PTR_DEF2 arg
|
||||
|
||||
#define SHAREDI_PTR_DEF2(name, type, oplist) \
|
||||
// OPLIST to handle a counter of atomic type
|
||||
#define SHAREDI_ATOMIC_OPLIST (TYPE(atomic_int), \
|
||||
INIT_SET(atomic_init), \
|
||||
ADD(atomic_fetch_add), \
|
||||
SUB(atomic_fetch_sub), \
|
||||
IT_CREF(atomic_load))
|
||||
|
||||
// OPLIST to handle a counter of non-atomic type with its helper functions.
|
||||
#define SHAREDI_INTEGER_OPLIST (TYPE(int), \
|
||||
INIT_SET(sharedi_integer_init_set), \
|
||||
ADD(sharedi_integer_add), \
|
||||
SUB(sharedi_integer_sub), \
|
||||
IT_CREF(sharedi_integer_cref))
|
||||
static inline void sharedi_integer_init_set(int *p, int val) { *p = val; }
|
||||
static inline int sharedi_integer_add(int *p, int val) { int r = *p; *p += val; return r; }
|
||||
static inline int sharedi_integer_sub(int *p, int val) { int r = *p; *p -= val; return r; }
|
||||
static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
|
||||
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
|
||||
assert(shared != NULL); \
|
||||
assert(*shared == NULL || M_GET_IT_CREF cpt_oplist ( &(*shared)->cpt) >= 1); \
|
||||
} while (0)
|
||||
|
||||
#define SHAREDI_PTR_DEF2(name, type, oplist, cpt_oplist) \
|
||||
\
|
||||
typedef struct M_C(name, _s){ \
|
||||
type *data; /* Pointer to the data */ \
|
||||
atomic_int cpt; /* Counter of how many points to the data */ \
|
||||
type *data; /* Pointer to the data */ \
|
||||
M_GET_TYPE cpt_oplist cpt; /* Counter of how many points to the data */ \
|
||||
bool combineAlloc; /* Does the data and the ptr share the slot? */ \
|
||||
} *M_C(name, _t)[1]; \
|
||||
\
|
||||
@@ -99,10 +140,10 @@
|
||||
return; \
|
||||
} \
|
||||
ptr->data = data; \
|
||||
atomic_init (&ptr->cpt, 1); \
|
||||
M_GET_INIT_SET cpt_oplist (&ptr->cpt, 1); \
|
||||
ptr->combineAlloc = false; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -119,16 +160,16 @@
|
||||
type *data = &p->data; \
|
||||
M_GET_INIT oplist(*data); \
|
||||
ptr->data = data; \
|
||||
atomic_init (&ptr->cpt, 1); \
|
||||
M_GET_INIT_SET cpt_oplist (&ptr->cpt, 1); \
|
||||
ptr->combineAlloc = true; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _NULL_p)(const M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
return *shared == NULL; \
|
||||
} \
|
||||
\
|
||||
@@ -136,22 +177,22 @@
|
||||
M_C(name, _init_set)(M_C(name, _t) dest, \
|
||||
const M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert (dest != shared); \
|
||||
*dest = *shared; \
|
||||
if (*dest != NULL) { \
|
||||
int n = atomic_fetch_add(&((*dest)->cpt), 1); \
|
||||
int n = M_GET_ADD cpt_oplist ( &((*dest)->cpt), 1); \
|
||||
(void) n; /* unused return value */ \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest); \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name, _t) dest) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest); \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
if (*dest != NULL) { \
|
||||
if (atomic_fetch_sub(&((*dest)->cpt), 1) == 1) { \
|
||||
if (M_GET_SUB cpt_oplist ( &((*dest)->cpt), 1) == 1) { \
|
||||
bool combineAlloc = (*dest)->combineAlloc; \
|
||||
/* Note: if combineAlloc is true, the address of the slot \
|
||||
combining both data & ptr is the same as the address of the \
|
||||
@@ -164,7 +205,7 @@
|
||||
} \
|
||||
*dest = NULL; \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest); \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -178,8 +219,8 @@
|
||||
M_C(name, _set)(M_C(name, _t) dest, \
|
||||
const M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest); \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_set)(dest, shared); \
|
||||
} \
|
||||
@@ -188,19 +229,19 @@
|
||||
M_C(name, _init_move)(M_C(name, _t) dest, \
|
||||
M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert (dest != NULL && dest != shared); \
|
||||
*dest = *shared; \
|
||||
*shared = NULL; \
|
||||
SHAREDI_CONTRACT(dest); \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(M_C(name, _t) dest, \
|
||||
M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest); \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert (dest != shared); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_move)(dest, shared); \
|
||||
@@ -210,26 +251,26 @@
|
||||
M_C(name, _swap)(M_C(name, _t) p1, \
|
||||
M_C(name, _t) p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1); \
|
||||
SHAREDI_CONTRACT(p2); \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
M_SWAP (struct M_C(name, _s)*, *p1, *p2); \
|
||||
SHAREDI_CONTRACT(p1); \
|
||||
SHAREDI_CONTRACT(p2); \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(const M_C(name, _t) p1, \
|
||||
const M_C(name, _t) p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1); \
|
||||
SHAREDI_CONTRACT(p2); \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
return *p1 == *p2; \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
M_C(name, _cref)(const M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
assert (data != NULL); \
|
||||
@@ -239,18 +280,139 @@
|
||||
static inline type * \
|
||||
M_C(name, _ref)(M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
assert (data != NULL); \
|
||||
return data; \
|
||||
} \
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
/********************************** SHARED RESOURCE ************************************/
|
||||
|
||||
#define SHAREDI_CONTRACT(shared) do { \
|
||||
assert(shared != NULL); \
|
||||
assert(*shared == NULL || atomic_load (&(*shared)->cpt) >= 1); \
|
||||
#define SHAREDI_RESOURCE_CONTRACT(s) do { \
|
||||
assert (s != NULL); \
|
||||
assert (s->buffer != NULL); \
|
||||
} while (0)
|
||||
|
||||
// deferred
|
||||
#define SHAREDI_RESOURCE_DEF(arg) SHAREDI_RESOURCE_DEF2 arg
|
||||
|
||||
#define SHAREDI_RESOURCE_DEF2(name, type, oplist) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _atype_s) { \
|
||||
atomic_uint cpt; \
|
||||
type x; \
|
||||
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(type) +sizeof(atomic_uint) ? M_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(type) -sizeof(atomic_uint) : 1]; \
|
||||
} M_C(name, _atype_t); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
genint_t core; \
|
||||
M_C(name, _atype_t) *buffer; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
unsigned int idx; \
|
||||
struct M_C(name, _s) *ref; \
|
||||
} M_C(name, _it_t)[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(M_C(name, _t) s, size_t n) \
|
||||
{ \
|
||||
assert(s != NULL); \
|
||||
assert (n > 0); \
|
||||
s->buffer = M_GET_REALLOC oplist (M_C(name, _atype_t), NULL, n); \
|
||||
if (M_UNLIKELY (s->buffer == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _atype_t)) * n); \
|
||||
return; \
|
||||
} \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_GET_INIT oplist (s->buffer[i].x); \
|
||||
atomic_init (&s->buffer[i].cpt, 0U); \
|
||||
} \
|
||||
genint_init(s->core, n); \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name, _t) s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
size_t n = genint_size(s->core); \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_GET_CLEAR oplist (s->buffer[i].x); \
|
||||
} \
|
||||
M_GET_FREE oplist (s->buffer); \
|
||||
s->buffer = NULL; \
|
||||
genint_clear(s->core); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(M_C(name, _it_t) it, M_C(name, _t) s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
assert (it != NULL); \
|
||||
unsigned int idx = genint_pop(s->core); \
|
||||
it->idx = idx; \
|
||||
it->ref = s; \
|
||||
if (M_LIKELY (idx != -1U)) { \
|
||||
assert(atomic_load(&s->buffer[idx].cpt) == 0); \
|
||||
atomic_store(&s->buffer[idx].cpt, 1U); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(M_C(name, _it_t) it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return it->idx == -1U; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(M_C(name, _it_t) it) \
|
||||
{ \
|
||||
assert (it != NULL && it->ref != NULL && it->idx != -1U); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
return &it->ref->buffer[it->idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline const type * \
|
||||
M_C(name, _cref)(M_C(name, _it_t) it) \
|
||||
{ \
|
||||
assert (it != NULL && it->ref != NULL && it->idx != -1U); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _end)(M_C(name, _it_t) it, M_C(name, _t) s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
assert (it != NULL); \
|
||||
assert (it->ref == s); \
|
||||
unsigned int idx = it->idx; \
|
||||
if (M_LIKELY (idx != -1U)) { \
|
||||
unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \
|
||||
if (c == 1) { \
|
||||
genint_push(it->ref->core, idx); \
|
||||
} \
|
||||
it->idx = -1U; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(M_C(name, _it_t) itd, M_C(name, _it_t) its) \
|
||||
{ \
|
||||
assert (itd != NULL && its != NULL); \
|
||||
SHAREDI_RESOURCE_CONTRACT(its->ref); \
|
||||
itd->ref = its->ref; \
|
||||
unsigned int idx = its->idx; \
|
||||
itd->idx = idx; \
|
||||
if (M_LIKELY (idx != -1U)) { \
|
||||
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
|
||||
assert (c >= 1); \
|
||||
} \
|
||||
} \
|
||||
|
||||
|
||||
#endif
|
||||
+460
-83
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SNAPSHOT Module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -27,13 +27,31 @@
|
||||
|
||||
#include "m-atomic.h"
|
||||
#include "m-core.h"
|
||||
#include "m-genint.h"
|
||||
|
||||
/* Define a snapshot and it function
|
||||
USAGE: SNAPSHOT_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_DEF(name, ...) \
|
||||
SNAPSHOTI_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
|
||||
(name, __VA_ARGS__ )))
|
||||
// For compatibility with previous version
|
||||
#define SNAPSHOT_DEF SNAPSHOT_SPSC_DEF
|
||||
|
||||
/* Define a SRSW snapshot and it function
|
||||
USAGE: SNAPSHOT_SPSC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_SPSC_DEF(name, ...) \
|
||||
SNAPSHOTI_SRSW_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
|
||||
(name, __VA_ARGS__ )))
|
||||
|
||||
/* Define a SPMC snapshot and it function
|
||||
USAGE: SNAPSHOT_SPMC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_SPMC_DEF(name, ...) \
|
||||
SNAPSHOTI_SPMC_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
|
||||
(name, __VA_ARGS__ )))
|
||||
|
||||
/* Define a MPMC snapshot and it function
|
||||
USAGE: SNAPSHOT_MPMC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_MPMC_DEF(name, ...) \
|
||||
SNAPSHOTI_MPMC_DEF(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
|
||||
(name, __VA_ARGS__ )))
|
||||
|
||||
/* Define the oplist of a snapshot.
|
||||
USAGE: SNAPSHOT_OPLIST(name[, oplist]) */
|
||||
@@ -61,47 +79,55 @@
|
||||
,M_IF_METHOD(MOVE, oplist)(MOVE(M_C(name, _move)),) \
|
||||
)
|
||||
|
||||
|
||||
/******************************** INTERNAL SRSW **********************************/
|
||||
|
||||
/* Flag defining the atomic state of a snapshot:
|
||||
* - r: Index of the read buffer Range [0..2]
|
||||
* - w: Index of the write buffer Range [0..2]
|
||||
* - f: Next index of the write buffer when a shot is taken Range [0..2]
|
||||
* - b: Boolean indicating that the read buffer shall be updated
|
||||
*/
|
||||
#define SNAPSHOTI_FLAG(r, w, f, b) \
|
||||
#define SNAPSHOTI_SRSW_FLAG(r, w, f, b) \
|
||||
((unsigned char)( ( (r) << 4) | ((w) << 2) | ((f)) | ((b) << 6)))
|
||||
#define SNAPSHOTI_R(flags) \
|
||||
#define SNAPSHOTI_SRSW_R(flags) \
|
||||
(((flags) >> 4) & 0x03u)
|
||||
#define SNAPSHOTI_W(flags) \
|
||||
#define SNAPSHOTI_SRSW_W(flags) \
|
||||
(((flags) >> 2) & 0x03u)
|
||||
#define SNAPSHOTI_F(flags) \
|
||||
#define SNAPSHOTI_SRSW_F(flags) \
|
||||
(((flags) >> 0) & 0x03u)
|
||||
#define SNAPSHOTI_B(flags) \
|
||||
#define SNAPSHOTI_SRSW_B(flags) \
|
||||
(((flags) >> 6) & 0x01u)
|
||||
|
||||
/* NOTE: Due to atomic_load only accepting non-const pointer,
|
||||
we can't have any const in the interface. */
|
||||
#define SNAPSHOTI_FLAGS_CONTRACT(flags) \
|
||||
assert(SNAPSHOTI_R(flags) != SNAPSHOTI_W(flags) \
|
||||
&& SNAPSHOTI_R(flags) != SNAPSHOTI_F(flags) \
|
||||
&& SNAPSHOTI_W(flags) != SNAPSHOTI_F(flags))
|
||||
#define SNAPSHOTI_CONTRACT(snap) do { \
|
||||
#define SNAPSHOTI_SRSW_FLAGS_CONTRACT(flags) \
|
||||
assert(SNAPSHOTI_SRSW_R(flags) != SNAPSHOTI_SRSW_W(flags) \
|
||||
&& SNAPSHOTI_SRSW_R(flags) != SNAPSHOTI_SRSW_F(flags) \
|
||||
&& SNAPSHOTI_SRSW_W(flags) != SNAPSHOTI_SRSW_F(flags))
|
||||
#define SNAPSHOTI_SRSW_CONTRACT(snap) do { \
|
||||
assert((snap) != NULL); \
|
||||
unsigned char f = atomic_load (&(snap)->flags); \
|
||||
SNAPSHOTI_FLAGS_CONTRACT(f); \
|
||||
SNAPSHOTI_SRSW_FLAGS_CONTRACT(f); \
|
||||
} while (0)
|
||||
|
||||
//defered
|
||||
#define SNAPSHOTI_DEF(arg) SNAPSHOTI_DEF2 arg
|
||||
// Defered evaluation (TBC if it really helps).
|
||||
#define SNAPSHOTI_SRSW_DEF(arg) SNAPSHOTI_SRSW_DEF2 arg
|
||||
|
||||
// This is basically an atomic triple buffer between a produced thread
|
||||
// and a consummer thread.
|
||||
// TODO: Analyse generalisation to N produced threads and M consummer threads
|
||||
#define SNAPSHOTI_MAX_BUFFER 3
|
||||
// This is basically an atomic triple buffer (Lock Free)
|
||||
// between a produced thread and a consummer thread.
|
||||
#define SNAPSHOTI_SRSW_MAX_BUFFER 3
|
||||
|
||||
#define SNAPSHOTI_DEF2(name, type, oplist) \
|
||||
\
|
||||
#define SNAPSHOTI_SRSW_DEF2(name, type, oplist) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
type x; \
|
||||
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(type) ? M_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(type) : 1]; \
|
||||
} M_C(name, _aligned_type_t); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
type data[SNAPSHOTI_MAX_BUFFER]; \
|
||||
M_C(name, _aligned_type_t) data[SNAPSHOTI_SRSW_MAX_BUFFER]; \
|
||||
atomic_uchar flags; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
@@ -110,137 +136,488 @@
|
||||
static inline void M_C(name, _init)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
assert(snap != NULL); \
|
||||
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
|
||||
M_GET_INIT oplist(snap->data[i]); \
|
||||
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
|
||||
M_GET_INIT oplist(snap->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, SNAPSHOTI_FLAG(0, 1, 2, 0)); \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
atomic_init (&snap->flags, SNAPSHOTI_SRSW_FLAG(0, 1, 2, 0)); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline void M_C(name, _clear)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
|
||||
M_GET_CLEAR oplist(snap->data[i]); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(snap); \
|
||||
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
|
||||
M_GET_CLEAR oplist(snap->data[i].x); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline void M_C(name, _init_set)(M_C(name, _t) snap, \
|
||||
M_C(name, _t) org) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(org); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(org); \
|
||||
assert(snap != NULL && snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
|
||||
M_GET_INIT_SET oplist(snap->data[i], org->data[i]); \
|
||||
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
|
||||
M_GET_INIT_SET oplist(snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline void M_C(name, _set)(M_C(name, _t) snap, \
|
||||
M_C(name, _t) org) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
SNAPSHOTI_CONTRACT(org); \
|
||||
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
|
||||
M_GET_SET oplist(snap->data[i], org->data[i]); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(snap); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
|
||||
M_GET_SET oplist(snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
M_IF_METHOD(INIT_MOVE, oplist)( \
|
||||
static inline void M_C(name, _init_move)(M_C(name, _t) snap, \
|
||||
M_C(name, _t) org) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(org); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(org); \
|
||||
assert(snap != NULL && snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
|
||||
M_GET_INIT_MOVE oplist(snap->data[i], org->data[i]); \
|
||||
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
|
||||
M_GET_INIT_MOVE oplist(snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_store (&snap->flags, atomic_load(&org->flags)); \
|
||||
atomic_store (&org->flags, SNAPSHOTI_FLAG(0,0,0,0) ); \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
atomic_store (&org->flags, SNAPSHOTI_SRSW_FLAG(0,0,0,0) ); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(snap); \
|
||||
} \
|
||||
,) /* IF_METHOD (INIT_MOVE) */ \
|
||||
\
|
||||
\
|
||||
M_IF_METHOD(MOVE, oplist)( \
|
||||
static inline void M_C(name, _move)(M_C(name, _t) snap, \
|
||||
M_C(name, _t) org) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
SNAPSHOTI_CONTRACT(org); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(snap); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(org); \
|
||||
assert(snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_MAX_BUFFER; i++) { \
|
||||
M_GET_MOVE oplist(snap->data[i], org->data[i]); \
|
||||
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
|
||||
M_GET_MOVE oplist(snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_store (&snap->flags, atomic_load(&org->flags)); \
|
||||
atomic_store (&org->flags, SNAPSHOTI_FLAG(0,0,0,0) ); \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
atomic_store (&org->flags, SNAPSHOTI_SRSW_FLAG(0,0,0,0) ); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(snap); \
|
||||
} \
|
||||
,) /* IF_METHOD (MOVE) */ \
|
||||
\
|
||||
\
|
||||
\
|
||||
static inline type *M_C(name, _write)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(snap); \
|
||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||
/* Atomic CAS operation */ \
|
||||
do { \
|
||||
/* Swap F and W buffer, setting exchange flag */ \
|
||||
nextFlags = SNAPSHOTI_FLAG(SNAPSHOTI_R(origFlags), \
|
||||
SNAPSHOTI_F(origFlags), \
|
||||
SNAPSHOTI_W(origFlags), 1); \
|
||||
/* FIXME: Is exponential backoff really needed ? */ \
|
||||
nextFlags = SNAPSHOTI_SRSW_FLAG(SNAPSHOTI_SRSW_R(origFlags), \
|
||||
SNAPSHOTI_SRSW_F(origFlags), \
|
||||
SNAPSHOTI_SRSW_W(origFlags), 1); \
|
||||
/* exponential backoff is not needed as there can't be more \
|
||||
than 2 threads which try to update the data. */ \
|
||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||
nextFlags)); \
|
||||
/* Return new write buffer for new updating */ \
|
||||
return &snap->data[SNAPSHOTI_W(nextFlags)]; \
|
||||
return &snap->data[SNAPSHOTI_SRSW_W(nextFlags)].x; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline const type *M_C(name, _read)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(snap); \
|
||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||
/* Atomic CAS operation */ \
|
||||
do { \
|
||||
/* If no exchange registered, do nothing and keep the same */ \
|
||||
if (!SNAPSHOTI_B(origFlags)) { \
|
||||
if (!SNAPSHOTI_SRSW_B(origFlags)) { \
|
||||
nextFlags = origFlags; \
|
||||
break; \
|
||||
} \
|
||||
/* Swap R and F buffer, clearing exchange flag */ \
|
||||
nextFlags = SNAPSHOTI_FLAG(SNAPSHOTI_F(origFlags), \
|
||||
SNAPSHOTI_W(origFlags), \
|
||||
SNAPSHOTI_R(origFlags), 0); \
|
||||
/* FIXME: Is exponential backoff really needed ? */ \
|
||||
nextFlags = SNAPSHOTI_SRSW_FLAG(SNAPSHOTI_SRSW_F(origFlags), \
|
||||
SNAPSHOTI_SRSW_W(origFlags), \
|
||||
SNAPSHOTI_SRSW_R(origFlags), 0); \
|
||||
/* exponential backoff is not needed as there can't be more \
|
||||
than 2 threads which try to update the data. */ \
|
||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||
nextFlags)); \
|
||||
/* Return current read buffer */ \
|
||||
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_R(nextFlags)]); \
|
||||
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SRSW_R(nextFlags)].x); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline bool M_C(name, _updated_p)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load (&snap->flags); \
|
||||
return SNAPSHOTI_B(flags); \
|
||||
return SNAPSHOTI_SRSW_B(flags); \
|
||||
} \
|
||||
\
|
||||
static inline type *M_C(name, _get_write_buffer)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load(&snap->flags); \
|
||||
return &snap->data[SNAPSHOTI_W(flags)]; \
|
||||
return &snap->data[SNAPSHOTI_SRSW_W(flags)].x; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline const type *M_C(name, _get_read_buffer)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_CONTRACT(snap); \
|
||||
SNAPSHOTI_SRSW_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load(&snap->flags); \
|
||||
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_R(flags)]); \
|
||||
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SRSW_R(flags)].x); \
|
||||
} \
|
||||
|
||||
// FIXME: Method SWAP ?
|
||||
|
||||
/******************************** INTERNAL SPMC **********************************/
|
||||
|
||||
#define SNAPSHOTI_SPMC_INT_FLAG(w, n) ( ((w) << 1) | (n) )
|
||||
#define SNAPSHOTI_SPMC_INT_FLAG_W(f) ((f) >> 1)
|
||||
#define SNAPSHOTI_SPMC_INT_FLAG_N(f) ((f) & 1)
|
||||
|
||||
// 2 more buffer than the number of readers are needed
|
||||
#define SNAPSHOTI_SPMC_EXTRA_BUFFER 2
|
||||
|
||||
// due to genint
|
||||
#define SNAPSHOTI_SPMC_MAX_READER (4096-SNAPSHOTI_SPMC_EXTRA_BUFFER)
|
||||
|
||||
// structure to handle SPMC snapshot but return a unique index in a buffer array.
|
||||
typedef struct snapshot_mrsw_int_s {
|
||||
atomic_uint lastNext;
|
||||
unsigned int currentWrite;
|
||||
size_t n;
|
||||
atomic_uint *cptTab;
|
||||
genint_t freeList;
|
||||
} snapshot_mrsw_int_t[1];
|
||||
|
||||
// can't check currentWrite due to potential data race on it
|
||||
#define SNAPSHOTI_SPMC_INT_CONTRACT(s) do { \
|
||||
assert (s != NULL); \
|
||||
assert (s->n > 0 && s->n <= SNAPSHOTI_SPMC_MAX_READER); \
|
||||
assert (SNAPSHOTI_SPMC_INT_FLAG_W(atomic_load(&s->lastNext)) \
|
||||
<= s->n + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
assert (s->cptTab != NULL); \
|
||||
} while (0)
|
||||
|
||||
static inline void snapshot_mrsw_int_init(snapshot_mrsw_int_t s, size_t n)
|
||||
{
|
||||
assert (s != NULL);
|
||||
assert (n >= 1 && n <= SNAPSHOTI_SPMC_MAX_READER);
|
||||
s->n = n;
|
||||
n += SNAPSHOTI_SPMC_EXTRA_BUFFER;
|
||||
atomic_uint *ptr = M_MEMORY_REALLOC (atomic_uint, NULL, n);
|
||||
if (M_UNLIKELY (ptr == NULL)) {
|
||||
M_MEMORY_FULL(sizeof (atomic_uint) * n);
|
||||
return;
|
||||
}
|
||||
s->cptTab = ptr;
|
||||
for(size_t i = 0; i < n; i++)
|
||||
atomic_init(&s->cptTab[i], 0U);
|
||||
genint_init (s->freeList, n);
|
||||
// Get a free buffer and set it as available for readers
|
||||
unsigned int w = genint_pop(s->freeList);
|
||||
assert (w != -1U);
|
||||
atomic_store(&s->cptTab[w], 1U);
|
||||
atomic_init(&s->lastNext, SNAPSHOTI_SPMC_INT_FLAG(w, true));
|
||||
// Get working buffer
|
||||
s->currentWrite = genint_pop(s->freeList);
|
||||
assert (s->currentWrite != -1U);
|
||||
atomic_store(&s->cptTab[s->currentWrite], 1U);
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
static inline void snapshot_mrsw_int_clear(snapshot_mrsw_int_t s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_MEMORY_FREE (s->cptTab);
|
||||
genint_clear(s->freeList);
|
||||
s->cptTab = NULL;
|
||||
s->n = 0;
|
||||
}
|
||||
|
||||
static inline unsigned int snapshot_mrsw_int_get_write_idx(snapshot_mrsw_int_t s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
return s->currentWrite;
|
||||
}
|
||||
|
||||
static inline unsigned int snapshot_mrsw_int_write_idx(snapshot_mrsw_int_t s, unsigned int idx)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
unsigned int newNext, previous = atomic_load(&s->lastNext);
|
||||
do {
|
||||
newNext = SNAPSHOTI_SPMC_INT_FLAG(idx, true);
|
||||
} while (!atomic_compare_exchange_weak(&s->lastNext, &previous, newNext));
|
||||
if (SNAPSHOTI_SPMC_INT_FLAG_N(previous)) {
|
||||
// Reuse previous buffer as it was not used by any reader
|
||||
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
|
||||
// Some other read threads may already have try to reserve this index
|
||||
// So atomic_load(&s->cptTab[idx]) can be greater than 1.
|
||||
// However they will fail to ack it in lastNext, and remove their reservation later
|
||||
} else {
|
||||
// Free the write index
|
||||
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
|
||||
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
|
||||
assert (c != 0 && c <= s->n + 1);
|
||||
// Get a new buffer.
|
||||
if (c != 1) {
|
||||
// If someone else keeps a ref on the buffer, we can't reuse it
|
||||
// get another free one.
|
||||
idx = genint_pop(s->freeList);
|
||||
// TODO: sometimes fails...
|
||||
assert(idx != -1U);
|
||||
}
|
||||
assert (idx < s->n + SNAPSHOTI_SPMC_EXTRA_BUFFER);
|
||||
assert (atomic_load(&s->cptTab[idx]) == 0);
|
||||
atomic_store(&s->cptTab[idx], 1U);
|
||||
}
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
return idx;
|
||||
}
|
||||
|
||||
static inline unsigned int snapshot_mrsw_int_write(snapshot_mrsw_int_t s)
|
||||
{
|
||||
s->currentWrite = snapshot_mrsw_int_write_idx(s, s->currentWrite);
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
return s->currentWrite;
|
||||
}
|
||||
|
||||
static inline unsigned int snapshot_mrsw_int_write_start(snapshot_mrsw_int_t s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
// Get a new buffer.
|
||||
unsigned int idx = genint_pop(s->freeList);
|
||||
assert (idx != -1U);
|
||||
assert (idx < s->n + SNAPSHOTI_SPMC_EXTRA_BUFFER);
|
||||
assert (atomic_load(&s->cptTab[idx]) == 0);
|
||||
atomic_store(&s->cptTab[idx], 1U);
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
return idx;
|
||||
}
|
||||
|
||||
static inline void snapshot_mrsw_int_write_end(snapshot_mrsw_int_t s, unsigned int idx)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
unsigned int newNext, previous = atomic_load(&s->lastNext);
|
||||
do {
|
||||
newNext = SNAPSHOTI_SPMC_INT_FLAG(idx, true);
|
||||
} while (!atomic_compare_exchange_weak(&s->lastNext, &previous, newNext));
|
||||
|
||||
// Free the previous write buffer
|
||||
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
|
||||
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
|
||||
assert (c != 0 && c <= s->n + 1);
|
||||
if (c == 1) {
|
||||
genint_push(s->freeList, idx);
|
||||
}
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
static inline unsigned int snapshot_mrsw_int_read_start(snapshot_mrsw_int_t s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
unsigned int idx, previous;
|
||||
reload:
|
||||
// Load the last published index + Next flag
|
||||
previous = atomic_load(&s->lastNext);
|
||||
while (true) {
|
||||
// Get the last published index
|
||||
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
|
||||
// Load the number of threads using this index
|
||||
unsigned int c = atomic_load(&s->cptTab[idx]);
|
||||
assert (c <= s->n + 1);
|
||||
// Reserve the index if it still being reserved by someone else
|
||||
if (M_UNLIKELY (c == 0
|
||||
|| !atomic_compare_exchange_strong(&s->cptTab[idx], &c, c+1)))
|
||||
goto reload;
|
||||
// Try to ack it
|
||||
unsigned int newNext = SNAPSHOTI_SPMC_INT_FLAG(idx, false);
|
||||
reforce:
|
||||
if (M_LIKELY (atomic_compare_exchange_strong(&s->lastNext, &previous, newNext)))
|
||||
break;
|
||||
// We have been preempted by another thread
|
||||
if (idx == SNAPSHOTI_SPMC_INT_FLAG_W(previous)) {
|
||||
// This is still ok if the index has not changed
|
||||
// We can get previous to true again if the writer has recycled the index,
|
||||
// while we reserved it, and the reader get prempted until its CAS.
|
||||
if (M_UNLIKELY (SNAPSHOTI_SPMC_INT_FLAG_N(previous) == true)) goto reforce;
|
||||
break;
|
||||
}
|
||||
// Free the reserved index as we failed it to ack it
|
||||
c = atomic_fetch_sub(&s->cptTab[idx], 1U);
|
||||
assert (c != 0 && c <= s->n+1);
|
||||
if (c == 1) {
|
||||
genint_push(s->freeList, idx);
|
||||
}
|
||||
}
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
return idx;
|
||||
}
|
||||
|
||||
static inline void snapshot_mrsw_int_read_end(snapshot_mrsw_int_t s, unsigned int idx)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
assert (idx < s->n + SNAPSHOTI_SPMC_EXTRA_BUFFER);
|
||||
// Decrement reference counter of the buffer
|
||||
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
|
||||
assert (c != 0 && c <= s->n+1);
|
||||
if (c == 1) {
|
||||
// Buffer no longer used by any reader thread.
|
||||
// Push back index in free list
|
||||
genint_push(s->freeList, idx);
|
||||
}
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
#define SNAPSHOTI_SPMC_CONTRACT(snap) do { \
|
||||
assert (snap != NULL); \
|
||||
assert (snap->data != NULL); \
|
||||
} while (0)
|
||||
|
||||
|
||||
// Defered evaluation (TBC if it really helps).
|
||||
#define SNAPSHOTI_SPMC_DEF(arg) SNAPSHOTI_SPMC_DEF2 arg
|
||||
|
||||
#define SNAPSHOTI_SPMC_DEF2(name, type, oplist) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
type x; \
|
||||
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION > sizeof(type) ? M_ALIGN_FOR_CACHELINE_EXCLUSION - sizeof(type) : 1]; \
|
||||
} M_C(name, _aligned_type_t); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _aligned_type_t) *data; \
|
||||
snapshot_mrsw_int_t core; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
static inline void M_C(name, _init)(M_C(name, _t) snap, size_t nReader) \
|
||||
{ \
|
||||
assert (snap != NULL); \
|
||||
assert (nReader > 0 && nReader <= SNAPSHOTI_SPMC_MAX_READER); \
|
||||
snap->data = M_GET_REALLOC oplist (M_C(name, _aligned_type_t), \
|
||||
NULL, \
|
||||
nReader+SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
if (M_UNLIKELY (snap->data == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _aligned_type_t)) * \
|
||||
(nReader+SNAPSHOTI_SPMC_EXTRA_BUFFER)); \
|
||||
return; \
|
||||
} \
|
||||
for(size_t i = 0; i < nReader + SNAPSHOTI_SPMC_EXTRA_BUFFER; i++) { \
|
||||
M_GET_INIT oplist(snap->data[i].x); \
|
||||
} \
|
||||
snapshot_mrsw_int_init(snap->core, nReader); \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _clear)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
for(int i = 0; i < SNAPSHOTI_SRSW_MAX_BUFFER; i++) { \
|
||||
M_GET_CLEAR oplist(snap->data[i].x); \
|
||||
} \
|
||||
M_GET_FREE oplist (snap->data); \
|
||||
snapshot_mrsw_int_clear(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline type *M_C(name, _write)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_write(snap->core); \
|
||||
return &snap->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline const type *M_C(name, _read_start)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_read_start(snap->core); \
|
||||
return M_CONST_CAST(type, &snap->data[idx].x); \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _read_end)(M_C(name, _t) snap, const type *old) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
assert (old != NULL); \
|
||||
const M_C(name, _aligned_type_t) *oldx; \
|
||||
oldx = M_CTYPE_FROM_FIELD(M_C(name, _aligned_type_t), old, type, x); \
|
||||
assert (oldx >= snap->data); \
|
||||
assert (oldx < snap->data + snap->core->n+SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
const unsigned int idx = oldx - snap->data; \
|
||||
snapshot_mrsw_int_read_end(snap->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline type *M_C(name, _get_write_buffer)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_get_write_idx(snap->core); \
|
||||
return &snap->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
//TODO: _set_, _init_set
|
||||
|
||||
|
||||
/******************************** INTERNAL MPMC **********************************/
|
||||
|
||||
// MPMC is built upon SPMC
|
||||
|
||||
// Defered evaluation (TBC if it really helps).
|
||||
#define SNAPSHOTI_MPMC_DEF(arg) SNAPSHOTI_MPMC_DEF2 arg
|
||||
|
||||
#define SNAPSHOTI_MPMC_DEF2(name, type, oplist) \
|
||||
\
|
||||
SNAPSHOTI_SPMC_DEF((M_C(name, _mrsw), type, oplist)) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _mrsw_t) core; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
static inline void M_C(name, _init)(M_C(name, _t) snap, size_t nReader, size_t nWriter) \
|
||||
{ \
|
||||
M_C(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
|
||||
unsigned int idx = snap->core->core->currentWrite; \
|
||||
snap->core->core->currentWrite = -1; \
|
||||
snapshot_mrsw_int_write_end(snap->core->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _clear)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
M_C(name, _mrsw_clear)(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline type *M_C(name, _write_start)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap->core); \
|
||||
const unsigned int idx = snapshot_mrsw_int_write_start(snap->core->core); \
|
||||
return &snap->core->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _write_end)(M_C(name, _t) snap, type *old) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap->core); \
|
||||
const M_C(name, _mrsw_aligned_type_t) *oldx; \
|
||||
oldx = M_CTYPE_FROM_FIELD(M_C(name, _mrsw_aligned_type_t), old, type, x); \
|
||||
assert (oldx >= snap->core->data); \
|
||||
assert (oldx < snap->core->data + snap->core->core->n + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
const unsigned int idx = oldx - snap->core->data; \
|
||||
snapshot_mrsw_int_write_end(snap->core->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline const type *M_C(name, _read_start)(M_C(name, _t) snap) \
|
||||
{ \
|
||||
return M_C(name, _mrsw_read_start)(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _read_end)(M_C(name, _t) snap, const type *old) \
|
||||
{ \
|
||||
M_C(name, _mrsw_read_end)(snap->core, old); \
|
||||
} \
|
||||
\
|
||||
|
||||
//TODO: _set_, _init_set
|
||||
|
||||
#endif
|
||||
+333
-95
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Dynamic Size String Module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -43,7 +43,7 @@
|
||||
// This macro defines the contract of a string.
|
||||
// Note: A ==> B is represented as not(A) or B
|
||||
// Note: use of strlen can slow down a lot the program in some cases.
|
||||
#define STRING_CONTRACT(v) do { \
|
||||
#define STRINGI_CONTRACT(v) do { \
|
||||
M_ASSUME (v != NULL); \
|
||||
M_ASSUME (v->ptr != NULL || (v->size == 0 && v->alloc == 0)); \
|
||||
STRINGI_ASSUME (v->ptr == NULL || v->size == strlen(v->ptr)); \
|
||||
@@ -52,7 +52,13 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
/********************************** EXTERNAL ************************************/
|
||||
/****************************** EXTERNAL *******************************/
|
||||
|
||||
/***********************************************************************/
|
||||
/* */
|
||||
/* DYNAMIC STRING */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
|
||||
/* Index returned in case of error */
|
||||
#define STRING_FAILURE ((size_t)-1)
|
||||
@@ -72,13 +78,13 @@ string_init(string_t v)
|
||||
{
|
||||
v->size = v->alloc = 0;
|
||||
v->ptr = NULL;
|
||||
STRING_CONTRACT(v);
|
||||
STRINGI_CONTRACT(v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_clear(string_t v)
|
||||
{
|
||||
STRING_CONTRACT(v);
|
||||
STRINGI_CONTRACT(v);
|
||||
M_MEMORY_FREE(v->ptr);
|
||||
v->size = v->alloc = 0;
|
||||
v->ptr = NULL;
|
||||
@@ -91,7 +97,7 @@ static inline void stringi_clear2(string_t *v) { string_clear(*v); }
|
||||
static inline char *
|
||||
string_clear_get_str(string_t v)
|
||||
{
|
||||
STRING_CONTRACT(v);
|
||||
STRINGI_CONTRACT(v);
|
||||
char *p = v->ptr;
|
||||
v->size = v->alloc = 0;
|
||||
v->ptr = NULL;
|
||||
@@ -101,31 +107,31 @@ string_clear_get_str(string_t v)
|
||||
static inline void
|
||||
string_clean(string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
v->size = 0;
|
||||
if (M_LIKELY (v->ptr))
|
||||
v->ptr[0] = 0;
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
string_size(const string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
return v->size;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
string_capacity(const string_t v)
|
||||
{
|
||||
STRING_CONTRACT(v);
|
||||
STRINGI_CONTRACT(v);
|
||||
return v->alloc;
|
||||
}
|
||||
|
||||
static inline char
|
||||
string_get_char(const string_t v, size_t index)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
M_ASSUME( v->ptr != NULL && index < v->size);
|
||||
return v->ptr[index];
|
||||
}
|
||||
@@ -133,10 +139,11 @@ string_get_char(const string_t v, size_t index)
|
||||
static inline bool
|
||||
string_empty_p(const string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
return v->size == 0;
|
||||
}
|
||||
|
||||
// Size includes the final null char
|
||||
static inline void
|
||||
stringi_fit2size (string_t v, size_t size)
|
||||
{
|
||||
@@ -163,7 +170,7 @@ stringi_fit2size (string_t v, size_t size)
|
||||
static inline void
|
||||
string_reserve(string_t v, size_t alloc)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
/* NOTE: Reserve below needed size, perform a shrink to fit */
|
||||
if (v->size + 1 > alloc) {
|
||||
alloc = v->size+1;
|
||||
@@ -183,25 +190,25 @@ string_reserve(string_t v, size_t alloc)
|
||||
v->ptr = ptr; // Can be != ptr if v->ptr was NULL before.
|
||||
v->alloc = alloc;
|
||||
}
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_set_str(string_t v, const char str[])
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
M_ASSUME(str != NULL);
|
||||
size_t size = strlen(str);
|
||||
stringi_fit2size(v, size+1);
|
||||
memcpy(v->ptr, str, size+1);
|
||||
v->size = size;
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_set_strn(string_t v, const char str[], size_t n)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
M_ASSUME(str != NULL);
|
||||
size_t len = strlen(str);
|
||||
size_t size = M_MIN (len, n);
|
||||
@@ -209,21 +216,21 @@ string_set_strn(string_t v, const char str[], size_t n)
|
||||
memcpy(v->ptr, str, size);
|
||||
v->ptr[size] = 0;
|
||||
v->size = size;
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline const char*
|
||||
string_get_cstr(const string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
return M_UNLIKELY (v->ptr == NULL) ? "" : v->ptr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_set (string_t v1, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v1);
|
||||
STRING_CONTRACT (v2);
|
||||
STRINGI_CONTRACT (v1);
|
||||
STRINGI_CONTRACT (v2);
|
||||
if (M_LIKELY (v1 != v2)) {
|
||||
size_t size = v2->size;
|
||||
stringi_fit2size(v1, size+1);
|
||||
@@ -235,14 +242,14 @@ string_set (string_t v1, const string_t v2)
|
||||
}
|
||||
v1->size = size;
|
||||
}
|
||||
STRING_CONTRACT (v1);
|
||||
STRINGI_CONTRACT (v1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_set_n(string_t v, const string_t ref, size_t offset, size_t length)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRING_CONTRACT (ref);
|
||||
STRINGI_CONTRACT (v);
|
||||
STRINGI_CONTRACT (ref);
|
||||
assert (offset <= ref->size);
|
||||
assert (v != ref); // Not supported yet
|
||||
if (M_UNLIKELY (ref->size == 0)) {
|
||||
@@ -273,7 +280,7 @@ string_init_set_str(string_t v1, const char str[])
|
||||
static inline void
|
||||
string_init_move(string_t v1, string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v2);
|
||||
STRINGI_CONTRACT (v2);
|
||||
v1->size = v2->size;
|
||||
v1->alloc = v2->alloc;
|
||||
v1->ptr = v2->ptr;
|
||||
@@ -281,19 +288,19 @@ string_init_move(string_t v1, string_t v2)
|
||||
v2->size = 0;
|
||||
v2->alloc = 0;
|
||||
v2->ptr = NULL;
|
||||
STRING_CONTRACT (v1);
|
||||
STRINGI_CONTRACT (v1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_swap(string_t v1, string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v1);
|
||||
STRING_CONTRACT (v2);
|
||||
STRINGI_CONTRACT (v1);
|
||||
STRINGI_CONTRACT (v2);
|
||||
M_SWAP (size_t, v1->size, v2->size);
|
||||
M_SWAP (size_t, v1->alloc, v2->alloc);
|
||||
M_SWAP (char *, v1->ptr, v2->ptr);
|
||||
STRING_CONTRACT (v1);
|
||||
STRING_CONTRACT (v2);
|
||||
STRINGI_CONTRACT (v1);
|
||||
STRINGI_CONTRACT (v2);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -306,30 +313,30 @@ string_move(string_t v1, string_t v2)
|
||||
static inline void
|
||||
string_push_back (string_t v, char c)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
stringi_fit2size(v, v->size+2);
|
||||
v->ptr[v->size++] = c;
|
||||
v->ptr[v->size] = 0;
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_cat_str(string_t v, const char str[])
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
M_ASSUME (str != NULL);
|
||||
const size_t size = strlen(str);
|
||||
stringi_fit2size(v, v->size + size + 1);
|
||||
memcpy(&v->ptr[v->size], str, size + 1);
|
||||
v->size += size;
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_cat(string_t v, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v2);
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v2);
|
||||
STRINGI_CONTRACT (v);
|
||||
const size_t size = v2->size;
|
||||
if (M_LIKELY (size > 0)) {
|
||||
stringi_fit2size(v, v->size + size + 1);
|
||||
@@ -338,13 +345,13 @@ string_cat(string_t v, const string_t v2)
|
||||
v->size += size;
|
||||
v->ptr[v->size] = 0;
|
||||
}
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline int
|
||||
string_cmp_str(const string_t v1, const char str[])
|
||||
{
|
||||
STRING_CONTRACT (v1);
|
||||
STRINGI_CONTRACT (v1);
|
||||
M_ASSUME (str != NULL);
|
||||
return strcmp(string_get_cstr(v1), str);
|
||||
}
|
||||
@@ -352,15 +359,15 @@ string_cmp_str(const string_t v1, const char str[])
|
||||
static inline int
|
||||
string_cmp(const string_t v1, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v1);
|
||||
STRING_CONTRACT (v2);
|
||||
STRINGI_CONTRACT (v1);
|
||||
STRINGI_CONTRACT (v2);
|
||||
return strcmp(string_get_cstr(v1), string_get_cstr(v2));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
string_equal_str_p(const string_t v1, const char str[])
|
||||
{
|
||||
STRING_CONTRACT(v1);
|
||||
STRINGI_CONTRACT(v1);
|
||||
M_ASSUME (str != NULL);
|
||||
return string_cmp_str(v1, str) == 0;
|
||||
}
|
||||
@@ -368,8 +375,8 @@ string_equal_str_p(const string_t v1, const char str[])
|
||||
static inline bool
|
||||
string_equal_p(const string_t v1, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT(v1);
|
||||
STRING_CONTRACT(v2);
|
||||
STRINGI_CONTRACT(v1);
|
||||
STRINGI_CONTRACT(v2);
|
||||
return v1->size == v2->size && string_cmp(v1, v2) == 0;
|
||||
}
|
||||
|
||||
@@ -377,7 +384,7 @@ string_equal_p(const string_t v1, const string_t v2)
|
||||
static inline int
|
||||
string_cmpi_str(const string_t v1, const char p2[])
|
||||
{
|
||||
STRING_CONTRACT (v1);
|
||||
STRINGI_CONTRACT (v1);
|
||||
M_ASSUME (p2 != NULL);
|
||||
// strcasecmp is POSIX
|
||||
const char *p1 = string_get_cstr(v1);
|
||||
@@ -399,7 +406,7 @@ string_cmpi(const string_t v1, const string_t v2)
|
||||
static inline size_t
|
||||
string_search_char (const string_t v, char c, size_t start)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
assert (start <= v->size);
|
||||
const char *p = M_ASSIGN_CAST(const char*,
|
||||
strchr(string_get_cstr(v)+start, c));
|
||||
@@ -409,7 +416,7 @@ string_search_char (const string_t v, char c, size_t start)
|
||||
static inline size_t
|
||||
string_search_rchar (const string_t v, char c, size_t start)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
assert (start <= v->size);
|
||||
// NOTE: Can implement it in a faster way than the libc function
|
||||
// by scanning backward from the bottom of the string (which is
|
||||
@@ -422,7 +429,7 @@ string_search_rchar (const string_t v, char c, size_t start)
|
||||
static inline size_t
|
||||
string_search_str (const string_t v, const char str[], size_t start)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
assert (start <= v->size);
|
||||
M_ASSUME (str != NULL);
|
||||
const char *p = M_ASSIGN_CAST(const char*,
|
||||
@@ -433,7 +440,7 @@ string_search_str (const string_t v, const char str[], size_t start)
|
||||
static inline size_t
|
||||
string_search (const string_t v1, const string_t v2, size_t start)
|
||||
{
|
||||
STRING_CONTRACT (v2);
|
||||
STRINGI_CONTRACT (v2);
|
||||
assert (start <= v1->size);
|
||||
return string_search_str(v1, string_get_cstr(v2), start);
|
||||
}
|
||||
@@ -441,7 +448,7 @@ string_search (const string_t v1, const string_t v2, size_t start)
|
||||
static inline size_t
|
||||
string_search_pbrk(const string_t v1, const char first_of[], size_t start)
|
||||
{
|
||||
STRING_CONTRACT (v1);
|
||||
STRINGI_CONTRACT (v1);
|
||||
assert (start <= v1->size);
|
||||
M_ASSUME (first_of != NULL);
|
||||
const char *p = M_ASSIGN_CAST(const char*,
|
||||
@@ -452,63 +459,63 @@ string_search_pbrk(const string_t v1, const char first_of[], size_t start)
|
||||
static inline int
|
||||
string_strcoll_str(const string_t v, const char str[])
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
return strcoll(string_get_cstr(v), str);
|
||||
}
|
||||
|
||||
static inline int
|
||||
string_strcoll (const string_t v1, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v2);
|
||||
STRINGI_CONTRACT (v2);
|
||||
return string_strcoll_str(v1, string_get_cstr(v2));
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
string_spn(const string_t v1, const char accept[])
|
||||
{
|
||||
STRING_CONTRACT (v1);
|
||||
STRINGI_CONTRACT (v1);
|
||||
M_ASSUME (accept != NULL);
|
||||
return strspn(string_get_cstr(v1), accept);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
string_cspn(const string_t v1, const char accept[])
|
||||
string_cspn(const string_t v1, const char reject[])
|
||||
{
|
||||
STRING_CONTRACT (v1);
|
||||
M_ASSUME (accept != NULL);
|
||||
return strcspn(string_get_cstr(v1), accept);
|
||||
STRINGI_CONTRACT (v1);
|
||||
M_ASSUME (reject != NULL);
|
||||
return strcspn(string_get_cstr(v1), reject);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_left(string_t v, size_t index)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
if (index >= v->size)
|
||||
return;
|
||||
M_ASSUME (v->ptr != NULL);
|
||||
v->ptr[index] = 0;
|
||||
v->size = index;
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
// Note: this is an index, not the size to keep from the right !
|
||||
static inline void
|
||||
string_right(string_t v, size_t index)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
if (index >= v->size) {
|
||||
if (v->ptr != NULL) {
|
||||
v->ptr[0] = 0;
|
||||
v->size = 0;
|
||||
}
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
return;
|
||||
}
|
||||
M_ASSUME (v->ptr != NULL);
|
||||
size_t s2 = v->size - index;
|
||||
memmove (&v->ptr[0], &v->ptr[index], s2+1);
|
||||
v->size = s2;
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -521,7 +528,7 @@ string_mid (string_t v, size_t index, size_t size)
|
||||
static inline size_t
|
||||
string_replace_str (string_t v, const char str1[], const char str2[], size_t start)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
M_ASSUME (str1 != NULL && str2 != NULL);
|
||||
size_t i = string_search_str(v, str1, start);
|
||||
if (i != STRING_FAILURE) {
|
||||
@@ -532,7 +539,7 @@ string_replace_str (string_t v, const char str1[], const char str2[], size_t sta
|
||||
memmove(&v->ptr[i+str2_l], &v->ptr[i+str1_l], v->size - i - str1_l + 1);
|
||||
memcpy (&v->ptr[i], str2, str2_l);
|
||||
v->size += str2_l - str1_l;
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -540,16 +547,16 @@ string_replace_str (string_t v, const char str1[], const char str2[], size_t sta
|
||||
static inline size_t
|
||||
string_replace (string_t v, const string_t v1, const string_t v2, size_t start)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRING_CONTRACT (v1);
|
||||
STRING_CONTRACT (v2);
|
||||
STRINGI_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v1);
|
||||
STRINGI_CONTRACT (v2);
|
||||
return string_replace_str(v, string_get_cstr(v1), string_get_cstr(v2), start);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_replace_at (string_t v, size_t pos, size_t len, const char str2[])
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
M_ASSUME (pos+len < v->size && str2 != NULL);
|
||||
const size_t str1_l = len;
|
||||
const size_t str2_l = strlen(str2);
|
||||
@@ -558,13 +565,13 @@ string_replace_at (string_t v, size_t pos, size_t len, const char str2[])
|
||||
memmove(&v->ptr[pos+str2_l], &v->ptr[pos+str1_l], v->size - pos - str1_l + 1);
|
||||
memcpy (&v->ptr[pos], str2, str2_l);
|
||||
v->size += str2_l - str1_l;
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline int
|
||||
string_printf (string_t v, const char format[], ...)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
M_ASSUME (format != NULL);
|
||||
va_list args;
|
||||
int size;
|
||||
@@ -583,14 +590,14 @@ string_printf (string_t v, const char format[], ...)
|
||||
v->size = (size_t) size;
|
||||
}
|
||||
va_end (args);
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline int
|
||||
string_cat_printf (string_t v, const char format[], ...)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
M_ASSUME (format != NULL);
|
||||
va_list args;
|
||||
int size;
|
||||
@@ -608,14 +615,15 @@ string_cat_printf (string_t v, const char format[], ...)
|
||||
v->size += (size_t) size;
|
||||
}
|
||||
va_end (args);
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
string_fgets(string_t v, FILE *f, string_fgets_t arg)
|
||||
{
|
||||
STRING_CONTRACT(v);
|
||||
STRINGI_CONTRACT(v);
|
||||
assert (f != NULL);
|
||||
stringi_fit2size (v, 100);
|
||||
M_ASSUME(v->ptr != NULL);
|
||||
v->size = 0;
|
||||
@@ -624,13 +632,13 @@ string_fgets(string_t v, FILE *f, string_fgets_t arg)
|
||||
while (fgets(&v->ptr[v->size], v->alloc - v->size, f) != NULL) {
|
||||
retcode = true; /* Something has been read */
|
||||
v->size += strlen(&v->ptr[v->size]);
|
||||
STRING_CONTRACT(v);
|
||||
STRINGI_CONTRACT(v);
|
||||
if (arg != STRING_READ_FILE && v->ptr[v->size-1] == '\n') {
|
||||
if (arg == STRING_READ_PURE_LINE) {
|
||||
v->size --;
|
||||
v->ptr[v->size] = 0; /* Remove EOL */
|
||||
}
|
||||
STRING_CONTRACT(v);
|
||||
STRINGI_CONTRACT(v);
|
||||
return retcode; /* Normal terminaison */
|
||||
} else if (v->ptr[v->size-1] != '\n' && !feof(f)) {
|
||||
/* The string buffer is not big enough:
|
||||
@@ -638,7 +646,7 @@ string_fgets(string_t v, FILE *f, string_fgets_t arg)
|
||||
stringi_fit2size (v, v->alloc + v->alloc/2);
|
||||
}
|
||||
}
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
return retcode; /* Abnormal terminaison */
|
||||
}
|
||||
|
||||
@@ -647,7 +655,8 @@ string_fget_word (string_t v, const char separator[], FILE *f)
|
||||
{
|
||||
char buffer[128];
|
||||
char c = 0;
|
||||
STRING_CONTRACT(v);
|
||||
STRINGI_CONTRACT(v);
|
||||
assert (f != NULL);
|
||||
assert (1+20+2+strlen(separator)+3 < sizeof buffer);
|
||||
stringi_fit2size (v, 10);
|
||||
v->size = 0;
|
||||
@@ -666,7 +675,7 @@ string_fget_word (string_t v, const char separator[], FILE *f)
|
||||
&& fscanf(f, buffer, &v->ptr[v->size], &c) == 2) {
|
||||
retcode = true;
|
||||
v->size += strlen(&v->ptr[v->size]);
|
||||
STRING_CONTRACT(v);
|
||||
STRINGI_CONTRACT(v);
|
||||
if (strchr(separator, c) != NULL)
|
||||
return retcode;
|
||||
/* Next char is not a separator: continue parsing */
|
||||
@@ -678,17 +687,18 @@ string_fget_word (string_t v, const char separator[], FILE *f)
|
||||
return retcode;
|
||||
}
|
||||
|
||||
static inline void
|
||||
static inline bool
|
||||
string_fputs(FILE *f, const string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
fputs(string_get_cstr(v), f);
|
||||
STRINGI_CONTRACT (v);
|
||||
assert (f != NULL);
|
||||
return fputs(string_get_cstr(v), f) >= 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
string_start_with_str_p(const string_t v, const char str[])
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
M_ASSUME (str != NULL);
|
||||
const char *v_str = string_get_cstr(v);
|
||||
while (*str){
|
||||
@@ -703,21 +713,21 @@ string_start_with_str_p(const string_t v, const char str[])
|
||||
static inline bool
|
||||
string_start_with_string_p(const string_t v, const string_t v2)
|
||||
{
|
||||
STRING_CONTRACT (v2);
|
||||
STRINGI_CONTRACT (v2);
|
||||
return string_start_with_str_p (v, string_get_cstr(v2));
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
string_hash(const string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
return m_core_hash(v->ptr, v->size);
|
||||
}
|
||||
|
||||
static inline void
|
||||
string_strim(string_t v)
|
||||
{
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
char *b = v->ptr;
|
||||
size_t size = v->size;
|
||||
while (size > 0 && (b[size-1] == ' ' || b[size-1] == '\n' || b[size-1] == '\r' || b[size-1] == '\t'))
|
||||
@@ -734,7 +744,7 @@ string_strim(string_t v)
|
||||
memmove (v->ptr, b, size);
|
||||
v->ptr[size] = 0;
|
||||
v->size = size;
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* I/O */
|
||||
@@ -743,8 +753,8 @@ string_get_str(string_t v, const string_t v2, bool append)
|
||||
{
|
||||
/* Output: "string" with quote around
|
||||
Replace " by \" within the string */
|
||||
STRING_CONTRACT(v2);
|
||||
STRING_CONTRACT(v);
|
||||
STRINGI_CONTRACT(v2);
|
||||
STRINGI_CONTRACT(v);
|
||||
M_ASSUME (v != v2); // Limitation
|
||||
if(append==false) v->size = 0;
|
||||
size_t targetSize = v->size + v2->size + 3;
|
||||
@@ -762,7 +772,7 @@ string_get_str(string_t v, const string_t v2, bool append)
|
||||
v->ptr[v->size ++] = '"';
|
||||
v->ptr[v->size] = 0;
|
||||
M_ASSUME (v->size <= targetSize);
|
||||
STRING_CONTRACT (v);
|
||||
STRINGI_CONTRACT (v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -770,7 +780,7 @@ string_out_str(FILE *f, const string_t v)
|
||||
{
|
||||
/* Output: "string" with quote around
|
||||
Replace " by \" within the string */
|
||||
STRING_CONTRACT(v);
|
||||
STRINGI_CONTRACT(v);
|
||||
M_ASSUME (f != NULL);
|
||||
fputc('"', f);
|
||||
for(size_t i = 0 ; i < v->size; i++) {
|
||||
@@ -786,7 +796,7 @@ string_out_str(FILE *f, const string_t v)
|
||||
static inline bool
|
||||
string_in_str(string_t v, FILE *f)
|
||||
{
|
||||
STRING_CONTRACT(v);
|
||||
STRINGI_CONTRACT(v);
|
||||
M_ASSUME (f != NULL);
|
||||
int c = fgetc(f);
|
||||
if (c != '"') return false;
|
||||
@@ -929,7 +939,7 @@ typedef struct {
|
||||
static inline void
|
||||
string_it(string_it_t it, const string_t str)
|
||||
{
|
||||
STRING_CONTRACT(str);
|
||||
STRINGI_CONTRACT(str);
|
||||
assert(it != NULL);
|
||||
it->ptr = str->ptr;
|
||||
it->next_ptr = str->ptr;
|
||||
@@ -972,7 +982,7 @@ string_get_cref (const string_it_t it)
|
||||
static inline void
|
||||
string_push_u (string_t str, string_unicode_t u)
|
||||
{
|
||||
STRING_CONTRACT(str);
|
||||
STRINGI_CONTRACT(str);
|
||||
char buffer[4+1];
|
||||
stringi_utf8_encode(buffer, u);
|
||||
string_cat_str(str, buffer);
|
||||
@@ -982,7 +992,7 @@ string_push_u (string_t str, string_unicode_t u)
|
||||
static inline size_t
|
||||
string_length_u(string_t str)
|
||||
{
|
||||
STRING_CONTRACT(str);
|
||||
STRINGI_CONTRACT(str);
|
||||
return stringi_utf8_length(string_get_cstr(str));
|
||||
}
|
||||
|
||||
@@ -990,7 +1000,7 @@ string_length_u(string_t str)
|
||||
static inline bool
|
||||
string_utf8_p(string_t str)
|
||||
{
|
||||
STRING_CONTRACT(str);
|
||||
STRINGI_CONTRACT(str);
|
||||
return stringi_utf8_valid_str_p(string_get_cstr(str));
|
||||
}
|
||||
|
||||
@@ -1158,4 +1168,232 @@ namespace m_string {
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
/* */
|
||||
/* BOUNDED STRING, aka char[N+1] */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
|
||||
#define BOUNDED_STRING_DEF(name, size) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
char s[size+1]; \
|
||||
} M_C(name,_t)[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(M_C(name,_t) s) \
|
||||
{ \
|
||||
assert(s != NULL); \
|
||||
s->s[0] = 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name,_t) s) \
|
||||
{ \
|
||||
assert(s != NULL); \
|
||||
/* nothing to do */ \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(M_C(name,_t) s) \
|
||||
{ \
|
||||
assert(s != NULL); \
|
||||
s->s[0] = 0; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const M_C(name,_t) s) \
|
||||
{ \
|
||||
assert(s != NULL); \
|
||||
return strlen(s->s); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _capacity)(const M_C(name,_t) s) \
|
||||
{ \
|
||||
assert(s != NULL); \
|
||||
(void)s; /* unused */ \
|
||||
return size+1; \
|
||||
} \
|
||||
\
|
||||
static inline char \
|
||||
M_C(name, _get_char)(const M_C(name,_t) s, size_t index) \
|
||||
{ \
|
||||
assert(s != NULL); \
|
||||
assert(index < size); \
|
||||
return s->s[index]; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const M_C(name,_t) s) \
|
||||
{ \
|
||||
assert(s != NULL); \
|
||||
return s->s[0] == 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set_str)(M_C(name,_t) s, const char str[]) \
|
||||
{ \
|
||||
assert (s != NULL && str != NULL); \
|
||||
strncpy(s->s, str, size+1); \
|
||||
s->s[size] = 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set_strn)(M_C(name,_t) s, const char str[], size_t n) \
|
||||
{ \
|
||||
assert (s != NULL && str != NULL); \
|
||||
size_t len = M_MIN(size, n); \
|
||||
strncpy(s->s, str, len+1); \
|
||||
s->s[len] = 0; \
|
||||
} \
|
||||
\
|
||||
static inline const char * \
|
||||
M_C(name, _get_cstr)(const M_C(name,_t) s) \
|
||||
{ \
|
||||
assert (s != NULL); \
|
||||
return s->s; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(M_C(name,_t) s, const M_C(name,_t) str) \
|
||||
{ \
|
||||
assert (s != NULL && str != NULL); \
|
||||
M_C(name, _set_str)(s, str->s); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set_n)(M_C(name,_t) s, const M_C(name,_t) str, \
|
||||
size_t offset, size_t length) \
|
||||
{ \
|
||||
assert (s != NULL && str != NULL); \
|
||||
assert (offset <= size); \
|
||||
M_C(name, _set_strn)(s, str->s+offset, length); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(M_C(name,_t) s, const M_C(name,_t) str) \
|
||||
{ \
|
||||
M_C(name,_init)(s); \
|
||||
M_C(name,_set)(s, str); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set_str)(M_C(name,_t) s, const char str[]) \
|
||||
{ \
|
||||
M_C(name,_init)(s); \
|
||||
M_C(name,_set_str)(s, str); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _cat_str)(M_C(name,_t) s, const char str[]) \
|
||||
{ \
|
||||
assert (s != NULL && str != NULL); \
|
||||
assert (strlen(s->s) <= size); \
|
||||
strncat(s->s, str, size-strlen(s->s)); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _cat)(M_C(name,_t) s, const M_C(name,_t) str) \
|
||||
{ \
|
||||
M_C(name, _cat_str)(s, str->s); \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
M_C(name, _cmp_str)(const M_C(name,_t) s, const char str[]) \
|
||||
{ \
|
||||
assert (s != NULL && str != NULL); \
|
||||
return strcmp(s->s, str); \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
M_C(name, _cmp)(const M_C(name,_t) s, const M_C(name,_t) str) \
|
||||
{ \
|
||||
assert (s != NULL && str != NULL); \
|
||||
return strcmp(s->s, str->s); \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
M_C(name, _equal_str_p)(const M_C(name,_t) s, const char str[]) \
|
||||
{ \
|
||||
assert (s != NULL && str != NULL); \
|
||||
return strcmp(s->s, str) == 0; \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
M_C(name, _equal_p)(const M_C(name,_t) s, const M_C(name,_t) str) \
|
||||
{ \
|
||||
assert (s != NULL && str != NULL); \
|
||||
return strcmp(s->s, str->s) == 0; \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
M_C(name, _printf)(M_C(name,_t) s, const char format[], ...) \
|
||||
{ \
|
||||
assert (s != NULL && format != NULL); \
|
||||
va_list args; \
|
||||
int ret; \
|
||||
va_start (args, format); \
|
||||
ret = vsnprintf (s->s, size+1, format, args); \
|
||||
va_end (args); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
M_C(name, _cat_printf)(M_C(name,_t) s, const char format[], ...) \
|
||||
{ \
|
||||
assert (s != NULL && format != NULL); \
|
||||
va_list args; \
|
||||
int ret; \
|
||||
va_start (args, format); \
|
||||
size_t length = strlen(s->s); \
|
||||
assert(length <= size); \
|
||||
ret = vsnprintf (&s->s[length], size+1-length, format, args); \
|
||||
va_end (args); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _fgets)(M_C(name,_t)s, FILE *f, string_fgets_t arg) \
|
||||
{ \
|
||||
assert (s != NULL && f != NULL); \
|
||||
assert (arg != STRING_READ_FILE); \
|
||||
char *ret = fgets(s->s, size+1, f); \
|
||||
s->s[size] = 0; \
|
||||
if (ret != NULL && arg == STRING_READ_PURE_LINE) { \
|
||||
size_t length = strlen(s->s); \
|
||||
if (length > 0 && s->s[length-1] == '\n') \
|
||||
s->s[length-1] = 0; \
|
||||
} \
|
||||
return ret != NULL; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _fputs)(FILE *f, const M_C(name,_t) s) \
|
||||
{ \
|
||||
assert(f != NULL && s != NULL); \
|
||||
return fputs(s->s, f) >= 0; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _hash)(const M_C(name,_t) s) \
|
||||
{ \
|
||||
assert (s != NULL); \
|
||||
/* Cannot use m_core_hash: not aligned on an int */ \
|
||||
M_HASH_DECL(hash); \
|
||||
const char *str = s->s; \
|
||||
while (*str) M_HASH_UP(hash, *str++); \
|
||||
return M_HASH_FINAL(hash); \
|
||||
} \
|
||||
|
||||
|
||||
/* Define the OPLIST of a BOUNDED_STRING */
|
||||
#define BOUNDED_STRING_OPLIST(name) \
|
||||
(INIT(M_C(name,_init)), INIT_SET(M_C(name,_init_set)), \
|
||||
SET(M_C(name,_set)), CLEAR(M_C(name,_clear)), HASH(M_C(name,_hash)), \
|
||||
EQUAL(M_C(name,_equal_p)), CMP(M_C(name,_cmp)), TYPE(M_C(name,_t)), \
|
||||
)
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - VARIANT module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+64
-24
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB / WORKER - Extra worker interface
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -128,6 +128,9 @@ typedef struct worker_s {
|
||||
|
||||
/* The global reset function */
|
||||
void (*resetFunc_g)(void);
|
||||
|
||||
/* The global clear function */
|
||||
void (*clearFunc_g)(void);
|
||||
} worker_t[1];
|
||||
|
||||
/* Return the number of CPU of the system */
|
||||
@@ -145,7 +148,7 @@ workeri_get_cpu_count(void)
|
||||
nm[0] = CTL_HW;
|
||||
nm[1] = HW_NCPU;
|
||||
sysctl(nm, 2, &count, &len, NULL, 0);
|
||||
return MAX(1, count);
|
||||
return M_MAX(1, count);
|
||||
#elif defined (_SC_NPROCESSORS_ONLN)
|
||||
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#else
|
||||
@@ -153,6 +156,29 @@ workeri_get_cpu_count(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Execute a work order */
|
||||
static inline void
|
||||
workeri_exec(worker_order_t *w)
|
||||
{
|
||||
assert (w!= NULL && w->block != NULL);
|
||||
//printf ("Starting thread with data %p\n", w->data);
|
||||
#if WORKER_USE_CLANG_BLOCK
|
||||
//printf ("Running %s f=%p b=%p\n", (w->func == NULL) ? "Blocks" : "Function", w->func, w->blockFunc);
|
||||
if (w->func == NULL)
|
||||
w->blockFunc(w->data);
|
||||
else
|
||||
#endif
|
||||
#if WORKER_USE_CPP_FUNCTION
|
||||
//printf ("Running %s f=%p b=%p\n", (w->function == NULL) ? "Lambda" : "Function", w->func, w->blockFunc);
|
||||
if (w->function)
|
||||
w->function(w->data);
|
||||
else
|
||||
#endif
|
||||
w->func(w->data);
|
||||
atomic_fetch_add (&w->block->num_terminated_spawn, 1);
|
||||
}
|
||||
|
||||
|
||||
/* The worker thread */
|
||||
static inline void
|
||||
workeri_thread(void *arg)
|
||||
@@ -164,24 +190,12 @@ workeri_thread(void *arg)
|
||||
g->resetFunc_g();
|
||||
//printf ("Waiting for data (queue: %lu / %lu)\n", worker_queue_size(g->queue_g), worker_queue_capacity(g->queue_g));
|
||||
worker_queue_pop(&w, g->queue_g);
|
||||
if (w.block == NULL) return;
|
||||
//printf ("Starting thread with data %p\n", w.data);
|
||||
#if WORKER_USE_CLANG_BLOCK
|
||||
//printf ("Running %s f=%p b=%p\n", (w.func == NULL) ? "Blocks" : "Function", w.func, w.blockFunc);
|
||||
if (w.func == NULL)
|
||||
w.blockFunc(w.data);
|
||||
else
|
||||
#endif
|
||||
#if WORKER_USE_CPP_FUNCTION
|
||||
//printf ("Running %s f=%p b=%p\n", (w.function == NULL) ? "Lambda" : "Function", w.func, w.blockFunc);
|
||||
if (w.function)
|
||||
w.function(w.data);
|
||||
else
|
||||
#endif
|
||||
w.func(w.data);
|
||||
if (w.block == NULL) break;
|
||||
workeri_exec(&w);
|
||||
worker_queue_pop_release(g->queue_g);
|
||||
atomic_fetch_add (&w.block->num_terminated_spawn, 1);
|
||||
}
|
||||
if (g->clearFunc_g != NULL)
|
||||
g->clearFunc_g();
|
||||
}
|
||||
|
||||
/* Initialization of the worker module
|
||||
@@ -189,9 +203,10 @@ workeri_thread(void *arg)
|
||||
@numWorker: number of worker to create
|
||||
@extraQueue: number of extra work order we can get if all workers are full
|
||||
@resetFunc: function to reset the state of a worker between work orders (or NULL if none)
|
||||
@clearFunc: function to clear the state of a worker before terminaning (or NULL if none)
|
||||
*/
|
||||
static inline void
|
||||
worker_init(worker_t g, unsigned int numWorker, unsigned int extraQueue, void (*resetFunc)(void))
|
||||
worker_init(worker_t g, unsigned int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
|
||||
{
|
||||
if (numWorker == 0)
|
||||
numWorker = workeri_get_cpu_count()-1;
|
||||
@@ -202,10 +217,13 @@ worker_init(worker_t g, unsigned int numWorker, unsigned int extraQueue, void (*
|
||||
M_ASSERT_INIT (g->worker != NULL);
|
||||
g->numWorker_g = numWorker;
|
||||
g->resetFunc_g = resetFunc;
|
||||
g->clearFunc_g = clearFunc;
|
||||
for(size_t i = 0; i < numWorker; i++) {
|
||||
m_thread_create(g->worker[i].id, workeri_thread, M_ASSIGN_CAST(void*, g));
|
||||
}
|
||||
}
|
||||
// Define function with default values.
|
||||
#define worker_init(...) worker_init(M_DEFAULT_ARGS(5, (0, 0, NULL, NULL), __VA_ARGS__))
|
||||
|
||||
/* Clear of the worker module */
|
||||
static inline void
|
||||
@@ -213,7 +231,10 @@ worker_clear(worker_t g)
|
||||
{
|
||||
for(unsigned int i = 0; i < g->numWorker_g; i++) {
|
||||
worker_order_t w = WORKER_EMPTY_ORDER;
|
||||
worker_queue_push (g->queue_g, w);
|
||||
// Normaly all worker threads shall be waiting at this
|
||||
// stage, so all push won't block as the queue is empty.
|
||||
// But for robustness, let's wait.
|
||||
worker_queue_push_blocking (g->queue_g, w, true);
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < g->numWorker_g; i++) {
|
||||
@@ -288,17 +309,36 @@ worker_spawn_function(worker_t g, worker_sync_t block, std::function<void(void *
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Test if all work orders are finished */
|
||||
static inline bool
|
||||
worker_sync_p(worker_sync_t block)
|
||||
{
|
||||
/* If the number of spawns is greated than the number
|
||||
of terminated spawns, some spawns are still working.
|
||||
So wait for terminaison */
|
||||
return (atomic_load(&block->num_spawn) == atomic_load (&block->num_terminated_spawn));
|
||||
}
|
||||
|
||||
/* Wait for all work orders to be finished */
|
||||
static inline void
|
||||
worker_sync(worker_sync_t block)
|
||||
{
|
||||
//printf ("Waiting for thread terminasion.\n");
|
||||
/* If the number of spawns is greated than the number
|
||||
of terminated spawns, some spawns are still working.
|
||||
So wait for terminaison */
|
||||
while (atomic_load(&block->num_spawn) != atomic_load (&block->num_terminated_spawn));
|
||||
while (!worker_sync_p(block)) ;
|
||||
}
|
||||
|
||||
/* Flush any work order in the queue if some remains.*/
|
||||
static inline void
|
||||
worker_flush(worker_t g)
|
||||
{
|
||||
worker_order_t w;
|
||||
while (worker_queue_pop_blocking (&w, g->queue_g, false) == true) {
|
||||
workeri_exec(&w);
|
||||
worker_queue_pop_release(g->queue_g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return the number of workers */
|
||||
static inline size_t
|
||||
worker_count(worker_t g)
|
||||
|
||||
+1
-2
@@ -1,10 +1,9 @@
|
||||
#NOTE: Neither GMP not pthread is not a real dependency. It is only used for the test suite.
|
||||
CC=cc -std=c99
|
||||
WCFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -ftrapv
|
||||
XCFLAGS=
|
||||
CFLAGS=$(WCFLAGS) $(XCFLAGS)
|
||||
CPPFLAGS=-I..
|
||||
LDFLAGS=-pthread -lgmp
|
||||
LDFLAGS=-pthread
|
||||
RM=rm -f
|
||||
|
||||
all:
|
||||
|
||||
+11
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -49,17 +49,26 @@
|
||||
#undef M_UNLIKELY
|
||||
#undef M_MEMORY_FULL
|
||||
#undef M_SWAP
|
||||
#undef STRING_CONTRACT
|
||||
#undef STRINGI_CONTRACT
|
||||
#undef ARRAYI_CONTRACT
|
||||
#undef LIST_CONTRACT
|
||||
#undef DICTI_CONTRACT
|
||||
#undef DICTI_OA_CONTRACT
|
||||
#undef SHAREDI_CONTRACT
|
||||
#undef SHAREDI_RESSOURCE_CONTRACT
|
||||
#undef BUFFERI_CONTRACT
|
||||
#undef BUFFERI_PROTECTED_CONTRACT
|
||||
#undef ILISTI_CONTRACT
|
||||
#undef DEQUEI_CONTRACT
|
||||
#undef QUEUEI_MPMC_CONTRACT
|
||||
#undef RBTREEI_CONTRACT_NODE
|
||||
#undef RBTREEI_CONTRACT
|
||||
#undef LISTI_CONTRACT
|
||||
#undef LISTI_DUAL_PUSH_CONTRACT
|
||||
#undef NDEBUG
|
||||
#undef atomic_init
|
||||
#undef atomic_load
|
||||
#undef atomic_store
|
||||
#else
|
||||
/* For normal builds, empty macros which does nothing */
|
||||
#define START_COVERAGE
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
#ifndef MY_MPZ_T
|
||||
#define MY_MPZ_T
|
||||
|
||||
#include "m-string.h"
|
||||
|
||||
/* This is a trivial encapsulation of an opquae structure.
|
||||
Used for test purpose only.*/
|
||||
typedef struct my_mpz_s {
|
||||
unsigned int n;
|
||||
unsigned int a;
|
||||
unsigned int *ptr;
|
||||
} my_mpz_t[1];
|
||||
|
||||
static void my_mpz_init(my_mpz_t z)
|
||||
{
|
||||
z->n = 1;
|
||||
z->a = 1;
|
||||
z->ptr = (unsigned int*) calloc(1, sizeof(unsigned int));
|
||||
if (!z->ptr) abort();
|
||||
}
|
||||
|
||||
static void my_mpz_clear(my_mpz_t z)
|
||||
{
|
||||
free(z->ptr);
|
||||
z->ptr = NULL;
|
||||
}
|
||||
|
||||
static void my_mpz_init_set(my_mpz_t d, const my_mpz_t s)
|
||||
{
|
||||
d->n = s->n;
|
||||
d->a = s->n;
|
||||
d->ptr = (unsigned int *) calloc (s->n, sizeof(unsigned int));
|
||||
memcpy(d->ptr, s->ptr, sizeof(unsigned int) * s->n);
|
||||
}
|
||||
|
||||
static void my_mpz_set(my_mpz_t d, const my_mpz_t s)
|
||||
{
|
||||
my_mpz_clear(d);
|
||||
my_mpz_init_set(d, s);
|
||||
}
|
||||
|
||||
static void my_mpz_set_ui(my_mpz_t d, unsigned int v)
|
||||
{
|
||||
d->n = 1;
|
||||
d->ptr[0] = v;
|
||||
}
|
||||
|
||||
static void my_mpz_init_set_ui(my_mpz_t d, unsigned int v)
|
||||
{
|
||||
my_mpz_init(d);
|
||||
my_mpz_set_ui(d, v);
|
||||
}
|
||||
|
||||
static unsigned int my_mpz_get_ui(const my_mpz_t z)
|
||||
{
|
||||
return z->ptr[0];
|
||||
}
|
||||
|
||||
static void my_mpz_add(my_mpz_t d, const my_mpz_t a, const my_mpz_t b)
|
||||
{
|
||||
d->ptr[0] = a->ptr[0] + b->ptr[0];
|
||||
}
|
||||
|
||||
static void my_mpz_out_str(FILE *f, const my_mpz_t z)
|
||||
{
|
||||
assert(z->n == 1);
|
||||
fprintf(f, "%u", z->ptr[0]);
|
||||
}
|
||||
|
||||
static bool my_mpz_in_str(my_mpz_t z, FILE *f)
|
||||
{
|
||||
z->n = 1;
|
||||
return fscanf(f, "%u", &z->ptr[0]) == 1;
|
||||
}
|
||||
|
||||
static bool my_mpz_equal_p(const my_mpz_t z1, const my_mpz_t z2)
|
||||
{
|
||||
if (z1->n != z2->n) return false;
|
||||
return memcmp(z1->ptr, z2->ptr, z1->n*sizeof(unsigned int)) == 0;
|
||||
}
|
||||
|
||||
static int my_mpz_cmp(const my_mpz_t z1, const my_mpz_t z2)
|
||||
{
|
||||
if (z1->n != z2->n) return z1-> n < z2->n ? -1 : 1;
|
||||
return memcmp(z1->ptr, z2->ptr, z1->n*sizeof(unsigned int));
|
||||
}
|
||||
|
||||
static int my_mpz_cmp_ui(const my_mpz_t z1, unsigned int z2)
|
||||
{
|
||||
if (z1->n != 1) return z1-> n < 1 ? -1 : 1;
|
||||
return memcmp(z1->ptr, &z2, sizeof(unsigned int));
|
||||
}
|
||||
|
||||
static void my_mpz_str(string_t str, const my_mpz_t z, bool append)
|
||||
{
|
||||
if (append) string_cat_printf (str, "%u", z->ptr[0]);
|
||||
else string_printf (str, "%u", z->ptr[0]);
|
||||
}
|
||||
|
||||
#define MYMPZ_OPLIST \
|
||||
(INIT(my_mpz_init), INIT_SET(my_mpz_init_set), SET(my_mpz_set), CLEAR(my_mpz_clear), \
|
||||
OUT_STR(my_mpz_out_str), IN_STR(my_mpz_in_str), EQUAL(my_mpz_equal_p), \
|
||||
GET_STR(my_mpz_str) )
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "m-list.h"
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
@@ -163,6 +185,14 @@ static void test_array(void)
|
||||
assert (array_int_size(l) == 0);
|
||||
assert( algo_array_sort_p(l) == true);
|
||||
|
||||
for(int i = -14025; i < 324035; i+=17)
|
||||
array_int_push_back(l, i);
|
||||
for(int i = -14025; i < 324035; i+=7)
|
||||
array_int_push_back(l, i);
|
||||
assert( algo_array_sort_p(l) == false);
|
||||
array_int_special_stable_sort(l);
|
||||
assert( algo_array_sort_p(l) == true);
|
||||
|
||||
array_int_clear(l);
|
||||
|
||||
ALGO_INIT_VA(l, ARRAY_OPLIST(array_int), 1, 2, 3, 4, 5);
|
||||
|
||||
+23
-39
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -21,41 +21,13 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <gmp.h>
|
||||
#include "mympz.h"
|
||||
#include "m-array.h"
|
||||
|
||||
static void my_mpz_out_str(FILE *f, const mpz_t z)
|
||||
{
|
||||
mpz_out_str (f, 10, z);
|
||||
}
|
||||
|
||||
static bool my_mpz_in_str(mpz_t z, FILE *f)
|
||||
{
|
||||
return mpz_inp_str (z, f, 10) > 0;
|
||||
}
|
||||
|
||||
static bool my_mpz_equal_p(const mpz_t z1, const mpz_t z2)
|
||||
{
|
||||
return mpz_cmp (z1, z2) == 0;
|
||||
}
|
||||
|
||||
#include "m-string.h"
|
||||
static void my_mpz_str(string_t str, const mpz_t z, bool append)
|
||||
{
|
||||
char *s = mpz_get_str(NULL, 10, z);
|
||||
assert (s != NULL);
|
||||
if (append) string_cat_str (str, s);
|
||||
else string_set_str (str, s);
|
||||
free(s);
|
||||
}
|
||||
|
||||
#include "coverage.h"
|
||||
|
||||
START_COVERAGE
|
||||
ARRAY_DEF(array_uint, unsigned int)
|
||||
ARRAY_DEF(array_mpz, mpz_t,
|
||||
(INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), \
|
||||
OUT_STR(my_mpz_out_str), IN_STR(my_mpz_in_str), EQUAL(my_mpz_equal_p), \
|
||||
GET_STR(my_mpz_str) ))
|
||||
ARRAY_DEF(array_mpz, my_mpz_t, MYMPZ_OPLIST)
|
||||
END_COVERAGE
|
||||
#define ARRAY_UINT_OPLIST ARRAY_OPLIST(array_uint)
|
||||
|
||||
@@ -86,6 +58,10 @@ static void test_uint(void)
|
||||
}
|
||||
assert( s == 100 * 99 /2);
|
||||
|
||||
array_uint_pop_at(&s, v, 49);
|
||||
assert (s == 49);
|
||||
array_uint_push_at(v, 49, 49);
|
||||
|
||||
array_uint_pop_at (NULL, v, 0);
|
||||
assert(array_uint_size(v) == 99);
|
||||
s= 0;
|
||||
@@ -125,9 +101,17 @@ static void test_uint(void)
|
||||
assert(array_uint_size(v) == 1000);
|
||||
assert(*array_uint_cget(v, 999) == 0);
|
||||
|
||||
array_uint_t v2;
|
||||
array_uint_t v2, v3;
|
||||
array_uint_init_set(v2,v);
|
||||
array_uint_init(v3);
|
||||
array_uint_push_back(v3, 459320);
|
||||
array_uint_set(v3, v);
|
||||
assert (array_uint_equal_p(v3, v));
|
||||
array_uint_push_back(v3, 459320);
|
||||
array_uint_set(v3, v);
|
||||
assert (array_uint_equal_p(v3, v));
|
||||
array_uint_clear(v);
|
||||
array_uint_clear(v3);
|
||||
assert(array_uint_size(v2) == 1000);
|
||||
assert(*array_uint_cget(v2, 999) == 0);
|
||||
array_uint_push_at (v2, 0, 1742);
|
||||
@@ -170,11 +154,11 @@ static void test_uint(void)
|
||||
static void test_mpz(void)
|
||||
{
|
||||
array_mpz_t array1, array2;
|
||||
mpz_t z;
|
||||
my_mpz_t z;
|
||||
|
||||
array_mpz_init (array1);
|
||||
array_mpz_init (array2);
|
||||
mpz_init (z);
|
||||
my_mpz_init (z);
|
||||
|
||||
// Test empty
|
||||
FILE *f = fopen ("a-marray.dat", "wt");
|
||||
@@ -191,7 +175,7 @@ static void test_mpz(void)
|
||||
|
||||
// Test non empty
|
||||
for(int n = 0; n < 1000; n++) {
|
||||
mpz_set_ui (z, n);
|
||||
my_mpz_set_ui (z, n);
|
||||
array_mpz_push_back (array1, z);
|
||||
}
|
||||
|
||||
@@ -212,18 +196,18 @@ static void test_mpz(void)
|
||||
M_LET(str, STRING_OPLIST) {
|
||||
array_mpz_get_str(str, array1, false);
|
||||
assert (string_cmp_str (str, "[]") == 0);
|
||||
mpz_set_ui (z, 17);
|
||||
my_mpz_set_ui (z, 17);
|
||||
array_mpz_push_back (array1, z);
|
||||
array_mpz_get_str(str, array1, false);
|
||||
assert (string_cmp_str (str, "[17]") == 0);
|
||||
mpz_set_ui (z, 42);
|
||||
my_mpz_set_ui (z, 42);
|
||||
array_mpz_push_back (array1, z);
|
||||
array_mpz_get_str(str, array1, true);
|
||||
assert (string_cmp_str (str, "[17][17,42]") == 0);
|
||||
// NOTE: Not the same order than list...
|
||||
}
|
||||
|
||||
mpz_clear (z);
|
||||
my_mpz_clear (z);
|
||||
array_mpz_clear(array2);
|
||||
array_mpz_clear(array1);
|
||||
}
|
||||
|
||||
+41
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -105,6 +105,17 @@ static void test1(void)
|
||||
assert (b == false);
|
||||
assert (bitset_size(set) == 196);
|
||||
|
||||
bitset_set_str(set, "[1010101010101010101000000000000000000000000000000000000000000000000000001111]");
|
||||
bitset_push_at(set, 23, true);
|
||||
bitset_t set3;
|
||||
bitset_init(set3);
|
||||
bitset_set_str(set3, "[10101010101010101010000100000000000000000000000000000000000000000000000001111]");
|
||||
assert(bitset_equal_p(set, set3));
|
||||
bitset_push_at(set, 25, true);
|
||||
bitset_set_str(set3, "[101010101010101010100001010000000000000000000000000000000000000000000000001111]");
|
||||
assert(bitset_equal_p(set, set3));
|
||||
bitset_clear(set3);
|
||||
|
||||
bitset_clean(set);
|
||||
for(int i = 0; i < 200; i++)
|
||||
bitset_push_back(set, (i*17547854547UL)&1) ;
|
||||
@@ -144,6 +155,15 @@ static void test1(void)
|
||||
assert (bitset_get(set2, 2) == false);
|
||||
assert (bitset_get(set2, 75) == true);
|
||||
|
||||
bitset_set_at (set2, 3, false);
|
||||
bitset_set_at (set2, 76, true);
|
||||
bitset_flip_at (set2, 2);
|
||||
bitset_flip_at (set2, 75);
|
||||
assert (bitset_get(set2, 2) == true);
|
||||
assert (bitset_get(set2, 3) == false);
|
||||
assert (bitset_get(set2, 75) == false);
|
||||
assert (bitset_get(set2, 76) == true);
|
||||
|
||||
bitset_set(set, set2);
|
||||
bitset_set_at(set, 199, !bitset_get(set, 199));
|
||||
assert(!bitset_equal_p(set, set2));
|
||||
@@ -182,6 +202,20 @@ static void test1(void)
|
||||
bitset_clear(set2);
|
||||
}
|
||||
|
||||
static void test2(void)
|
||||
{
|
||||
M_LET(set1, bitset_t) {
|
||||
bitset_t set2;
|
||||
bitset_push_back(set1, true);
|
||||
bitset_init_move(set2, set1);
|
||||
bool b;
|
||||
bitset_pop_back(&b, set2);
|
||||
assert(b);
|
||||
bitset_init(set1);
|
||||
bitset_move(set1, set2);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_str(void)
|
||||
{
|
||||
bitset_t set1, set2;
|
||||
@@ -253,15 +287,15 @@ static void test_logic(void)
|
||||
bitset_set_str(s2, "[11100000000000000000010000000000000000000000000000000000000000000]");
|
||||
assert(bitset_equal_p(s1, s2));
|
||||
|
||||
bitset_set_str(s1, "[1010000000000000000001111111111110]");
|
||||
bitset_set_str(s2, "[1100000000000000000111111111111111]");
|
||||
bitset_set_str(s1, "[10100000000000000000011111111111100000000000000000000000000000000]");
|
||||
bitset_set_str(s2, "[110000000000000000011111111111111100000000000000000000000000000000]");
|
||||
bitset_xor (s1, s2);
|
||||
bitset_set_str(s2, "[0110000000000000000110000000000001]");
|
||||
bitset_set_str(s2, "[01100000000000000001100000000000010000000000000000000000000000000]");
|
||||
assert(bitset_equal_p(s1, s2));
|
||||
|
||||
bitset_set_str(s1, "[1010000000000000000000000000000000000]");
|
||||
bitset_set_str(s1, "[1010000000000000000000000000000000000000000000000000000000000000001]");
|
||||
bitset_not (s1);
|
||||
bitset_set_str(s2, "[0101111111111111111111111111111111111]");
|
||||
bitset_set_str(s2, "[0101111111111111111111111111111111111111111111111111111111111111110]");
|
||||
assert(bitset_equal_p(s1, s2));
|
||||
|
||||
}
|
||||
@@ -277,6 +311,7 @@ static void test_let(void)
|
||||
int main(void)
|
||||
{
|
||||
test1();
|
||||
test2();
|
||||
test_str();
|
||||
test_logic();
|
||||
test_let();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -27,6 +27,7 @@ START_COVERAGE
|
||||
// Define a fixed queue of unsigned int
|
||||
BUFFER_DEF(buffer_uint, unsigned int, 10, BUFFER_QUEUE|BUFFER_BLOCKING)
|
||||
QUEUE_MPMC_DEF(queue_uint, unsigned int, BUFFER_QUEUE)
|
||||
QUEUE_SPSC_DEF(squeue_uint, unsigned int, BUFFER_QUEUE)
|
||||
END_COVERAGE
|
||||
|
||||
// Define a variable stack of float
|
||||
@@ -97,11 +98,14 @@ static void test_global(void)
|
||||
assert (!buffer_uint_empty_p(g_buff));
|
||||
assert (buffer_uint_full_p(g_buff));
|
||||
assert (buffer_uint_size(g_buff) == 10);
|
||||
|
||||
assert (buffer_uint_push_blocking(g_buff, 15, false) == false);
|
||||
|
||||
buffer_uint_clean(g_buff);
|
||||
assert (buffer_uint_empty_p(g_buff));
|
||||
assert (!buffer_uint_full_p(g_buff));
|
||||
assert (buffer_uint_size(g_buff) == 0);
|
||||
unsigned int s;
|
||||
assert (buffer_uint_pop_blocking(&s, g_buff, false) == false);
|
||||
|
||||
assert (buffer_uint_overwrite(g_buff) == 0);
|
||||
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <gmp.h>
|
||||
#include "mympz.h"
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
@@ -158,8 +158,8 @@ static void test_map(void)
|
||||
|
||||
static void test_let(void)
|
||||
{
|
||||
M_LET(z, M_CLASSIC_OPLIST(mpz)) {
|
||||
mpz_add(z,z,z);
|
||||
M_LET(z, M_CLASSIC_OPLIST(my_mpz)) {
|
||||
my_mpz_add(z,z,z);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+30
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -21,7 +21,7 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <gmp.h> // For testing purpose only.
|
||||
#include "mympz.h"
|
||||
|
||||
#include "m-string.h"
|
||||
#include "m-deque.h"
|
||||
@@ -31,6 +31,7 @@
|
||||
START_COVERAGE
|
||||
DEQUE_DEF(deque, int)
|
||||
END_COVERAGE
|
||||
DEQUE_DEF(deque_mpz, my_mpz_t, MYMPZ_OPLIST)
|
||||
|
||||
#define OPL DEQUE_OPLIST(deque)
|
||||
|
||||
@@ -42,19 +43,21 @@ static void test_ti1(int n)
|
||||
|
||||
for(int i =0; i < n ;i++) {
|
||||
deque_push_back(d, i);
|
||||
assert(*deque_back(d) == i);
|
||||
deque_push_front(d, i);
|
||||
assert(*deque_front(d) == i);
|
||||
}
|
||||
assert (*deque_back(d) == n-1);
|
||||
assert (*deque_front(d) == n-1);
|
||||
assert (!deque_empty_p(d));
|
||||
assert (deque_size(d) == (size_t)2*n);
|
||||
int s = 0;
|
||||
for(int i =0; i < 2*n ;i++) {
|
||||
int z;
|
||||
if ((i % 3) == 0)
|
||||
if ((i % 3) == 0) {
|
||||
deque_pop_front(&z, d);
|
||||
else
|
||||
assert (z > *deque_front(d) );
|
||||
} else {
|
||||
deque_pop_back(&z, d);
|
||||
}
|
||||
s += z;
|
||||
}
|
||||
assert (s == n*(n-1) );
|
||||
@@ -138,6 +141,8 @@ static void test_it(void)
|
||||
deque_previous(it);
|
||||
assert (deque_end_p(it) || !deque_last_p(it));
|
||||
}
|
||||
deque_previous(it);
|
||||
assert (deque_end_p(it));
|
||||
deque_it_end(it, d);
|
||||
assert (deque_end_p(it));
|
||||
assert (deque_last_p(it));
|
||||
@@ -201,6 +206,23 @@ static void test_set(void)
|
||||
}
|
||||
}
|
||||
|
||||
// This test showed a very bad behavior in the memory allocator
|
||||
// deque will continously allocate a new space whereas at most only
|
||||
// one item is in the container!
|
||||
// This is still quite slow.
|
||||
static void test_advance(void)
|
||||
{
|
||||
deque_t d;
|
||||
int j;
|
||||
deque_init(d);
|
||||
for(int i = 0; i < 100000000; i ++) {
|
||||
deque_push_back(d, i);
|
||||
deque_pop_front(&j, d);
|
||||
assert (i == j);
|
||||
}
|
||||
deque_clear(d);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test1();
|
||||
@@ -210,4 +232,6 @@ int main(void)
|
||||
test_ti1(10000);
|
||||
test_it();
|
||||
test_set();
|
||||
test_advance();
|
||||
exit(0);
|
||||
}
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -42,6 +42,7 @@ DICT_DEF2(dict_str, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
|
||||
DICT_OA_DEF2(dict_oa_int, int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)), int, M_DEFAULT_OPLIST)
|
||||
END_COVERAGE
|
||||
|
||||
DICT_STOREHASH_DEF2(dict_str2, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
|
||||
DICT_SET_DEF2(dict_setstr, string_t, STRING_OPLIST)
|
||||
|
||||
/* Helper structure */
|
||||
|
||||
+91
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -21,8 +21,13 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "m-mutex.h"
|
||||
#include "m-atomic.h"
|
||||
|
||||
#include "m-genint.h"
|
||||
|
||||
#define MAX_N 256
|
||||
|
||||
static void test(size_t n)
|
||||
{
|
||||
genint_t s;
|
||||
@@ -46,9 +51,91 @@ static void test(size_t n)
|
||||
genint_clear(s);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
/*******************************************************/
|
||||
|
||||
genint_t global;
|
||||
atomic_bool tab_g[MAX_N];
|
||||
|
||||
static void conso(void *p)
|
||||
{
|
||||
for(size_t n = 1; n < 256; n++) {
|
||||
test(n);
|
||||
size_t n = *(size_t*)p;
|
||||
for(int i = 0; i < 100000; i++) {
|
||||
unsigned int tab[4];
|
||||
for(int j= 0; j < 4; j++) {
|
||||
tab[j] = genint_pop(global);
|
||||
if (tab[j] != -1U) {
|
||||
assert (tab[j] < n);
|
||||
assert (atomic_load(&tab_g[tab[j]]) == false);
|
||||
atomic_store(&tab_g[tab[j]], true);
|
||||
}
|
||||
}
|
||||
for(int j = 0; j < 4; j++) {
|
||||
if (tab[j] != -1U) {
|
||||
assert (tab[j] < n);
|
||||
assert (atomic_load(&tab_g[tab[j]]) == true);
|
||||
atomic_store(&tab_g[tab[j]], false);
|
||||
genint_push(global, tab[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test2(size_t n)
|
||||
{
|
||||
m_thread_t idx[4];
|
||||
|
||||
genint_init(global, n);
|
||||
for(int i = 0; i < MAX_N; i++)
|
||||
atomic_init(&tab_g[i], false);
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
m_thread_create (idx[i], conso, (void*)&n);
|
||||
}
|
||||
for(int i = 0; i < 4;i++) {
|
||||
m_thread_join(idx[i]);
|
||||
}
|
||||
|
||||
genint_clear(global);
|
||||
}
|
||||
|
||||
// In this test, the dimension of the global and the number of threads
|
||||
// match: we cannot have a failure.
|
||||
static void conso2(void *p)
|
||||
{
|
||||
size_t n = *(size_t*)p;
|
||||
for(int i = 0; i < 1000000; i++) {
|
||||
unsigned int j = genint_pop(global);
|
||||
assert (j != -1U);
|
||||
assert (j < n);
|
||||
genint_push(global, j);
|
||||
}
|
||||
}
|
||||
|
||||
static void test3(size_t n)
|
||||
{
|
||||
m_thread_t idx[MAX_N];
|
||||
assert (n <= MAX_N);
|
||||
|
||||
genint_init(global, n);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
m_thread_create (idx[i], conso2, (void*)&n);
|
||||
}
|
||||
for(size_t i = 0; i < n;i++) {
|
||||
m_thread_join(idx[i]);
|
||||
}
|
||||
genint_clear(global);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
for(size_t n = 1; n < MAX_N; n++) {
|
||||
test(n);
|
||||
}
|
||||
for(size_t n = 1; n < MAX_N; n+=17) {
|
||||
test2(n);
|
||||
}
|
||||
for(size_t n = 2; n < 6; n++) {
|
||||
test3(n);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
+10
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MLIB - TEST module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -99,6 +99,15 @@ static void test(void)
|
||||
assert(false);
|
||||
}
|
||||
|
||||
ilist_tname_push_back (list, &x3);
|
||||
assert (ilist_tname_size (list) == 1);
|
||||
ilist_tname_push_front (list, &x1);
|
||||
assert (ilist_tname_size (list) == 2);
|
||||
ilist_tname_push_after (&x1, &x2);
|
||||
assert (ilist_tname_size (list) == 3);
|
||||
assert (ilist_tname_front (list)->n == 1);
|
||||
assert (ilist_tname_back (list)->n == 3);
|
||||
|
||||
ilist_tname_clear(list);
|
||||
}
|
||||
|
||||
|
||||
+293
-43
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -21,40 +21,17 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <gmp.h> // For testing purpose only.
|
||||
#include "mympz.h"
|
||||
#include "m-string.h"
|
||||
#include "m-list.h"
|
||||
|
||||
static void my_mpz_out_str(FILE *f, const mpz_t z)
|
||||
{
|
||||
mpz_out_str (f, 10, z);
|
||||
}
|
||||
|
||||
static bool my_mpz_in_str(mpz_t z, FILE *f)
|
||||
{
|
||||
return mpz_inp_str (z, f, 10) > 0;
|
||||
}
|
||||
|
||||
static bool my_mpz_equal_p(const mpz_t z1, const mpz_t z2)
|
||||
{
|
||||
return mpz_cmp (z1, z2) == 0;
|
||||
}
|
||||
|
||||
static void my_mpz_str(string_t str, const mpz_t z, bool append)
|
||||
{
|
||||
char *s = mpz_get_str(NULL, 10, z);
|
||||
if (append) string_cat_str (str, s);
|
||||
else string_set_str (str, s);
|
||||
free(s);
|
||||
}
|
||||
|
||||
#include "coverage.h"
|
||||
START_COVERAGE
|
||||
LIST_DEF(list_uint, unsigned int)
|
||||
LIST_DEF(list_mpz, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), \
|
||||
OUT_STR(my_mpz_out_str), IN_STR(my_mpz_in_str), EQUAL(my_mpz_equal_p), \
|
||||
GET_STR(my_mpz_str)))
|
||||
LIST_DEF(list_mpz, my_mpz_t, MYMPZ_OPLIST)
|
||||
LIST_DUAL_PUSH_DEF(list2_double, double)
|
||||
END_COVERAGE
|
||||
LIST_DUAL_PUSH_DEF(list2_mpz, my_mpz_t, MYMPZ_OPLIST)
|
||||
#define LIST_UINT_OPLIST LIST_OPLIST(list_uint)
|
||||
|
||||
static void test_uint(void)
|
||||
@@ -211,36 +188,36 @@ static void test_uint(void)
|
||||
static void test_mpz(void)
|
||||
{
|
||||
list_mpz_t v;
|
||||
mpz_t z, x, s;
|
||||
my_mpz_t z, x, s;
|
||||
|
||||
mpz_init (z);
|
||||
mpz_init (x);
|
||||
mpz_init (s);
|
||||
my_mpz_init (z);
|
||||
my_mpz_init (x);
|
||||
my_mpz_init (s);
|
||||
|
||||
list_mpz_init(v);
|
||||
assert (list_mpz_empty_p(v) == true);
|
||||
|
||||
mpz_set_ui (z, 2);
|
||||
my_mpz_set_ui (z, 2);
|
||||
list_mpz_push_back(v, z);
|
||||
assert (list_mpz_empty_p(v) == false);
|
||||
|
||||
list_mpz_pop_back(&x, v);
|
||||
assert( mpz_cmp (x, z) == 0);
|
||||
assert( my_mpz_equal_p (x, z));
|
||||
assert (list_mpz_empty_p(v) == true);
|
||||
assert (list_mpz_size(v) == 0);
|
||||
|
||||
for(unsigned int i = 0; i < 1000; i ++) {
|
||||
mpz_set_ui (z, i);
|
||||
my_mpz_set_ui (z, i);
|
||||
list_mpz_push_back(v, z);
|
||||
}
|
||||
assert (list_mpz_size(v) == 1000);
|
||||
|
||||
list_mpz_it_t u;
|
||||
mpz_set_ui (s, 0);
|
||||
my_mpz_set_ui (s, 0);
|
||||
for(list_mpz_it(u, v); !list_mpz_end_p(u); list_mpz_next(u)) {
|
||||
mpz_add (s, s, *list_mpz_cref(u));
|
||||
my_mpz_add (s, s, *list_mpz_cref(u));
|
||||
}
|
||||
assert (mpz_get_ui(s) == 1000*999/2);
|
||||
assert (my_mpz_get_ui(s) == 1000*999/2);
|
||||
|
||||
FILE *f = fopen ("a-mlist.dat", "wt");
|
||||
if (!f) abort();
|
||||
@@ -260,11 +237,11 @@ static void test_mpz(void)
|
||||
M_LET(str, STRING_OPLIST) {
|
||||
list_mpz_get_str(str, v, false);
|
||||
assert (string_cmp_str (str, "[]") == 0);
|
||||
mpz_set_ui (z, 17);
|
||||
my_mpz_set_ui (z, 17);
|
||||
list_mpz_push_back (v, z);
|
||||
list_mpz_get_str(str, v, false);
|
||||
assert (string_cmp_str (str, "[17]") == 0);
|
||||
mpz_set_ui (z, 42);
|
||||
my_mpz_set_ui (z, 42);
|
||||
list_mpz_push_back (v, z);
|
||||
list_mpz_get_str(str, v, true);
|
||||
assert (string_cmp_str (str, "[17][42,17]") == 0);
|
||||
@@ -272,14 +249,287 @@ static void test_mpz(void)
|
||||
|
||||
list_mpz_clear(v);
|
||||
|
||||
mpz_clear (z);
|
||||
mpz_clear (x);
|
||||
mpz_clear (s);
|
||||
my_mpz_clear (z);
|
||||
my_mpz_clear (x);
|
||||
my_mpz_clear (s);
|
||||
}
|
||||
|
||||
static void test_dual_push1(void)
|
||||
{
|
||||
list2_double_t list;
|
||||
double d;
|
||||
|
||||
list2_double_init(list);
|
||||
assert(list2_double_empty_p(list));
|
||||
assert(list2_double_size(list) == 0);
|
||||
|
||||
list2_double_push_back(list, 2.0);
|
||||
assert(!list2_double_empty_p(list));
|
||||
assert (*list2_double_back(list) == 2.0);
|
||||
assert (*list2_double_front(list) == 2.0);
|
||||
list2_double_pop_back(&d, list);
|
||||
assert (d == 2.0);
|
||||
assert(list2_double_empty_p(list));
|
||||
assert(list2_double_size(list) == 0);
|
||||
|
||||
list2_double_push_front(list, 3.0);
|
||||
assert (*list2_double_back(list) == 3.0);
|
||||
assert (*list2_double_front(list) == 3.0);
|
||||
assert(!list2_double_empty_p(list));
|
||||
list2_double_pop_back(&d, list);
|
||||
assert (d == 3.0);
|
||||
assert(list2_double_empty_p(list));
|
||||
assert(list2_double_size(list) == 0);
|
||||
|
||||
list2_double_push_back(list, 2.0);
|
||||
list2_double_push_back(list, 3.0);
|
||||
list2_double_push_front(list, 1.0);
|
||||
list2_double_push_front(list, 0.0);
|
||||
assert (*list2_double_back(list) == 3.0);
|
||||
assert (*list2_double_front(list) == 0.0);
|
||||
list2_double_pop_back(&d, list);
|
||||
assert (d == 3.0);
|
||||
list2_double_pop_back(&d, list);
|
||||
assert (d == 2.0);
|
||||
list2_double_pop_back(&d, list);
|
||||
assert (d == 1.0);
|
||||
list2_double_pop_back(&d, list);
|
||||
assert (d == 0.0);
|
||||
assert(list2_double_empty_p(list));
|
||||
|
||||
list2_double_push_back_new(list);
|
||||
list2_double_pop_back(&d, list);
|
||||
assert (d == 0.0);
|
||||
list2_double_push_front_new(list);
|
||||
list2_double_pop_back(&d, list);
|
||||
assert (d == 0.0);
|
||||
|
||||
list2_double_push_back_new(list);
|
||||
list2_double_pop_back(NULL, list);
|
||||
assert(list2_double_empty_p(list));
|
||||
list2_double_push_front_new(list);
|
||||
list2_double_pop_back(NULL, list);
|
||||
assert(list2_double_empty_p(list));
|
||||
|
||||
for(double e = 0.0; e < 1024.0; e += 1.0) {
|
||||
if (e < 1000.0)
|
||||
list2_double_push_front(list, e);
|
||||
if (e >= 24.0 && e < 1000.0) {
|
||||
assert (list2_double_size (list) == 25);
|
||||
}
|
||||
if (e >= 24.0) {
|
||||
list2_double_pop_back(&d, list);
|
||||
assert (d + 24.0 == e);
|
||||
}
|
||||
}
|
||||
|
||||
list2_double_push_back(list, 15);
|
||||
list2_double_t list2;
|
||||
list2_double_init(list2);
|
||||
assert(list2_double_empty_p(list2));
|
||||
assert(!list2_double_empty_p(list));
|
||||
list2_double_swap(list, list2);
|
||||
assert(!list2_double_empty_p(list2));
|
||||
assert(list2_double_empty_p(list));
|
||||
list2_double_clear(list2);
|
||||
|
||||
for(double e = 0.0; e < 1024.0; e += 1.0) {
|
||||
list2_double_push_back(list, e);
|
||||
}
|
||||
list2_double_init_set (list2, list);
|
||||
assert(list2_double_equal_p(list, list2));
|
||||
|
||||
list2_double_reverse(list2);
|
||||
for(double e = 0.0; e < 1024.0 ; e += 1.0) {
|
||||
list2_double_pop_back(&d, list2);
|
||||
assert (d == e);
|
||||
}
|
||||
assert(list2_double_empty_p(list2));
|
||||
|
||||
list2_double_splice(list2, list);
|
||||
assert(list2_double_size(list2) == 1024);
|
||||
assert(list2_double_size(list) == 0);
|
||||
list2_double_set(list, list2);
|
||||
assert(list2_double_size(list) == 1024);
|
||||
list2_double_splice(list2, list);
|
||||
assert(list2_double_size(list2) == 2048);
|
||||
assert(list2_double_size(list) == 0);
|
||||
|
||||
list2_double_move(list, list2);
|
||||
list2_double_clear(list);
|
||||
}
|
||||
|
||||
static void test_dual_it1(void)
|
||||
{
|
||||
list2_double_t list;
|
||||
list2_double_it_t it, it2;
|
||||
double d;
|
||||
|
||||
list2_double_init(list);
|
||||
|
||||
list2_double_it(it, list);
|
||||
assert(list2_double_end_p(it));
|
||||
list2_double_it_end(it, list);
|
||||
assert(list2_double_end_p(it));
|
||||
|
||||
for(double e = 0.0; e < 1024.0 ; e += 1.0)
|
||||
list2_double_push_front(list, e);
|
||||
|
||||
list2_double_it(it, list);
|
||||
assert(!list2_double_end_p(it));
|
||||
list2_double_it_set (it2, it);
|
||||
assert(list2_double_it_equal_p(it2, it));
|
||||
list2_double_it_end(it, list);
|
||||
assert(!list2_double_it_equal_p(it2, it));
|
||||
assert(list2_double_end_p(it));
|
||||
assert(!list2_double_end_p(it2));
|
||||
assert(*list2_double_ref(it2) == 0.0);
|
||||
|
||||
d = 0.0;
|
||||
for(list2_double_it(it, list) ;
|
||||
!list2_double_end_p(it) ;
|
||||
list2_double_next(it) ) {
|
||||
double e = *list2_double_cref(it);
|
||||
assert(e == d);
|
||||
if (list2_double_last_p(it))
|
||||
assert (d == 1023.0);
|
||||
d += 1.0;
|
||||
}
|
||||
assert (d == 1024.0);
|
||||
|
||||
// Insert in last
|
||||
list2_double_it_end(it, list);
|
||||
list2_double_insert(list, it, -1.0);
|
||||
d = -1.0;
|
||||
for(list2_double_it(it, list) ;
|
||||
!list2_double_end_p(it) ;
|
||||
list2_double_next(it) ) {
|
||||
double e = *list2_double_cref(it);
|
||||
assert(e == d);
|
||||
if (list2_double_last_p(it))
|
||||
list2_double_it_set(it2, it);
|
||||
d += 1.0;
|
||||
}
|
||||
assert (d == 1024.0);
|
||||
assert(*list2_double_back(list) == -1.0);
|
||||
assert(*list2_double_front(list) == 1023.0);
|
||||
|
||||
// Insert in front
|
||||
list2_double_insert(list, it2, 1024.0);
|
||||
d = -1.0;
|
||||
for(list2_double_it(it, list) ;
|
||||
!list2_double_end_p(it) ;
|
||||
list2_double_next(it) ) {
|
||||
double e = *list2_double_cref(it);
|
||||
assert(e == d);
|
||||
d += 1.0;
|
||||
}
|
||||
assert (d == 1025.0);
|
||||
assert(*list2_double_back(list) == -1.0);
|
||||
assert(*list2_double_front(list) == 1024.0);
|
||||
|
||||
// Insert in between
|
||||
list2_double_it(it, list) ;
|
||||
list2_double_insert(list, it, -0.5);
|
||||
d = -1.0;
|
||||
for(list2_double_it(it, list) ;
|
||||
!list2_double_end_p(it) ;
|
||||
list2_double_next(it) ) {
|
||||
double e = *list2_double_cref(it);
|
||||
assert(e == d);
|
||||
d += (d < 0.0) ? 0.5 : 1.0;
|
||||
}
|
||||
assert (d == 1025.0);
|
||||
assert(*list2_double_back(list) == -1.0);
|
||||
assert(*list2_double_front(list) == 1024.0);
|
||||
|
||||
// Remove in between
|
||||
list2_double_it(it, list) ;
|
||||
list2_double_next(it);
|
||||
assert (*list2_double_cref(it) == -0.5);
|
||||
list2_double_remove(list, it);
|
||||
d = -1.0;
|
||||
for(list2_double_it(it, list) ;
|
||||
!list2_double_end_p(it) ;
|
||||
list2_double_next(it) ) {
|
||||
double e = *list2_double_cref(it);
|
||||
assert(e == d);
|
||||
if (list2_double_last_p(it))
|
||||
list2_double_it_set(it2, it);
|
||||
d += 1.0;
|
||||
}
|
||||
assert (d == 1025.0);
|
||||
assert(*list2_double_back(list) == -1.0);
|
||||
assert(*list2_double_front(list) == 1024.0);
|
||||
|
||||
// Remove front
|
||||
list2_double_remove(list, it2);
|
||||
d = -1.0;
|
||||
for(list2_double_it(it, list) ;
|
||||
!list2_double_end_p(it) ;
|
||||
list2_double_next(it) ) {
|
||||
double e = *list2_double_cref(it);
|
||||
assert(e == d);
|
||||
d += 1.0;
|
||||
}
|
||||
assert (d == 1024.0);
|
||||
assert(*list2_double_back(list) == -1.0);
|
||||
assert(*list2_double_front(list) == 1023.0);
|
||||
|
||||
// Remove back
|
||||
list2_double_it(it, list);
|
||||
list2_double_remove(list, it);
|
||||
d = 0.0;
|
||||
for(list2_double_it(it, list) ;
|
||||
!list2_double_end_p(it) ;
|
||||
list2_double_next(it) ) {
|
||||
double e = *list2_double_cref(it);
|
||||
assert(e == d);
|
||||
d += 1.0;
|
||||
}
|
||||
assert (d == 1024.0);
|
||||
assert(*list2_double_back(list) == 0.0);
|
||||
assert(*list2_double_front(list) == 1023.0);
|
||||
|
||||
list2_double_t list2;
|
||||
list2_double_init_set(list2, list);
|
||||
|
||||
// Splice back the back of list
|
||||
list2_double_it(it, list);
|
||||
list2_double_splice_back(list2, list, it);
|
||||
assert(*list2_double_back(list) == 1.0);
|
||||
assert(*list2_double_cref(it) == 1.0);
|
||||
list2_double_it(it2, list2);
|
||||
assert(*list2_double_cref(it2) == 0.0);
|
||||
list2_double_next(it2);
|
||||
assert(*list2_double_cref(it2) == 0.0);
|
||||
list2_double_next(it2);
|
||||
assert(*list2_double_cref(it2) == 1.0);
|
||||
|
||||
// Splice back an element of list
|
||||
list2_double_next(it);
|
||||
list2_double_splice_back(list2, list, it);
|
||||
assert(*list2_double_back(list) == 1.0);
|
||||
assert(*list2_double_cref(it) == 3.0);
|
||||
list2_double_it(it2, list2);
|
||||
assert(*list2_double_cref(it2) == 2.0);
|
||||
list2_double_next(it2);
|
||||
assert(*list2_double_cref(it2) == 0.0);
|
||||
list2_double_next(it2);
|
||||
assert(*list2_double_cref(it2) == 0.0);
|
||||
list2_double_next(it2);
|
||||
assert(*list2_double_cref(it2) == 1.0);
|
||||
|
||||
list2_double_clear(list2);
|
||||
list2_double_clear(list);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_uint();
|
||||
test_mpz();
|
||||
test_dual_push1();
|
||||
test_dual_it1();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -99,4 +99,5 @@ int main(void)
|
||||
{
|
||||
test1();
|
||||
test2();
|
||||
exit(0);
|
||||
}
|
||||
+78
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -43,21 +43,57 @@ static void uint_get_str(string_t str, unsigned int u, bool append)
|
||||
#include "coverage.h"
|
||||
START_COVERAGE
|
||||
RBTREE_DEF(rbtree_uint, unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, IN_STR(uint_in_str M_IPTR), OUT_STR(uint_out_str), GET_STR(uint_get_str)) )
|
||||
RBTREE_DEF(rbtree_float, float)
|
||||
END_COVERAGE
|
||||
|
||||
RBTREE_DEF(rbtree_float, float)
|
||||
|
||||
#define UINT_OPLIST RBTREE_OPLIST(rbtree_uint)
|
||||
#define FLOAT_OP RBTREE_OPLIST(rbtree_float)
|
||||
|
||||
static void test_uint(void)
|
||||
{
|
||||
rbtree_uint_t tree, tree2;
|
||||
rbtree_uint_t tree, tree2, tree3;
|
||||
rbtree_uint_init(tree);
|
||||
assert (rbtree_uint_empty_p(tree));
|
||||
rbtree_uint_init_set(tree2, tree);
|
||||
assert (rbtree_uint_empty_p(tree2));
|
||||
rbtree_uint_clear(tree);
|
||||
|
||||
rbtree_uint_push(tree, 10);
|
||||
rbtree_uint_push(tree, 5);
|
||||
rbtree_uint_push(tree, 17);
|
||||
rbtree_uint_push(tree, 3);
|
||||
rbtree_uint_push(tree, 11);
|
||||
assert(rbtree_uint_size(tree) == 5);
|
||||
assert(rbtree_uint_empty_p(tree) == false);
|
||||
const unsigned int tab[] = {3, 5, 10, 11, 17};
|
||||
int k = 0;
|
||||
for M_EACH(item, tree, UINT_OPLIST) {
|
||||
assert (tab[k] == *item);
|
||||
k ++;
|
||||
}
|
||||
assert (k == 5);
|
||||
rbtree_uint_it_t it, it2;
|
||||
for (rbtree_uint_it_last(it, tree) ; !rbtree_uint_end_p(it) ; rbtree_uint_previous(it)) {
|
||||
k--;
|
||||
rbtree_uint_it_set(it2, it);
|
||||
assert(rbtree_uint_it_equal_p(it2, it));
|
||||
assert (tab[k] == *rbtree_uint_cref(it2) );
|
||||
}
|
||||
rbtree_uint_it_end(it, tree);
|
||||
assert (rbtree_uint_end_p(it));
|
||||
assert(!rbtree_uint_it_equal_p(it2, it));
|
||||
assert( k == 0);
|
||||
assert (rbtree_uint_hash(tree) != 0);
|
||||
|
||||
rbtree_uint_init(tree3);
|
||||
rbtree_uint_push(tree3, 5);
|
||||
rbtree_uint_move(tree3, tree);
|
||||
rbtree_uint_clear(tree3);
|
||||
|
||||
rbtree_uint_init_move(tree, tree2);
|
||||
rbtree_uint_init_move(tree2, tree);
|
||||
assert (rbtree_uint_empty_p(tree2));
|
||||
|
||||
const unsigned int max = 1001;
|
||||
for(unsigned int num = 1; num < max; num++) {
|
||||
rbtree_uint_init(tree);
|
||||
@@ -65,6 +101,11 @@ static void test_uint(void)
|
||||
rbtree_uint_push(tree, i);
|
||||
assert(rbtree_uint_size(tree) == num);
|
||||
assert(rbtree_uint_empty_p(tree) == false);
|
||||
if (num > 10) {
|
||||
rbtree_uint_push(tree, 10);
|
||||
assert(rbtree_uint_size(tree) == num);
|
||||
assert(rbtree_uint_empty_p(tree) == false);
|
||||
}
|
||||
unsigned int count = 0;
|
||||
for M_EACH(item, tree, UINT_OPLIST) {
|
||||
assert (count == *item);
|
||||
@@ -72,11 +113,16 @@ static void test_uint(void)
|
||||
}
|
||||
assert (*rbtree_uint_min(tree) == 0);
|
||||
assert (*rbtree_uint_max(tree) == num-1);
|
||||
assert (*rbtree_uint_cmin(tree) == 0);
|
||||
assert (*rbtree_uint_cmax(tree) == num-1);
|
||||
assert (count == num);
|
||||
rbtree_uint_set(tree2, tree);
|
||||
unsigned int *ptr = rbtree_uint_get(tree2, num/2);
|
||||
assert (ptr != NULL);
|
||||
assert (*ptr == num/2);
|
||||
const unsigned int *cptr = rbtree_uint_cget(tree2, num/2);
|
||||
assert (cptr != NULL);
|
||||
assert (*cptr == num/2);
|
||||
rbtree_uint_clear(tree);
|
||||
|
||||
bool b = rbtree_uint_pop(NULL, tree2, num+1);
|
||||
@@ -92,7 +138,7 @@ static void test_uint(void)
|
||||
assert(b);
|
||||
ptr = rbtree_uint_get(tree2, i);
|
||||
assert (ptr == NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rbtree_uint_init (tree);
|
||||
@@ -110,6 +156,32 @@ static void test_uint(void)
|
||||
rbtree_uint_clear(tree2);
|
||||
}
|
||||
|
||||
static void test_uint_permut(void)
|
||||
{
|
||||
const unsigned int max = 1001;
|
||||
unsigned int tab[1001];
|
||||
for(unsigned int num = 1; num < max; num++) {
|
||||
rbtree_uint_t tree;
|
||||
rbtree_uint_init(tree);
|
||||
for(unsigned int i = 0; i < num; i++)
|
||||
tab[i] = i;
|
||||
for(unsigned int i = 0; i < 2 * num; i++) {
|
||||
int j = rand() % num;
|
||||
int k = rand() % num;
|
||||
M_SWAP(unsigned int, tab[j], tab[k]);
|
||||
}
|
||||
for(unsigned int i = 0; i < num; i++)
|
||||
rbtree_uint_push(tree, tab[i]);
|
||||
unsigned int k = 0;
|
||||
for M_EACH(item, tree, UINT_OPLIST) {
|
||||
assert (k == *item);
|
||||
k++;
|
||||
}
|
||||
rbtree_uint_clear(tree);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_float(void)
|
||||
{
|
||||
M_LET(tree, FLOAT_OP) {
|
||||
@@ -172,6 +244,7 @@ static void test_io(void)
|
||||
int main(void)
|
||||
{
|
||||
test_uint();
|
||||
test_uint_permut();
|
||||
test_float();
|
||||
test_io();
|
||||
exit(0);
|
||||
|
||||
+55
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -20,16 +20,18 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <gmp.h>
|
||||
#include <assert.h>
|
||||
#include "mympz.h"
|
||||
|
||||
#include "m-shared.h"
|
||||
|
||||
#include "coverage.h"
|
||||
START_COVERAGE
|
||||
SHARED_PTR_DEF(shared_int, int)
|
||||
SHARED_RESOURCE_DEF(shared_ressource, my_mpz_t, M_CLASSIC_OPLIST(my_mpz))
|
||||
END_COVERAGE
|
||||
SHARED_PTR_DEF(shared_mpz, mpz_t, M_CLASSIC_OPLIST(mpz))
|
||||
SHARED_PTR_DEF(shared_mpz, my_mpz_t, M_CLASSIC_OPLIST(my_mpz))
|
||||
SHARED_PTR_RELAXED_DEF(shared_relaxed_int, int)
|
||||
|
||||
static int f(const shared_int_t p)
|
||||
{
|
||||
@@ -128,9 +130,59 @@ static void test2(void)
|
||||
shared_int_clear(p1);
|
||||
}
|
||||
|
||||
#define MAX_RESSOURCE 10
|
||||
|
||||
static void test_ressource(int n)
|
||||
{
|
||||
shared_ressource_t ressource;
|
||||
shared_ressource_it_t it[MAX_RESSOURCE];
|
||||
shared_ressource_it_t copy[MAX_RESSOURCE];
|
||||
shared_ressource_it_t onemore;
|
||||
|
||||
shared_ressource_init (ressource, n);
|
||||
for(int i = 0; i < n ; i++) {
|
||||
shared_ressource_it (it[i], ressource);
|
||||
assert (!shared_ressource_end_p(it[i]));
|
||||
my_mpz_t *z = shared_ressource_ref(it[i]);
|
||||
assert (z != NULL);
|
||||
my_mpz_set_ui(*z, i);
|
||||
}
|
||||
shared_ressource_it (onemore, ressource);
|
||||
assert (shared_ressource_end_p(onemore));
|
||||
for(int i = 0; i < n ; i++) {
|
||||
shared_ressource_it_set (copy[i], it[i]);
|
||||
assert (!shared_ressource_end_p(copy[i]));
|
||||
const my_mpz_t *z = shared_ressource_cref(copy[i]);
|
||||
assert (z != NULL);
|
||||
assert (my_mpz_cmp_ui(*z, i) == 0);
|
||||
}
|
||||
shared_ressource_it (onemore, ressource);
|
||||
assert (shared_ressource_end_p(onemore));
|
||||
for(int i = 0; i < n ; i++) {
|
||||
shared_ressource_end (it[i], ressource);
|
||||
}
|
||||
shared_ressource_it (onemore, ressource);
|
||||
assert (shared_ressource_end_p(onemore));
|
||||
for(int i = n-1; i >= 0 ; i--) {
|
||||
const my_mpz_t *z = shared_ressource_cref(copy[i]);
|
||||
assert (z != NULL);
|
||||
shared_ressource_end (copy[i], ressource);
|
||||
assert (shared_ressource_end_p(copy[i]));
|
||||
shared_ressource_it (onemore, ressource);
|
||||
assert (!shared_ressource_end_p(onemore));
|
||||
shared_ressource_end (onemore, ressource);
|
||||
shared_ressource_end (copy[i], ressource);
|
||||
}
|
||||
|
||||
shared_ressource_clear(ressource);
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test1();
|
||||
test2();
|
||||
for(int i = 1; i < MAX_RESSOURCE; i++)
|
||||
test_ressource(i);
|
||||
exit(0);
|
||||
}
|
||||
+213
-21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -26,11 +26,34 @@
|
||||
#include "m-mutex.h"
|
||||
|
||||
#include "coverage.h"
|
||||
|
||||
// Long Structure with a simple CRC to check for proper passing
|
||||
typedef struct {
|
||||
unsigned int n;
|
||||
unsigned long long spare1;
|
||||
unsigned int c;
|
||||
unsigned long long spare2;
|
||||
unsigned int p;
|
||||
} data_t;
|
||||
|
||||
static void data_crc(data_t *p) { p->p = -p->n; p->c = ~p->n; }
|
||||
static void data_init(data_t *p) { p->n = 0; p->spare1 = 0; p->spare2 = 0; data_crc(p); }
|
||||
static void data_valid_p(const data_t *p) { assert (p->n == -p->p && p->n == ~p->c); }
|
||||
static void data_clear(data_t *p) { (void) p;}
|
||||
static void data_set(data_t *p, data_t o) { p->n = o.n; data_crc(p); }
|
||||
|
||||
#define DATA_OPLIST \
|
||||
(INIT(data_init M_IPTR), INIT_SET(data_set M_IPTR), SET(data_set M_IPTR), CLEAR(data_clear M_IPTR))
|
||||
|
||||
START_COVERAGE
|
||||
SNAPSHOT_DEF(snapshot_uint, unsigned int)
|
||||
SNAPSHOT_DEF(snapshot_mpz, mpz_t,
|
||||
(INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear)))
|
||||
SNAPSHOT_SPSC_DEF(snapshot_uint, unsigned int)
|
||||
SNAPSHOT_SPSC_DEF(snapshot_mpz, mpz_t,
|
||||
(INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear)))
|
||||
SNAPSHOT_SPMC_DEF(snapshot_mrsw_data, data_t, DATA_OPLIST)
|
||||
SNAPSHOT_MPMC_DEF(snapshot_mrmw_data, data_t, DATA_OPLIST)
|
||||
END_COVERAGE
|
||||
SNAPSHOT_DEF(snapshot_data, data_t, DATA_OPLIST )
|
||||
|
||||
|
||||
static void test_uint(void)
|
||||
{
|
||||
@@ -75,21 +98,6 @@ static void test_uint(void)
|
||||
assert (*snapshot_uint_read(t) == 3);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned int n;
|
||||
unsigned int c;
|
||||
unsigned int p;
|
||||
} data_t;
|
||||
|
||||
static void data_crc(data_t *p) { p->p = -p->n; p->c = ~p->n; }
|
||||
static void data_init(data_t *p) { p->n = 0; data_crc(p); }
|
||||
static void data_clear(data_t *p) { (void) p;}
|
||||
static void data_set(data_t *p, data_t o) { p->p = o.p; data_crc(p); }
|
||||
|
||||
SNAPSHOT_DEF(snapshot_data, data_t,
|
||||
(INIT(data_init M_IPTR), INIT_SET(data_set M_IPTR), SET(data_set M_IPTR), CLEAR(data_clear M_IPTR))
|
||||
)
|
||||
|
||||
snapshot_data_t g_buff;
|
||||
|
||||
static void conso(void *arg)
|
||||
@@ -97,8 +105,7 @@ static void conso(void *arg)
|
||||
assert (arg == NULL);
|
||||
while (true) {
|
||||
const data_t *p = snapshot_data_read(g_buff);
|
||||
assert (p->n == -p->p);
|
||||
assert (p->n == ~p->c);
|
||||
data_valid_p(p);
|
||||
if (p->n == 0)
|
||||
return;
|
||||
}
|
||||
@@ -140,10 +147,195 @@ static void test_global(void)
|
||||
snapshot_data_clear(g_buff);
|
||||
}
|
||||
|
||||
static void test_mrsw_int1(void)
|
||||
{
|
||||
snapshot_mrsw_int_t idx;
|
||||
snapshot_mrsw_int_init(idx, 1);
|
||||
|
||||
assert (snapshot_mrsw_int_get_write_idx(idx) == 1);
|
||||
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 1);
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 1);
|
||||
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 0);
|
||||
snapshot_mrsw_int_read_end(idx, 0);
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 0);
|
||||
snapshot_mrsw_int_read_end(idx, 0);
|
||||
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 1);
|
||||
assert (snapshot_mrsw_int_write(idx) == 2);
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 2);
|
||||
snapshot_mrsw_int_read_end(idx, 1);
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 1);
|
||||
|
||||
snapshot_mrsw_int_clear(idx);
|
||||
}
|
||||
|
||||
static void test_mrsw_int2(void)
|
||||
{
|
||||
snapshot_mrsw_int_t idx;
|
||||
snapshot_mrsw_int_init(idx, 2);
|
||||
|
||||
assert (snapshot_mrsw_int_get_write_idx(idx) == 1);
|
||||
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 1);
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 1);
|
||||
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 0);
|
||||
snapshot_mrsw_int_read_end(idx, 0);
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 0);
|
||||
snapshot_mrsw_int_read_end(idx, 0);
|
||||
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 1);
|
||||
assert (snapshot_mrsw_int_write(idx) == 2);
|
||||
assert (snapshot_mrsw_int_write(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 2);
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 0);
|
||||
assert (snapshot_mrsw_int_write(idx) == 3);
|
||||
snapshot_mrsw_int_read_end(idx, 1);
|
||||
assert (snapshot_mrsw_int_read_start(idx) == 2);
|
||||
assert (snapshot_mrsw_int_write(idx) == 1);
|
||||
snapshot_mrsw_int_read_end(idx, 0);
|
||||
|
||||
snapshot_mrsw_int_clear(idx);
|
||||
}
|
||||
|
||||
snapshot_mrsw_data_t global_mrsw;
|
||||
|
||||
static void conso2(void *arg)
|
||||
{
|
||||
assert (arg == NULL);
|
||||
while (true) {
|
||||
const data_t *p = snapshot_mrsw_data_read_start(global_mrsw);
|
||||
assert (p != NULL);
|
||||
data_valid_p(p);
|
||||
if (p->n == 0)
|
||||
return;
|
||||
snapshot_mrsw_data_read_end(global_mrsw, p);
|
||||
}
|
||||
}
|
||||
|
||||
static void prod2(void *arg)
|
||||
{
|
||||
assert (arg == NULL);
|
||||
data_t *p = snapshot_mrsw_data_get_write_buffer(global_mrsw);
|
||||
for(unsigned int i = 1; i < 200000;i++) {
|
||||
assert (p != NULL);
|
||||
p->n = i * i;
|
||||
data_crc(p);
|
||||
p = snapshot_mrsw_data_write(global_mrsw);
|
||||
}
|
||||
p->n = 0;
|
||||
data_crc(p);
|
||||
p = snapshot_mrsw_data_write(global_mrsw);
|
||||
assert (p != NULL);
|
||||
}
|
||||
|
||||
#define MAX_WRITER 8
|
||||
#define MAX_READER 8
|
||||
|
||||
static void test_mrsw_global(int reader)
|
||||
{
|
||||
m_thread_t idx_w;
|
||||
m_thread_t idx[MAX_READER];
|
||||
|
||||
snapshot_mrsw_data_init(global_mrsw, reader);
|
||||
data_t *p = snapshot_mrsw_data_write(global_mrsw);
|
||||
assert (p != NULL);
|
||||
p->n = 42;
|
||||
data_crc(p);
|
||||
p = snapshot_mrsw_data_write(global_mrsw);
|
||||
assert (p != NULL);
|
||||
|
||||
for(int i = 0 ; i < reader; i++)
|
||||
m_thread_create (idx[i], conso2, NULL);
|
||||
m_thread_create (idx_w, prod2, NULL);
|
||||
|
||||
m_thread_join(idx_w);
|
||||
for(int i = 0 ; i < reader; i++)
|
||||
m_thread_join(idx[i]);
|
||||
|
||||
snapshot_mrsw_data_clear(global_mrsw);
|
||||
}
|
||||
|
||||
snapshot_mrmw_data_t global_mrmw;
|
||||
|
||||
static void conso3(void *arg)
|
||||
{
|
||||
assert (arg == NULL);
|
||||
while (true) {
|
||||
const data_t *p = snapshot_mrmw_data_read_start(global_mrmw);
|
||||
assert (p != NULL);
|
||||
data_valid_p(p);
|
||||
if (p->n == 0)
|
||||
return;
|
||||
snapshot_mrmw_data_read_end(global_mrmw, p);
|
||||
}
|
||||
}
|
||||
|
||||
static void prod3(void *arg)
|
||||
{
|
||||
assert (arg == NULL);
|
||||
for(unsigned int i = 1; i < 20000000;i++) {
|
||||
data_t *p = snapshot_mrmw_data_write_start(global_mrmw);
|
||||
assert (p != NULL);
|
||||
p->n = i * i;
|
||||
data_crc(p);
|
||||
snapshot_mrmw_data_write_end(global_mrmw, p);
|
||||
}
|
||||
data_t *p = snapshot_mrmw_data_write_start(global_mrmw);
|
||||
p->n = 0;
|
||||
data_crc(p);
|
||||
snapshot_mrmw_data_write_end(global_mrmw, p);
|
||||
}
|
||||
|
||||
static void test_mrmw_global(int reader, int writer)
|
||||
{
|
||||
m_thread_t idx_w[MAX_WRITER];
|
||||
m_thread_t idx[MAX_READER];
|
||||
|
||||
snapshot_mrmw_data_init(global_mrmw, reader, writer);
|
||||
data_t *p = snapshot_mrmw_data_write_start(global_mrmw);
|
||||
assert (p != NULL);
|
||||
p->n = 42;
|
||||
data_crc(p);
|
||||
snapshot_mrmw_data_write_end(global_mrmw, p);
|
||||
|
||||
for(int i = 0 ; i < reader; i++)
|
||||
m_thread_create (idx[i], conso3, NULL);
|
||||
for(int i = 0 ; i < writer; i++)
|
||||
m_thread_create (idx_w[i], prod3, NULL);
|
||||
|
||||
for(int i = 0 ; i < writer; i++)
|
||||
m_thread_join(idx_w[i]);
|
||||
for(int i = 0 ; i < reader; i++)
|
||||
m_thread_join(idx[i]);
|
||||
|
||||
snapshot_mrmw_data_clear(global_mrmw);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_uint();
|
||||
test_global();
|
||||
test_mrsw_int1();
|
||||
test_mrsw_int2();
|
||||
test_mrsw_global(1);
|
||||
test_mrsw_global(2);
|
||||
test_mrsw_global(4);
|
||||
test_mrsw_global(MAX_READER);
|
||||
test_mrmw_global(1, 1);
|
||||
test_mrmw_global(MAX_READER/4, MAX_WRITER/4);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
+64
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -24,11 +24,14 @@
|
||||
#define STRING_WITHIN_TEST
|
||||
#include "m-string.h"
|
||||
|
||||
BOUNDED_STRING_DEF(string16, 16)
|
||||
|
||||
static void test1(void)
|
||||
{
|
||||
M_LET(s1, s2, string_t) {
|
||||
string_set_str(s1, "Success!");
|
||||
string_set(s2, s1);
|
||||
assert(string_equal_p(s1, s2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +114,7 @@ static void test_utf8_it(void)
|
||||
string_clear(s);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
static void test0(void)
|
||||
{
|
||||
string_t s1;
|
||||
string_t s2;
|
||||
@@ -147,6 +150,9 @@ int main(void)
|
||||
assert (strcmp(string_get_cstr(s1), "Hello beautiful world!") == 0);
|
||||
|
||||
string_clean(s1);
|
||||
string_set_n (s2, s1, 0, 5);
|
||||
assert(string_empty_p(s2));
|
||||
|
||||
string_set_str(s1, "Hello");
|
||||
string_cat_str(s1, ", world!");
|
||||
assert (string_size(s1) == 13);
|
||||
@@ -418,8 +424,64 @@ int main(void)
|
||||
|
||||
string_clear (s1);
|
||||
string_clear (s2);
|
||||
}
|
||||
|
||||
static void test_bounded1(void)
|
||||
{
|
||||
string16_t s, d;
|
||||
string16_init(s);
|
||||
assert (string16_empty_p(s));
|
||||
assert (string16_size(s) == 0);
|
||||
assert (string16_capacity(s) == 17);
|
||||
string16_set_str(s, "Hello");
|
||||
assert (!string16_empty_p(s));
|
||||
assert (string16_size(s) == 5);
|
||||
assert (string16_equal_str_p(s, "Hello"));
|
||||
assert (string16_cmp_str(s, "Hello") == 0);
|
||||
assert (string16_get_char(s, 1) == 'e');
|
||||
assert (strcmp(string16_get_cstr(s), "Hello") == 0);
|
||||
string16_clean(s);
|
||||
assert (string16_empty_p(s));
|
||||
assert (string16_size(s) == 0);
|
||||
string16_set_str(s, "Hello, world! How do you do?");
|
||||
assert (!string16_empty_p(s));
|
||||
assert (string16_size(s) == 16);
|
||||
assert (string16_equal_str_p(s, "Hello, world! Ho"));
|
||||
string16_set_strn(s, "Hello, world! How do you do?", 17);
|
||||
assert (!string16_empty_p(s));
|
||||
assert (string16_size(s) == 16);
|
||||
assert (string16_equal_str_p(s, "Hello, world! Ho"));
|
||||
string16_set_strn(s, "Hello, world! How do you do?", 15);
|
||||
assert (!string16_empty_p(s));
|
||||
assert (string16_size(s) == 15);
|
||||
assert (string16_equal_str_p(s, "Hello, world! H"));
|
||||
string16_cat_str(s, "ow do you do?");
|
||||
assert (string16_size(s) == 16);
|
||||
assert (!string16_equal_str_p(s, "Hello, world! H"));
|
||||
assert (string16_equal_str_p(s, "Hello, world! Ho"));
|
||||
string16_printf(s, "HeH:%d", 16);
|
||||
assert (string16_size(s) == 6);
|
||||
assert (string16_equal_str_p(s, "HeH:16"));
|
||||
string16_cat_printf(s, " GeG:%d/%d FRE:%d", 17, 42, 13);
|
||||
assert (string16_size(s) == 16);
|
||||
assert (string16_equal_str_p(s, "HeH:16 GeG:17/42"));
|
||||
assert (string16_hash(s) != 0);
|
||||
|
||||
string16_set_strn(s, "Hello, world! How do you do?", 15);
|
||||
string16_init_set(d, s);
|
||||
string16_clean(s);
|
||||
assert (string16_equal_str_p(d, "Hello, world! H"));
|
||||
|
||||
string16_clear(d);
|
||||
string16_clear(s);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test0();
|
||||
test1();
|
||||
test_utf8_basic();
|
||||
test_utf8_it();
|
||||
test_bounded1();
|
||||
exit(0);
|
||||
}
|
||||
+15
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -21,28 +21,28 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <gmp.h>
|
||||
|
||||
#include "mympz.h"
|
||||
#include "m-string.h"
|
||||
|
||||
#include "m-tuple.h"
|
||||
|
||||
#include "coverage.h"
|
||||
START_COVERAGE
|
||||
TUPLE_DEF2(pair,
|
||||
(key, string_t, (INIT(string_init), INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear))),
|
||||
(value, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear) )))
|
||||
(value, my_mpz_t, MYMPZ_OPLIST) )
|
||||
END_COVERAGE
|
||||
|
||||
// No cmp defined
|
||||
TUPLE_DEF2(triple,
|
||||
(key, string_t, (INIT(string_init), INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear), CMP(string_cmp))),
|
||||
(value, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear) )),
|
||||
(value, my_mpz_t, MYMPZ_OPLIST ),
|
||||
(data, const char *, ()))
|
||||
|
||||
// cmp shall be defined
|
||||
TUPLE_DEF2(pair3,
|
||||
(key, string_t, (INIT(string_init), INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear), CMP(string_cmp), HASH(string_hash), EQUAL(string_equal_p))),
|
||||
(value, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), CMP(mpz_cmp) )))
|
||||
(value, my_mpz_t, M_OPEXTEND( MYMPZ_OPLIST, CMP(my_mpz_cmp)) ) )
|
||||
|
||||
TUPLE_DEF2(pair_str,
|
||||
(vala, string_t, STRING_OPLIST),
|
||||
@@ -98,33 +98,33 @@ int main(void)
|
||||
|
||||
pair_init (p1);
|
||||
string_set_str(p1->key, "HELLO");
|
||||
mpz_set_str(p1->value, "1742", 10);
|
||||
my_mpz_set_ui(p1->value, 1742);
|
||||
pair_init_set (p2, p1);
|
||||
assert(mpz_cmp_ui(p2->value, 1742) == 0);
|
||||
assert(my_mpz_cmp_ui(p2->value, 1742) == 0);
|
||||
assert(string_equal_str_p(p2->key, "HELLO"));
|
||||
string_set_str(p2->key, "HELLO WORLD");
|
||||
mpz_set_str(p2->value, "174217", 10);
|
||||
my_mpz_set_ui(p2->value, 174217);
|
||||
pair_set(p1, p1);
|
||||
pair_set(p1, p2);
|
||||
assert(mpz_cmp_ui(p1->value, 174217) == 0);
|
||||
assert(my_mpz_cmp_ui(p1->value, 174217) == 0);
|
||||
assert(string_equal_str_p(p1->key, "HELLO WORLD"));
|
||||
pair_clear(p1);
|
||||
pair_clear(p2);
|
||||
|
||||
string_t s;
|
||||
mpz_t z;
|
||||
my_mpz_t z;
|
||||
pair3_t p3, p4;
|
||||
string_init_set_str(s, "HELLO");
|
||||
mpz_init_set_ui (z, 1442);
|
||||
my_mpz_init_set_ui (z, 1442);
|
||||
pair3_init_set2(p3, s, z);
|
||||
pair3_init_set2(p4, s, z);
|
||||
int i = pair3_cmp (p3, p4);
|
||||
assert (i == 0);
|
||||
mpz_set_ui (z, 1443);
|
||||
my_mpz_set_ui (z, 1443);
|
||||
pair3_set_value(p4, z);
|
||||
i = pair3_cmp (p3, p4);
|
||||
assert (i < 0);
|
||||
mpz_set_ui (z, 1442);
|
||||
my_mpz_set_ui (z, 1442);
|
||||
string_set_str(s, "HELLN");
|
||||
pair3_set_key(p4, s);
|
||||
i = pair3_cmp (p3, p4);
|
||||
@@ -132,7 +132,7 @@ int main(void)
|
||||
pair3_clear(p3);
|
||||
pair3_clear(p4);
|
||||
string_clear(s);
|
||||
mpz_clear(z);
|
||||
my_mpz_clear(z);
|
||||
|
||||
check_io();
|
||||
check_swap();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -21,9 +21,9 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <gmp.h>
|
||||
|
||||
#include "mympz.h"
|
||||
#include "m-string.h"
|
||||
|
||||
#include "m-variant.h"
|
||||
|
||||
#include "coverage.h"
|
||||
@@ -138,7 +138,7 @@ static void test_pair(void)
|
||||
|
||||
VARIANT_DEF2(triple,
|
||||
(s, string_t, STRING_OPLIST),
|
||||
(z, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear) )),
|
||||
(z, my_mpz_t, (INIT(my_mpz_init), INIT_SET(my_mpz_init_set), SET(my_mpz_set), CLEAR(my_mpz_clear) )),
|
||||
(i, int, M_DEFAULT_OPLIST) )
|
||||
|
||||
static void
|
||||
@@ -148,10 +148,10 @@ test_triple(void)
|
||||
triple_init(t);
|
||||
string_t s;
|
||||
string_init(s);
|
||||
mpz_t z;
|
||||
mpz_init(z);
|
||||
my_mpz_t z;
|
||||
my_mpz_init(z);
|
||||
|
||||
mpz_set_str(z, "125567890456789345784567812345678", 10);
|
||||
my_mpz_set_ui(z, 2556789045);
|
||||
string_set_str(s, "FHZKJHFKZUHFKZHFUHZFUHURHYERUYEUIRYEIURYIEYRIU");
|
||||
assert( triple_type(t) == triple_EMPTY);
|
||||
|
||||
@@ -165,9 +165,9 @@ test_triple(void)
|
||||
assert( triple_type(t) == triple_z);
|
||||
triple_set_z(t, z);
|
||||
assert( triple_type(t) == triple_z);
|
||||
assert( mpz_cmp (z, *triple_get_z(t)) == 0);
|
||||
assert( my_mpz_cmp (z, *triple_get_z(t)) == 0);
|
||||
|
||||
mpz_clear(z);
|
||||
my_mpz_clear(z);
|
||||
string_clear(s);
|
||||
triple_clear(t);
|
||||
}
|
||||
|
||||
+17
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -30,10 +30,10 @@ static int fib(int n);
|
||||
struct fib2_s {
|
||||
int x, n;
|
||||
};
|
||||
volatile bool resetFunc_called;
|
||||
atomic_bool resetFunc_called = ATOMIC_VAR_INIT(false);
|
||||
static void resetFunc(void)
|
||||
{
|
||||
resetFunc_called = true;
|
||||
atomic_store(&resetFunc_called, true);
|
||||
}
|
||||
|
||||
static void subfunc_1 (void *data) {
|
||||
@@ -58,12 +58,22 @@ static int fib(int n)
|
||||
|
||||
static void test1(void)
|
||||
{
|
||||
resetFunc_called = false;
|
||||
atomic_store(&resetFunc_called, false);
|
||||
worker_init(w_g, 0, 0, resetFunc);
|
||||
int result = fib(39);
|
||||
assert (result == 63245986);
|
||||
worker_clear(w_g);
|
||||
assert (resetFunc_called == true);
|
||||
assert (atomic_load(&resetFunc_called) == true || workeri_get_cpu_count() == 1);
|
||||
}
|
||||
|
||||
static void test1bis(void)
|
||||
{
|
||||
atomic_store(&resetFunc_called, false);
|
||||
worker_init(w_g, 0, 0, NULL, resetFunc);
|
||||
int result = fib(4);
|
||||
assert (result == 3);
|
||||
worker_clear(w_g);
|
||||
assert (atomic_load(&resetFunc_called) == true || workeri_get_cpu_count() == 1);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && (!defined(__clang__) || WORKER_USE_CLANG_BLOCK || WORKER_USE_CPP_FUNCTION)
|
||||
@@ -103,5 +113,7 @@ static void test2(void) {}
|
||||
int main(void)
|
||||
{
|
||||
test1();
|
||||
test1bis();
|
||||
test2();
|
||||
exit(0);
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+25
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,6 +28,9 @@ ARRAY_DEF(array_uint, unsigned int)
|
||||
unsigned int add_two(const array_uint_t tab, size_t i, size_t j);
|
||||
void size_to_exactly(array_uint_t tab, size_t n);
|
||||
void push_back (array_uint_t tab, unsigned int n);
|
||||
void unpop(array_uint_t tab);
|
||||
void unpop_if(array_uint_t tab, unsigned int x);
|
||||
void construct(void *p);
|
||||
|
||||
unsigned int add_two(const array_uint_t tab, size_t i, size_t j)
|
||||
{
|
||||
@@ -44,3 +47,24 @@ void push_back (array_uint_t tab, unsigned int n)
|
||||
{
|
||||
array_uint_push_back(tab, n);
|
||||
}
|
||||
|
||||
void unpop(array_uint_t tab)
|
||||
{
|
||||
array_uint_pop_back(NULL, tab);
|
||||
}
|
||||
|
||||
void unpop_if(array_uint_t tab, unsigned int x)
|
||||
{
|
||||
if (x == *array_uint_back(tab))
|
||||
array_uint_pop_back(NULL, tab);
|
||||
}
|
||||
|
||||
array_uint_t global;
|
||||
extern void f(void *p);
|
||||
void construct(void *p)
|
||||
{
|
||||
array_uint_it_t mark;
|
||||
array_uint_it_end(mark, global);
|
||||
f(p);
|
||||
array_uint_pop_until(global, mark);
|
||||
}
|
||||
+24
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2018, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -24,7 +24,8 @@
|
||||
#include "m-list.h"
|
||||
#include "m-i-list.h"
|
||||
|
||||
LIST_DEF(dbl, double)
|
||||
LIST_DEF(list_dbl, double)
|
||||
LIST_DUAL_PUSH_DEF(list_dbl2, double)
|
||||
|
||||
void f_push_back(list_dbl_t list);
|
||||
double f_iterator(list_dbl_t list);
|
||||
@@ -36,19 +37,37 @@ void f_push_back(list_dbl_t list)
|
||||
|
||||
double f_iterator(list_dbl_t list)
|
||||
{
|
||||
list_it_dbl_t it;
|
||||
list_dbl_it_t it;
|
||||
double s = 0.0;
|
||||
for(list_dbl_it(it, list); !list_dbl_end_p(it); list_dbl_next(it))
|
||||
s += *list_dbl_cref(it);
|
||||
return s;
|
||||
}
|
||||
|
||||
void f2_push_back(list_dbl2_t list);
|
||||
double f2_iterator(list_dbl2_t list);
|
||||
|
||||
void f2_push_back(list_dbl2_t list)
|
||||
{
|
||||
list_dbl2_push_back(list, 2.0);
|
||||
}
|
||||
|
||||
double f2_iterator(list_dbl2_t list)
|
||||
{
|
||||
list_dbl2_it_t it;
|
||||
double s = 0.0;
|
||||
for(list_dbl2_it(it, list); !list_dbl2_end_p(it); list_dbl2_next(it))
|
||||
s += *list_dbl2_cref(it);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
struct itest {
|
||||
int n;
|
||||
ILIST_INTERFACE (list, struct itest);
|
||||
ILIST_INTERFACE (ilist_list, struct itest);
|
||||
};
|
||||
|
||||
ILIST_DEF(list, struct itest)
|
||||
ILIST_DEF(ilist_list, struct itest)
|
||||
|
||||
extern void f_init(ilist_list_t l);
|
||||
void f_init(ilist_list_t l)
|
||||
|
||||
Reference in new issue
Block a user