89 Commits
Author SHA1 Message Date
Patrick Pelissier f4e3d9cd4c Release V0.7.4 2025-05-07 21:02:01 +02:00
Patrick Pelissier 4988661b7d Fix target armv6 (2) for Continuous Integration 2025-05-06 00:47:29 +02:00
Patrick Pelissier 7033a922c7 Fix target armv6 for Continuous Integration 2025-05-05 23:50:43 +02:00
Patrick Pelissier dd607252eb Add target risc64, ppc64le and armv6 for Continuous Integration 2025-05-05 23:46:09 +02:00
Patrick Pelissier 73da9a4316 Update obsolete header section 2025-04-18 21:58:15 +02:00
Patrick Pelissier b3a0d70147 Fix memory safety errors in examples. 2025-04-08 21:46:16 +02:00
Patrick Pelissier c55bb6b9ad Fix random segfault on AARCH64 CI 2025-03-13 22:24:13 +01:00
Patrick Pelissier 68fdc2dde1 Fix undefined behavior in using setjmp 2025-03-06 15:38:44 +01:00
Patrick Pelissier 8877af10b0 Update copyright 2025-03-03 23:45:04 +01:00
Patrick Pelissier 782963dec5 Add example of disabling small name usage 2025-03-01 12:20:28 +01:00
Patrick Pelissier 36d11bc2bd Fix small name usage 2025-03-01 12:19:35 +01:00
Patrick Pelissier 6d621703eb Copyright go to 2025 year 2025-03-01 11:03:38 +01:00
Patrick Pelissier 76b40d247d Fix #133 : forgotten const for second argument (reported by Brian Sipos) 2025-02-03 23:12:22 +01:00
Patrick Pelissier 033deac9f5 Workaround for GCC 12 bug in warning 2025-02-03 23:06:41 +01:00
Patrick Pelissier b60553165d Fix usage of M_USE_SMALL_NAME (Reported by Brian Sipos) 2025-02-03 22:33:07 +01:00
Patrick Pelissier e1a4d359a2 Update doc 2025-02-02 10:50:41 +01:00
Patrick Pelissier 4ab2615a1c Clarify constraint on _splice 2024-12-25 20:48:34 +01:00
Patrick Pelissier 9136a4a972 Update 2024-12-08 19:34:15 +01:00
Patrick Pelissier 55dcf0e438 Fix example 2024-11-30 13:04:45 +01:00
Patrick Pelissier fb604f02b7 Update / add todo 2024-11-30 10:26:11 +01:00
Patrick Pelissier 1db417e30e Rename _new_copy into _clone 2024-11-30 10:25:51 +01:00
Patrick Pelissier 5b77fe7207 Add some missing const in the interface 2024-11-30 10:25:36 +01:00
Patrick Pelissier dd509f2b7e Update documentation of new shared pointer interface. 2024-11-30 10:25:15 +01:00
Patrick Pelissier 50d4e15297 Simplify lock as mutex should be released by the thread that performed the initial lock to be portable 2024-11-26 22:26:25 +01:00
Patrick Pelissier f6d1b16338 Fix C++ warning 2024-11-25 00:04:54 +01:00
Patrick Pelissier 64a035559d Update test suite 2024-11-24 23:57:22 +01:00
Patrick Pelissier c4bc37560c Improve testing of new shared pointer
Adding measure of coverage. Need to move some codes outside the main C file, to avoid polluting the measure of the coverage by some functions we don't need to measure.
2024-11-24 18:21:21 +01:00
Patrick Pelissier e7309b7d3a Add forgotten "const" attribute to string_length_u and string_utf8_p 2024-11-24 18:20:19 +01:00
Patrick Pelissier c461b4eca4 Update shared pointer new interface 2024-11-24 11:26:30 +01:00
Patrick Pelissier f21d427de1 Convert example to new shared ptr interface 2024-11-16 18:02:13 +01:00
Patrick Pelissier 0f9edaa7ee Fix oplist usage of new shared-ptr 2024-11-16 18:01:58 +01:00
Patrick Pelissier 64888127c4 Update to get the lastest v2 2024-11-16 16:55:42 +01:00
Patrick Pelissier d5b4ec249b Update test suite 2024-11-16 13:26:21 +01:00
Patrick Pelissier 0bcd78a8f5 Fix warning. 2024-11-12 22:31:05 +01:00
Patrick Pelissier 27b0850af4 Fix case of the same variable is passed as 2/3 arguments of a function. 2024-11-12 22:26:45 +01:00
Patrick Pelissier ae55ccfc40 Update test to consider change of default for deque 2024-11-11 23:56:33 +01:00
Patrick Pelissier 5bf644ccf0 Improve test suite 2024-11-11 22:38:10 +01:00
Patrick Pelissier 3f09adc507 Fix ADD/SUB/MUL/DIV methods of a shared pointer 2024-11-11 22:38:02 +01:00
Patrick Pelissier 4e851142c2 Change the operator POP of a DEQUE to pop_front instead of pop_back:
it is more inline with what we expects / uses a deque for.
(buffer FIFO)
2024-11-11 22:36:56 +01:00
Patrick Pelissier fec6b42260 Add comment 2024-11-11 21:47:54 +01:00
Patrick Pelissier 9dbc48aa5d Update 2024-11-09 19:07:08 +01:00
Patrick Pelissier b92bae34eb Update comments 2024-11-09 14:54:16 +01:00
Patrick Pelissier 8faf7f79c4 Add first test cases for m-shared-ptr 2024-11-09 14:27:16 +01:00
Patrick Pelissier c3e29a16df Fix warnings 2024-11-09 14:26:57 +01:00
Patrick Pelissier 1bc33a10fc Fix issues (WIP) 2024-11-09 11:12:12 +01:00
Patrick Pelissier b7074d1c69 Fix some issues 2024-11-06 23:13:23 +01:00
Patrick Pelissier 26d541fe06 Move internal functions to internal namespace 2024-11-05 23:17:28 +01:00
Patrick Pelissier 2991c7cc5a Add oplist 2024-11-02 23:35:21 +01:00
Patrick Pelissier 4e7cbae766 Add short name support 2024-11-02 17:35:25 +01:00
Patrick Pelissier d5e0620e4c Minor fix 2024-11-02 17:21:59 +01:00
Patrick Pelissier 32cfbd23bc Update comments. 2024-11-02 16:59:40 +01:00
Patrick Pelissier 0e09681a6a Move m_typeof to core module. 2024-10-30 23:42:45 +01:00
Patrick Pelissier bc8098b337 Update comments. 2024-10-30 23:31:47 +01:00
Patrick Pelissier c5692e7e9f Update comment 2024-10-28 17:46:48 +01:00
Patrick Pelissier f43db93791 Adding first WIP version of the new shared pointer header. 2024-10-27 22:01:00 +01:00
Patrick Pelissier 14c954c6ce Adding new property:
multithread safety if the container handles itself the multi thread
2024-10-27 20:38:36 +01:00
Patrick Pelissier 60280087c7 Fix default of FULL_P 2024-10-27 20:37:57 +01:00
Patrick Pelissier 1e57d9c6d6 Fix default of FULL_P 2024-10-27 19:48:47 +01:00
Patrick Pelissier eeaf74d24f Add FULL_P operator
Add M_EMPLACE_LIST_TYPE_VAR_ALTER which doesn't put a comma before.
2024-10-26 16:56:54 +02:00
Patrick Pelissier a318d36c35 Fix concurrent access. 2024-10-19 11:55:41 +02:00
Patrick Pelissier edcf8ee37a Final update of the byte string 2024-10-05 11:40:23 +02:00
Patrick Pelissier 8a1f30eeff Finish implementation of Byte String 2024-10-05 10:23:47 +02:00
Patrick Pelissier 2995b119b7 Add precision 2024-10-05 10:21:19 +02:00
Patrick Pelissier 08bd5a888b Fix formatting 2024-10-05 10:21:09 +02:00
Patrick Pelissier 2f1b17f805 Fix for clang 2024-09-26 22:36:45 +02:00
Patrick Pelissier 0379f5f1c6 Add header for handling Byte String as per #123
API designed for streaming bytes and easy integration with other libraries.
2024-09-26 22:33:03 +02:00
Patrick Pelissier 45b11fb49b Fix #129:
Support of incomplete type in m-shared.
2024-09-21 12:39:29 +02:00
Patrick Pelissier 82ea4341de Fix documentation (#128) 2024-08-19 22:02:56 +02:00
Patrick Pelissier 341d145b4d Fix internal terminoligy 2024-07-26 23:22:58 +02:00
Patrick Pelissier 847f52fa5e Fix clang warning 2024-07-11 22:07:51 +02:00
Patrick Pelissier 02828a0109 Fix interface of Intrusive List
(Reported by Brian Sipos):
* incorrect clear operator usage
* useless prototype of _insert, inconsistent with the policy of other functions
* syntax error in _insert
2024-07-11 21:41:14 +02:00
Patrick Pelissier 0f7d5bf366 Update doc 2024-06-15 09:51:51 +02:00
Patrick Pelissier 1277c75ea3 Update doc 2024-06-15 09:47:10 +02:00
Patrick Pelissier 47a51ee5c4 Update doc 2024-06-15 09:45:13 +02:00
Patrick Pelissier 3f102c2270 Use of memcmp instead of strcmp for string_equal_p 2024-06-12 23:15:56 +02:00
Patrick Pelissier 4ba55dc3ca Rename new USE directive to be uniform with string one. 2024-06-08 00:08:27 +02:00
Patrick Pelissier 2c0db40158 Simplify logic for set_at of both dict,
(after analyzing which condition is likely)
which should help code size & performance
a little bit.
2024-06-01 23:49:08 +02:00
Patrick Pelissier 8987288a10 Fix spelling 2024-06-01 11:05:35 +02:00
Patrick Pelissier cf8c2afddd Fix warning on previous modification 2024-06-01 11:03:39 +02:00
Patrick Pelissier 0a8e336037 Fix internal & subtil issue
when comparing two methods to check for their presence in an oplist, we may generate the name of an already existing macro.
For example, in the oplist (SIZE())
when we expanded we get the macro M_ADD_SIZE to check if ADD is present,
but M_ADD_SIZE is an already existing macro, which generates an error.
To avoid this issue, define a prefix for the definition of the operators (M_X)
2024-06-01 10:47:21 +02:00
Patrick Pelissier e7e29d913e Add new example of variant 2024-06-01 10:16:59 +02:00
Patrick Pelissier f3ebc8c7eb Update comments 2024-06-01 10:16:47 +02:00
Patrick Pelissier 2d4fc9dc97 Allow generation of EMPLACE_TYPE
for variant if all oplists defined a FIELD operator.
2024-06-01 10:16:39 +02:00
Patrick Pelissier afedb06dee Fix buffer overflow in 32 bits mode 2024-05-28 23:31:26 +02:00
Patrick Pelissier 3fd2146bbe Fix issue in 32 bits mode 2024-05-28 23:31:16 +02:00
Patrick Pelissier 8e70b6175a Fix clang warning 2024-05-28 23:14:44 +02:00
Patrick Pelissier 67e9c8ff06 New internal string format:
* maximum size of a string is 2^32-1 now by default on a 64 bits system (can be increased using M_USE_STRING_LARGE_INDEX if needed).
* This reduce consumption of a string_t from 24 bytes to 16 bytes.
* Change the stack representation of a string, so that it lets 15 allocated bytes for the user even in 64 bytes mode. For 32 bits system, it increases to 15 allocated byte for stack representation.
* synthetic performance benchmark shows a little bit of decrease of performance. But performance in real application shows a significant increase (probably due to the reduced size of the type).
*Augment test suite to be sure to test all corner cases of the new representaiton.
2024-05-28 23:05:54 +02:00
Patrick Pelissier bf59c53921 Migrate to V0.7.4 2024-05-27 00:39:00 +02:00
Patrick Pelissier 5589105f5c Update comments 2024-05-27 00:34:24 +02:00
112 changed files with 4617 additions and 491 deletions

No files matched your search

+68 -1
View File
@@ -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 -1
View File
@@ -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
+5 -5
View File
@@ -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
+792 -31
View File
File diff suppressed because it is too large. Load diff
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 138 KiB

+4 -4
View File
@@ -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);
}
+7 -8
View File
@@ -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);
+56
View File
@@ -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
View File
@@ -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);
}
+9 -9
View File
@@ -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");
}
}
+73
View File
@@ -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);
}
+108
View File
@@ -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);
}
+6 -6
View File
@@ -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 */
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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); \
+111 -83
View File
@@ -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 ,) */
+4 -4
View File
@@ -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)),) \
+25 -28
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+7 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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:
+2 -2
View File
@@ -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)) { \
+69 -33
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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:
+2 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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:
+325
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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:
+2 -2
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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:
+555
View File
@@ -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);
}
+7
View File
@@ -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))
+6 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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