Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4e3d9cd4c | ||
|
|
4988661b7d | ||
|
|
7033a922c7 | ||
|
|
dd607252eb | ||
|
|
73da9a4316 | ||
|
|
b3a0d70147 | ||
|
|
c55bb6b9ad | ||
|
|
68fdc2dde1 | ||
|
|
8877af10b0 | ||
|
|
782963dec5 | ||
|
|
36d11bc2bd | ||
|
|
6d621703eb | ||
|
|
76b40d247d | ||
|
|
033deac9f5 | ||
|
|
b60553165d | ||
|
|
e1a4d359a2 | ||
|
|
4ab2615a1c | ||
|
|
9136a4a972 | ||
|
|
55dcf0e438 | ||
|
|
fb604f02b7 | ||
|
|
1db417e30e | ||
|
|
5b77fe7207 | ||
|
|
dd509f2b7e | ||
|
|
50d4e15297 | ||
|
|
f6d1b16338 | ||
|
|
64a035559d | ||
|
|
c4bc37560c | ||
|
|
e7309b7d3a | ||
|
|
c461b4eca4 | ||
|
|
f21d427de1 | ||
|
|
0f9edaa7ee | ||
|
|
64888127c4 | ||
|
|
d5b4ec249b | ||
|
|
0bcd78a8f5 | ||
|
|
27b0850af4 | ||
|
|
ae55ccfc40 | ||
|
|
5bf644ccf0 | ||
|
|
3f09adc507 | ||
|
|
4e851142c2 | ||
|
|
fec6b42260 | ||
|
|
9dbc48aa5d | ||
|
|
b92bae34eb | ||
|
|
8faf7f79c4 | ||
|
|
c3e29a16df | ||
|
|
1bc33a10fc | ||
|
|
b7074d1c69 | ||
|
|
26d541fe06 | ||
|
|
2991c7cc5a | ||
|
|
4e7cbae766 | ||
|
|
d5e0620e4c | ||
|
|
32cfbd23bc | ||
|
|
0e09681a6a | ||
|
|
bc8098b337 | ||
|
|
c5692e7e9f | ||
|
|
f43db93791 | ||
|
|
14c954c6ce | ||
|
|
60280087c7 | ||
|
|
1e57d9c6d6 | ||
|
|
eeaf74d24f | ||
|
|
a318d36c35 | ||
|
|
edcf8ee37a | ||
|
|
8a1f30eeff | ||
|
|
2995b119b7 | ||
|
|
08bd5a888b | ||
|
|
2f1b17f805 | ||
|
|
0379f5f1c6 | ||
|
|
45b11fb49b | ||
|
|
82ea4341de | ||
|
|
341d145b4d | ||
|
|
847f52fa5e | ||
|
|
02828a0109 | ||
|
|
0f7d5bf366 | ||
|
|
1277c75ea3 | ||
|
|
47a51ee5c4 | ||
|
|
3f102c2270 | ||
|
|
4ba55dc3ca | ||
|
|
2c0db40158 | ||
|
|
8987288a10 | ||
|
|
cf8c2afddd | ||
|
|
0a8e336037 | ||
|
|
e7e29d913e | ||
|
|
f3ebc8c7eb | ||
|
|
2d4fc9dc97 | ||
|
|
afedb06dee | ||
|
|
3fd2146bbe | ||
|
|
8e70b6175a | ||
|
|
67e9c8ff06 | ||
|
|
bf59c53921 | ||
|
|
5589105f5c |
No files matched your search
@@ -141,13 +141,80 @@ jobs:
|
||||
name: Build on aarch64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2.5.0
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
name: Run commands on aarch64
|
||||
id: make
|
||||
timeout-minutes: 60
|
||||
with:
|
||||
arch: aarch64
|
||||
distro: bullseye
|
||||
# Not required, but speeds up builds
|
||||
githubToken: ${{ github.token }}
|
||||
shell: /bin/sh
|
||||
run: |
|
||||
apt-get update -q -y
|
||||
apt-get install -q -y build-essential git gcc
|
||||
lscpu
|
||||
cd tests && make check -j 2 && make clean
|
||||
|
||||
# The host should always be linux
|
||||
build_armv6:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build on armv6
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
name: Run commands on armv6
|
||||
id: make
|
||||
timeout-minutes: 60
|
||||
with:
|
||||
arch: armv6
|
||||
distro: alpine_latest
|
||||
# Not required, but speeds up builds
|
||||
githubToken: ${{ github.token }}
|
||||
shell: /bin/sh
|
||||
run: |
|
||||
apk update
|
||||
apk add build-base gcc make
|
||||
cd tests && make check -j 2 && make clean
|
||||
|
||||
# The host should always be linux
|
||||
build_riscv64:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build on riscv64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
name: Run commands on riscv64
|
||||
id: make
|
||||
timeout-minutes: 60
|
||||
with:
|
||||
arch: riscv64
|
||||
distro: ubuntu22.04
|
||||
# Not required, but speeds up builds
|
||||
githubToken: ${{ github.token }}
|
||||
shell: /bin/sh
|
||||
run: |
|
||||
apt-get update -q -y
|
||||
apt-get install -q -y build-essential git gcc
|
||||
lscpu
|
||||
cd tests && make check -j 2 && make clean
|
||||
|
||||
# The host should always be linux
|
||||
build_ppc64le:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build on ppc64le
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
name: Run commands on ppc64le
|
||||
id: make
|
||||
timeout-minutes: 60
|
||||
with:
|
||||
arch: ppc64le
|
||||
distro: ubuntu22.04
|
||||
# Not required, but speeds up builds
|
||||
githubToken: ${{ github.token }}
|
||||
shell: /bin/sh
|
||||
run: |
|
||||
apt-get update -q -y
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017-2023, Patrick Pelissier
|
||||
Copyright (c) 2017-2025, Patrick Pelissier
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2024, Patrick Pelissier
|
||||
# Copyright (c) 2017-2025, Patrick Pelissier
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@@ -34,14 +34,14 @@ DESTDIR=
|
||||
|
||||
# Package name & version.
|
||||
PACKAGE=m_lib-$(VERSION)
|
||||
VERSION=0.7.3
|
||||
VERSION=0.7.4
|
||||
|
||||
# Define the contain of the distribution tarball
|
||||
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-generic.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-thread.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tree.h m-try.h m-tuple.h m-variant.h m-worker.h
|
||||
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-generic.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-thread.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tree.h m-try.h m-tuple.h m-variant.h m-worker.h m-bstring.h m-shared-ptr.h
|
||||
DOC1=LICENSE README.md
|
||||
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png doc/bench-array-log.png doc/bench-array.png doc/bench-list-log.png doc/bench-list.png doc/bench-oset-log.png doc/bench-oset.png doc/bench-umap-log.png doc/bench-umap.png doc/cc.sh
|
||||
EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex11-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c example/ex-no-stdio.c example/ex11-count-lines.c example/ex11-json-net.c example/ex11-rbtree02.c example/ex-curl.c example/ex-dict05.c example/ex-dict06.c example/exm-lib.c example/exm-main.c example/exn-lib.c example/exn-main.c example/exm-header.h example/exn-header.h example/ex-alloc1.c example/ex-alloc2.c example/ex-try01.c example/ex11-generic01.c
|
||||
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mfuncobj.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/tgen-mserial.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt tests/fail-chain-oplist.c tests/fail-incompatible.c tests/fail-no-oplist.c tests/test-mishared.c tests/check-array.cpp tests/check-deque.cpp tests/check-dplist.cpp tests/check-list.cpp tests/check-rbtree.cpp tests/check-uset.cpp tests/check-generic.hpp tests/test-mtree.c tests/check-bptree-map.cpp tests/check-bptree-set.cpp tests/check-prioqueue.cpp tests/check-umap.cpp tests/test-mtry.c tests/tgen-mmap.c tests/tgen-try.c tests/tgen-tuple.c tests/test-mgeneric.c
|
||||
EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex11-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c example/ex-no-stdio.c example/ex11-count-lines.c example/ex11-json-net.c example/ex11-rbtree02.c example/ex-curl.c example/ex-dict05.c example/ex-dict06.c example/exm-lib.c example/exm-main.c example/exn-lib.c example/exn-main.c example/exm-header.h example/exn-header.h example/ex-alloc1.c example/ex-alloc2.c example/ex-try01.c example/ex11-generic01.c example/ex-bptree02.c example/ex-i-list.c example/ex11-generic02.c example/ex11-small-name.c example/ex11-variant01.c
|
||||
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mfuncobj.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/tgen-mserial.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt tests/fail-chain-oplist.c tests/fail-incompatible.c tests/fail-no-oplist.c tests/test-mishared.c tests/check-array.cpp tests/check-deque.cpp tests/check-dplist.cpp tests/check-list.cpp tests/check-rbtree.cpp tests/check-uset.cpp tests/check-generic.hpp tests/test-mtree.c tests/check-bptree-map.cpp tests/check-bptree-set.cpp tests/check-prioqueue.cpp tests/check-umap.cpp tests/test-mtry.c tests/tgen-mmap.c tests/tgen-try.c tests/tgen-tuple.c tests/test-mgeneric.c tests/test-mbstring.c tests/except-array.c tests/except-bitset.c tests/except-deque.c tests/except-list.c tests/except-string.c tests/test-mshared-ptr.c tests/test-mshared-ptr.h tests/test-obj-except.h
|
||||
|
||||
.PHONY: all test check doc clean distclean depend install uninstall dist
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 138 KiB |
+4
-4
@@ -61,11 +61,11 @@ static void astar(array_point_t path, const string_t maze, int width)
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
point_emplace(next, current->x + deltas[i].x, current->y + deltas[i].y, 0);
|
||||
if (string_get_char(maze, point_index(next, width)) != '#') {
|
||||
int *new_cost = cost_point_get(costs, current);
|
||||
int new_cost = *cost_point_get(costs, current);
|
||||
int *cost = cost_point_get(costs, next);
|
||||
if (cost == NULL || *new_cost < *cost) {
|
||||
cost_point_set_at(costs, next, *new_cost);
|
||||
next->priority = *new_cost + abs(goal->x - next->x) + abs(goal->y - next->y);
|
||||
if (cost == NULL || new_cost < *cost) {
|
||||
cost_point_set_at(costs, next, new_cost);
|
||||
next->priority = new_cost + abs(goal->x - next->x) + abs(goal->y - next->y);
|
||||
prio_point_push(front, next);
|
||||
step_point_set_at(from, next, current);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m-buffer.h"
|
||||
#include "m-shared.h"
|
||||
#include "m-shared-ptr.h"
|
||||
#include "m-thread.h"
|
||||
|
||||
/* Global variable to stop scheduling */
|
||||
@@ -99,8 +99,8 @@ SHARED_PTR_DEF(shared_bigdata, 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
|
||||
BUFFER_DEF(buffer_bigdata, shared_bigdata_t, MY_QUEUE_SIZE,
|
||||
BUFFER_QUEUE|BUFFER_PUSH_INIT_POP_MOVE, SHARED_PTR_OPLIST(shared_bigdata))
|
||||
BUFFER_DEF(buffer_bigdata, shared_bigdata_t *, MY_QUEUE_SIZE,
|
||||
BUFFER_QUEUE|BUFFER_PUSH_INIT_POP_MOVE, SHARED_PTR_OPLIST(shared_bigdata, M_OPL_bigdata_t()))
|
||||
|
||||
/* Let's build a Thread synchros tree:
|
||||
*
|
||||
@@ -134,8 +134,7 @@ static void thread1 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_init_new (ptr);
|
||||
shared_bigdata_t *ptr = shared_bigdata_new ();
|
||||
perform_acquisition(*shared_bigdata_ref(ptr));
|
||||
buffer_bigdata_push(buf_t1tot2, ptr);
|
||||
buffer_bigdata_push(buf_t1tot3, ptr);
|
||||
@@ -146,7 +145,7 @@ static void thread2 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_t *ptr;
|
||||
buffer_bigdata_pop(&ptr, buf_t1tot2); // NOTE: Pop has been configured to init ptr
|
||||
perform_computation2(*shared_bigdata_ref(ptr));
|
||||
shared_bigdata_clear(ptr);
|
||||
@@ -156,7 +155,7 @@ static void thread3 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_t *ptr;
|
||||
buffer_bigdata_pop(&ptr, buf_t1tot3); // NOTE: Pop has been configured to init ptr
|
||||
perform_computation3(*shared_bigdata_ref(ptr));
|
||||
buffer_bigdata_push(buf_t3tot4, ptr);
|
||||
@@ -167,7 +166,7 @@ static void thread4 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_t *ptr;
|
||||
buffer_bigdata_pop(&ptr, buf_t3tot4); // NOTE: Pop has been configured to init ptr
|
||||
perform_computation4(*shared_bigdata_ref(ptr));
|
||||
shared_bigdata_clear(ptr);
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "m-i-list.h"
|
||||
|
||||
typedef struct data_s {
|
||||
M_ILIST_INTERFACE(list1, struct data_s);
|
||||
char *ptr;
|
||||
int n;
|
||||
} data_t;
|
||||
|
||||
static void
|
||||
data_init(data_t *p)
|
||||
{
|
||||
M_ILIST_INIT_FIELD(list1, *p);
|
||||
p->ptr = malloc(100);
|
||||
p->n = 100;
|
||||
}
|
||||
|
||||
static void
|
||||
data_clear(data_t *p)
|
||||
{
|
||||
free(p->ptr);
|
||||
p->n = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
data_init_set(data_t *p, data_t s)
|
||||
{
|
||||
p->ptr = malloc(s.n);
|
||||
p->n = s.n;
|
||||
memcpy(p->ptr, s.ptr, s.n);
|
||||
}
|
||||
|
||||
#define DATA_OP (INIT(API_2(data_init)), INIT_SET(API_2(data_init_set)), CLEAR(API_2(data_clear)) )
|
||||
|
||||
M_ILIST_DEF(list1, data_t, DATA_OP)
|
||||
|
||||
data_t pool[100];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
list1_t l;
|
||||
|
||||
list1_init(l);
|
||||
data_init(&pool[0]);
|
||||
list1_push_back(l, &pool[0]);
|
||||
data_init(&pool[1]);
|
||||
list1_push_back(l, &pool[1]);
|
||||
|
||||
list1_it_t it;
|
||||
list1_it(it, l);
|
||||
data_init(&pool[2]);
|
||||
list1_insert(l, it, &pool[2]);
|
||||
|
||||
list1_clear(l);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
+5
-2
@@ -208,11 +208,14 @@ dict_read_from_file(dict_mph_t dict, array_string_t arr, const char filename[])
|
||||
// Not clean as items of 'dict' points are linked to items of 'arr'
|
||||
// and the containers are not aware of this link.
|
||||
array_string_push_back (arr, str);
|
||||
dict_mph_set_at(dict, string_get_cstr(*array_string_back(arr)), line);
|
||||
line++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now 'arr' won't change anymore and we can get reliable pointers from it.
|
||||
for M_EACH(item, arr, array_string_t) {
|
||||
dict_mph_set_at(dict, string_get_cstr(*item), line);
|
||||
line++;
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
@@ -225,15 +225,15 @@ int main(void)
|
||||
M_PRINT("\nThe array is equal to ", (array, my_array_t), "\n");
|
||||
} /* All variables are automatically cleared beyond this point */
|
||||
|
||||
// Define an array of mpz_t as { 1, 2, 1 } (with auto promotion from integer / string / double)
|
||||
// The auto-promotion uses _Generic feature and is available only in C11.
|
||||
M_LET ( (az, (1), ("2"), (1.0)), array_mpz_t)
|
||||
M_LET ( roots, array_mpfr_t) {
|
||||
// Compute roots
|
||||
compute_roots(roots, az);
|
||||
// Display of roots:
|
||||
M_PRINT("Roots of ", (az, array_mpz_t), " are ", (roots, array_mpfr_t), "\n");
|
||||
}
|
||||
// Define an array of mpz_t as { 1, 2, 1 } (with auto promotion from integer / string / double)
|
||||
// The auto-promotion uses _Generic feature and is available only in C11.
|
||||
M_LET ( (az, (1), ("2"), (1.0)), array_mpz_t)
|
||||
M_LET ( roots, array_mpfr_t) {
|
||||
// Compute roots
|
||||
compute_roots(roots, az);
|
||||
// Display of roots:
|
||||
M_PRINT("Roots of ", (az, array_mpz_t), " are ", (roots, array_mpfr_t), "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// Disable small name usage
|
||||
#define M_USE_SMALL_NAME 0
|
||||
|
||||
#include "m-algo.h"
|
||||
#include "m-array.h"
|
||||
#include "m-atomic.h"
|
||||
#include "m-bitset.h"
|
||||
#include "m-bptree.h"
|
||||
#include "m-bstring.h"
|
||||
#include "m-buffer.h"
|
||||
#include "m-c-mempool.h"
|
||||
#include "m-concurrent.h"
|
||||
#include "m-deque.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-funcobj.h"
|
||||
#include "m-generic.h"
|
||||
#include "m-genint.h"
|
||||
#include "m-i-list.h"
|
||||
#include "m-i-shared.h"
|
||||
#include "m-list.h"
|
||||
#include "m-mempool.h"
|
||||
#include "m-prioqueue.h"
|
||||
#include "m-rbtree.h"
|
||||
#include "m-serial-bin.h"
|
||||
#include "m-serial-json.h"
|
||||
//#include "m-shared.h" // API incompatible with m-shared-ptr.h (exclusive)
|
||||
#include "m-shared-ptr.h"
|
||||
#include "m-snapshot.h"
|
||||
#include "m-string.h"
|
||||
#include "m-thread.h"
|
||||
#include "m-tree.h"
|
||||
#include "m-try.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-variant.h"
|
||||
#include "m-worker.h"
|
||||
|
||||
M_ARRAY_DEF(array, m_string_t)
|
||||
M_ALGO_DEF(array, M_ARRAY_OPLIST(array, M_STRING_OPLIST))
|
||||
M_BPTREE_DEF2(bptree, 11, m_string_t, m_string_t)
|
||||
M_BUFFER_DEF(queue, m_string_t, 10, M_BUFFER_QUEUE)
|
||||
M_LIST_DEF(list, m_string_t)
|
||||
M_LIST_DUAL_PUSH_DEF(list2, m_string_t)
|
||||
M_DEQUE_DEF(deque, m_string_t)
|
||||
M_DICT_DEF2(dict, m_string_t, m_string_t)
|
||||
M_DICT_OA_DEF2(dict_oa, m_string_t, m_string_t)
|
||||
M_DICT_SET_DEF(dict_set, m_string_t)
|
||||
M_DICT_OASET_DEF(dict_oa_set, m_string_t)
|
||||
M_RBTREE_DEF(rbtree, m_string_t)
|
||||
M_FUNC_OBJ_INS_DEF(compare_by /* name of the instance */,
|
||||
array_cmp_obj /* name of the interface */,
|
||||
(a, b) /* name of the input parameters of the function like object. The type are inherited from the interface. */, {
|
||||
/* code of the function object */
|
||||
if (m_string_equal_cstr_p(self->sort_field, "normal"))
|
||||
return m_string_cmp(a, b);
|
||||
else
|
||||
return -m_string_cmp(a, b);
|
||||
},
|
||||
/* Additional fields stored in the function object */
|
||||
(sort_field, m_string_t) )
|
||||
M_PRIOQUEUE_DEF(prio_queue, m_string_t)
|
||||
M_SHARED_PTR_DEF(shared_string, m_string_t)
|
||||
M_SNAPSHOT_SPSC_DEF(snap1, m_string_t)
|
||||
M_SNAPSHOT_SPMC_DEF(snap2, m_string_t)
|
||||
M_SNAPSHOT_MPMC_DEF(snap3, m_string_t)
|
||||
M_TREE_DEF(tree, m_string_t)
|
||||
M_TUPLE_DEF2(tuple, (a, m_string_t))
|
||||
M_VARIANT_DEF2(variant, (a, m_string_t))
|
||||
M_WORKER_SPAWN_DEF2(worker, (filename, m_string_t) )
|
||||
|
||||
int main(void)
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
#include <stdio.h>
|
||||
#include "m-variant.h"
|
||||
#include "m-list.h"
|
||||
|
||||
// Define the variant with the given basic types
|
||||
// A variant is an union of all its type, with the information needed to identify which type it holds
|
||||
VARIANT_DEF2(obj,
|
||||
(boolean, bool, M_BOOL_OPLIST),
|
||||
(integer, int, M_BASIC_OPLIST),
|
||||
(real, double, M_BASIC_OPLIST),
|
||||
(cstr, const char*, M_CSTR_OPLIST))
|
||||
// Associate obj_t to its oplist, so that we can only use 'obj_t'
|
||||
// and M*LIB knows how to handle this type properly
|
||||
// We need to extend the oplist with FIELD so that M*LIB is able to generate 'emplace' functions
|
||||
#define M_OPL_obj_t() \
|
||||
VARIANT_OPLIST(obj, M_OPEXTEND(M_BOOL_OPLIST, FIELD(boolean)), \
|
||||
M_OPEXTEND(M_BASIC_OPLIST, FIELD(integer)), \
|
||||
M_OPEXTEND(M_BASIC_OPLIST, FIELD(real)), \
|
||||
M_OPEXTEND(M_CSTR_OPLIST, FIELD(cstr)))
|
||||
|
||||
// Define a list over the variant
|
||||
LIST_DEF(list, obj_t)
|
||||
// Associate list_t to its oplist, so that we can only use 'list_t'
|
||||
#define M_OPL_list_t() LIST_OPLIST(list, M_OPL_obj_t())
|
||||
|
||||
/* Print the type of the object */
|
||||
static void print_obj(obj_t o, const char name[])
|
||||
{
|
||||
if (obj_empty_p(o)) {
|
||||
printf("Object %s is empty\n", name);
|
||||
}
|
||||
if (obj_boolean_p(o)) {
|
||||
printf("Object %s is a boolean (%d)\n", name, *obj_get_boolean(o));
|
||||
}
|
||||
if (obj_integer_p(o)) {
|
||||
printf("Object %s is an integer (%d)\n", name, *obj_get_integer(o));
|
||||
}
|
||||
if (obj_real_p(o)) {
|
||||
printf("Object %s is a float (%f)\n", name, *obj_get_real(o));
|
||||
}
|
||||
if (obj_cstr_p(o)) {
|
||||
printf("Object %s is C string (%s)\n", name, *obj_get_cstr(o));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void f(void)
|
||||
{
|
||||
// Initialize & afterward clear the object
|
||||
M_LET(o, obj_t) {
|
||||
print_obj(o, "1st init");
|
||||
obj_set_real(o, 23.4);
|
||||
print_obj(o, "1st+set");
|
||||
} // Now the object is out of scope and is cleared.
|
||||
|
||||
// Initialize, set as an integer of value '12' & afterward clear the object
|
||||
// () around 12 means that we want to 'emplace' object using the input '12' to construct the object in-place,
|
||||
// rather than setting it from an already existing 'obj_t'.
|
||||
// It checks for the type of 12, find it is an integer, and initialize o with this value
|
||||
// It won't work if there is multiple compatible type in the variant
|
||||
M_LET( (o, (12)), obj_t) {
|
||||
print_obj(o, "2nd init");
|
||||
obj_set_cstr(o, "Hello");
|
||||
print_obj(o, "2nd+set");
|
||||
}
|
||||
|
||||
M_LET( (o, (true)), obj_t) {
|
||||
// In C11, a 'true' value is an 'int' type, not a bool!
|
||||
print_obj(o, "3rd init");
|
||||
obj_set_boolean(o, true);
|
||||
print_obj(o, "3rd+set");
|
||||
// Without "()" around the source, it will set the value using the object builtin copy.
|
||||
M_LET( (p, o), obj_t) {
|
||||
print_obj(o, "3rd+rec");
|
||||
// We can also print the object directly:
|
||||
printf("OBJ=");
|
||||
obj_out_str(stdout, o);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void g(void)
|
||||
{
|
||||
// Initialize a list of obj_t and clear it afterwards
|
||||
M_LET(l, list_t){
|
||||
// Let's emplace some type in the list
|
||||
list_emplace_back_boolean(l, true);
|
||||
list_emplace_back_integer(l, 12);
|
||||
list_emplace_back_cstr(l, "World");
|
||||
list_emplace_back_real(l, 17.42);
|
||||
// We can iterate on the list
|
||||
for M_EACH(item, l, list_t) {
|
||||
print_obj(*item, "loop");
|
||||
}
|
||||
// We can also print the object directly:
|
||||
printf("LIST=");
|
||||
list_out_str(stdout, l);
|
||||
printf("\n");
|
||||
} // Clear & free the list
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
f();
|
||||
g();
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - ALGO module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -178,11 +178,11 @@
|
||||
* Created Function objects are part of the public interface */
|
||||
#define M_ALG0_DEF_FUNCOBJ(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
FUNC_OBJ_ITF_DEF(M_F(name, _test_obj), bool, type_t const) \
|
||||
FUNC_OBJ_ITF_DEF(M_F(name, _eq_obj), bool, type_t const, type_t const ) \
|
||||
FUNC_OBJ_ITF_DEF(M_F(name, _cmp_obj), int, type_t const, type_t const ) \
|
||||
FUNC_OBJ_ITF_DEF(M_F(name, _transform_obj), void, type_t *, type_t const ) \
|
||||
FUNC_OBJ_ITF_DEF(M_F(name, _apply_obj), void, type_t * ) \
|
||||
M_FUNC_OBJ_ITF_DEF(M_F(name, _test_obj), bool, type_t const) \
|
||||
M_FUNC_OBJ_ITF_DEF(M_F(name, _eq_obj), bool, type_t const, type_t const ) \
|
||||
M_FUNC_OBJ_ITF_DEF(M_F(name, _cmp_obj), int, type_t const, type_t const ) \
|
||||
M_FUNC_OBJ_ITF_DEF(M_F(name, _transform_obj), void, type_t *, type_t const )\
|
||||
M_FUNC_OBJ_ITF_DEF(M_F(name, _apply_obj), void, type_t * ) \
|
||||
|
||||
|
||||
/* Define the sort functions with the CMP operator using the order selected */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - dynamic ARRAY module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -958,6 +958,7 @@
|
||||
{ \
|
||||
M_ARRA4_CONTRACT(a1); \
|
||||
M_ARRA4_CONTRACT(a2); \
|
||||
M_ASSERT(a1 != a2); \
|
||||
if (M_LIKELY (a2->size > 0)) { \
|
||||
size_t newSize = a1->size + a2->size; \
|
||||
/* To overflow newSize, we need to a1 and a2 a little bit above \
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin stdatomic wrapper for C++ compatibility
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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 - BITSET module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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 - B+TREE module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
|
||||
+601
@@ -0,0 +1,601 @@
|
||||
/*
|
||||
* M*LIB - Byte String module
|
||||
*
|
||||
* Copyright (c) 2017-2025, 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.
|
||||
*/
|
||||
#ifndef MSTARLIB_BSTRING_H
|
||||
#define MSTARLIB_BSTRING_H
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Byte String Type definition*/
|
||||
typedef struct m_bstring_s {
|
||||
size_t size; // Number of effective BYTES
|
||||
size_t alloc; // Size of the allocated buffer
|
||||
size_t offset; // Offset where the effective BYTES are stored in the allocated buffer
|
||||
uint8_t *ptr; // Pointer to the allocated buffer
|
||||
} m_bstring_t[1];
|
||||
|
||||
// Contract of a bstring
|
||||
#define M_BSTRING_CONTRACT(o) do { \
|
||||
M_ASSERT( (o)->size + (o)->offset >= (o)->size ); \
|
||||
M_ASSERT( (o)->alloc >= (o)->size + (o)->offset ); \
|
||||
M_ASSERT( (o)->ptr != NULL || (o)->alloc == 0); \
|
||||
} while (0)
|
||||
|
||||
M_INLINE size_t
|
||||
m_bstring_size(const m_bstring_t s)
|
||||
{
|
||||
M_BSTRING_CONTRACT(s);
|
||||
return s->size;
|
||||
}
|
||||
|
||||
M_INLINE size_t
|
||||
m_bstring_capacity(const m_bstring_t s)
|
||||
{
|
||||
M_BSTRING_CONTRACT(s);
|
||||
return s->alloc;
|
||||
}
|
||||
|
||||
M_INLINE uint8_t *
|
||||
m_bstr1ng_cstr(const m_bstring_t v)
|
||||
{
|
||||
return &v->ptr[v->offset];
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_init(m_bstring_t s)
|
||||
{
|
||||
s->size = 0;
|
||||
s->alloc = 0;
|
||||
s->offset = 0;
|
||||
s->ptr = NULL;
|
||||
M_BSTRING_CONTRACT(s);
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_clear(m_bstring_t s)
|
||||
{
|
||||
M_BSTRING_CONTRACT(s);
|
||||
M_MEMORY_FREE(s->ptr);
|
||||
s->offset = (size_t) -1;
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_reset(m_bstring_t s)
|
||||
{
|
||||
M_BSTRING_CONTRACT(s);
|
||||
s->size = 0;
|
||||
s->offset = 0;
|
||||
M_BSTRING_CONTRACT(s);
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_swap(m_bstring_t s1, m_bstring_t s2)
|
||||
{
|
||||
M_BSTRING_CONTRACT(s1);
|
||||
M_BSTRING_CONTRACT(s2);
|
||||
m_bstring_t tmp;
|
||||
memcpy(tmp, s1, sizeof (m_bstring_t));
|
||||
memcpy(s1, s2, sizeof (m_bstring_t));
|
||||
memcpy(s2, tmp, sizeof (m_bstring_t));
|
||||
M_BSTRING_CONTRACT(s1);
|
||||
M_BSTRING_CONTRACT(s2);
|
||||
}
|
||||
|
||||
/* Return the selected byte-character of the string */
|
||||
M_INLINE uint8_t
|
||||
m_bstring_get_byte(const m_bstring_t v, size_t index)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX(index, v->size);
|
||||
return m_bstr1ng_cstr(v)[index];
|
||||
}
|
||||
|
||||
/* Set the selected byte-character of the string */
|
||||
M_INLINE void
|
||||
m_bstring_set_byte(m_bstring_t v, size_t index, const uint8_t c)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX(index, v->size);
|
||||
m_bstr1ng_cstr(v)[index] = c;
|
||||
}
|
||||
|
||||
/* Test if the string is empty or not */
|
||||
M_INLINE bool
|
||||
m_bstring_empty_p(const m_bstring_t v)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
return v->size == 0;
|
||||
}
|
||||
|
||||
/* Internal method to fit the Byte string to the given size
|
||||
Ensures that the Byte String capacity is greater than size_alloc+offset
|
||||
The returned Byte String 'v' no longer has a **correct** size field.
|
||||
If exact_alloc is true, it will request exactly the request size for the buffer
|
||||
on reallocation otherwise it will augment the requested size to amortize the future
|
||||
allocations.
|
||||
Return a pointer to the writable string.
|
||||
*/
|
||||
M_INLINE uint8_t *
|
||||
m_bstr1ng_fit2size (m_bstring_t v, size_t size_alloc, bool exact_alloc)
|
||||
{
|
||||
// Very unlikely overflow case
|
||||
if (M_UNLIKELY_NOMEM (v->offset > v->offset + size_alloc)) {
|
||||
goto allocation_error;
|
||||
}
|
||||
M_ASSERT_INDEX (v->offset, v->offset + size_alloc);
|
||||
// Note: this function may be called in context where the contract is not fulfilled.
|
||||
if (M_UNLIKELY (v->offset + size_alloc > v->alloc)) {
|
||||
// Insufficient current allocation to store the new string
|
||||
|
||||
// Check if there is a too big offset that can be reduced
|
||||
if (v->offset > v->size / 8 && v->offset > 16) {
|
||||
// Move back the effective bytes to the beginning of the buffer
|
||||
memmove(&v->ptr[0], &v->ptr[v->offset], v->size);
|
||||
v->offset = 0;
|
||||
// If it is now sufficient, we can return.
|
||||
if (size_alloc <= v->alloc)
|
||||
return v->ptr;
|
||||
}
|
||||
|
||||
// Alloc a new array. Compute the requested allocation size
|
||||
size_t alloc = (v->offset + size_alloc + (exact_alloc ? 0 : size_alloc / 2));
|
||||
alloc = M_MAX(alloc, 16);
|
||||
if (M_UNLIKELY_NOMEM (alloc < size_alloc)) {
|
||||
goto allocation_error;
|
||||
}
|
||||
uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, alloc);
|
||||
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
|
||||
goto allocation_error;
|
||||
}
|
||||
// The string cannot be fully embedded anymore.
|
||||
v->ptr = ptr;
|
||||
v->alloc = alloc;
|
||||
// Size is not set as the function is called in context
|
||||
// where the caller already know the final size of the string,
|
||||
// so it will update it.
|
||||
return &v->ptr[v->offset];
|
||||
}
|
||||
return &v->ptr[v->offset];
|
||||
allocation_error:
|
||||
M_MEMORY_FULL(size_alloc);
|
||||
// NOTE: Return is currently broken.
|
||||
abort();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Push the byte 'c' in the bstring 'v' */
|
||||
M_INLINE void
|
||||
m_bstring_push_back (m_bstring_t v, uint8_t c)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
const size_t size = v->size;
|
||||
uint8_t *ptr = m_bstr1ng_fit2size(v, size+1, false);
|
||||
ptr[size] = c;
|
||||
v->size = size + 1;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Push the array of bytes from 'buffer' in the bstring 'v' */
|
||||
M_INLINE void
|
||||
m_bstring_push_back_bytes (m_bstring_t v, size_t n, const void *buffer)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
const size_t size = v->size;
|
||||
M_ASSERT_INDEX (size, size + n);
|
||||
uint8_t *ptr = m_bstr1ng_fit2size(v, size+n, false);
|
||||
memcpy(&ptr[size], buffer, n);
|
||||
v->size = size + n;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_splice(m_bstring_t dst, m_bstring_t src)
|
||||
{
|
||||
M_BSTRING_CONTRACT (dst);
|
||||
M_BSTRING_CONTRACT (src);
|
||||
M_ASSERT(src != dst);
|
||||
m_bstring_push_back_bytes(dst, m_bstring_size(src), m_bstr1ng_cstr(src));
|
||||
m_bstring_reset(src);
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_init_set(m_bstring_t v, const m_bstring_t org)
|
||||
{
|
||||
m_bstring_init(v);
|
||||
m_bstring_push_back_bytes(v, m_bstring_size(org), m_bstr1ng_cstr(org));
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_set(m_bstring_t v, const m_bstring_t org)
|
||||
{
|
||||
m_bstring_reset(v);
|
||||
m_bstring_push_back_bytes(v, m_bstring_size(org), m_bstr1ng_cstr(org));
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_init_move(m_bstring_t v, m_bstring_t org)
|
||||
{
|
||||
M_BSTRING_CONTRACT (org);
|
||||
memcpy(v, org, sizeof (m_bstring_t));
|
||||
org->offset = (size_t) -1;
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_move(m_bstring_t v, m_bstring_t org)
|
||||
{
|
||||
m_bstring_clear(v);
|
||||
m_bstring_init_move(v, org);
|
||||
}
|
||||
|
||||
M_INLINE size_t
|
||||
m_bstring_hash(const m_bstring_t v)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
return m_core_hash(m_bstr1ng_cstr(v), m_bstring_size(v));
|
||||
}
|
||||
|
||||
M_INLINE int
|
||||
m_bstring_cmp(const m_bstring_t v1, const m_bstring_t v2)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v1);
|
||||
M_BSTRING_CONTRACT (v2);
|
||||
const size_t s1 = m_bstring_size(v1);
|
||||
const size_t s2 = m_bstring_size(v2);
|
||||
int ret = memcmp(m_bstr1ng_cstr(v1), m_bstr1ng_cstr(v2), M_MIN(s1, s2));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (s1 != s2)
|
||||
return s1 < s2 ? -1 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
M_INLINE int
|
||||
m_bstring_cmp_bytes(const m_bstring_t v1, size_t s2, const void *p2)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v1);
|
||||
const size_t s1 = m_bstring_size(v1);
|
||||
int ret = memcmp(m_bstr1ng_cstr(v1), p2, M_MIN(s1, s2));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (s1 != s2)
|
||||
return s1 < s2 ? -1 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
M_INLINE bool
|
||||
m_bstring_equal_p(const m_bstring_t v1, const m_bstring_t v2)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v1);
|
||||
M_BSTRING_CONTRACT (v2);
|
||||
const size_t s1 = m_bstring_size(v1);
|
||||
const size_t s2 = m_bstring_size(v2);
|
||||
if (s1 != s2)
|
||||
return false;
|
||||
return memcmp(m_bstr1ng_cstr(v1), m_bstr1ng_cstr(v2), s1) == 0;
|
||||
}
|
||||
|
||||
M_INLINE bool
|
||||
m_bstring_equal_bytes_p(const m_bstring_t v1, size_t s2, const void *buffer)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v1);
|
||||
const size_t s1 = m_bstring_size(v1);
|
||||
if (s1 != s2)
|
||||
return false;
|
||||
return memcmp(m_bstr1ng_cstr(v1), buffer, s1) == 0;
|
||||
}
|
||||
|
||||
M_INLINE uint8_t
|
||||
m_bstring_pop_back(m_bstring_t v)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX(0, v->size);
|
||||
uint8_t c = m_bstr1ng_cstr(v)[v->size-1];
|
||||
v->size --;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
return c;
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_pop_back_bytes(size_t n, void *buffer, m_bstring_t v)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX(n-1, v->size);
|
||||
memcpy(buffer, &m_bstr1ng_cstr(v)[v->size-n], n);
|
||||
v->size -= n;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
M_INLINE uint8_t
|
||||
m_bstring_pop_front(m_bstring_t v)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX(0, v->size);
|
||||
uint8_t c = m_bstr1ng_cstr(v)[0];
|
||||
v->size --;
|
||||
v->offset++;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
return c;
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_pop_front_bytes(size_t n, void *buffer, m_bstring_t v)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX(n-1, v->size);
|
||||
memcpy(buffer, &m_bstr1ng_cstr(v)[0], n);
|
||||
v->size -= n;
|
||||
v->offset += n;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_push_bytes_at (m_bstring_t v, size_t pos, size_t n, const void *buffer)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
const size_t size = v->size;
|
||||
M_ASSERT_INDEX (pos, size+1); //pos == size ==> equivalent to _push_back_bytes
|
||||
M_ASSERT_INDEX (size, size + n);
|
||||
uint8_t *ptr = m_bstr1ng_fit2size(v, size+n, false);
|
||||
memmove(&ptr[pos+n], &ptr[pos], size-pos);
|
||||
memcpy(&ptr[pos], buffer, n);
|
||||
v->size = size + n;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_pop_bytes_at(size_t n, void *buffer, m_bstring_t v, size_t pos)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
const size_t size = v->size;
|
||||
M_ASSERT_INDEX (pos, size);
|
||||
M_ASSERT_INDEX(n-1, size-pos);
|
||||
uint8_t *ptr = m_bstr1ng_cstr(v);
|
||||
memcpy(buffer, &ptr[pos], n);
|
||||
memmove(&ptr[pos], &ptr[pos+n], size-pos-n);
|
||||
v->size -= n;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_resize (m_bstring_t v, size_t n)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
const size_t size = v->size;
|
||||
if (n > size) {
|
||||
uint8_t *ptr = m_bstr1ng_fit2size(v, n, true);
|
||||
memset(&ptr[size], 0, n-size);
|
||||
}
|
||||
v->size = n;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_reserve (m_bstring_t v, size_t n)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
const size_t size = v->size;
|
||||
if ( (n != 0 || v->size != 0) && n < v->offset + size) {
|
||||
n = v->offset + size;
|
||||
}
|
||||
if (n == 0) {
|
||||
M_MEMORY_FREE(v->ptr);
|
||||
v->offset = 0;
|
||||
v->size = 0;
|
||||
v->alloc = 0;
|
||||
v->ptr = NULL;
|
||||
} else {
|
||||
uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, n);
|
||||
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
|
||||
M_MEMORY_FULL(n);
|
||||
}
|
||||
// The string cannot be fully embedded anymore.
|
||||
v->ptr = ptr;
|
||||
v->alloc = n;
|
||||
}
|
||||
M_BSTRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
M_INLINE const uint8_t *
|
||||
m_bstring_view(const m_bstring_t v, size_t offset, size_t size_requested)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX (offset+size_requested, v->size+1);
|
||||
return &m_bstr1ng_cstr(v)[offset];
|
||||
}
|
||||
|
||||
// Acquire / release direct write access: once acquired, user can directly wite at the returned pointer for the requested size
|
||||
// All other operations on the bstring are forbidden during direct access.
|
||||
// This allows passing the bstring buffer to be formatted by different API
|
||||
M_INLINE uint8_t *
|
||||
m_bstring_acquire_access(m_bstring_t v, size_t offset, size_t size_requested)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT_INDEX (offset+size_requested, v->size+1);
|
||||
// Break canonical representation (this will generate assertion if a normal API is called now)
|
||||
M_SWAP(size_t, v->size, v->alloc);
|
||||
return &m_bstr1ng_cstr(v)[offset];
|
||||
}
|
||||
|
||||
M_INLINE void
|
||||
m_bstring_release_access(m_bstring_t v)
|
||||
{
|
||||
M_ASSERT( v->size >= v->alloc + v->offset );
|
||||
// Restore canonical representation
|
||||
M_SWAP(size_t, v->size, v->alloc);
|
||||
M_BSTRING_CONTRACT (v);
|
||||
}
|
||||
|
||||
// No Iterator planned for this container (No added value)
|
||||
|
||||
#if M_USE_STDIO
|
||||
|
||||
M_INLINE size_t
|
||||
m_bstring_fwrite(FILE *f, const m_bstring_t v)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT (f != NULL);
|
||||
return fwrite(m_bstr1ng_cstr(v), 1, m_bstring_size(v), f);
|
||||
}
|
||||
|
||||
M_INLINE bool
|
||||
m_bstring_fread(m_bstring_t v, FILE *f, size_t num)
|
||||
{
|
||||
M_BSTRING_CONTRACT (v);
|
||||
M_ASSERT (f != NULL);
|
||||
m_bstring_reset(v);
|
||||
//TODO: option to read all the file num=-1?
|
||||
if (M_UNLIKELY(num == 0)) {
|
||||
return true;
|
||||
}
|
||||
uint8_t *ptr = m_bstr1ng_fit2size(v, num, true);
|
||||
size_t n = fread(ptr, 1, num, f);
|
||||
M_ASSERT (n <= num);
|
||||
v->size = n;
|
||||
return n == num;
|
||||
}
|
||||
|
||||
#endif // Have stdio
|
||||
|
||||
// No formatted string input/output. Only serializer
|
||||
|
||||
/* Transform the Byte String 'v2'
|
||||
and output it in the given serializer
|
||||
See serialization for return code.
|
||||
*/
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_bstring_out_serial(m_serial_write_t serial, const m_bstring_t v)
|
||||
{
|
||||
M_ASSERT (serial != NULL && serial->m_interface != NULL);
|
||||
M_BSTRING_CONTRACT (v);
|
||||
m_serial_local_t local;
|
||||
m_serial_return_code_t ret;
|
||||
size_t size = m_bstring_size(v);
|
||||
uint8_t *ptr = m_bstr1ng_cstr(v);
|
||||
ret = serial->m_interface->write_array_start(local, serial, size);
|
||||
if (size > 0) {
|
||||
ret |= serial->m_interface->write_integer(serial, ptr[0], 1);
|
||||
for(size_t i = 1; i < size; i++) {
|
||||
ret |= serial->m_interface->write_array_next(local, serial);
|
||||
ret |= serial->m_interface->write_integer(serial, ptr[i], 1);
|
||||
}
|
||||
}
|
||||
ret |= serial->m_interface->write_array_end(local, serial);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read from the serializer
|
||||
and set the converted value in the byte string 'v'.
|
||||
See serialization for return code.
|
||||
*/
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_bstring_in_serial(m_bstring_t v, m_serial_read_t f)
|
||||
{
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL);
|
||||
M_BSTRING_CONTRACT (v);
|
||||
m_serial_return_code_t ret;
|
||||
m_serial_local_t local;
|
||||
size_t estimated_size = 0, real_size = 0;
|
||||
m_bstring_reset(v);
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size);
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) {
|
||||
return ret;
|
||||
}
|
||||
uint8_t *ptr = m_bstr1ng_fit2size(v, estimated_size, true);
|
||||
do {
|
||||
long long val;
|
||||
ret = f->m_interface->read_integer(f, &val, 1);
|
||||
if (ret != M_SERIAL_OK_DONE) { break; }
|
||||
ptr[real_size++] = (uint8_t) val;
|
||||
ret = f->m_interface->read_array_next(local, f);
|
||||
} while (ret == M_SERIAL_OK_CONTINUE);
|
||||
v->size = real_size;
|
||||
M_BSTRING_CONTRACT (v);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Define the OPLIST of a BYTE STRING */
|
||||
#define M_BSTRING_OPLIST \
|
||||
(INIT(m_bstring_init),INIT_SET(m_bstring_init_set), SET(m_bstring_set), \
|
||||
INIT_MOVE(m_bstring_init_move), MOVE(m_bstring_move), \
|
||||
SWAP(m_bstring_swap), RESET(m_bstring_reset), \
|
||||
EMPTY_P(m_bstring_empty_p), \
|
||||
CLEAR(m_bstring_clear), HASH(m_bstring_hash), EQUAL(m_bstring_equal_p), \
|
||||
CMP(m_bstring_cmp), TYPE(m_bstring_t), GENTYPE(struct m_bstring_s*), \
|
||||
OUT_SERIAL(m_bstring_out_serial), IN_SERIAL(m_bstring_in_serial), \
|
||||
)
|
||||
|
||||
/********************************************************************************/
|
||||
/* */
|
||||
/* Define the small name (i.e. without the prefix) of the API provided by this */
|
||||
/* header if it is needed */
|
||||
/* */
|
||||
/********************************************************************************/
|
||||
#if M_USE_SMALL_NAME
|
||||
|
||||
#define bstring_t m_bstring_t
|
||||
#define bstring_size m_bstring_size
|
||||
#define bstring_capacity m_bstring_capacity
|
||||
#define bstring_init m_bstring_init
|
||||
#define bstring_clear m_bstring_clear
|
||||
#define bstring_reset m_bstring_reset
|
||||
#define bstring_get_byte m_bstring_get_byte
|
||||
#define bstring_set_byte m_bstring_set_byte
|
||||
#define bstring_empty_p m_bstring_empty_p
|
||||
#define bstring_push_back m_bstring_push_back
|
||||
#define bstring_push_back_bytes m_bstring_push_back_bytes
|
||||
#define bstring_init_set m_bstring_init_set
|
||||
#define bstring_set m_bstring_set
|
||||
#define bstring_init_move m_bstring_init_move
|
||||
#define bstring_move m_bstring_move
|
||||
#define bstring_cmp m_bstring_cmp
|
||||
#define bstring_cmp_bytes m_bstring_cmp_bytes
|
||||
#define bstring_equal_p m_bstring_equal_p
|
||||
#define bstring_equal_bytes_p m_bstring_equal_bytes_p
|
||||
#define bstring_pop_back m_bstring_pop_back
|
||||
#define bstring_pop_back_bytes m_bstring_pop_back_bytes
|
||||
#define bstring_pop_front m_bstring_pop_front
|
||||
#define bstring_pop_front_bytes m_bstring_pop_front_bytes
|
||||
#define bstring_push_bytes_at m_bstring_push_bytes_at
|
||||
#define bstring_pop_bytes_at m_bstring_pop_bytes_at
|
||||
#define bstring_resize m_bstring_resize
|
||||
#define bstring_reserve m_bstring_reserve
|
||||
#define bstring_view m_bstring_view
|
||||
#define bstring_acquire_access m_bstring_acquire_access
|
||||
#define bstring_release_access m_bstring_release_access
|
||||
#define bstring_hash m_bstring_hash
|
||||
#define bstring_fread m_bstring_fread
|
||||
#define bstring_fwrite m_bstring_fwrite
|
||||
#define bstring_out_serial m_bstring_out_serial
|
||||
#define bstring_in_serial m_bstring_in_serial
|
||||
#define bstring_swap m_bstring_swap
|
||||
#define bstring_splice m_bstring_splice
|
||||
#define BSTRING_OPLIST M_BSTRING_OPLIST
|
||||
|
||||
#endif
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
+6
-5
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Fixed size (Bounded) QUEUE & STACK interface
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -162,7 +162,7 @@ m_buff3r_number_init(m_buff3r_number_ct n, unsigned int policy)
|
||||
}
|
||||
|
||||
M_INLINE unsigned int
|
||||
m_buff3r_number_load(m_buff3r_number_ct n, unsigned int policy)
|
||||
m_buff3r_number_load(const m_buff3r_number_ct n, unsigned int policy)
|
||||
{
|
||||
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
|
||||
// Perform a memory acquire so that further usage of the buffer
|
||||
@@ -527,7 +527,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
} \
|
||||
\
|
||||
M_INLINE bool \
|
||||
M_F(name, _empty_p)(buffer_t v) \
|
||||
M_F(name, _empty_p)(const buffer_t v) \
|
||||
{ \
|
||||
M_BUFF3R_CONTRACT(v,m_size); \
|
||||
/* If the buffer has been configured with deferred pop \
|
||||
@@ -541,7 +541,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
} \
|
||||
\
|
||||
M_INLINE bool \
|
||||
M_F(name, _full_p)(buffer_t v) \
|
||||
M_F(name, _full_p)(const buffer_t v) \
|
||||
{ \
|
||||
M_BUFF3R_CONTRACT(v,m_size); \
|
||||
return m_buff3r_number_load (v->number[0], policy) \
|
||||
@@ -549,7 +549,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
} \
|
||||
\
|
||||
M_INLINE size_t \
|
||||
M_F(name, _size)(buffer_t v) \
|
||||
M_F(name, _size)(const buffer_t v) \
|
||||
{ \
|
||||
M_BUFF3R_CONTRACT(v,m_size); \
|
||||
return m_buff3r_number_load (v->number[0], policy); \
|
||||
@@ -1315,6 +1315,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
,POP(M_F(name,_pop)) \
|
||||
,OPLIST(oplist) \
|
||||
,EMPTY_P(M_F(name, _empty_p)), \
|
||||
,FULL_P(M_F(name, _full_p)), \
|
||||
,GET_SIZE(M_F(name, _size)) \
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Concurrent memory pool allocator
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Basic Protected Concurrent module over container.
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -343,7 +343,7 @@
|
||||
} \
|
||||
M_CALL_SET(oplist, out->data, src->data); \
|
||||
if (out < src) { \
|
||||
M_F(name, _read_lock)(src); \
|
||||
M_F(name, _read_unlock)(src); \
|
||||
M_F(name, _write_unlock)(out); \
|
||||
} else { \
|
||||
M_F(name, _write_unlock)(out); \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Extended Pre-processing macros module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -71,7 +71,7 @@
|
||||
/* Define M*LIB version */
|
||||
#define M_CORE_VERSION_MAJOR 0
|
||||
#define M_CORE_VERSION_MINOR 7
|
||||
#define M_CORE_VERSION_PATCHLEVEL 3
|
||||
#define M_CORE_VERSION_PATCHLEVEL 4
|
||||
|
||||
/* M_ASSUME is equivalent to M_ASSERT, but gives hints to compiler
|
||||
about how to optimize the code if NDEBUG is defined.
|
||||
@@ -142,7 +142,6 @@
|
||||
# define M_ATTR_COLD_FUNCTION
|
||||
#endif
|
||||
|
||||
|
||||
/* Prefetch . */
|
||||
#if defined(__GNUC__)
|
||||
# define M_PREFETCH(p) __builtin_prefetch((p), 0, 0)
|
||||
@@ -153,6 +152,17 @@
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* Definition of the typeof keyword
|
||||
In C23, we can use the standard keyword.
|
||||
Otherwise we use some extensions of the compilers. */
|
||||
#ifdef _MSC_VER
|
||||
#define m_typeof(x) decltype(x)
|
||||
#elif defined(__GNUC__)
|
||||
#define m_typeof(x) __typeof__(x)
|
||||
#else
|
||||
#define m_typeof(x) typeof(x)
|
||||
#endif
|
||||
|
||||
/* Ignore some warnings detected by some compilers in the library.
|
||||
* Whatever we do, there is some warnings that cannot be fixed.
|
||||
* So they are ignored in order to avoid polluting the user with
|
||||
@@ -3370,87 +3380,90 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
|
||||
/* Helper internal macros to make M_GET_METHOD works.
|
||||
List of supported methods for an oplist */
|
||||
#define M_INIT_INIT(a) ,a,
|
||||
#define M_INIT_SET_INIT_SET(a) ,a,
|
||||
#define M_INIT_MOVE_INIT_MOVE(a) ,a,
|
||||
#define M_INIT_WITH_INIT_WITH(a) ,a,
|
||||
#define M_SWAP_SWAP(a) ,a,
|
||||
#define M_SET_SET(a) ,a,
|
||||
#define M_MOVE_MOVE(a) ,a,
|
||||
#define M_CLEAR_CLEAR(a) ,a,
|
||||
#define M_HASH_HASH(a) ,a,
|
||||
#define M_EQUAL_EQUAL(a) ,a,
|
||||
#define M_CMP_CMP(a) ,a,
|
||||
#define M_TYPE_TYPE(a) ,a,
|
||||
#define M_SUBTYPE_SUBTYPE(a) ,a,
|
||||
#define M_GENTYPE_GENTYPE(a) ,a,
|
||||
#define M_SUBTYPE_PTR_SUBTYPE_PTR(a) ,a,
|
||||
#define M_NAME_NAME(a) ,a,
|
||||
#define M_OPLIST_OPLIST(a) ,a,
|
||||
#define M_SORT_SORT(a) ,a,
|
||||
#define M_SPLICE_BACK_SPLICE_BACK(a) ,a,
|
||||
#define M_SPLICE_AT_SPLICE_AT(a) ,a,
|
||||
#define M_IT_TYPE_IT_TYPE(a) ,a,
|
||||
#define M_IT_FIRST_IT_FIRST(a) ,a,
|
||||
#define M_IT_LAST_IT_LAST(a) ,a,
|
||||
#define M_IT_END_IT_END(a) ,a,
|
||||
#define M_IT_SET_IT_SET(a) ,a,
|
||||
#define M_IT_END_P_IT_END_P(a) ,a,
|
||||
#define M_IT_LAST_P_IT_LAST_P(a) ,a,
|
||||
#define M_IT_EQUAL_P_IT_EQUAL_P(a) ,a,
|
||||
#define M_IT_NEXT_IT_NEXT(a) ,a,
|
||||
#define M_IT_PREVIOUS_IT_PREVIOUS(a) ,a,
|
||||
#define M_IT_REF_IT_REF(a) ,a,
|
||||
#define M_IT_CREF_IT_CREF(a) ,a,
|
||||
#define M_IT_REMOVE_IT_REMOVE(a) ,a,
|
||||
#define M_IT_INSERT_IT_INSERT(a) ,a,
|
||||
#define M_EMPTY_P_EMPTY_P(a) ,a,
|
||||
#define M_ADD_ADD(a) ,a,
|
||||
#define M_SUB_SUB(a) ,a,
|
||||
#define M_MUL_MUL(a) ,a,
|
||||
#define M_DIV_DIV(a) ,a,
|
||||
#define M_RESET_RESET(a) ,a,
|
||||
#define M_KEY_TYPE_KEY_TYPE(a) ,a,
|
||||
#define M_VALUE_TYPE_VALUE_TYPE(a) ,a,
|
||||
#define M_KEY_OPLIST_KEY_OPLIST(a) ,a,
|
||||
#define M_VALUE_OPLIST_VALUE_OPLIST(a) ,a,
|
||||
#define M_GET_KEY_GET_KEY(a) ,a,
|
||||
#define M_SET_KEY_SET_KEY(a) ,a,
|
||||
#define M_SAFE_GET_KEY_SAFE_GET_KEY(a) ,a,
|
||||
#define M_ERASE_KEY_ERASE_KEY(a) ,a,
|
||||
#define M_GET_SIZE_GET_SIZE(a) ,a,
|
||||
#define M_PUSH_PUSH(a) ,a,
|
||||
#define M_POP_POP(a) ,a,
|
||||
#define M_PUSH_MOVE_PUSH_MOVE(a) ,a,
|
||||
#define M_POP_MOVE_POP_MOVE(a) ,a,
|
||||
#define M_REVERSE_REVERSE(a) ,a,
|
||||
#define M_GET_STR_GET_STR(a) ,a,
|
||||
#define M_PARSE_STR_PARSE_STR(a) ,a,
|
||||
#define M_OUT_STR_OUT_STR(a) ,a,
|
||||
#define M_IN_STR_IN_STR(a) ,a,
|
||||
#define M_OUT_SERIAL_OUT_SERIAL(a) ,a,
|
||||
#define M_IN_SERIAL_IN_SERIAL(a) ,a,
|
||||
#define M_SEPARATOR_SEPARATOR(a) ,a,
|
||||
#define M_EXT_ALGO_EXT_ALGO(a) ,a,
|
||||
#define M_INC_ALLOC_INC_ALLOC(a) ,a,
|
||||
#define M_OOR_SET_OOR_SET(a) ,a,
|
||||
#define M_OOR_EQUAL_OOR_EQUAL(a) ,a,
|
||||
#define M_LIMITS_LIMITS(a) ,a,
|
||||
#define M_PROPERTIES_PROPERTIES(a) ,a,
|
||||
#define M_EMPLACE_TYPE_EMPLACE_TYPE(a) ,a,
|
||||
#define M_X_INIT_INIT(a) ,a,
|
||||
#define M_X_INIT_SET_INIT_SET(a) ,a,
|
||||
#define M_X_INIT_MOVE_INIT_MOVE(a) ,a,
|
||||
#define M_X_INIT_WITH_INIT_WITH(a) ,a,
|
||||
#define M_X_SWAP_SWAP(a) ,a,
|
||||
#define M_X_SET_SET(a) ,a,
|
||||
#define M_X_MOVE_MOVE(a) ,a,
|
||||
#define M_X_CLEAR_CLEAR(a) ,a,
|
||||
#define M_X_HASH_HASH(a) ,a,
|
||||
#define M_X_EQUAL_EQUAL(a) ,a,
|
||||
#define M_X_CMP_CMP(a) ,a,
|
||||
#define M_X_TYPE_TYPE(a) ,a,
|
||||
#define M_X_SUBTYPE_SUBTYPE(a) ,a,
|
||||
#define M_X_GENTYPE_GENTYPE(a) ,a,
|
||||
#define M_X_SUBTYPE_PTR_SUBTYPE_PTR(a) ,a,
|
||||
#define M_X_NAME_NAME(a) ,a,
|
||||
#define M_X_FIELD_FIELD(a) ,a,
|
||||
#define M_X_OPLIST_OPLIST(a) ,a,
|
||||
#define M_X_SORT_SORT(a) ,a,
|
||||
#define M_X_SPLICE_BACK_SPLICE_BACK(a) ,a,
|
||||
#define M_X_SPLICE_AT_SPLICE_AT(a) ,a,
|
||||
#define M_X_IT_TYPE_IT_TYPE(a) ,a,
|
||||
#define M_X_IT_FIRST_IT_FIRST(a) ,a,
|
||||
#define M_X_IT_LAST_IT_LAST(a) ,a,
|
||||
#define M_X_IT_END_IT_END(a) ,a,
|
||||
#define M_X_IT_SET_IT_SET(a) ,a,
|
||||
#define M_X_IT_END_P_IT_END_P(a) ,a,
|
||||
#define M_X_IT_LAST_P_IT_LAST_P(a) ,a,
|
||||
#define M_X_IT_EQUAL_P_IT_EQUAL_P(a) ,a,
|
||||
#define M_X_IT_NEXT_IT_NEXT(a) ,a,
|
||||
#define M_X_IT_PREVIOUS_IT_PREVIOUS(a) ,a,
|
||||
#define M_X_IT_REF_IT_REF(a) ,a,
|
||||
#define M_X_IT_CREF_IT_CREF(a) ,a,
|
||||
#define M_X_IT_REMOVE_IT_REMOVE(a) ,a,
|
||||
#define M_X_IT_INSERT_IT_INSERT(a) ,a,
|
||||
#define M_X_EMPTY_P_EMPTY_P(a) ,a,
|
||||
#define M_X_FULL_P_FULL_P(a) ,a,
|
||||
#define M_X_ADD_ADD(a) ,a,
|
||||
#define M_X_SUB_SUB(a) ,a,
|
||||
#define M_X_MUL_MUL(a) ,a,
|
||||
#define M_X_DIV_DIV(a) ,a,
|
||||
#define M_X_RESET_RESET(a) ,a,
|
||||
#define M_X_KEY_TYPE_KEY_TYPE(a) ,a,
|
||||
#define M_X_VALUE_TYPE_VALUE_TYPE(a) ,a,
|
||||
#define M_X_KEY_OPLIST_KEY_OPLIST(a) ,a,
|
||||
#define M_X_VALUE_OPLIST_VALUE_OPLIST(a) ,a,
|
||||
#define M_X_GET_KEY_GET_KEY(a) ,a,
|
||||
#define M_X_SET_KEY_SET_KEY(a) ,a,
|
||||
#define M_X_SAFE_GET_KEY_SAFE_GET_KEY(a) ,a,
|
||||
#define M_X_ERASE_KEY_ERASE_KEY(a) ,a,
|
||||
#define M_X_GET_SIZE_GET_SIZE(a) ,a,
|
||||
#define M_X_PUSH_PUSH(a) ,a,
|
||||
#define M_X_POP_POP(a) ,a,
|
||||
#define M_X_PUSH_MOVE_PUSH_MOVE(a) ,a,
|
||||
#define M_X_POP_MOVE_POP_MOVE(a) ,a,
|
||||
#define M_X_REVERSE_REVERSE(a) ,a,
|
||||
#define M_X_GET_STR_GET_STR(a) ,a,
|
||||
#define M_X_PARSE_STR_PARSE_STR(a) ,a,
|
||||
#define M_X_OUT_STR_OUT_STR(a) ,a,
|
||||
#define M_X_IN_STR_IN_STR(a) ,a,
|
||||
#define M_X_OUT_SERIAL_OUT_SERIAL(a) ,a,
|
||||
#define M_X_IN_SERIAL_IN_SERIAL(a) ,a,
|
||||
#define M_X_SEPARATOR_SEPARATOR(a) ,a,
|
||||
#define M_X_EXT_ALGO_EXT_ALGO(a) ,a,
|
||||
#define M_X_INC_ALLOC_INC_ALLOC(a) ,a,
|
||||
#define M_X_OOR_SET_OOR_SET(a) ,a,
|
||||
#define M_X_OOR_EQUAL_OOR_EQUAL(a) ,a,
|
||||
#define M_X_LIMITS_LIMITS(a) ,a,
|
||||
#define M_X_PROPERTIES_PROPERTIES(a) ,a,
|
||||
#define M_X_EMPLACE_TYPE_EMPLACE_TYPE(a) ,a,
|
||||
// As attribute customization
|
||||
#define M_NEW_NEW(a) ,a,
|
||||
#define M_DEL_DEL(a) ,a,
|
||||
#define M_REALLOC_REALLOC(a) ,a,
|
||||
#define M_FREE_FREE(a) ,a,
|
||||
#define M_MEMPOOL_MEMPOOL(a) ,a,
|
||||
#define M_MEMPOOL_LINKAGE_MEMPOOL_LINKAGE(a) ,a,
|
||||
#define M_SIZE_SIZE(a) ,a,
|
||||
#define M_CONTEXT_CONTEXT(a) ,a,
|
||||
#define M_POLICY_POLICY(a) ,a,
|
||||
#define M_X_NEW_NEW(a) ,a,
|
||||
#define M_X_DEL_DEL(a) ,a,
|
||||
#define M_X_REALLOC_REALLOC(a) ,a,
|
||||
#define M_X_FREE_FREE(a) ,a,
|
||||
#define M_X_MEMPOOL_MEMPOOL(a) ,a,
|
||||
#define M_X_MEMPOOL_LINKAGE_MEMPOOL_LINKAGE(a) ,a,
|
||||
#define M_X_SIZE_SIZE(a) ,a,
|
||||
#define M_X_CONTEXT_CONTEXT(a) ,a,
|
||||
#define M_X_POLICY_POLICY(a) ,a,
|
||||
// As properties only
|
||||
#define M_LET_AS_INIT_WITH_LET_AS_INIT_WITH(a) ,a,
|
||||
#define M_NOCLEAR_NOCLEAR(a) ,a,
|
||||
#define M_X_LET_AS_INIT_WITH_LET_AS_INIT_WITH(a) ,a,
|
||||
#define M_X_NOCLEAR_NOCLEAR(a) ,a,
|
||||
#define M_X_THREADSAFE_THREADSAFE(a) ,a,
|
||||
|
||||
/* From an oplist - an unorded list of methods : like "INIT(mpz_init),CLEAR(mpz_clear),SET(mpz_set)" -
|
||||
Return the given method in the oplist or the default method.
|
||||
@@ -3458,7 +3471,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
M_GET_METHOD(INIT, my_default, INIT(mpz_init),CLEAR(mpz_clear),SET(mpz_set)) --> mpz_init
|
||||
M_GET_METHOD(INIT, my_default, CLEAR(mpz_clear),SET(mpz_set)) --> my_default */
|
||||
#define M_GET_METHOD(method, method_default, ...) \
|
||||
M_RET_ARG2 (M_MAP2B(M_C, M_C3(M_, method, _), __VA_ARGS__), method_default,)
|
||||
M_RET_ARG2 (M_MAP2B(M_C, M_C3(M_X_, method, _), __VA_ARGS__), method_default,)
|
||||
|
||||
/* Get the given method */
|
||||
#define M_GET_INIT(...) M_GET_METHOD(INIT, M_INIT_DEFAULT, __VA_ARGS__)
|
||||
@@ -3477,6 +3490,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
#define M_GET_SUBTYPE_PTR(...) M_GET_METHOD(SUBTYPE_PTR, M_NO_DEF_SUBTYPE_PTR, __VA_ARGS__)
|
||||
#define M_GET_GENTYPE(...) M_GET_METHOD(GENTYPE, M_NO_DEF_GENTYPE, __VA_ARGS__)
|
||||
#define M_GET_NAME(...) M_GET_METHOD(NAME, M_NO_DEF_NAME, __VA_ARGS__)
|
||||
#define M_GET_FIELD(...) M_GET_METHOD(FIELD, M_NO_DEF_FIELD, __VA_ARGS__)
|
||||
#define M_GET_OPLIST(...) M_GET_METHOD(OPLIST, (), __VA_ARGS__)
|
||||
#define M_GET_SORT(...) M_GET_METHOD(SORT, M_NO_DEF_SORT, __VA_ARGS__)
|
||||
#define M_GET_SPLICE_BACK(...) M_GET_METHOD(SPLICE_BACK, M_NO_DEF_SPLICE_BACK, __VA_ARGS__)
|
||||
@@ -3496,6 +3510,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
#define M_GET_IT_REMOVE(...) M_GET_METHOD(IT_REMOVE, M_NO_DEF_IT_REMOVE, __VA_ARGS__)
|
||||
#define M_GET_IT_INSERT(...) M_GET_METHOD(IT_INSERT, M_NO_DEF_IT_INSERT, __VA_ARGS__)
|
||||
#define M_GET_EMPTY_P(...) M_GET_METHOD(EMPTY_P, M_NO_DEF_EMPTY_P, __VA_ARGS__)
|
||||
#define M_GET_FULL_P(...) M_GET_METHOD(FULL_P, M_FALSE_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_ADD(...) M_GET_METHOD(ADD, M_ADD_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_SUB(...) M_GET_METHOD(SUB, M_SUB_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_MUL(...) M_GET_METHOD(MUL, M_MUL_DEFAULT, __VA_ARGS__)
|
||||
@@ -3558,6 +3573,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
//#define M_CALL_SUBTYPE_PTR(oplist, ...) M_APPLY_API(M_GET_SUBTYPE_PTR oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_GENTYPE(oplist, ...) M_APPLY_API(M_GET_GENTYPE oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_NAME(oplist, ...) M_APPLY_API(M_GET_NAME oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_FIELD(oplist, ...) M_APPLY_API(M_GET_FIELD oplist, oplist, __VA_ARGS__)
|
||||
//#define M_CALL_OPLIST(oplist, ...) M_APPLY_API(M_GET_OPLIST oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_SORT(oplist, ...) M_APPLY_API(M_GET_SORT oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_SPLICE_BACK(oplist, ...) M_APPLY_API(M_GET_SPLICE_BACK oplist, oplist, __VA_ARGS__)
|
||||
@@ -3577,6 +3593,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
#define M_CALL_IT_REMOVE(oplist, ...) M_APPLY_API(M_GET_IT_REMOVE oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_IT_INSERT(oplist, ...) M_APPLY_API(M_GET_IT_INSERT oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_EMPTY_P(oplist, ...) M_APPLY_API(M_GET_EMPTY_P oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_FULL_P(oplist, ...) M_APPLY_API(M_GET_FULL_P oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_ADD(oplist, ...) M_APPLY_API(M_GET_ADD oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_SUB(oplist, ...) M_APPLY_API(M_GET_SUB oplist, oplist, __VA_ARGS__)
|
||||
#define M_CALL_MUL(oplist, ...) M_APPLY_API(M_GET_MUL oplist, oplist, __VA_ARGS__)
|
||||
@@ -3922,6 +3939,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
#define M_NOTHING_DEFAULT(...) ((void)(__VA_ARGS__))
|
||||
#define M_EMPTY_DEFAULT(...) ((void)1)
|
||||
#define M_TRUE_DEFAULT(...) true
|
||||
#define M_FALSE_DEFAULT(...) false
|
||||
#define M_NEW_DEFAULT(a) M_MEMORY_ALLOC(a)
|
||||
#define M_DEL_DEFAULT(a) M_MEMORY_DEL(a)
|
||||
#define M_REALLOC_DEFAULT(t,p,s) M_MEMORY_REALLOC(t,p,s)
|
||||
@@ -4809,6 +4827,16 @@ m_core_parse2_enum (const char str[], const char **endptr)
|
||||
#define M_EMPLACE_LIST_TYPE_VAR_SINGLE(prefix, emplace_type) \
|
||||
, emplace_type const prefix
|
||||
|
||||
/* Expand to the list of emplace type with their variable name
|
||||
to use in the function declaration (doesn't start with a , but slower) */
|
||||
#define M_EMPLACE_LIST_TYPE_VAR_ALTER(prefix, emplace_type) \
|
||||
M_IF(M_PARENTHESIS_P( emplace_type ))(M_EMPLACE_LIST_TYPE_VAR_ALTER_MULTI, M_EMPLACE_LIST_TYPE_VAR_ALTER_SINGLE)(prefix, emplace_type)
|
||||
#define M_EMPLACE_LIST_TYPE_VAR_ALTER_MULTI(prefix, emplace_type) \
|
||||
M_MAP3(M_EMPLACE_LIST_TYPE_VAR_ALTER_MULTI_F, prefix, M_ID emplace_type)
|
||||
#define M_EMPLACE_LIST_TYPE_VAR_ALTER_MULTI_F(prefix, num, type) \
|
||||
M_IF(M_EQUAL(1, num))( /*void*/, M_DEFERRED_COMMA) type const M_C(prefix, num)
|
||||
#define M_EMPLACE_LIST_TYPE_VAR_ALTER_SINGLE(prefix, emplace_type) \
|
||||
emplace_type const prefix
|
||||
|
||||
/* Expand to the list of variable name based on the the declaration with
|
||||
emplace type to use in the INIT_WITH or specific method call (start with a ,) */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - DEQUE module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -115,7 +115,7 @@
|
||||
#define M_D3QU3_DEF_TYPE(name, type, oplist, deque_t, it_t, node_t) \
|
||||
\
|
||||
typedef struct M_F(name, _node_s) { \
|
||||
ILIST_INTERFACE(M_F(name, _node_list), struct M_F(name, _node_s)); \
|
||||
M_ILIST_INTERFACE(M_F(name, _node_list), struct M_F(name, _node_s)); \
|
||||
size_t size; \
|
||||
type data[M_MIN_FLEX_ARRAY_SIZE]; \
|
||||
} node_t; \
|
||||
@@ -127,7 +127,7 @@
|
||||
The interfaces are compatible. \
|
||||
*/ \
|
||||
/* FIXME: How can I separate public types and private implementation? */ \
|
||||
ILIST_DEF(M_F(name, _node_list), node_t, (DEL(M_GET_FREE oplist)) ) \
|
||||
M_ILIST_DEF(M_F(name, _node_list), node_t, (DEL(M_GET_FREE oplist)) ) \
|
||||
\
|
||||
/* Define an internal iterator */ \
|
||||
typedef struct M_F(name, _it2_s) { \
|
||||
@@ -1105,7 +1105,7 @@
|
||||
,RESET(M_F(name,_reset)) \
|
||||
,GET_SIZE(M_F(name, _size)) \
|
||||
,PUSH(M_F(name,_push_back)) \
|
||||
,POP(M_F(name,_pop_back)) \
|
||||
,POP(M_F(name,_pop_front)) \
|
||||
,OPLIST(oplist) \
|
||||
,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_F(name, _get_str)),) \
|
||||
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_F(name, _parse_str)),) \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - DICTIONARY Module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -156,7 +156,7 @@
|
||||
/*****************************************************************************/
|
||||
|
||||
// Define the maximum index
|
||||
#ifdef M_USE_64BITS_INDEX
|
||||
#ifdef M_USE_DICT_LARGE_INDEX
|
||||
typedef uint64_t m_index_t;
|
||||
#else
|
||||
typedef uint32_t m_index_t;
|
||||
@@ -169,7 +169,7 @@ typedef struct {
|
||||
} m_indexhash_t;
|
||||
|
||||
// Define a basic array over such pair
|
||||
ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
|
||||
M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
|
||||
|
||||
/* Performing Quadratic probing
|
||||
Replace it by '1' to perform linear probing */
|
||||
@@ -179,12 +179,22 @@ ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
|
||||
# define M_D1CT_OA_PROBING(s) ((s)++)
|
||||
#endif
|
||||
|
||||
/* Lower Bound of the hash table */
|
||||
/* Lower Bound of the hash table
|
||||
We shall have 2*M_D1CT_OA_LOWER_BOUND < M_D1CT_OA_UPPER_BOUND
|
||||
*/
|
||||
#ifndef M_D1CT_OA_LOWER_BOUND
|
||||
#define M_D1CT_OA_LOWER_BOUND 0.2
|
||||
#endif
|
||||
|
||||
/* Upper Bound of the hash table */
|
||||
/* Upper Bound of the hash table
|
||||
The container is designed for an upper bound in the range [0.5-0.75]
|
||||
Using higher upper bound (even by a slow amount) will deteriorate a lot the performance:
|
||||
an upper-bound of 0.875 is ~3 times slower than an upper bound of 0.7 for lockup of key not present
|
||||
(without considering prefetch of cache-lines which improve performance).
|
||||
This is due to the esperance of the number of reads before reading an empty value which is:
|
||||
(1-q)*sum(q^k*(k+1),k=0 .. infinity) = 1/(1-q)
|
||||
which is the estimated number of iteration before stopping the search loop.
|
||||
*/
|
||||
#ifndef M_D1CT_OA_UPPER_BOUND
|
||||
#define M_D1CT_OA_UPPER_BOUND 0.7
|
||||
#endif
|
||||
@@ -607,23 +617,13 @@ ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
|
||||
m_index_t hash = (m_index_t) M_CALL_HASH(key_oplist, key); \
|
||||
m_index_t p = hash & mask; \
|
||||
\
|
||||
if (M_UNLIKELY (hash == map->index[p].hash)) { \
|
||||
m_index_t d = map->index[p].index; \
|
||||
M_ASSERT(d <= map->freelist_count); \
|
||||
if (d >= 2 && M_CALL_EQUAL(key_oplist, map->data[d].pair.key, key)) { \
|
||||
M_CALL_SET(value_oplist, map->data[d].pair.value, value); \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (M_UNLIKELY( map->index[p].index != 0)) { \
|
||||
/* Test if bucket is not empty ? (50 % likely) */ \
|
||||
if (map->index[p].index != 0) { \
|
||||
/* Find the insertion point as the bucket[] is not empty */ \
|
||||
m_index_t delPos = (m_index_t) -1; \
|
||||
if (map->index[p].index == 1) delPos = p; \
|
||||
m_index_t s = 1U; \
|
||||
do { \
|
||||
p = (p + M_D1CT_OA_PROBING(s)) & mask; \
|
||||
if (hash == (map->index[p].hash)) { \
|
||||
if (M_UNLIKELY(hash == (map->index[p].hash))) { \
|
||||
m_index_t d = map->index[p].index; \
|
||||
M_ASSERT(d <= map->freelist_count); \
|
||||
if (d >= 2 && M_CALL_EQUAL(key_oplist, map->data[d].pair.key, key)) { \
|
||||
@@ -632,6 +632,7 @@ ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
|
||||
} \
|
||||
} \
|
||||
if (map->index[p].index == 1 && delPos == (m_index_t) -1) delPos = p; \
|
||||
p = (p + M_D1CT_OA_PROBING(s)) & mask; \
|
||||
} while (map->index[p].index != 0); \
|
||||
if (delPos != (m_index_t) -1) { \
|
||||
p = delPos; \
|
||||
@@ -1222,6 +1223,7 @@ ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
|
||||
M_F(name, _splice)(dict_t d1, dict_t d2) \
|
||||
{ \
|
||||
dict_it_t it; \
|
||||
M_ASSERT(d1 != d2); \
|
||||
/* NOTE: Despite using set_at, the accessing of the item in d1 \
|
||||
is not as random as other uses of the HASH table as d2 \
|
||||
uses the same order than d1 */ \
|
||||
@@ -1442,7 +1444,7 @@ enum m_d1ct_oa_element_e {
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \
|
||||
\
|
||||
/* NOTE: We don't want a real oplist for this sub type */ \
|
||||
ARRAY_DEF(M_F(name, _array_pair), M_F(name, _pair_ct), \
|
||||
M_ARRAY_DEF(M_F(name, _array_pair), M_F(name, _pair_ct), \
|
||||
(INIT(M_NOTHING_DEFAULT), SET(M_MEMCPY_DEFAULT), \
|
||||
INIT_SET(M_MEMCPY_DEFAULT), CLEAR(M_NOTHING_DEFAULT))) \
|
||||
\
|
||||
@@ -1658,19 +1660,13 @@ enum m_d1ct_oa_element_e {
|
||||
const size_t mask = dict->mask; \
|
||||
size_t p = M_CALL_HASH(key_oplist, key) & mask; \
|
||||
\
|
||||
/* NOTE: Likely cache miss */ \
|
||||
if (M_UNLIKELY (M_CALL_EQUAL(key_oplist, data[p].key, key)) ) { \
|
||||
M_CALL_SET(value_oplist, data[p].value, value); \
|
||||
return; \
|
||||
} \
|
||||
if (M_UNLIKELY (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) ) ) { \
|
||||
/* Test if bucket is not empty? (50% chance) */ \
|
||||
if (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) ) { \
|
||||
/* Find the insertion point as the bucket[] is not empty */ \
|
||||
size_t delPos = SIZE_MAX; \
|
||||
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED)) delPos = p; \
|
||||
size_t s = 1U; \
|
||||
do { \
|
||||
p = (p + M_D1CT_OA_PROBING(s)) & mask; \
|
||||
if (M_CALL_EQUAL(key_oplist, data[p].key, key)) { \
|
||||
if (M_UNLIKELY(M_CALL_EQUAL(key_oplist, data[p].key, key))) { \
|
||||
M_CALL_SET(value_oplist, data[p].value, value); \
|
||||
return; \
|
||||
} \
|
||||
@@ -1679,6 +1675,7 @@ enum m_d1ct_oa_element_e {
|
||||
&& (delPos == (size_t)-1)) { \
|
||||
delPos = p; \
|
||||
} \
|
||||
p = (p + M_D1CT_OA_PROBING(s)) & mask; \
|
||||
} while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) ); \
|
||||
if (delPos != SIZE_MAX) { \
|
||||
p = delPos; \
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Function Object module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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
-12
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Generic module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -101,17 +101,6 @@
|
||||
/********************************** INTERNAL *********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Definition of the typeof keyword
|
||||
In C23, we can use the standard keyword.
|
||||
Otherwise we use some extensions of the compilers. */
|
||||
#ifdef _MSC_VER
|
||||
#define m_typeof(x) decltype(x)
|
||||
#elif defined(__GNUC__)
|
||||
#define m_typeof(x) __typeof__(x)
|
||||
#else
|
||||
#define m_typeof(x) typeof(x)
|
||||
#endif
|
||||
|
||||
// Instead of using expensive M_SEQ(1,50), precompute it:
|
||||
#define M_G3N_SEQ_INT \
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, \
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Integer Generator (GENINT) module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
|
||||
+8
-13
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Intrusive List module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -71,6 +71,10 @@
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
#define M_ILIST_INIT_FIELD(name, obj) do { \
|
||||
(obj).name.next = NULL; \
|
||||
(obj).name.prev = NULL; \
|
||||
} while(0)
|
||||
|
||||
/*****************************************************************************/
|
||||
/******************************** INTERNAL ***********************************/
|
||||
@@ -117,7 +121,6 @@ typedef struct m_il1st_head_s {
|
||||
IT_REF(M_F(name,_ref)), \
|
||||
IT_CREF(M_F(name,_cref)), \
|
||||
IT_REMOVE(M_F(name,_remove)), \
|
||||
M_IF_METHOD(NEW, oplist)(IT_INSERT(M_F(name,_insert)),), \
|
||||
OPLIST(oplist), \
|
||||
SPLICE_BACK(M_F(name,_splice_back)) \
|
||||
)
|
||||
@@ -517,30 +520,22 @@ typedef struct m_il1st_head_s {
|
||||
type *obj = M_TYPE_FROM_FIELD(type, it->current, \
|
||||
struct m_il1st_head_s, name); \
|
||||
M_F(name, _unlink)(obj); \
|
||||
M_CALL_CLEAR(oplist, obj); \
|
||||
M_CALL_CLEAR(oplist, *obj); \
|
||||
M_IF_METHOD(DEL, oplist)(M_CALL_DEL(oplist, obj), (void) 0); \
|
||||
M_F(name, _next)(it); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD2(NEW, INIT_SET, oplist)( \
|
||||
M_INLINE void \
|
||||
M_F(name, _insert)(list_t list, it_t it, type x) \
|
||||
M_F(name, _insert)(list_t list, it_t it, type *p) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
type *p = M_CALL_NEW(oplist, type); \
|
||||
if (M_UNLIKELY_NOMEM (p == NULL)) { \
|
||||
M_MEMORY_FULL (sizeof (type)); \
|
||||
return ; \
|
||||
} \
|
||||
M_CALL_INIT_SET(oplist, *p, x); \
|
||||
type *obj = M_F(name, _ref)(it); \
|
||||
M_F(name, _push_after)(obj, p); \
|
||||
it->current = p; \
|
||||
it->current = &p->name; \
|
||||
(void) list; \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
, /* NEW & INIT_SET not defined */) \
|
||||
\
|
||||
M_INLINE type * \
|
||||
M_F(name, _pop_back)(list_t list) \
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - INTRUSIVE SHARED PTR Module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - LIST module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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 - MEMPOOL module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin Mutex & Thread wrapper (compatibility layer)
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - dynamic priority queue module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -131,7 +131,7 @@
|
||||
*/
|
||||
#define M_PR1OQUEUE_DEF_P3(name, type, oplist, prioqueue_t, it_t) \
|
||||
/* Definition of the internal array used to construct the priority queue */ \
|
||||
ARRAY_DEF(M_F(name, _array), type, oplist) \
|
||||
M_ARRAY_DEF(M_F(name, _array), type, oplist) \
|
||||
M_PR1OQUEUE_DEF_TYPE(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
M_PR1OQUEUE_DEF_CORE(name, type, oplist, prioqueue_t, it_t) \
|
||||
@@ -476,7 +476,7 @@
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
M_INLINE void \
|
||||
M_F(name, _get_str)(string_t str, const prioqueue_t p, bool append) \
|
||||
M_F(name, _get_str)(m_string_t str, const prioqueue_t p, bool append) \
|
||||
{ \
|
||||
M_F(name, _array_get_str)(str, p->array, append); \
|
||||
} \
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - RED BLACK TREE module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Serial BIN
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -400,7 +400,7 @@ m_ser1al_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
|
||||
Set 's' with the string if succeeds
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
m_ser1al_bin_read_string(m_serial_read_t serial, struct m_string_s *s){
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
M_ASSERT(f != NULL && s != NULL);
|
||||
// First read the number of non null characters
|
||||
|
||||
+11
-7
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Serial JSON
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -71,15 +71,17 @@ m_ser1al_json_write_float(m_serial_write_t serial, const long double data, const
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_json_write_string(m_serial_write_t serial, const char data[], size_t length)
|
||||
{
|
||||
M_ASSERT(length == (m_str1ng_size_t) length);
|
||||
M_ASSERT_SLOW(length == strlen(data) );
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
M_ASSERT(f != NULL && data != NULL);
|
||||
/* HACK: Build dummy string to reuse m_string_out_str */
|
||||
m_string_t v2;
|
||||
uintptr_t ptr = (uintptr_t) data;
|
||||
v2->u.heap.size = length;
|
||||
v2->u.heap.alloc = length + 1;
|
||||
v2->ptr = (char*)ptr;
|
||||
v2->u.heap.size = (m_str1ng_size_t) length;
|
||||
v2->u.heap.alloc[sizeof(m_str1ng_size_t)-2] = 1;
|
||||
v2->u.heap.alloc[sizeof(m_str1ng_size_t)-1] = 31;
|
||||
v2->u.heap.ptr = (char*)ptr;
|
||||
m_string_out_str(f, v2);
|
||||
return M_UNLIKELY(ferror(f)) ? m_core_serial_fail() : M_SERIAL_OK_DONE;
|
||||
}
|
||||
@@ -620,15 +622,17 @@ m_ser1al_str_json_write_float(m_serial_write_t serial, const long double data, c
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_str_json_write_string(m_serial_write_t serial, const char data[], size_t length)
|
||||
{
|
||||
M_ASSERT(length == (m_str1ng_size_t) length);
|
||||
M_ASSERT_SLOW(length == strlen(data) );
|
||||
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
|
||||
M_ASSERT(f != NULL && data != NULL);
|
||||
/* HACK: Build dummy string to reuse m_string_get_str */
|
||||
m_string_t v2;
|
||||
uintptr_t ptr = (uintptr_t) data;
|
||||
v2->u.heap.size = length;
|
||||
v2->u.heap.alloc = length + 1;
|
||||
v2->ptr = (char*)ptr;
|
||||
v2->u.heap.size = (m_str1ng_size_t) length;
|
||||
v2->u.heap.alloc[sizeof(m_str1ng_size_t)-2] = 1;
|
||||
v2->u.heap.alloc[sizeof(m_str1ng_size_t)-1] = 31;
|
||||
v2->u.heap.ptr = (char*)ptr;
|
||||
m_string_get_str(f, v2, true);
|
||||
return M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
+1386
File diff suppressed because it is too large.
Load diff
+7
-5
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SHARED Pointer Module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -183,10 +183,12 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
typedef shared_t M_F(name, _ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
\
|
||||
typedef struct M_F(name, _combine_s) { \
|
||||
struct M_F(name, _s) ptr; \
|
||||
type data; \
|
||||
} M_F(name, combine_ct)[1]; \
|
||||
M_IF(M_OR(M_TEST_METHOD_P(INIT, oplist), M_TEST_METHOD_ALTER_P(EMPLACE_TYPE, oplist)))( \
|
||||
typedef struct M_F(name, _combine_s) { \
|
||||
struct M_F(name, _s) ptr; \
|
||||
type data; \
|
||||
} M_F(name, combine_ct)[1]; \
|
||||
, /* nothing to do */ )
|
||||
|
||||
/* Define the core functions */
|
||||
#define M_SHAR3D_PTR_DEF_CORE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SNAPSHOT Module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -774,7 +774,7 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
{ \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap->core); \
|
||||
const M_F(name, _mrsw_aligned_type_ct) *oldx; \
|
||||
oldx = M_CTYPE_FROM_FIELD(M_F(name, _mrsw_aligned_type_ct), old, type, x); \
|
||||
oldx = (const M_F(name, _mrsw_aligned_type_ct) *) old; \
|
||||
M_ASSERT (oldx >= snap->core->data); \
|
||||
M_ASSERT (oldx < snap->core->data + snap->core->core->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
|
||||
M_ASSERT(snap->core->core->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER < UINT_MAX); \
|
||||
|
||||
+194
-120
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Dynamic Size String Module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -40,22 +40,39 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_ASSERT_SLOW (m_string_size(v) == strlen(m_string_get_cstr(v))); \
|
||||
M_ASSERT (m_string_get_cstr(v)[m_string_size(v)] == 0); \
|
||||
M_ASSERT (m_string_size(v) < m_string_capacity(v)); \
|
||||
M_ASSERT (m_string_capacity(v) < sizeof (m_str1ng_heap_ct) || !m_str1ng_stack_p(v)); \
|
||||
} while(0)
|
||||
|
||||
// string if it is heap allocated
|
||||
/* Define the maximum size of a string
|
||||
By default it is a little bit less than 2^32 bytes, which should be enough for
|
||||
most programs. Otherwise it can be increased. */
|
||||
#ifdef M_USE_STRING_LARGE_INDEX
|
||||
typedef uint64_t m_str1ng_size_t;
|
||||
#define m_str1ng_size_clz m_core_clz64
|
||||
#else
|
||||
typedef uint32_t m_str1ng_size_t;
|
||||
#define m_str1ng_size_clz m_core_clz32
|
||||
#endif
|
||||
|
||||
// The string representation if it heap allocated
|
||||
typedef struct m_str1ng_heap_s {
|
||||
size_t size;
|
||||
size_t alloc;
|
||||
char *ptr;
|
||||
m_str1ng_size_t size;
|
||||
unsigned char alloc[sizeof (m_str1ng_size_t)];
|
||||
} m_str1ng_heap_ct;
|
||||
// string if it is stack allocated
|
||||
typedef struct m_str1ng_stack_s {
|
||||
char buffer[sizeof (m_str1ng_heap_ct)];
|
||||
} m_str1ng_stack_ct;
|
||||
// both cases of string are possible
|
||||
|
||||
/* Define the union between a heap allocated string and its inline representation
|
||||
If buffer[sizeof(m_str1ng_heap_ct)-2] == 0 then
|
||||
It is a embedded based string where buffer is the string, with a maximum allocation of 15 bytes
|
||||
In this case buffer[sizeof(m_str1ng_heap_ct)-1] is the size of the string
|
||||
Otherwise it is a heap representation then
|
||||
ptr is the pointer to the data, size its size, and alloc a representation of the capacity:
|
||||
alloc[sizeof (m_str1ng_size_t)-2] << alloc[sizeof (m_str1ng_size_t)-1]
|
||||
we shall have alloc[sizeof (m_str1ng_size_t)-2] == buffer[sizeof(m_str1ng_heap_ct)-2]
|
||||
so that in case of heap representation, the field buffer[sizeof(m_str1ng_heap_ct)-2] is != 0
|
||||
*/
|
||||
typedef union m_str1ng_union_u {
|
||||
m_str1ng_heap_ct heap;
|
||||
m_str1ng_stack_ct stack;
|
||||
m_str1ng_heap_ct heap;
|
||||
char buffer[sizeof (m_str1ng_heap_ct)];
|
||||
} m_str1ng_union_ct;
|
||||
|
||||
/* State of the UTF8 decoding machine state */
|
||||
@@ -101,7 +118,6 @@ typedef enum {
|
||||
/* This is the main structure of this module, representing a dynamic string */
|
||||
typedef struct m_string_s {
|
||||
m_str1ng_union_ct u;
|
||||
char *ptr;
|
||||
} m_string_t[1];
|
||||
|
||||
// Pointer to a Dynamic string
|
||||
@@ -137,23 +153,17 @@ typedef struct m_string_it_s {
|
||||
m_string_: public methods
|
||||
*/
|
||||
|
||||
/* Internal method to test if the string is stack based or heap based
|
||||
We test if the ptr is NULL or not.
|
||||
This is not particularly efficient from a memory point of view
|
||||
(as we could reuse the pointer field to store some data)
|
||||
but it should be enough for most of "small" strings as most
|
||||
of the strings are less than 14 characters (64 bits architecture).
|
||||
Moreover it generates quite efficient code.
|
||||
NOTE: We set the pointer to NULL (instead of storing a pointer to
|
||||
the stack buffer for example) for stack based allocation so that
|
||||
the string structure remains trivially movable (which is an important
|
||||
property to have).
|
||||
/* Internal method to test if the characters of the string are fully embedded in the struct,
|
||||
or if the characters are allocated on the heap.
|
||||
Embedded representation ensures that the penultimate byte is 0.
|
||||
By encoding, we ensure that the penultimate byte of 'alloc' (of the heap representation)
|
||||
cannot be 0.
|
||||
*/
|
||||
M_INLINE bool
|
||||
m_str1ng_stack_p(const m_string_t s)
|
||||
m_str1ng_embedded_p(const m_string_t s)
|
||||
{
|
||||
// Function can be called when contract is not fulfilled
|
||||
return (s->ptr == NULL);
|
||||
return (s->u.buffer[sizeof(m_str1ng_heap_ct)-2] == 0);
|
||||
}
|
||||
|
||||
/* Internal method to set the size of the string (excluding final nul char) */
|
||||
@@ -161,12 +171,13 @@ M_INLINE void
|
||||
m_str1ng_set_size(m_string_t s, size_t size)
|
||||
{
|
||||
// Function can be called when contract is not fulfilled
|
||||
if (m_str1ng_stack_p(s)) {
|
||||
if (m_str1ng_embedded_p(s)) {
|
||||
M_ASSERT (size < sizeof (m_str1ng_heap_ct) - 1);
|
||||
// The size of the string is stored as the last char of the buffer.
|
||||
s->u.stack.buffer[sizeof (m_str1ng_heap_ct) - 1] = (char) size;
|
||||
s->u.buffer[sizeof(m_str1ng_heap_ct)-1] = (char) size;
|
||||
} else {
|
||||
s->u.heap.size = size;
|
||||
M_ASSUME(size == (m_str1ng_size_t) size);
|
||||
s->u.heap.size = (m_str1ng_size_t) size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,10 +186,9 @@ M_INLINE size_t
|
||||
m_string_size(const m_string_t s)
|
||||
{
|
||||
// Function can be called when contract is not fulfilled
|
||||
// Reading both values before calling the '?' operator enables compiler to generate branchless code
|
||||
const size_t s_stack = (size_t) s->u.stack.buffer[sizeof (m_str1ng_heap_ct) - 1];
|
||||
const size_t s_embed = (size_t) s->u.buffer[sizeof(m_str1ng_heap_ct)-1];
|
||||
const size_t s_heap = s->u.heap.size;
|
||||
return m_str1ng_stack_p(s) ? s_stack : s_heap;
|
||||
return m_str1ng_embedded_p(s) ? s_embed : s_heap;
|
||||
}
|
||||
|
||||
/* Return the capacity of the string (including the final nul char) */
|
||||
@@ -186,10 +196,58 @@ M_INLINE size_t
|
||||
m_string_capacity(const m_string_t s)
|
||||
{
|
||||
// Function can be called when contract is not fulfilled
|
||||
// Reading both values before calling the '?' operator enables compiler to generate branchless code
|
||||
const size_t c_stack = sizeof (m_str1ng_heap_ct) - 1;
|
||||
const size_t c_heap = s->u.heap.alloc;
|
||||
return m_str1ng_stack_p(s) ? c_stack : c_heap;
|
||||
const size_t c_embed = sizeof (m_str1ng_heap_ct) - 1;
|
||||
const size_t c_heap = (m_str1ng_size_t) s->u.heap.alloc[sizeof (m_str1ng_size_t)-2] << s->u.heap.alloc[sizeof (m_str1ng_size_t)-1];
|
||||
return m_str1ng_embedded_p(s) ? c_embed : c_heap;
|
||||
}
|
||||
|
||||
/* Internal function to round up the allocation size to the next allowed representation
|
||||
Return the rounded allocation and the pair (m,e) used to encode it
|
||||
An overflow occurs if the result is strictly lower than 'alloc' before casting.
|
||||
*/
|
||||
M_INLINE m_str1ng_size_t
|
||||
m_str1ng_round_capacity(unsigned char *m, unsigned char *e, m_str1ng_size_t alloc)
|
||||
{
|
||||
// We will encode 'alloc' as a number m<<e with (m,e) being unsigned char.
|
||||
// alloc is strictly greater than 0, but with casting to m_str1ng_size_t, it may be 0.
|
||||
// Compute the number of bits needed to represent 'alloc'
|
||||
unsigned b = (unsigned) sizeof(m_str1ng_size_t) * CHAR_BIT - m_str1ng_size_clz(alloc);
|
||||
if (b <= CHAR_BIT) {
|
||||
// It can be fully representable. No rounding needed.
|
||||
*m = (unsigned char) alloc;
|
||||
*e = 0;
|
||||
} else {
|
||||
/* It cannot be fully represented: Round it to the next upper representation of m << e
|
||||
with m and e unsigned char.
|
||||
Keep only the '7' upper bits of alloc, and round it to the next representation so that
|
||||
m << e is bigger or equal to alloc.
|
||||
Worst case is when alloc = 0x7F01 (i.e. all 7 upper bits are 1)
|
||||
Performing the rounding will generate a carry, so we get for mantissa 0x80 which is on 8 bits.
|
||||
That's why we shift by '7' and not by '8', so that 0x80 remains representable as an
|
||||
unsigned char. Otherwise we would need to take into account this case, and shift mantissa by
|
||||
one and increase exponent by one.
|
||||
If alloc was >= 0xFE000001, rounding will overflow the max of a m_str1ng_size_t
|
||||
and *m == 0.
|
||||
This case should be handled by the caller as an overflow error
|
||||
(return value is lower than input)
|
||||
*/
|
||||
*m = (unsigned char) ((alloc + ((1U <<(b-(CHAR_BIT-1)))-1))>>(b-(CHAR_BIT-1)));
|
||||
*e = (unsigned char) (b - (CHAR_BIT-1));
|
||||
}
|
||||
// Worst case is when the rounding overflow the size m_str1ng_size_t
|
||||
M_ASSERT (((m_str1ng_size_t) *m << *e) >= alloc || *m == 0);
|
||||
return (m_str1ng_size_t) *m << *e;
|
||||
}
|
||||
|
||||
/* Internal function to save the allocation size to the next allowed representation
|
||||
as returned by m_str1ng_round_capacity */
|
||||
M_INLINE void
|
||||
m_str1ng_set_capacity(m_string_t s, unsigned char m, unsigned char e)
|
||||
{
|
||||
// Function can be called when contract is not fulfilled
|
||||
M_ASSERT(m != 0);
|
||||
s->u.heap.alloc[sizeof (m_str1ng_size_t)-2] = m;
|
||||
s->u.heap.alloc[sizeof (m_str1ng_size_t)-1] = e;
|
||||
}
|
||||
|
||||
/* Return a writable pointer to the array of char of the string */
|
||||
@@ -197,9 +255,9 @@ M_INLINE char*
|
||||
m_str1ng_get_cstr(m_string_t v)
|
||||
{
|
||||
// Function can be called when contract is not fulfilled
|
||||
char *const ptr_stack = &v->u.stack.buffer[0];
|
||||
char *const ptr_heap = v->ptr;
|
||||
return m_str1ng_stack_p(v) ? ptr_stack : ptr_heap;
|
||||
char *const ptr_embed = &v->u.buffer[0];
|
||||
char *const ptr_heap = v->u.heap.ptr;
|
||||
return m_str1ng_embedded_p(v) ? ptr_embed : ptr_heap;
|
||||
}
|
||||
|
||||
/* Return the string view a classic C string (const char *) */
|
||||
@@ -208,9 +266,9 @@ m_string_get_cstr(const m_string_t v)
|
||||
{
|
||||
// Function cannot be called when contract is not fulfilled
|
||||
// but it is called by contract (so no contract check to avoid infinite recursion).
|
||||
const char *const ptr_stack = &v->u.stack.buffer[0];
|
||||
const char *const ptr_heap = v->ptr;
|
||||
return m_str1ng_stack_p(v) ? ptr_stack : ptr_heap;
|
||||
const char *const ptr_embed = &v->u.buffer[0];
|
||||
const char *const ptr_heap = v->u.heap.ptr;
|
||||
return m_str1ng_embedded_p(v) ? ptr_embed : ptr_heap;
|
||||
}
|
||||
|
||||
/* Initialize the dynamic string (constructor)
|
||||
@@ -218,9 +276,7 @@ m_string_get_cstr(const m_string_t v)
|
||||
M_INLINE void
|
||||
m_string_init(m_string_t s)
|
||||
{
|
||||
s->ptr = NULL;
|
||||
s->u.stack.buffer[0] = 0;
|
||||
m_str1ng_set_size(s, 0);
|
||||
memset(s, 0, sizeof(m_string_t));
|
||||
M_STR1NG_CONTRACT(s);
|
||||
}
|
||||
|
||||
@@ -229,13 +285,14 @@ M_INLINE void
|
||||
m_string_clear(m_string_t v)
|
||||
{
|
||||
M_STR1NG_CONTRACT(v);
|
||||
if (!m_str1ng_stack_p(v)) {
|
||||
M_MEMORY_FREE(v->ptr);
|
||||
v->ptr = NULL;
|
||||
if (!m_str1ng_embedded_p(v)) {
|
||||
M_MEMORY_FREE(v->u.heap.ptr);
|
||||
v->u.heap.ptr = NULL;
|
||||
}
|
||||
/* This is not needed but is safer to make
|
||||
the string invalid so that it can be detected. */
|
||||
v->u.stack.buffer[sizeof (m_str1ng_heap_ct) - 1] = CHAR_MAX;
|
||||
v->u.buffer[sizeof(m_str1ng_heap_ct)-2] = 0;
|
||||
v->u.buffer[sizeof(m_str1ng_heap_ct)-1] = CHAR_MAX;
|
||||
}
|
||||
|
||||
M_INLINE m_string_ptr m_str1ng_init_ref(m_string_t v) { m_string_init(v); return v; }
|
||||
@@ -248,10 +305,10 @@ M_INLINE char *
|
||||
m_string_clear_get_cstr(m_string_t v)
|
||||
{
|
||||
M_STR1NG_CONTRACT(v);
|
||||
char *p = v->ptr;
|
||||
if (m_str1ng_stack_p(v)) {
|
||||
// The string was stack allocated.
|
||||
p = v->u.stack.buffer;
|
||||
char *p = v->u.heap.ptr;
|
||||
if (m_str1ng_embedded_p(v)) {
|
||||
// The characters are embedded in the string.
|
||||
p = &v->u.buffer[0];
|
||||
// Need to allocate a heap string to return the copy.
|
||||
size_t alloc = m_string_size(v)+1;
|
||||
char *ptr = M_MEMORY_REALLOC (char, NULL, alloc);
|
||||
@@ -263,8 +320,8 @@ m_string_clear_get_cstr(m_string_t v)
|
||||
memcpy(ptr, p, alloc);
|
||||
p = ptr;
|
||||
}
|
||||
v->ptr = NULL;
|
||||
v->u.stack.buffer[sizeof (m_str1ng_heap_ct) - 1] = CHAR_MAX;
|
||||
v->u.buffer[sizeof(m_str1ng_heap_ct)-2] = 0;
|
||||
v->u.buffer[sizeof(m_str1ng_heap_ct)-1] = CHAR_MAX;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -307,7 +364,8 @@ m_string_empty_p(const m_string_t v)
|
||||
/* Internal method to fit the string to the given size
|
||||
Ensures that the string capacity is greater than size_alloc
|
||||
(size_alloc shall include the final null char).
|
||||
It may move the string from stack based to heap based.
|
||||
It may transform the string from embedded based to heap based.
|
||||
The string 'v' no longer has a working size field.
|
||||
Return a pointer to the writable string.
|
||||
*/
|
||||
M_INLINE char *
|
||||
@@ -323,7 +381,9 @@ m_str1ng_fit2size (m_string_t v, size_t size_alloc)
|
||||
if (M_UNLIKELY (size_alloc > old_alloc)) {
|
||||
// Insufficient current allocation to store the new string
|
||||
// Perform an allocation on the heap.
|
||||
size_t alloc = size_alloc + size_alloc / 2;
|
||||
size_t alloc = (size_alloc + size_alloc / 2);
|
||||
unsigned char m, e;
|
||||
alloc = m_str1ng_round_capacity(&m, &e, (m_str1ng_size_t) alloc);
|
||||
if (M_UNLIKELY_NOMEM (alloc <= size_alloc)) {
|
||||
/* Overflow in alloc computation */
|
||||
M_MEMORY_FULL(sizeof (char) * alloc);
|
||||
@@ -331,27 +391,28 @@ m_str1ng_fit2size (m_string_t v, size_t size_alloc)
|
||||
abort();
|
||||
return NULL;
|
||||
}
|
||||
char *ptr = M_MEMORY_REALLOC (char, v->ptr, alloc);
|
||||
char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr;
|
||||
ptr = M_MEMORY_REALLOC (char, ptr, alloc);
|
||||
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
|
||||
M_MEMORY_FULL(sizeof (char) * alloc);
|
||||
// NOTE: Return is currently broken.
|
||||
abort();
|
||||
return NULL;
|
||||
}
|
||||
// The pointer cannot be the stack buffer of the string.
|
||||
// as it is heap allocated
|
||||
M_ASSERT(ptr != &v->u.stack.buffer[0]);
|
||||
if (m_str1ng_stack_p(v)) {
|
||||
// The string was stack allocated.
|
||||
/* Copy the stack allocation into the new heap allocation */
|
||||
const size_t size = (size_t) v->u.stack.buffer[sizeof (m_str1ng_heap_ct) - 1] + 1U;
|
||||
M_ASSERT( size <= alloc);
|
||||
M_ASSERT( size <= sizeof (v->u.stack.buffer)-1);
|
||||
memcpy(ptr, &v->u.stack.buffer[0], size);
|
||||
// The pointer cannot be the embedded buffer of the string as it is heap allocated
|
||||
M_ASSERT(ptr != &v->u.buffer[0]);
|
||||
if (m_str1ng_embedded_p(v)) {
|
||||
// The string was fully embedded.
|
||||
/* Copy the embedded characters into the new heap allocation */
|
||||
const size_t size = (size_t) v->u.buffer[sizeof(m_str1ng_heap_ct) - 1];
|
||||
memcpy(ptr, &v->u.buffer[0], size+1);
|
||||
}
|
||||
// The string cannot be stack allocated anymore.
|
||||
v->ptr = ptr;
|
||||
v->u.heap.alloc = alloc;
|
||||
// The string cannot be fully embedded anymore.
|
||||
v->u.heap.ptr = ptr;
|
||||
m_str1ng_set_capacity(v, m, e);
|
||||
// Size is not set as the function is called in context
|
||||
// where the caller already know the final size of the string,
|
||||
// so it will update it.
|
||||
return ptr;
|
||||
}
|
||||
return m_str1ng_get_cstr(v);
|
||||
@@ -371,35 +432,42 @@ m_string_reserve(m_string_t v, size_t alloc)
|
||||
}
|
||||
M_ASSERT (alloc > 0);
|
||||
if (alloc < sizeof (m_str1ng_heap_ct)) {
|
||||
// Allocation can fit in the stack space
|
||||
if (!m_str1ng_stack_p(v)) {
|
||||
/* Transform Heap Allocate to Stack Allocate */
|
||||
char *ptr = &v->u.stack.buffer[0];
|
||||
memcpy(ptr, v->ptr, size+1);
|
||||
M_MEMORY_FREE(v->ptr);
|
||||
v->ptr = NULL;
|
||||
m_str1ng_set_size(v, size);
|
||||
// All characters can fit in am embedded structure
|
||||
if (!m_str1ng_embedded_p(v)) {
|
||||
/* Move the characters from the heap to within the structure */
|
||||
char *ptr = &v->u.buffer[0];
|
||||
char *oldptr = v->u.heap.ptr;
|
||||
memcpy(ptr, oldptr, size+1);
|
||||
// Free the allocated memory on the heap
|
||||
M_MEMORY_FREE(oldptr);
|
||||
v->u.buffer[sizeof(m_string_t)-2] = 0;
|
||||
v->u.buffer[sizeof(m_string_t)-1] = (char) size;
|
||||
} else {
|
||||
/* Already a stack based alloc: nothing to do */
|
||||
/* Already a fully embedded based type: nothing to do */
|
||||
}
|
||||
} else {
|
||||
// Allocation cannot fit in the stack space
|
||||
// Allocation cannot fit in the embedded structure space
|
||||
// Need to allocate in heap space
|
||||
// If the string is stack allocated, v->ptr is NULL
|
||||
// and it will therefore perform the initial allocation
|
||||
char *ptr = M_MEMORY_REALLOC (char, v->ptr, alloc);
|
||||
unsigned char m, e;
|
||||
size_t r_alloc = m_str1ng_round_capacity(&m, &e, (m_str1ng_size_t) alloc);
|
||||
if (M_UNLIKELY_NOMEM (alloc > r_alloc)) {
|
||||
M_MEMORY_FULL(sizeof (char) * alloc);
|
||||
return;
|
||||
}
|
||||
char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr;
|
||||
ptr = M_MEMORY_REALLOC (char, ptr, r_alloc);
|
||||
if (M_UNLIKELY_NOMEM (ptr == NULL) ) {
|
||||
M_MEMORY_FULL(sizeof (char) * alloc);
|
||||
return;
|
||||
}
|
||||
if (m_str1ng_stack_p(v)) {
|
||||
// Copy from stack space to heap space the string
|
||||
char *ptr_stack = &v->u.stack.buffer[0];
|
||||
memcpy(ptr, ptr_stack, size+1);
|
||||
v->u.heap.size = size;
|
||||
if (m_str1ng_embedded_p(v)) {
|
||||
// Copy the characters embedded in the structure to the allocated heap space
|
||||
memcpy(ptr, &v->u.buffer[0], size+1);
|
||||
M_ASSERT(size == (m_str1ng_size_t) size);
|
||||
v->u.heap.size = (m_str1ng_size_t) size;
|
||||
}
|
||||
v->ptr = ptr;
|
||||
v->u.heap.alloc = alloc;
|
||||
v->u.heap.ptr = ptr;
|
||||
m_str1ng_set_capacity(v, m, e);
|
||||
}
|
||||
M_STR1NG_CONTRACT (v);
|
||||
}
|
||||
@@ -429,6 +497,7 @@ m_string_set_cstrn(m_string_t v, const char str[], size_t n)
|
||||
char *ptr = m_str1ng_fit2size(v, size+1);
|
||||
// The memcpy will not copy the final null char of the string
|
||||
memcpy(ptr, str, size);
|
||||
// Cannot copy the final null char using memcpy
|
||||
ptr[size] = 0;
|
||||
m_str1ng_set_size(v, size);
|
||||
M_STR1NG_CONTRACT (v);
|
||||
@@ -460,6 +529,7 @@ m_string_set_n(m_string_t v, const m_string_t ref, size_t offset, size_t length)
|
||||
char *ptr = m_str1ng_fit2size(v, size+1);
|
||||
// v may be equal to ref, so a memmove is needed instead of a memcpy
|
||||
memmove(ptr, m_string_get_cstr(ref) + offset, size);
|
||||
// Cannot copy the final null char using memcpy
|
||||
ptr[size] = 0;
|
||||
m_str1ng_set_size(v, size);
|
||||
M_STR1NG_CONTRACT (v);
|
||||
@@ -498,7 +568,8 @@ m_string_init_move(m_string_t v1, m_string_t v2)
|
||||
M_STR1NG_CONTRACT (v2);
|
||||
memcpy(v1, v2, sizeof (m_string_t));
|
||||
// Note: nullify v2 to be safer
|
||||
v2->ptr = NULL;
|
||||
v2->u.buffer[sizeof(m_str1ng_heap_ct)-2] = 0;
|
||||
v2->u.buffer[sizeof(m_str1ng_heap_ct)-1] = CHAR_MAX;
|
||||
M_STR1NG_CONTRACT (v1);
|
||||
}
|
||||
|
||||
@@ -508,11 +579,10 @@ m_string_swap(m_string_t v1, m_string_t v2)
|
||||
{
|
||||
M_STR1NG_CONTRACT (v1);
|
||||
M_STR1NG_CONTRACT (v2);
|
||||
// Even if it is stack based, we swap the heap representation
|
||||
// which alias the stack based
|
||||
M_SWAP (size_t, v1->u.heap.size, v2->u.heap.size);
|
||||
M_SWAP (size_t, v1->u.heap.alloc, v2->u.heap.alloc);
|
||||
M_SWAP (char *, v1->ptr, v2->ptr);
|
||||
m_string_t tmp;
|
||||
memcpy(tmp, v1, sizeof(m_string_t));
|
||||
memcpy(v1, v2, sizeof(m_string_t));
|
||||
memcpy(v2, tmp, sizeof(m_string_t));
|
||||
M_STR1NG_CONTRACT (v1);
|
||||
M_STR1NG_CONTRACT (v2);
|
||||
}
|
||||
@@ -606,14 +676,15 @@ m_string_equal_p(const m_string_t v1, const m_string_t v2)
|
||||
{
|
||||
/* m_string_equal_p can be called with (at most) one string which is an OOR value.
|
||||
In case of OOR value, .ptr is NULL and .alloc is the maximum or the maximum-1.
|
||||
As it will detect a stack based string, it will read the size from the alloc fied
|
||||
As it will detect a full embedded based string, it will read the size from the alloc fied
|
||||
as 0xFF or 0xFE. In both cases, the size cannot be equal to a normal string
|
||||
so the test m_string_size(v1) == m_string_size(v2) is false in this case.
|
||||
*/
|
||||
M_ASSERT(v1 != NULL);
|
||||
M_ASSERT(v2 != NULL);
|
||||
/* Optimization: both strings shall have at least the same size */
|
||||
return m_string_size(v1) == m_string_size(v2) && m_string_cmp(v1, v2) == 0;
|
||||
return m_string_size(v1) == m_string_size(v2)
|
||||
&& memcmp(m_string_get_cstr(v1), m_string_get_cstr(v2), m_string_size(v1)) == 0;
|
||||
}
|
||||
|
||||
/* Test if the string is equal to the C string
|
||||
@@ -1017,7 +1088,7 @@ m_string_set_ui(m_string_t v, unsigned int n)
|
||||
{
|
||||
M_STR1NG_CONTRACT (v);
|
||||
char buffer[M_STR1NG_INT_MAX_SIZE];
|
||||
m_str1ng_fit2size(v, M_STR1NG_INT_MAX_SIZE);
|
||||
m_str1ng_fit2size(v, M_STR1NG_INT_MAX_SIZE+1);
|
||||
unsigned i = 0, j = 0;
|
||||
do {
|
||||
// 0123456789 are mandatory in this order as characters, as per C standard.
|
||||
@@ -1040,7 +1111,7 @@ m_string_set_si(m_string_t v, int n)
|
||||
M_STR1NG_CONTRACT (v);
|
||||
// Compute the maximum number of characters needed for the buffer.
|
||||
char buffer[M_STR1NG_INT_MAX_SIZE];
|
||||
m_str1ng_fit2size(v, M_STR1NG_INT_MAX_SIZE);
|
||||
m_str1ng_fit2size(v, M_STR1NG_INT_MAX_SIZE+1);
|
||||
unsigned i = 0, j = 0;
|
||||
bool neg = n < 0;
|
||||
unsigned n0 = neg ? 0U -(unsigned) n : (unsigned) n;
|
||||
@@ -1213,7 +1284,7 @@ m_string_fgets(m_string_t v, FILE *f, m_string_fgets_t arg)
|
||||
M_IF_EXCEPTION( m_str1ng_get_cstr(v)[size] = 0 );
|
||||
/* The string buffer is not big enough:
|
||||
increase it and continue reading */
|
||||
/* v cannot be stack alloc */
|
||||
/* v cannot be a full embedded type */
|
||||
ptr = m_str1ng_fit2size (v, alloc + alloc/2);
|
||||
alloc = m_string_capacity(v);
|
||||
}
|
||||
@@ -1389,15 +1460,15 @@ m_string_strim(m_string_t v, const char tab[])
|
||||
M_INLINE bool
|
||||
m_string_oor_equal_p(const m_string_t s, unsigned char n)
|
||||
{
|
||||
return (s->ptr == NULL) & (s->u.heap.alloc == ~(size_t)n);
|
||||
return (s->u.buffer[sizeof (m_str1ng_heap_ct)-2] == 0) & (s->u.buffer[sizeof (m_str1ng_heap_ct)-1] == (char) ~n);
|
||||
}
|
||||
|
||||
/* Set the uninitialized string to the OOR value */
|
||||
M_INLINE void
|
||||
m_string_oor_set(m_string_t s, unsigned char n)
|
||||
{
|
||||
s->ptr = NULL;
|
||||
s->u.heap.alloc = ~(size_t)n;
|
||||
s->u.buffer[sizeof (m_str1ng_heap_ct)-2] = 0;
|
||||
s->u.buffer[sizeof (m_str1ng_heap_ct)-1] = (char) ~n;
|
||||
}
|
||||
|
||||
/* I/O */
|
||||
@@ -1917,15 +1988,14 @@ m_string_it_set_ref(m_string_it_t it, m_string_t s, m_string_unicode_t new_u)
|
||||
size_t old_u_size = (size_t) (str - it->ptr);
|
||||
// We need to replace old_u by new_u. Both are variable length
|
||||
size_t str_size = m_string_size(s);
|
||||
m_str1ng_fit2size(s, str_size + new_u_size - old_u_size + 1);
|
||||
ptr = m_str1ng_get_cstr(s); // ptr may be reallocated!
|
||||
if (new_u_size != old_u_size) {
|
||||
ptr = m_str1ng_fit2size(s, str_size + new_u_size - old_u_size + 1);
|
||||
M_ASSUME( str_size+1 > (offset + old_u_size) );
|
||||
memmove(&ptr[offset+new_u_size], &ptr[offset + old_u_size],
|
||||
str_size+1 - offset - old_u_size);
|
||||
m_str1ng_set_size(s, str_size + new_u_size - old_u_size);
|
||||
}
|
||||
memcpy(&ptr[offset], &buffer[0], new_u_size);
|
||||
m_str1ng_set_size(s, str_size + new_u_size - old_u_size);
|
||||
it->ptr = &ptr[offset];
|
||||
M_STR1NG_IT_CONTRACT(it);
|
||||
M_STR1NG_CONTRACT(s);
|
||||
@@ -1976,7 +2046,7 @@ m_string_pop_u(m_string_unicode_t *u, m_string_t str)
|
||||
|
||||
/* Compute the length in UTF8 code points in the string */
|
||||
M_INLINE size_t
|
||||
m_string_length_u(m_string_t str)
|
||||
m_string_length_u(const m_string_t str)
|
||||
{
|
||||
M_STR1NG_CONTRACT(str);
|
||||
return m_str1ng_utf8_length(m_string_get_cstr(str));
|
||||
@@ -1984,7 +2054,7 @@ m_string_length_u(m_string_t str)
|
||||
|
||||
/* Check if a string is a valid UTF8 encoded stream */
|
||||
M_INLINE bool
|
||||
m_string_utf8_p(m_string_t str)
|
||||
m_string_utf8_p(const m_string_t str)
|
||||
{
|
||||
M_STR1NG_CONTRACT(str);
|
||||
return m_str1ng_utf8_valid_str_p(m_string_get_cstr(str));
|
||||
@@ -2055,8 +2125,9 @@ m_string_utf8_p(m_string_t str)
|
||||
#ifndef __cplusplus
|
||||
/* Initialize a constant string with the given C string */
|
||||
# define M_STRING_CTE(s) \
|
||||
(m_string_srcptr)((const m_string_t){{.u.heap = { .size = sizeof(s)-1, .alloc = sizeof(s) } , \
|
||||
.ptr = ((struct { long long _n; char _d[sizeof (s)]; }){ 0, s })._d }})
|
||||
(m_string_srcptr)((const m_string_t){{.u.heap = { .size = sizeof(s)-1, \
|
||||
.alloc = { [sizeof(m_str1ng_size_t)-2] = 1, [sizeof(m_str1ng_size_t)-1] = 31}, \
|
||||
.ptr = ((struct { long long _n; char _d[sizeof (s)]; }){ 0, s })._d }}})
|
||||
#else
|
||||
namespace m_lib {
|
||||
template <unsigned int N>
|
||||
@@ -2069,9 +2140,10 @@ namespace m_lib {
|
||||
inline m_aligned_string(const char lstr[])
|
||||
{
|
||||
this->string->u.heap.size = N -1;
|
||||
this->string->u.heap.alloc = N;
|
||||
this->string->u.heap.alloc[sizeof(m_str1ng_size_t)-2] = 1;
|
||||
this->string->u.heap.alloc[sizeof(m_str1ng_size_t)-1] = 31;
|
||||
memcpy (this->str, lstr, N);
|
||||
this->string->ptr = this->str;
|
||||
this->string->u.heap.ptr = this->str;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -2563,9 +2635,10 @@ namespace m_lib {
|
||||
/* Build dummy string to reuse m_string_get_str */ \
|
||||
uintptr_t ptr = (uintptr_t) &s->s[0]; \
|
||||
m_string_t v2; \
|
||||
v2->u.heap.size = strlen(s->s); \
|
||||
v2->u.heap.alloc = v2->u.heap.size + 1; \
|
||||
v2->ptr = (char*)ptr; \
|
||||
v2->u.heap.size = (m_str1ng_size_t) strlen(s->s); \
|
||||
v2->u.heap.alloc[sizeof(m_str1ng_size_t)-2] = 1; \
|
||||
v2->u.heap.alloc[sizeof(m_str1ng_size_t)-1] = 31; \
|
||||
v2->u.heap.ptr = (char*)ptr; \
|
||||
m_string_get_str(v, v2, append); \
|
||||
} \
|
||||
\
|
||||
@@ -2577,9 +2650,10 @@ namespace m_lib {
|
||||
/* Build dummy string to reuse m_string_get_str */ \
|
||||
uintptr_t ptr = (uintptr_t) &s->s[0]; \
|
||||
m_string_t v2; \
|
||||
v2->u.heap.size = strlen(s->s); \
|
||||
v2->u.heap.alloc = v2->u.heap.size + 1; \
|
||||
v2->ptr = (char*)ptr; \
|
||||
v2->u.heap.size = (m_str1ng_size_t) strlen(s->s); \
|
||||
v2->u.heap.alloc[sizeof(m_str1ng_size_t)-2] = 1; \
|
||||
v2->u.heap.alloc[sizeof(m_str1ng_size_t)-1] = 31; \
|
||||
v2->u.heap.ptr = (char*)ptr; \
|
||||
m_string_out_str(f, v2); \
|
||||
} \
|
||||
\
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin Mutex & Thread wrapper
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - TREE module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -1300,7 +1300,7 @@ typedef int32_t m_tr33_index_t;
|
||||
#define M_TR33_DEF_P4_IO(name, type, oplist, tree_t, it_t) \
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
M_INLINE void \
|
||||
M_F(name, _get_str)(string_t str, /*const*/ tree_t tree, bool append) { \
|
||||
M_F(name, _get_str)(m_string_t str, /*const*/ tree_t tree, bool append) { \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
|
||||
it_t it = M_F(name, _it)(tree); \
|
||||
while (!M_F(name, _end_p)(it)) { \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - try / catch mechanism for M*LIB
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -33,9 +33,27 @@
|
||||
* so that for each variable defined using M_LET,
|
||||
* its destructor is still called when exceptions are thrown.
|
||||
* It is either the C++ try,
|
||||
* or it uses a GCC or CLANG extension,
|
||||
* or the standard C compliant way (much slower).
|
||||
* or it uses a GCC extension,
|
||||
* or it uses a CLANG extension,
|
||||
* or the standard C compliant way through longjmp (slower).
|
||||
* The user can override the desired mechanism.
|
||||
*
|
||||
* Performance Measures of the mechanism costs to create recursively 100000 empty strings (RAII / no exception)
|
||||
* TCC : LET(longjmp): 6412 us ON_EXCEPTION(longjmp): 6550 us
|
||||
* CLANG : LET(longjmp): 3922 us ON_EXCEPTION(longjmp): 3972 us
|
||||
* CLANG+BLOCK: LET(BLOCK): 3549 us ON_EXCEPTION(longjmp): 4196 us
|
||||
* GCC (O2) : LET(nested): 1828 us ON_EXCEPTION(longjmp): 2033 us
|
||||
* G++ (O2/O3): LET(c++): 1850 us ON_EXCEPTION(c++): 1874 us
|
||||
* GCC (O3) : LET(nested): 1377 us ON_EXCEPTION(longjmp): 1402 us
|
||||
* CLANG++(O2/O3): LET(c++): 428 us ON_EXCEPTION(c++): 433 us
|
||||
* Therefore the C mechanism of try emulation is 3x times slower than the C++ "zero cost" implementation
|
||||
* in this scenario where the mechanism cost is the most measurable.
|
||||
* Most of the time difference comes from the size of the stack frame (memory bandwidth):
|
||||
* * 240 bytes for CLANG(block/longjmp)
|
||||
* * 80 bytes for GCC/nested
|
||||
* * 96 bytes for GCC/longjmp
|
||||
* * 64 bytes for G++ (!)
|
||||
* * 16 bytes for CLANG++
|
||||
*/
|
||||
#ifndef M_USE_TRY_MECHANISM
|
||||
# if defined(__has_extension)
|
||||
@@ -252,7 +270,7 @@ namespace m_lib {
|
||||
* The main difficulty is the mechanism to register the CLEAR operators
|
||||
* to call when throwing an exception.
|
||||
* Contrary to the C++ back-end, it is not cost-free as it adds some
|
||||
* instructions to the normal behavior of the program.
|
||||
* instructions to the normal behavior of the program, usually 5 store instructions.
|
||||
*/
|
||||
#else
|
||||
|
||||
@@ -292,12 +310,16 @@ typedef intptr_t m_try_jmp_buf[5];
|
||||
// this point in the stack frame. Each nodes are linked together, so that we can
|
||||
// analyze the stack frame on exception.
|
||||
typedef struct m_try_s {
|
||||
enum { M_STATE_TRY, M_STATE_EXCEPTION_IN_PROGRESS, M_STATE_EXCEPTION_CAUGHT,
|
||||
M_STATE_CLEAR_JMPBUF, M_STATE_CLEAR_CB } kind;
|
||||
struct m_try_s *next;
|
||||
enum { M_STATE_TRY, // Try block starts
|
||||
M_STATE_EXCEPTION_IN_PROGRESS, // A try block or jmpbuf is being in progress (before being caught)
|
||||
M_STATE_EXCEPTION_CAUGHT, // An exception in progress has been successfully caught (==> no rethrow)
|
||||
M_STATE_CLEAR_JMPBUF, // Need to jmpbuf here to clear things
|
||||
M_STATE_CLEAR_CB // Need to call the function to clear things
|
||||
} kind;
|
||||
struct m_try_s *next; // Next try block or clear mechanism on the stack frame.
|
||||
union {
|
||||
m_try_jmp_buf buf;
|
||||
struct { void (M_TRY_FUNC_OPERATOR func)(void*); void *data; } clear;
|
||||
m_try_jmp_buf buffer; // To use for M_STATE_CLEAR_JMPBUF
|
||||
struct { void (M_TRY_FUNC_OPERATOR func)(void*); void *data; } clear; // To use for M_STATE_CLEAR_CB
|
||||
} data;
|
||||
} m_try_t[1];
|
||||
|
||||
@@ -306,14 +328,14 @@ typedef struct m_try_s {
|
||||
#define M_TRY_B(cont, buf, exception) \
|
||||
for(bool cont = true ; cont ; cont = false) \
|
||||
for(m_try_t buf ; cont ; m_try_clear(buf), cont = false ) \
|
||||
for(const struct m_exception_s *exception = NULL; cont; cont = false, exception = exception) \
|
||||
if (m_try_init(buf))
|
||||
for(const struct m_exception_s *exception = (m_try_init(buf), NULL); cont; cont = false, exception = exception) \
|
||||
if (m_try_setjmp((buf->data.buffer)) == 0)
|
||||
|
||||
// Throw the error code
|
||||
#define M_THROW_1(error_code) \
|
||||
m_throw( &(const struct m_exception_s) { error_code, __LINE__, 0, __FILE__, { 0 } } )
|
||||
|
||||
// Throw the error code
|
||||
// Throw the error code and the associated data.
|
||||
#define M_THROW_N(error_code, ...) \
|
||||
m_throw( &(const struct m_exception_s) { error_code, __LINE__, M_NARGS(__VA_ARGS__), __FILE__, \
|
||||
{ __VA_ARGS__ } } )
|
||||
@@ -334,6 +356,7 @@ extern M_ATTR_NO_RETURN M_ATTR_COLD_FUNCTION void m_throw(const struct m_excepti
|
||||
|
||||
// Macro to add once in one source file to define theses global:
|
||||
#define M_TRY_DEF_ONCE_B() \
|
||||
/* Define the global variables */ \
|
||||
M_THREAD_ATTR struct m_try_s *m_global_error_list; \
|
||||
M_THREAD_ATTR struct m_exception_s m_global_exception; \
|
||||
\
|
||||
@@ -345,7 +368,7 @@ extern M_ATTR_NO_RETURN M_ATTR_COLD_FUNCTION void m_throw(const struct m_excepti
|
||||
/* Analyze the error list to see what has been registered */ \
|
||||
struct m_try_s *e = m_global_error_list; \
|
||||
while (e != NULL) { \
|
||||
/* A CLEAR operator has been registered: call it */ \
|
||||
/* A CLEAR by CB operator has been registered: call it */ \
|
||||
if (e->kind == M_STATE_CLEAR_CB) { \
|
||||
e->data.clear.func(e->data.clear.data); \
|
||||
} \
|
||||
@@ -358,12 +381,12 @@ extern M_ATTR_NO_RETURN M_ATTR_COLD_FUNCTION void m_throw(const struct m_excepti
|
||||
m_exception_set(&m_global_exception, exception); \
|
||||
e->kind = M_STATE_EXCEPTION_IN_PROGRESS; \
|
||||
m_global_error_list = e; \
|
||||
m_try_longjmp(e->data.buf, 1); \
|
||||
m_try_longjmp(e->data.buffer, 1); \
|
||||
} \
|
||||
/* Next stack frame */ \
|
||||
e = e->next; \
|
||||
} \
|
||||
/* No exception found. \
|
||||
/* No try block found. \
|
||||
Display the information and halt program . */ \
|
||||
M_RAISE_FATAL("Exception '%u' raised by (%s:%d) is not caught. Program aborted.\n", \
|
||||
exception->error_code, exception->filename, exception->line); \
|
||||
@@ -385,6 +408,9 @@ m_catch(m_try_t state, unsigned error_code, const struct m_exception_s **excepti
|
||||
M_ASSERT(m_global_error_list == state);
|
||||
M_ASSERT(state->kind == M_STATE_EXCEPTION_IN_PROGRESS);
|
||||
*exception = &m_global_exception;
|
||||
// If error_code is 0, we want to catch **all** errors.
|
||||
// Otherwise we want to cache only the given error
|
||||
// Return false if we don't catcht it.
|
||||
if (error_code != 0 && m_global_exception.error_code != error_code)
|
||||
return false;
|
||||
// The exception has been caught.
|
||||
@@ -395,6 +421,14 @@ m_catch(m_try_t state, unsigned error_code, const struct m_exception_s **excepti
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#if __GNUC__ >= 12
|
||||
/* Warnings disabled for GNU C in C mode (Affecting a global variable to the address of a local variable) */
|
||||
_Pragma("GCC diagnostic push")
|
||||
_Pragma("GCC diagnostic ignored \"-Wdangling-pointer\"")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialize the state to a TRY state.
|
||||
M_INLINE void
|
||||
m_try_init(m_try_t state)
|
||||
@@ -402,10 +436,8 @@ m_try_init(m_try_t state)
|
||||
state->kind = M_STATE_TRY;
|
||||
state->next = m_global_error_list;
|
||||
m_global_error_list = state;
|
||||
// setjmp needs to be done in the MACRO.
|
||||
// setjmp cannot be done here
|
||||
}
|
||||
#define m_try_init(s) \
|
||||
M_LIKELY ((m_try_init(s), m_try_setjmp(((s)->data.buf)) != 1))
|
||||
|
||||
// Disable the current TRY block.
|
||||
M_INLINE void
|
||||
@@ -429,6 +461,9 @@ m_try_clear(m_try_t state)
|
||||
// * post: which is called after the constructor
|
||||
// * final: which is called before the destructor.
|
||||
|
||||
// There is two mechanims: calling a CLEAR callback (faster but need compiler extension)
|
||||
// or using an intermediary jmpbuf_t longjmp (slower but standard compliant).
|
||||
|
||||
// We register a call to the CLEAR callback.
|
||||
// We don't modify m_global_error_list until we have successfully called the INIT operator
|
||||
// to avoid registering the CLEAR operator on exception whereas the object is not initialized yet.
|
||||
@@ -461,7 +496,8 @@ m_try_cb_final(m_try_t state)
|
||||
m_global_error_list = state->next;
|
||||
}
|
||||
|
||||
// Pre initialization function. Save the stack frame for a longjmp
|
||||
// We register a longjmp here to handle the cleaning of the exception at this function.
|
||||
// Pre initialization function.
|
||||
M_INLINE bool
|
||||
m_try_jump_pre(m_try_t state)
|
||||
{
|
||||
@@ -470,15 +506,13 @@ m_try_jump_pre(m_try_t state)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Post initialization function. Register the stack frame for a longjmp
|
||||
// Post initialization function. Save the stack frame for a longjmp
|
||||
M_INLINE void
|
||||
m_try_jump_post(m_try_t state)
|
||||
{
|
||||
M_ASSERT(state->next == m_global_error_list);
|
||||
m_global_error_list = state;
|
||||
}
|
||||
// And call setjmp to register the position in the code.
|
||||
#define m_try_jump_post(s) \
|
||||
M_LIKELY ((m_try_jump_post(s), m_try_setjmp(((s)->data.buf)) != 1))
|
||||
|
||||
// The object will be cleared.
|
||||
// We can pop the stack frame of the errors.
|
||||
@@ -488,6 +522,11 @@ m_try_jump_final(m_try_t state)
|
||||
m_global_error_list = state->next;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#if __GNUC__ >= 12
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Implement the M_LET injection macros, so that the CLEAR operator is called on exception
|
||||
//
|
||||
@@ -495,7 +534,7 @@ m_try_jump_final(m_try_t state)
|
||||
# error M*LIB: Internal error. C++ back-end requested within C implementation.
|
||||
|
||||
#elif M_USE_TRY_MECHANISM == 2
|
||||
// Use of CLANG blocks
|
||||
// Use of CLANG blocks, and register them as callback with a pointer to the variable
|
||||
|
||||
#define M_LET_TRY_INJECT_PRE_B(cont, oplist, name) \
|
||||
for(m_try_t M_C(m_try_state_, name); cont && \
|
||||
@@ -507,7 +546,7 @@ m_try_jump_final(m_try_t state)
|
||||
(void*) &name); cont; m_try_cb_final(M_C(m_try_state_, name)) )
|
||||
|
||||
#elif M_USE_TRY_MECHANISM == 3
|
||||
// Use of GCC nested functions.
|
||||
// Use of GCC nested functions, and register them as callback with a pointer to the variable
|
||||
|
||||
#define M_LET_TRY_INJECT_PRE_B(cont, oplist, name) \
|
||||
for(m_try_t M_C(m_try_state_, name); cont && \
|
||||
@@ -520,7 +559,7 @@ m_try_jump_final(m_try_t state)
|
||||
|
||||
#elif M_USE_TRY_MECHANISM == 4
|
||||
// STD C compliant (without compiler extension): use of setjmp
|
||||
// This is the basic implementation in case of compiler unknown.
|
||||
// This is the basic implementation in case of unknown compiler.
|
||||
// It uses setjmp/longjmp, and as such, is much slower than
|
||||
// other implementations.
|
||||
|
||||
@@ -534,9 +573,8 @@ m_try_jump_final(m_try_t state)
|
||||
// Register the stack frame and tests for the longjmp.
|
||||
// In which case call the CLEAR operator, unstack the error list and rethrow the error.
|
||||
#define M_LET_TRY_INJECT_POST_B(cont, oplist, name) \
|
||||
for( ; cont ; m_try_jump_final(M_C(m_try_state_, name))) \
|
||||
if (m_try_jump_post(M_C(m_try_state_, name)) \
|
||||
|| (M_CALL_CLEAR(oplist, name), m_try_jump_final(M_C(m_try_state_, name)), m_rethrow(), false))
|
||||
for(m_try_jump_post(M_C(m_try_state_, name)); cont ; m_try_jump_final(M_C(m_try_state_, name))) \
|
||||
if (m_try_setjmp(M_C(m_try_state_, name)->data.buffer) != 0) { M_CALL_CLEAR(oplist, name); m_try_jump_final(M_C(m_try_state_, name)); m_rethrow(); } else
|
||||
|
||||
#else
|
||||
# error M*LIB: Invalid value for M_USE_TRY_MECHANISM [1..4]
|
||||
@@ -553,9 +591,8 @@ m_try_jump_final(m_try_t state)
|
||||
// Register the stack frame and tests for the longjmp.
|
||||
// In which case call the CLEAR operator, unstack the error list and rethrow the error.
|
||||
#define M_DEFER_TRY_INJECT_POST_B(cont, ...) \
|
||||
for( ; cont ; m_try_jump_final(M_C(m_try_state_, cont))) \
|
||||
if (m_try_jump_post(M_C(m_try_state_, cont)) \
|
||||
|| (__VA_ARGS__ , m_try_jump_final(M_C(m_try_state_, cont)), m_rethrow(), false))
|
||||
for(m_try_jump_post(M_C(m_try_state_, cont)); cont ; m_try_jump_final(M_C(m_try_state_, cont))) \
|
||||
if (m_try_setjmp(M_C(m_try_state_, cont)->data.buffer) != 0) { __VA_ARGS__; m_try_jump_final(M_C(m_try_state_, cont)); m_rethrow(); } else
|
||||
|
||||
#endif /* cplusplus */
|
||||
|
||||
@@ -590,4 +627,3 @@ m_try_jump_final(m_try_t state)
|
||||
#define m_volatile volatile
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - TUPLE module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
|
||||
+16
-4
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - VARIANT module
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -194,9 +194,10 @@
|
||||
typedef \
|
||||
M_IF_METHOD(GENTYPE, M_VAR1ANT_GET_OPLIST a)( M_GET_GENTYPE M_VAR1ANT_GET_OPLIST a, M_VAR1ANT_GET_TYPE a) \
|
||||
M_C4(m_var1ant_, name, _gentype_, num); \
|
||||
typedef const \
|
||||
M_IF_METHOD(GENTYPE, M_VAR1ANT_GET_OPLIST a)( M_GET_GENTYPE M_VAR1ANT_GET_OPLIST a, M_VAR1ANT_GET_TYPE a) \
|
||||
M_C4(m_var1ant_, name, _const_gentype_, num);
|
||||
typedef \
|
||||
M_IF_METHOD(GENTYPE, M_VAR1ANT_GET_OPLIST a)( const M_GET_GENTYPE M_VAR1ANT_GET_OPLIST a, M_VAR1ANT_GET_TYPE a const) \
|
||||
M_C4(m_var1ant_, name, _const_gentype_, num); \
|
||||
typedef M_VAR1ANT_GET_TYPE a M_C4(m_var1ant_, name, _type_, M_VAR1ANT_GET_FIELD a);
|
||||
|
||||
#define M_VAR1ANT_DEFINE_UNION_ELE(name, a) \
|
||||
, M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value)
|
||||
@@ -793,8 +794,19 @@ M_INLINE void \
|
||||
M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(INIT_MOVE(M_F(name, _init_move)),), \
|
||||
M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(MOVE(M_F(name, _move)),), \
|
||||
M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_F(name, _swap)),), \
|
||||
M_IF_METHOD_ALL(FIELD, __VA_ARGS__)(M_VAR1ANT_OPLIST_EMPLACE_TYPE,M_EAT)(name, __VA_ARGS__), \
|
||||
)
|
||||
|
||||
/* Expand to an EMPLACE_TYPE compatible with OPLIST definition
|
||||
(Use M_REDUCE2 which is already used by M_IF_METHOD_ALL)
|
||||
*/
|
||||
#define M_VAR1ANT_OPLIST_EMPLACE_TYPE(name, ...) EMPLACE_TYPE( LIST( \
|
||||
M_REDUCE2(M_VAR1ANT_OPLIST_EMPLACE_TYPE_EXPAND, M_ID, name, __VA_ARGS__) \
|
||||
))
|
||||
#define M_VAR1ANT_OPLIST_EMPLACE_TYPE_EXPAND(name, oplist) \
|
||||
( M_C(_, M_GET_FIELD oplist), M_C3(name, _init_set_, M_GET_FIELD oplist), \
|
||||
M_C4(m_var1ant_, name, _type_, M_GET_FIELD oplist) )
|
||||
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB / WORKER - Extra worker interface
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -142,8 +142,8 @@ typedef struct m_work3r_thread_s {
|
||||
} m_work3r_thread_ct;
|
||||
|
||||
/* Definition of the queue that will record the work orders */
|
||||
BUFFER_DEF(m_work3r_queue, m_work3r_order_ct, 0,
|
||||
BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, M_WORK3R_OPLIST)
|
||||
M_BUFFER_DEF(m_work3r_queue, m_work3r_order_ct, 0,
|
||||
M_BUFFER_QUEUE|M_BUFFER_UNBLOCKING_PUSH|M_BUFFER_BLOCKING_POP|M_BUFFER_THREAD_SAFE|M_BUFFER_DEFERRED_POP, M_WORK3R_OPLIST)
|
||||
|
||||
/* Definition the global pool of workers */
|
||||
typedef struct m_worker_s {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
REM Copyright (c) 2017-2024, Patrick Pelissier
|
||||
REM Copyright (c) 2017-2025, Patrick Pelissier
|
||||
REM All rights reserved.
|
||||
REM
|
||||
REM Redistribution and use in source and binary forms, with or without
|
||||
|
||||
+3
-1
@@ -188,6 +188,7 @@ SYNTHESIS_DATA= M-ALGO test-malgo.c.c test-malgo.synt \
|
||||
M-ARRAY test-marray.c.c test-marray.synt \
|
||||
M-BITSET ../m-bitset.h test-mbitset.synt \
|
||||
M-BBPTREE test-mbptree.c test-mbptree.synt \
|
||||
M-BSTRING ../m-bstring.h test-mbstring.synt \
|
||||
M-BUFFER test-mbuffer.c.c test-mbuffer.synt \
|
||||
M-CONCURRENT test-mconcurrent.c.c test-mconcurrent.synt \
|
||||
M-CORE ../m-core.h test-mcore.synt \
|
||||
@@ -203,12 +204,13 @@ SYNTHESIS_DATA= M-ALGO test-malgo.c.c test-malgo.synt \
|
||||
M-RBTREE test-mrbtree.c.c test-mrbtree.synt \
|
||||
M-SERIAL-BIN ../m-serial-bin.h test-mserial-bin.synt \
|
||||
M-SERIAL-JSON ../m-serial-json.h test-mserial-json.synt \
|
||||
M-SHARED-PTR test-mshared-ptr.c.c test-mshared-ptr.synt \
|
||||
M-SHARED test-mshared.c.c test-mshared.synt \
|
||||
M-SNAPSHOT test-msnapshot.c.c test-msnapshot.synt \
|
||||
M-STRING ../m-string.h test-mstring.synt \
|
||||
M-TREE test-mtree.c.c test-mtree.synt \
|
||||
M-THREAD ../m-thread.h test-mmutex.synt \
|
||||
M-TRY ../m-try.h test-mtry.synt \
|
||||
M-TRY ../m-try.h test-mtry.synt \
|
||||
M-TUPLE test-mtuple.c.c test-mtuple.synt \
|
||||
M-VARIANT test-mvariant.c.c test-mvariant.synt \
|
||||
M-WORKER ../m-worker.h test-mworker.synt
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024, Patrick Pelissier
|
||||
* Copyright (c) 2021-2025, 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) 2021-2024, Patrick Pelissier
|
||||
* Copyright (c) 2021-2025, 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) 2021-2024-2024, Patrick Pelissier
|
||||
* Copyright (c) 2021-2025-2025, 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) 2021-2024, Patrick Pelissier
|
||||
* Copyright (c) 2021-2025, 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:
|
||||
@@ -56,4 +56,5 @@ void cmp_cont(deque_float_t a, std::deque<float> b)
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
#define HAVE_PUSH_FRONT
|
||||
#define HAVE_POP_FRONT
|
||||
#define HAVE_POP_BACK
|
||||
#include "check-generic.hpp"
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024, Patrick Pelissier
|
||||
* Copyright (c) 2021-2025, 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
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 Patrick Pelissier
|
||||
* Copyright (c) 2021-2025 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:
|
||||
@@ -134,7 +134,15 @@ void test(int select_test, int index,
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(POP, CONT_OPL)
|
||||
#ifdef HAVE_POP_BACK
|
||||
case 2:
|
||||
if (!c1.empty()) {
|
||||
M_C(CONT_NAME, _pop_back)(&b0, c0);
|
||||
b1 = c1.back();
|
||||
c1.pop_back();
|
||||
}
|
||||
break;
|
||||
#elif M_TEST_METHOD_P(POP, CONT_OPL)
|
||||
case 2:
|
||||
if (!c1.empty()) {
|
||||
M_CALL_POP(CONT_OPL, &b0, c0);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024, Patrick Pelissier
|
||||
* Copyright (c) 2021-2025, 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) 2021-2024-2024, Patrick Pelissier
|
||||
* Copyright (c) 2021-2025-2025, 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) 2021-2024, Patrick Pelissier
|
||||
* Copyright (c) 2021-2025, 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) 2021-2024, Patrick Pelissier
|
||||
* Copyright (c) 2021-2025, 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) 2021-2024, Patrick Pelissier
|
||||
* Copyright (c) 2021-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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,7 +1,7 @@
|
||||
/*
|
||||
* Test that the array module properly support exceptions
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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,7 +1,7 @@
|
||||
/*
|
||||
* Test that the bitset module properly support exceptions
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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,7 +1,7 @@
|
||||
/*
|
||||
* Test that the deque module properly support exceptions
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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 @@
|
||||
/*
|
||||
* Test that the list module properly support exceptions
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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,7 +1,7 @@
|
||||
/*
|
||||
* Test that the string module properly support exceptions
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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,325 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2025, 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-core.h"
|
||||
#include "coverage.h"
|
||||
|
||||
#include "m-bstring.h"
|
||||
|
||||
static void test0(void)
|
||||
{
|
||||
bstring_t b;
|
||||
|
||||
bstring_init(b);
|
||||
assert( bstring_empty_p(b) );
|
||||
assert( bstring_size(b) == 0);
|
||||
assert( bstring_capacity(b) == 0);
|
||||
assert( bstring_hash(b) != 0);
|
||||
bstring_clear(b);
|
||||
|
||||
bstring_init(b);
|
||||
assert( bstring_empty_p(b) );
|
||||
bstring_push_back(b, 23);
|
||||
assert( !bstring_empty_p(b) );
|
||||
assert( bstring_size(b) == 1);
|
||||
assert( bstring_capacity(b) != 0);
|
||||
assert( bstring_hash(b) != 0);
|
||||
bstring_reset(b);
|
||||
assert( bstring_empty_p(b) );
|
||||
assert( bstring_size(b) == 0);
|
||||
assert( bstring_capacity(b) != 0);
|
||||
assert( bstring_hash(b) != 0);
|
||||
bstring_clear(b);
|
||||
}
|
||||
|
||||
static void test1(void)
|
||||
{
|
||||
bstring_t b;
|
||||
uint8_t u;
|
||||
|
||||
bstring_init(b);
|
||||
|
||||
bstring_push_back(b, 23);
|
||||
assert( !bstring_empty_p(b) );
|
||||
u = bstring_get_byte(b, 0);
|
||||
assert(u == 23);
|
||||
bstring_set_byte(b, 0, 24);
|
||||
u = bstring_get_byte(b, 0);
|
||||
assert(u == 24);
|
||||
bstring_set_byte(b, 0, 25);
|
||||
u = bstring_pop_back(b);
|
||||
assert(u == 25);
|
||||
|
||||
for(int i = 0; i < 100; i++)
|
||||
bstring_push_back(b, (uint8_t) i);
|
||||
for(int i = 0; i < 100; i++) {
|
||||
u = bstring_get_byte(b, (size_t) i);
|
||||
assert(u == i);
|
||||
}
|
||||
for(int i = 0; i < 100; i++) {
|
||||
u = bstring_pop_front(b);
|
||||
assert(u == i);
|
||||
}
|
||||
assert( bstring_empty_p(b) );
|
||||
assert( bstring_size(b) == 0 );
|
||||
|
||||
for(int i = 0; i < 100; i++)
|
||||
bstring_push_back(b, (uint8_t) i);
|
||||
for(int i = 99; i >= 0 ; i--) {
|
||||
u = bstring_pop_back(b);
|
||||
assert(u == i);
|
||||
}
|
||||
assert( bstring_empty_p(b) );
|
||||
assert( bstring_size(b) == 0 );
|
||||
|
||||
bstring_resize(b, 400);
|
||||
assert( !bstring_empty_p(b) );
|
||||
assert( bstring_size(b) == 400 );
|
||||
for(int i = 0; i < 400; i++) {
|
||||
u = bstring_get_byte(b, (size_t) i);
|
||||
assert(u == 0);
|
||||
bstring_set_byte(b, (size_t) i, (uint8_t) i);
|
||||
}
|
||||
|
||||
bstring_resize(b, 100);
|
||||
assert( !bstring_empty_p(b) );
|
||||
assert( bstring_size(b) == 100 );
|
||||
for(int i = 0; i < 100; i++) {
|
||||
u = bstring_get_byte(b, (size_t) i);
|
||||
assert(u == i);
|
||||
}
|
||||
|
||||
bstring_resize(b, 200);
|
||||
assert( !bstring_empty_p(b) );
|
||||
assert( bstring_size(b) == 200 );
|
||||
for(int i = 0; i < 100; i++) {
|
||||
u = bstring_get_byte(b, (size_t) i);
|
||||
assert(u == i);
|
||||
u = bstring_get_byte(b, (size_t) i+100);
|
||||
assert(u == 0);
|
||||
}
|
||||
bstring_reserve(b, 0);
|
||||
assert( bstring_size(b) == 200 );
|
||||
|
||||
bstring_resize(b, 0);
|
||||
assert( bstring_size(b) == 0 );
|
||||
assert( bstring_capacity(b) != 0 );
|
||||
for(int i = 0; i < 1000; i++) {
|
||||
bstring_push_back(b, (uint8_t) i);
|
||||
u = bstring_pop_front(b);
|
||||
assert(u == (uint8_t) i);
|
||||
}
|
||||
|
||||
bstring_reserve(b, 0);
|
||||
assert( bstring_size(b) == 0 );
|
||||
assert( bstring_capacity(b) == 0 );
|
||||
bstring_push_back(b, 23);
|
||||
assert( !bstring_empty_p(b) );
|
||||
|
||||
bstring_reserve(b, 1000);
|
||||
assert( bstring_size(b) == 1);
|
||||
assert( bstring_capacity(b) == 1000 );
|
||||
|
||||
bstring_push_back(b, 25);
|
||||
bstring_push_back(b, 26);
|
||||
const uint8_t *p = bstring_view(b, 0, 3);
|
||||
assert( p[0] == 23);
|
||||
assert( p[1] == 25);
|
||||
assert( p[2] == 26);
|
||||
p = bstring_view(b, 1, 2);
|
||||
assert( p[0] == 25);
|
||||
assert( p[1] == 26);
|
||||
|
||||
uint8_t *w = bstring_acquire_access(b, 0, 3);
|
||||
assert( w[0] == 23);
|
||||
assert( w[1] == 25);
|
||||
assert( w[2] == 26);
|
||||
w[1] = 24;
|
||||
bstring_release_access(b);
|
||||
p = bstring_view(b, 1, 2);
|
||||
assert( p[0] == 24);
|
||||
assert( p[1] == 26);
|
||||
|
||||
bstring_clear(b);
|
||||
}
|
||||
|
||||
static void test2(void)
|
||||
{
|
||||
bstring_t b1, b2;
|
||||
|
||||
bstring_init(b1);
|
||||
for(int i = 0; i < 200; i++)
|
||||
bstring_push_back(b1, (uint8_t) i);
|
||||
bstring_init_set(b2, b1);
|
||||
assert (bstring_equal_p(b1, b2));
|
||||
assert (bstring_cmp(b1, b2) == 0);
|
||||
|
||||
bstring_push_back(b1, 200);;
|
||||
assert (!bstring_equal_p(b1, b2));
|
||||
assert (bstring_cmp(b1, b2) > 0);
|
||||
|
||||
bstring_push_back(b2, 201);;
|
||||
assert (!bstring_equal_p(b1, b2));
|
||||
assert (bstring_cmp(b1, b2) < 0);
|
||||
|
||||
bstring_set_byte(b2, 200, 200);
|
||||
bstring_push_back(b2, 202);;
|
||||
assert (!bstring_equal_p(b1, b2));
|
||||
assert (bstring_cmp(b1, b2) < 0);
|
||||
|
||||
bstring_swap(b1, b2);
|
||||
assert (bstring_cmp(b1, b2) > 0);
|
||||
bstring_swap(b1, b2);
|
||||
|
||||
bstring_set(b1, b2);
|
||||
assert (bstring_equal_p(b1, b2));
|
||||
assert (bstring_cmp(b1, b2) == 0);
|
||||
|
||||
bstring_splice(b2, b1);
|
||||
assert(bstring_size(b2) == 202*2);
|
||||
assert(bstring_size(b1) == 0);
|
||||
|
||||
bstring_clear(b1);
|
||||
bstring_init_move(b1, b2);
|
||||
assert(bstring_size(b1) == 202*2);
|
||||
bstring_init(b2);
|
||||
bstring_move(b2,b1);
|
||||
assert(bstring_size(b2) == 202*2);
|
||||
bstring_clear(b2);
|
||||
}
|
||||
|
||||
static void test3(void)
|
||||
{
|
||||
bstring_t b;
|
||||
uint8_t tab1[] = { 1, 2, 3};
|
||||
uint8_t tab2[] = { 4, 5, 6};
|
||||
uint8_t tab3[] = { 1, 2, 3, 4, 5, 6};
|
||||
uint8_t tab4[] = { 1, 2, 3, 4, 5, 6, 7};
|
||||
uint8_t tmp[3];
|
||||
|
||||
bstring_init(b);
|
||||
|
||||
bstring_push_back_bytes(b, sizeof tab1, tab1);
|
||||
assert( bstring_size(b) == sizeof tab1);
|
||||
assert( bstring_equal_bytes_p(b, sizeof tab1, tab1) );
|
||||
assert( bstring_cmp_bytes(b, sizeof tab1, tab1) == 0);
|
||||
|
||||
bstring_push_back_bytes(b, sizeof tab2, tab2);
|
||||
assert( bstring_size(b) == sizeof tab1 + sizeof tab2);
|
||||
assert( bstring_equal_bytes_p(b, sizeof tab3, tab3) );
|
||||
assert( bstring_equal_bytes_p(b, 1, tab3) == false);
|
||||
assert( bstring_cmp_bytes(b, sizeof tab3, tab3) == 0);
|
||||
assert( bstring_cmp_bytes(b, 1, tab3) > 0);
|
||||
assert( bstring_cmp_bytes(b, sizeof tab4, tab4) < 0);
|
||||
assert( bstring_cmp_bytes(b, sizeof tab2, tab2) < 0);
|
||||
|
||||
bstring_pop_back_bytes(sizeof tmp, tmp, b);
|
||||
assert(tmp[0] == 4 && tmp[1] == 5 && tmp[2] == 6);
|
||||
assert( bstring_size(b) == 3);
|
||||
bstring_pop_back_bytes(sizeof tmp, tmp, b);
|
||||
assert(tmp[0] == 1 && tmp[1] == 2 && tmp[2] == 3);
|
||||
assert( bstring_size(b) == 0);
|
||||
|
||||
bstring_push_back_bytes(b, sizeof tab3, tab3);
|
||||
bstring_pop_front_bytes(sizeof tmp, tmp, b);
|
||||
assert(tmp[0] == 1 && tmp[1] == 2 && tmp[2] == 3);
|
||||
assert( bstring_size(b) == 3);
|
||||
bstring_pop_front_bytes(sizeof tmp, tmp, b);
|
||||
assert(tmp[0] == 4 && tmp[1] == 5 && tmp[2] == 6);
|
||||
assert( bstring_size(b) == 0);
|
||||
|
||||
bstring_clear(b);
|
||||
}
|
||||
|
||||
static void test4(void)
|
||||
{
|
||||
bstring_t b;
|
||||
uint8_t tab1[] = { 1, 2, 6};
|
||||
uint8_t tab2[] = { 3, 4, 5};
|
||||
uint8_t tab3[] = { 1, 2, 3, 4, 5, 6};
|
||||
uint8_t tmp[3];
|
||||
|
||||
bstring_init(b);
|
||||
|
||||
bstring_push_back_bytes(b, sizeof tab1, tab1);
|
||||
bstring_push_bytes_at(b, 2, sizeof tab2, tab2);
|
||||
assert(bstring_size(b) == 6);
|
||||
assert( bstring_equal_bytes_p(b, sizeof tab3, tab3));
|
||||
|
||||
bstring_pop_bytes_at(3, tmp, b, 1);
|
||||
assert(tmp[0] == 2 && tmp[1] == 3 && tmp[2] == 4);
|
||||
assert(bstring_size(b) == 3);
|
||||
|
||||
bstring_clear(b);
|
||||
}
|
||||
|
||||
static void test_io(void)
|
||||
{
|
||||
uint8_t tab1[] = { 1, 2, 3};
|
||||
bstring_t b;
|
||||
|
||||
bstring_init(b);
|
||||
|
||||
FILE *f = fopen("a-mbstring.dat", "wb");
|
||||
if (!f) abort();
|
||||
size_t n = bstring_fwrite(f, b);
|
||||
assert(n == 0);
|
||||
fclose (f);
|
||||
|
||||
bstring_push_back_bytes(b, sizeof tab1, tab1);
|
||||
|
||||
f = fopen("a-mbstring.dat", "rb");
|
||||
if (!f) abort();
|
||||
bool success = bstring_fread(b, f, 0);
|
||||
assert(success);
|
||||
assert(bstring_size(b) == 0);
|
||||
fclose (f);
|
||||
|
||||
bstring_push_back_bytes(b, sizeof tab1, tab1);
|
||||
|
||||
f = fopen("a-mbstring.dat", "wb");
|
||||
if (!f) abort();
|
||||
n = bstring_fwrite(f, b);
|
||||
assert(n == sizeof tab1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen("a-mbstring.dat", "rb");
|
||||
if (!f) abort();
|
||||
success = bstring_fread(b, f, sizeof tab1);
|
||||
assert(success);
|
||||
assert(bstring_size(b) == sizeof tab1);
|
||||
assert(m_bstring_equal_bytes_p(b, sizeof tab1, tab1));
|
||||
fclose (f);
|
||||
|
||||
bstring_clear(b);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test0();
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
test_io();
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Test for Concurrent memory pool allocator
|
||||
*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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,6 +1,6 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
// Generic is not supported if not C11
|
||||
// TCC has some issues in the preprocessing.
|
||||
// See https://lists.nongnu.org/archive/html/tinycc-devel/2024-12/msg00004.html
|
||||
// See https://lists.nongnu.org/archive/html/tinycc-devel/2025-12/msg00004.html
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__TINYC__)
|
||||
|
||||
ARRAY_DEF(array_int, int)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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,555 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2025, 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 <stdio.h>
|
||||
|
||||
#include "m-shared-ptr.h"
|
||||
|
||||
#include "m-string.h"
|
||||
#include "m-array.h"
|
||||
#include "m-bptree.h"
|
||||
#include "m-deque.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-list.h"
|
||||
#include "m-prioqueue.h"
|
||||
#include "m-rbtree.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-variant.h"
|
||||
|
||||
#include "coverage.h"
|
||||
|
||||
// TEST WITH INT
|
||||
SHARED_PTR_DECL_AS(shared_int, SharedInt, M_BASIC_OPLIST)
|
||||
|
||||
// TEST WITH DOUBLE
|
||||
SHARED_PTR_DECL_AS(shared_double, SharedDouble, M_BASIC_OPLIST)
|
||||
extern SharedDouble *shared_double_new_from(double); // Workaround for test.
|
||||
|
||||
static void test_double(void)
|
||||
{
|
||||
SharedDouble *p = shared_double_new();
|
||||
SharedDouble *q = shared_double_new_from(2.0);
|
||||
SharedDouble *r = shared_double_new_from(1.0);
|
||||
SharedDouble *rr = shared_double_new_from(3.0);
|
||||
shared_double_add(p, q, r);
|
||||
assert(shared_double_equal_p(p, rr));
|
||||
shared_double_sub(p, q, r);
|
||||
assert(shared_double_equal_p(p, r));
|
||||
shared_double_mul(p, q, r);
|
||||
assert(shared_double_equal_p(p, q));
|
||||
shared_double_div(p, q, r);
|
||||
assert(shared_double_equal_p(p, q));
|
||||
shared_double_reset(p);
|
||||
shared_double_release(p);
|
||||
shared_double_release(q);
|
||||
shared_double_release(r);
|
||||
shared_double_release(rr);
|
||||
}
|
||||
|
||||
// TEST WITH STRING
|
||||
static inline void string_add(string_t d, const string_t a, const string_t b)
|
||||
{
|
||||
int ia = atoi(string_get_cstr(a));
|
||||
int ib = atoi(string_get_cstr(b));
|
||||
string_printf(d, "%d", ia+ib);
|
||||
}
|
||||
static inline void string_sub(string_t d, const string_t a, const string_t b)
|
||||
{
|
||||
int ia = atoi(string_get_cstr(a));
|
||||
int ib = atoi(string_get_cstr(b));
|
||||
string_printf(d, "%d", ia-ib);
|
||||
}
|
||||
static inline void string_mul(string_t d, const string_t a, const string_t b)
|
||||
{
|
||||
int ia = atoi(string_get_cstr(a));
|
||||
int ib = atoi(string_get_cstr(b));
|
||||
string_printf(d, "%d", ia*ib);
|
||||
}
|
||||
static inline void string_div(string_t d, const string_t a, const string_t b)
|
||||
{
|
||||
int ia = atoi(string_get_cstr(a));
|
||||
int ib = atoi(string_get_cstr(b));
|
||||
string_printf(d, "%d", ia/ib);
|
||||
}
|
||||
|
||||
#define STR_OPL M_OPEXTEND(STRING_OPLIST, POP(string_pop_u), GET_SIZE(string_length_u), ADD(string_add), SUB(string_sub), MUL(string_mul), DIV(string_div))
|
||||
SHARED_PTR_DECL(shared_string, STR_OPL)
|
||||
|
||||
static int str_callback(void *data, const string_unicode_t *u)
|
||||
{
|
||||
string_unicode_t *pu = (string_unicode_t *) data;
|
||||
*pu += *u;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int str_callback2(void *data, const string_unicode_t *u)
|
||||
{
|
||||
string_unicode_t *pu = (string_unicode_t *) data;
|
||||
*pu += *u;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void test_string(void)
|
||||
{
|
||||
shared_string_t *p = shared_string_new();
|
||||
shared_string_t *q = shared_string_make("Hello world");
|
||||
shared_string_t *r = shared_string_acquire(p);
|
||||
assert(p == r);
|
||||
assert(shared_string_equal_p(r, p));
|
||||
assert(!shared_string_equal_p(r, q));
|
||||
shared_string_t *p2 = shared_string_clone(p);
|
||||
assert(p2 != p);
|
||||
assert(shared_string_equal_p(p2, p));
|
||||
bool b = shared_string_empty_p(p);
|
||||
assert(b);
|
||||
shared_string_clear(p);
|
||||
b = shared_string_empty_p(r);
|
||||
assert(b);
|
||||
shared_string_copy(q, r);
|
||||
assert(shared_string_equal_p(r, q));
|
||||
shared_string_set(&q, r);
|
||||
assert(shared_string_equal_p(r, q));
|
||||
shared_string_t *r2 = shared_string_make("Hello world!");
|
||||
shared_string_copy(q, r2);
|
||||
assert(shared_string_equal_p(r2, q));
|
||||
shared_string_set(&q, r);
|
||||
assert(shared_string_equal_p(r, q));
|
||||
assert(shared_string_cmp(r, q) == 0);
|
||||
assert(shared_string_cmp(q, r) == 0);
|
||||
assert(shared_string_cmp(q, p) == 0);
|
||||
string_unicode_t u;
|
||||
b = shared_string_try_pop(&u, p2);
|
||||
assert(!b);
|
||||
b = shared_string_try_push(p2, 'X');
|
||||
assert(b);
|
||||
shared_string_push(p2, 'X');
|
||||
assert(shared_string_size(p2) == 2);
|
||||
b = shared_string_try_pop(&u, p2);
|
||||
assert(b);
|
||||
assert(shared_string_cmp(q, p2) < 0);
|
||||
assert(shared_string_cmp(p2, q) > 0);
|
||||
shared_string_push(p2, 'X');
|
||||
u = 0;
|
||||
int res = shared_string_for_each(p2, str_callback, (void*) &u);
|
||||
assert(res == 0);
|
||||
assert(u == 2* 'X');
|
||||
res = shared_string_for_each(p2, str_callback2, (void*) &u);
|
||||
assert(res == 1);
|
||||
assert(u == 3* 'X');
|
||||
shared_string_reset(q);
|
||||
assert(!shared_string_equal_p(r2, q));
|
||||
assert(shared_string_empty_p(q));
|
||||
assert(shared_string_hash(q) != 0);
|
||||
shared_string_swap(r2, r2);
|
||||
shared_string_swap(r2, q);
|
||||
assert(shared_string_empty_p(r2));
|
||||
assert(!shared_string_empty_p(q));
|
||||
shared_string_swap(q, r2);
|
||||
assert(!shared_string_empty_p(r2));
|
||||
assert(shared_string_empty_p(q));
|
||||
// todo: shared_string_splice
|
||||
// todo: shared_string_erase
|
||||
shared_string_release(r2);
|
||||
shared_string_clear(q);
|
||||
shared_string_release(r);
|
||||
shared_string_clear(p2);
|
||||
}
|
||||
|
||||
static void test_string_io(void)
|
||||
{
|
||||
shared_string_t *p = shared_string_new();
|
||||
shared_string_t *q = shared_string_make("Hello world");
|
||||
|
||||
FILE *f = m_core_fopen ("a-mshared-ptr.dat", "wt");
|
||||
if (!f) abort();
|
||||
shared_string_out_str(f, q);
|
||||
fclose (f);
|
||||
|
||||
f = m_core_fopen ("a-mshared-ptr.dat", "rt");
|
||||
if (!f) abort();
|
||||
bool b = shared_string_in_str (p, f);
|
||||
assert (b == true);
|
||||
assert (shared_string_equal_p (p, q));
|
||||
fclose(f);
|
||||
|
||||
shared_string_reset(p);
|
||||
M_LET(str, STRING_OPLIST) {
|
||||
shared_string_get_str(str, q, false);
|
||||
assert (string_cmp_str (str, "\"Hello world\"") == 0);
|
||||
const char *sp;
|
||||
b = shared_string_parse_str(p, string_get_cstr(str), &sp);
|
||||
assert(b);
|
||||
assert(*sp == 0);
|
||||
assert(shared_string_equal_p(p, q));
|
||||
}
|
||||
|
||||
shared_string_clear(p);
|
||||
shared_string_release(q);
|
||||
}
|
||||
|
||||
|
||||
// TEST WITH ARRAY
|
||||
ARRAY_DEF(array, int)
|
||||
// Provide a FULL_P operator
|
||||
static inline bool array_full_p(const array_t a) { return array_size(a) >= 10; }
|
||||
#define M_OPL_array_t() M_OPEXTEND( ARRAY_OPLIST(array, M_BASIC_OPLIST), SUBTYPE(int), FULL_P(array_full_p) )
|
||||
SHARED_PTR_DECL(shared_array, M_OPL_array_t() )
|
||||
|
||||
static int callback1(void *data, const int *el)
|
||||
{
|
||||
int *s_ptr = (int *) data;
|
||||
*s_ptr += *el;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int callback2(void *data, const int *el)
|
||||
{
|
||||
int *s_ptr = (int *) data;
|
||||
return *s_ptr == *el;
|
||||
}
|
||||
|
||||
static int callback3(void *data, int *el)
|
||||
{
|
||||
int *s_ptr = (int *) data;
|
||||
*el *= *s_ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_array(void)
|
||||
{
|
||||
shared_array_t *p = shared_array_new();
|
||||
bool b;
|
||||
int j;
|
||||
|
||||
for(int i = 0 ; i < 10; i++) {
|
||||
assert(!shared_array_full_p(p));
|
||||
assert(shared_array_size(p) == (size_t) i);
|
||||
b = shared_array_try_push(p, i);
|
||||
assert(b);
|
||||
}
|
||||
// We can only push 10 elements before being full.
|
||||
b = shared_array_try_push(p, 11);
|
||||
assert(!b);
|
||||
assert(shared_array_full_p(p));
|
||||
shared_array_get(&j, p, 4);
|
||||
assert( j == 4);
|
||||
|
||||
shared_array_set_at(p, 4, 5);
|
||||
shared_array_get(&j, p, 4);
|
||||
assert( j == 5);
|
||||
|
||||
shared_array_set_at(p, 4, 4);
|
||||
shared_array_get(&j, p, 4);
|
||||
assert( j == 4);
|
||||
|
||||
int s = 0;
|
||||
int r = shared_array_for_each(p, callback1, &s);
|
||||
assert(r == 0);
|
||||
assert(s == 9*10/2);
|
||||
|
||||
s = 4;
|
||||
r = shared_array_for_each(p, callback2, &s);
|
||||
assert(r == 1);
|
||||
|
||||
s = 2;
|
||||
r = shared_array_apply(p, callback3, &s);
|
||||
assert(r == 0);
|
||||
|
||||
s = 0;
|
||||
r = shared_array_for_each(p, callback1, &s);
|
||||
assert(r == 0);
|
||||
assert(s == 9*10);
|
||||
|
||||
for(int i = 9 ; i >= 0; i--) {
|
||||
b = shared_array_try_pop(&j, p);
|
||||
assert(b);
|
||||
assert(i * 2== j);
|
||||
}
|
||||
b = shared_array_try_pop(&j, p);
|
||||
assert(!b);
|
||||
|
||||
shared_array_safe_get(&r, p, 23);
|
||||
assert(r == 0);
|
||||
assert(shared_array_size(p) == 24);
|
||||
|
||||
shared_array_erase(p, 10);
|
||||
assert(shared_array_size(p) == 23);
|
||||
|
||||
b = shared_array_get(&r, p, 22);
|
||||
assert(b);
|
||||
assert(r == 0);
|
||||
|
||||
shared_array_release(p);
|
||||
}
|
||||
|
||||
|
||||
ARRAY_DEF(array_str, string_t)
|
||||
SHARED_PTR_DECL(shared_array_str, ARRAY_OPLIST(array_str, M_STRING_OPLIST))
|
||||
|
||||
static void test_array_string(void)
|
||||
{
|
||||
shared_array_str_t *p = shared_array_str_new();
|
||||
|
||||
M_LET( (x, ("Hello")), string_t)
|
||||
shared_array_str_push(p, x);
|
||||
|
||||
string_t tmp;
|
||||
string_init_set_str(tmp, "World");
|
||||
shared_array_str_push_move(p, &tmp); // No need to clear tmp
|
||||
|
||||
shared_array_str_emplace(p, "!");
|
||||
|
||||
bool b = shared_array_str_try_emplace(p, " ");
|
||||
assert(b);
|
||||
|
||||
string_init_set_str(tmp, "!");
|
||||
b = shared_array_str_try_push_move(p, &tmp); // No need to clear tmp
|
||||
assert(b);
|
||||
|
||||
shared_array_str_release(p);
|
||||
}
|
||||
|
||||
// TEST WITH LIST
|
||||
LIST_DEF(list, float)
|
||||
#define M_OPL_list_t() LIST_OPLIST(list, M_BASIC_OPLIST)
|
||||
SHARED_WEAK_PTR_DECL(shared_list, M_OPL_list_t())
|
||||
SHARED_WEAK_PTR_DEF_EXTERN(shared_list, list_t)
|
||||
|
||||
LIST_DUAL_PUSH_DEF(list2, int)
|
||||
SHARED_WEAK_PTR_DEF(shared_list2, list2_t, LIST_OPLIST(list2))
|
||||
|
||||
|
||||
// TEST WITH DICT
|
||||
DICT_DEF2(dict, float, float)
|
||||
#define M_OPL_dict_t() DICT_OPLIST(dict, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
SHARED_WEAK_PTR_DECL_AS(shared_dict, shared_dict_t, M_OPL_dict_t())
|
||||
SHARED_WEAK_PTR_DEF_EXTERN_AS(shared_dict, shared_dict_t, dict_t)
|
||||
|
||||
DICT_DEF2(string_pool, string_t, string_t)
|
||||
#define M_OPL_string_pool_t() DICT_OPLIST(string_pool, STRING_OPLIST, STRING_OPLIST)
|
||||
SHARED_PTR_DEF(string_pool_ts, string_pool_t, M_OPL_string_pool_t() )
|
||||
|
||||
DICT_SET_DEF(dict2, int)
|
||||
SHARED_PTR_DEF(shared_dict2, dict2_t, DICT_SET_OPLIST(dict2))
|
||||
|
||||
/* OA dict needs more operators than the default ones to work */
|
||||
static inline bool int_oor_equal_p(int s, unsigned char n)
|
||||
{
|
||||
return s == -n;
|
||||
}
|
||||
static inline void int_oor_set(int *s, unsigned char n)
|
||||
{
|
||||
*s = -n;
|
||||
}
|
||||
#define INT_OA_OPLIST \
|
||||
M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(int_oor_equal_p), OOR_SET(API_2(int_oor_set)))
|
||||
DICT_OA_DEF2(dict3, int, INT_OA_OPLIST, int, M_BASIC_OPLIST)
|
||||
SHARED_PTR_DEF(shared_dict3, dict3_t, DICT_OPLIST(dict3))
|
||||
|
||||
// TEST WITH TUPLE
|
||||
TUPLE_DEF2(point, (x, int), (y, int))
|
||||
#define M_OPL_point_t() TUPLE_OPLIST(point, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
SHARED_PTR_DEF(shared_point, point_t)
|
||||
|
||||
//SHARED_PTR_DECL(shared_point, ARRAY_OPLIST(array_str, M_STRING_OPLIST))
|
||||
//M_OPL_point_t())
|
||||
|
||||
// TEST WITH VARIANT
|
||||
VARIANT_DEF2(dimension, (x, int), (y, float))
|
||||
#define M_OPL_dimension_t() VARIANT_OPLIST(dimension, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
SHARED_PTR_DEF(shared_dimension, dimension_t)
|
||||
|
||||
|
||||
// TEST WITH DEQUE
|
||||
DEQUE_DEF(deque1, int)
|
||||
// Provide a FULL_P operator
|
||||
static inline bool deque1_full_p(const deque1_t a) { return deque1_size(a) >= 10; }
|
||||
#define M_OPL_deque1_t() M_OPEXTEND( DEQUE_OPLIST(deque1, M_BASIC_OPLIST), SUBTYPE(int), FULL_P(deque1_full_p) )
|
||||
SHARED_PTR_DEF(shared_deque1, deque1_t)
|
||||
|
||||
PRIOQUEUE_DEF(prio1, int)
|
||||
SHARED_PTR_DEF(shared_prio1, prio1_t, PRIOQUEUE_OPLIST(prio1))
|
||||
|
||||
// TEST WITH B+TREE
|
||||
BPTREE_DEF2(bptree1, 10, int, int)
|
||||
SHARED_PTR_DEF(shared_bptree1, bptree1_t, BPTREE_OPLIST2(bptree1, M_BASIC_OPLIST, M_BASIC_OPLIST))
|
||||
|
||||
BPTREE_DEF(bptree2, 10, int)
|
||||
SHARED_PTR_DEF(shared_bptree2, bptree2_t, BPTREE_OPLIST(bptree2))
|
||||
|
||||
// TEST WITH R/B TREE
|
||||
RBTREE_DEF(rbtree1, int)
|
||||
SHARED_PTR_DEF(shared_rbtree1, rbtree1_t, RBTREE_OPLIST(rbtree1))
|
||||
|
||||
/********************************/
|
||||
|
||||
static void conso(void *p)
|
||||
{
|
||||
shared_deque1_t *ptr = (shared_deque1_t*) p;
|
||||
for(int i = 0; i < 1000; i++) {
|
||||
int j;
|
||||
shared_deque1_pop(&j, ptr);
|
||||
assert (j == i);
|
||||
}
|
||||
shared_deque1_release(ptr);
|
||||
}
|
||||
|
||||
static void test_thread(void)
|
||||
{
|
||||
m_thread_t idx;
|
||||
shared_deque1_t *ptr = shared_deque1_new();
|
||||
m_thread_create (idx, conso, shared_deque1_acquire(ptr));
|
||||
for(int i = 0; i < 1000; i++) {
|
||||
// shared_deque1 is full if number of stored element is >= 10
|
||||
shared_deque1_push (ptr, i);
|
||||
}
|
||||
shared_deque1_release(ptr);
|
||||
m_thread_join(idx);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
// Define effective code when only _DECL was used.
|
||||
START_COVERAGE
|
||||
SHARED_PTR_DEF_EXTERN(shared_string, string_t, STR_OPL)
|
||||
END_COVERAGE
|
||||
// Non measured code
|
||||
#include "test-mshared-ptr.h"
|
||||
|
||||
static void test_string2(void)
|
||||
{
|
||||
M_LET( (x, ("Hello")), string_t) {
|
||||
shared_string_t *p = shared_string_new_from(x);
|
||||
assert(!shared_string_empty_p(p));
|
||||
assert(string_equal_str_p(*shared_string_cref(p), "Hello"));
|
||||
assert(string_equal_str_p(*shared_string_ref(p), "Hello"));
|
||||
shared_string_release(p);
|
||||
}
|
||||
|
||||
shared_string_t *p = shared_string_new();
|
||||
shared_string_t *q = shared_string_make("2");
|
||||
shared_string_t *r = shared_string_make("1");
|
||||
shared_string_t *rr = shared_string_make("3");
|
||||
shared_string_add(p, q, r);
|
||||
assert(shared_string_equal_p(p, rr));
|
||||
shared_string_add(p, r, q);
|
||||
assert(shared_string_equal_p(p, rr));
|
||||
shared_string_add(p, r, r);
|
||||
assert(shared_string_equal_p(p, q));
|
||||
shared_string_add(p, p, r);
|
||||
assert(shared_string_equal_p(p, rr));
|
||||
shared_string_add(p, r, r);
|
||||
assert(shared_string_equal_p(p, q));
|
||||
shared_string_add(p, r, p);
|
||||
assert(shared_string_equal_p(p, rr));
|
||||
shared_string_sub(p, q, r);
|
||||
assert(shared_string_equal_p(p, r));
|
||||
shared_string_add(p, p, p);
|
||||
assert(shared_string_equal_p(p, q));
|
||||
shared_string_mul(p, q, r);
|
||||
assert(shared_string_equal_p(p, q));
|
||||
shared_string_div(p, q, r);
|
||||
assert(shared_string_equal_p(p, q));
|
||||
shared_string_reset(p);
|
||||
shared_string_release(p);
|
||||
shared_string_release(q);
|
||||
shared_string_release(r);
|
||||
shared_string_release(rr);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
#define MAX_NUM 200
|
||||
|
||||
static void conso_thread1_string(void *p)
|
||||
{
|
||||
shared_string_t *ptr = (shared_string_t*) p;
|
||||
bool tmp[MAX_NUM] = {0};
|
||||
for(int i = 1; i < MAX_NUM; i++) {
|
||||
m_string_unicode_t j;
|
||||
shared_string_pop(&j, ptr);
|
||||
assert (j > 0 && j < MAX_NUM);
|
||||
assert(tmp[j] == false);
|
||||
tmp[j] = true;
|
||||
}
|
||||
shared_string_release(ptr);
|
||||
}
|
||||
|
||||
static void test_thread1_string(void)
|
||||
{
|
||||
m_thread_t idx;
|
||||
shared_string_t *ptr = shared_string_new();
|
||||
m_thread_create (idx, conso_thread1_string, shared_string_acquire(ptr));
|
||||
for(int i = 1; i < MAX_NUM; i++) {
|
||||
shared_string_push (ptr, (m_string_unicode_t) i);
|
||||
}
|
||||
shared_string_release(ptr);
|
||||
m_thread_join(idx);
|
||||
}
|
||||
|
||||
// This will test the proper handling of the read lock,
|
||||
// by pushing it to its limit.
|
||||
#define MAX_READER 8
|
||||
|
||||
static void conso_thread2_string(void *p)
|
||||
{
|
||||
shared_string_t *ptr = (shared_string_t*) p;
|
||||
size_t size = shared_string_size(ptr);
|
||||
for(int i = 0; i < 1000; i++) {
|
||||
size_t n = shared_string_size(ptr);
|
||||
assert( n >= size);
|
||||
size = n;
|
||||
}
|
||||
shared_string_release(ptr);
|
||||
}
|
||||
|
||||
static void test_thread2_string(void)
|
||||
{
|
||||
m_thread_t idx[MAX_READER];
|
||||
shared_string_t *ptr = shared_string_new();
|
||||
for(int i = 0; i < MAX_READER; i++) {
|
||||
m_thread_create (idx[i], conso_thread2_string, shared_string_acquire(ptr));
|
||||
}
|
||||
for(int i = 1; i < 100000; i++) {
|
||||
shared_string_push (ptr, (m_string_unicode_t) i);
|
||||
}
|
||||
shared_string_release(ptr);
|
||||
for(int i = 0; i < MAX_READER; i++) {
|
||||
m_thread_join(idx[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_string();
|
||||
test_string2();
|
||||
test_thread1_string();
|
||||
test_thread2_string();
|
||||
test_string_io();
|
||||
test_double();
|
||||
test_array();
|
||||
test_array_string();
|
||||
test_thread();
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Header for coverage purpose
|
||||
// Expand here all code that shall not be measured in coverage.
|
||||
// Since the functions are not declared as static inline, their coverage is measured
|
||||
SHARED_PTR_DEF_EXTERN_AS(shared_int, SharedInt, int, M_BASIC_OPLIST)
|
||||
SHARED_PTR_DEF_EXTERN_AS(shared_double, SharedDouble, double, M_OPEXTEND(M_BASIC_OPLIST, TYPE(double)))
|
||||
SHARED_PTR_DEF_EXTERN(shared_array, array_t)
|
||||
SHARED_PTR_DEF_EXTERN(shared_array_str, array_str_t, ARRAY_OPLIST(array_str, M_STRING_OPLIST))
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -38,6 +38,11 @@ SHARED_PTR_DEF_AS(SharedDouble, SharedDouble, double)
|
||||
SHARED_PTR_RELAXED_DEF_AS(SharedDouble2, SharedDouble2, double, M_BASIC_OPLIST)
|
||||
SHARED_RESOURCE_DEF_AS(SharedRessource, SharedRessource, SharedRessourceIt, double)
|
||||
|
||||
// Test with incomplete structure
|
||||
struct incomplete_s;
|
||||
extern void incomplete_clear(struct incomplete_s *ptr);
|
||||
SHARED_PTR_DEF( shared_incomplete, struct incomplete_s, (INIT(0), CLEAR(API_2(incomplete_clear))) )
|
||||
|
||||
static int f(const shared_int_t p)
|
||||
{
|
||||
return *shared_int_cref(p);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
@@ -765,11 +765,38 @@ static void test0(void)
|
||||
|
||||
string_init(s1);
|
||||
string_set_str(s1, "Hello");
|
||||
string_reserve(s1, 128);
|
||||
assert(string_equal_str_p(s1, "Hello"));
|
||||
for(i = 0 ; i < 2049; i++) {
|
||||
string_reserve(s1, i);
|
||||
assert(string_equal_str_p(s1, "Hello"));
|
||||
}
|
||||
string_clear(s1);
|
||||
}
|
||||
|
||||
static void test_rounding(void)
|
||||
{
|
||||
// The final cast to size_t is due to clang which now gives
|
||||
// warning even if the cast an integer to a bigger size(!)
|
||||
const size_t max = (size_t) -(m_str1ng_size_t)1;
|
||||
for(size_t a = max/2; a <= max && a != 0; a++) {
|
||||
unsigned char m, e;
|
||||
size_t x = (size_t) a + a/2;
|
||||
size_t nx = m_str1ng_round_capacity(&m, &e, (m_str1ng_size_t) x);
|
||||
if (nx >= x) {
|
||||
assert( x == (m_str1ng_size_t)x);
|
||||
}
|
||||
}
|
||||
if (max != -(size_t)1) {
|
||||
for(size_t a = max; a <= 2*max; a++) {
|
||||
unsigned char m, e;
|
||||
size_t x = (size_t) a + a/2;
|
||||
size_t nx = m_str1ng_round_capacity(&m, &e, (m_str1ng_size_t) x);
|
||||
if (nx >= x) {
|
||||
assert( x == (m_str1ng_size_t)x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_int(void)
|
||||
{
|
||||
string_t s;
|
||||
@@ -1005,6 +1032,7 @@ static void test_parse_standard_c_type(void)
|
||||
int main(void)
|
||||
{
|
||||
test0();
|
||||
test_rounding();
|
||||
test_M_LET();
|
||||
test_parse_standard_c_type();
|
||||
test_utf8_basic();
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
|
||||
+18
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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,6 +23,17 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if __GNUC__ >= 12
|
||||
/* Issue with GCC 12. It reports a variable as being not initialized
|
||||
whereas it is obviously initialized.
|
||||
See also https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109530
|
||||
*/
|
||||
_Pragma("GCC diagnostic push")
|
||||
_Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
# if !defined(__cplusplus)
|
||||
// The test shall finish with a raise fatal.
|
||||
#define M_RAISE_FATAL(...) do { \
|
||||
@@ -399,24 +410,9 @@ static void test3(void)
|
||||
assert(flow ++ == 0);
|
||||
M_TRY(test1) {
|
||||
assert(flow ++ == 1);
|
||||
#ifdef __GNUC__
|
||||
#if __GNUC__ >= 13
|
||||
/* Issue with GCC 13. It reports a variable as being not initialized
|
||||
whereas it is obviously initialized.
|
||||
See also https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109530
|
||||
*/
|
||||
_Pragma("GCC diagnostic push")
|
||||
_Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
|
||||
#endif
|
||||
#endif
|
||||
M_DEFER( assert(flow++ == 3) ) {
|
||||
assert(flow ++ == 2);
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
#if __GNUC__ >= 13
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
#endif
|
||||
} M_CATCH(test1, M_ERROR_MEMORY) {
|
||||
assert(0);
|
||||
}
|
||||
@@ -643,6 +639,12 @@ static void test_final(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if __GNUC__ >= 12
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test1();
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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-2024, Patrick Pelissier
|
||||
* Copyright (c) 2017-2025, 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:
|
||||
|
||||
Loaded 100 of 112 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user