Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91d40a0f43 | ||
|
|
25fe26deaa | ||
|
|
cd357c5eb7 | ||
|
|
561f67b3b9 | ||
|
|
15a02e3306 | ||
|
|
944d29e8bc | ||
|
|
aefba70c1e | ||
|
|
c9ed4ba820 | ||
|
|
df97ea848c | ||
|
|
93d810421d | ||
|
|
f560839516 | ||
|
|
8a9d5f6a00 | ||
|
|
5f05c1e169 | ||
|
|
3df2408ffb | ||
|
|
ffc2ec8c4b | ||
|
|
b0ebbb306e | ||
|
|
c3574aa290 | ||
|
|
eabc867c2a | ||
|
|
a03b2e80c6 | ||
|
|
c4f23640d5 | ||
|
|
a42b854f14 | ||
|
|
9aa08bfc59 | ||
|
|
06b79a6caa | ||
|
|
6d533bd52a | ||
|
|
1b4c608087 | ||
|
|
6ccc81fd92 | ||
|
|
6f7d3fcd79 | ||
|
|
7484dee707 | ||
|
|
a580aaac83 | ||
|
|
52bef353e0 | ||
|
|
826ecf76c0 | ||
|
|
2cf5bff32d | ||
|
|
1377d7a1c2 | ||
|
|
ab9284ca20 | ||
|
|
5dab01c1c7 | ||
|
|
f9c434401b | ||
|
|
76b9f9a715 | ||
|
|
2ee82c478b | ||
|
|
211121435d | ||
|
|
fffd1702a5 | ||
|
|
9aa99bf230 | ||
|
|
1671ca8d67 | ||
|
|
ad16b310e1 | ||
|
|
4dbcfd25b3 | ||
|
|
01167b09c4 | ||
|
|
15d0b86c62 | ||
|
|
edbcecb272 | ||
|
|
1689db7b9c | ||
|
|
f5bc8796f7 | ||
|
|
e893560a48 | ||
|
|
a4ff7c71f2 | ||
|
|
9f780805f0 | ||
|
|
749273d1bb | ||
|
|
d8fd2e3e69 | ||
|
|
d443a84254 | ||
|
|
ef614b19ee | ||
|
|
1c5c4aa50f | ||
|
|
5533ffffaa | ||
|
|
34c990e259 | ||
|
|
5f0b6b9f26 | ||
|
|
26eb882a30 | ||
|
|
4d0e799c7a | ||
|
|
6801f688a4 | ||
|
|
bdf29af9e9 | ||
|
|
79dabfc52f | ||
|
|
de2268c406 | ||
|
|
85ea1f40dc | ||
|
|
f89ba94689 | ||
|
|
0279dcc3cc | ||
|
|
62c8e005bb | ||
|
|
2a28f8d407 | ||
|
|
9802fc5098 | ||
|
|
f372a72fd8 | ||
|
|
9d661852b2 | ||
|
|
b343d356c3 | ||
|
|
2e4404ca7e | ||
|
|
29eebaf38d | ||
|
|
d0d69aebfa | ||
|
|
477c5853f1 | ||
|
|
55e7b3083a | ||
|
|
0b9e27fb7f | ||
|
|
36ac6d5104 | ||
|
|
d898d6d4cc | ||
|
|
e7388929c4 | ||
|
|
45f8b31efc | ||
|
|
ebf440731d | ||
|
|
501a4a65ec | ||
|
|
800d03f728 | ||
|
|
19ff6bfeac | ||
|
|
24f5739a3b | ||
|
|
b658598e02 | ||
|
|
47343a2893 | ||
|
|
c1f99359be | ||
|
|
bd89e162fc | ||
|
|
983a63fbbc | ||
|
|
978e0ea5d7 | ||
|
|
85c4b50b6f | ||
|
|
e77aec4619 | ||
|
|
d67e084010 | ||
|
|
b0a74f162e | ||
|
|
d92126b97e | ||
|
|
c055358fa2 | ||
|
|
9f89148b69 | ||
|
|
ef1145603a | ||
|
|
d169a06f79 | ||
|
|
8e15a8cfe9 | ||
|
|
6466cefbf4 | ||
|
|
bec9a897c9 | ||
|
|
37d47cb0f1 | ||
|
|
0854136005 | ||
|
|
9427931e45 | ||
|
|
6aa28b4cfe | ||
|
|
a29682ca29 | ||
|
|
f5afd6e275 | ||
|
|
7b5fd14bcf | ||
|
|
22ce001f03 | ||
|
|
6f761091cc | ||
|
|
bb9e0e4f6e | ||
|
|
5e658a81fe | ||
|
|
ddc722bf78 | ||
|
|
0818d0ac7c | ||
|
|
2f315793cd | ||
|
|
067a034bc9 | ||
|
|
201cc45fd8 | ||
|
|
7a270ffacb | ||
|
|
27bb62533a | ||
|
|
032388b790 | ||
|
|
f1e2f81e79 | ||
|
|
54d4b80368 | ||
|
|
8a0a556604 | ||
|
|
895f362628 | ||
|
|
d24b52586d | ||
|
|
d76585cb0e | ||
|
|
fb44be6efe | ||
|
|
0b6a5aaa97 | ||
|
|
c00fdc65a2 | ||
|
|
ab7490eb8a | ||
|
|
1a46c0cd3f | ||
|
|
22f595c015 | ||
|
|
68c76ad146 | ||
|
|
0b18792b96 | ||
|
|
464e8e5f8f | ||
|
|
45410f3f0c | ||
|
|
556e706343 | ||
|
|
1e534bd307 | ||
|
|
7a517ee3ae | ||
|
|
9bb1957afa | ||
|
|
86f942ee5f | ||
|
|
a23df528e4 | ||
|
|
0e9af6dfac | ||
|
|
99a8db1111 | ||
|
|
24cdf1ca5c | ||
|
|
f1b794b239 | ||
|
|
b4fdcbc547 | ||
|
|
ce9986f6d8 | ||
|
|
ad4dcae1db | ||
|
|
b3fa63c971 | ||
|
|
364101592b | ||
|
|
5b89196cd7 | ||
|
|
feb8b30048 | ||
|
|
8340cf70fb | ||
|
|
affb3778a0 | ||
|
|
c039f07f2d | ||
|
|
c180981768 | ||
|
|
2cfac5c332 | ||
|
|
8ba489eef3 | ||
|
|
a4cb6e3681 | ||
|
|
379e0be211 | ||
|
|
acb886c391 | ||
|
|
7f26ef0f1c | ||
|
|
1d8e541205 | ||
|
|
a4fa70a478 | ||
|
|
3d3a473716 | ||
|
|
e04b120d41 | ||
|
|
63eee6bba3 | ||
|
|
b396b42808 | ||
|
|
eb8b106f48 | ||
|
|
5d144991cb | ||
|
|
35718ae551 | ||
|
|
1dd9aff402 | ||
|
|
6d47074457 | ||
|
|
1943650ca3 | ||
|
|
5722f19939 | ||
|
|
7cf14b5d8a | ||
|
|
b3a1a75f6f | ||
|
|
eb7556f88f | ||
|
|
805c747c60 | ||
|
|
5f9feb833c | ||
|
|
efef35c1e1 | ||
|
|
b1b32f565d | ||
|
|
f4cd8eaff9 | ||
|
|
2cd5258f89 | ||
|
|
1b206931df | ||
|
|
f68840ef8c | ||
|
|
779c15ec08 | ||
|
|
29bcc00202 | ||
|
|
1ff0d9fac0 | ||
|
|
4488853642 | ||
|
|
d5dc5d083d | ||
|
|
784c42d850 | ||
|
|
8c1eb1fcb5 | ||
|
|
49180bfbe5 | ||
|
|
a3116dd813 | ||
|
|
23df465401 | ||
|
|
966170452f | ||
|
|
eaf7ae7dee | ||
|
|
8a6652646a | ||
|
|
2063bf879d | ||
|
|
2529d4ae49 | ||
|
|
439bc06423 | ||
|
|
ab6c90f42f | ||
|
|
ac9e9a83b9 | ||
|
|
e495b92ae5 | ||
|
|
50b1bedc54 | ||
|
|
4a80ccd5f4 | ||
|
|
6ca65dd60c | ||
|
|
b2be4d5397 | ||
|
|
de34cefa83 | ||
|
|
40c8dbae1e | ||
|
|
18af53cf38 | ||
|
|
8510318ba5 | ||
|
|
6ad02ffe56 | ||
|
|
535e45d564 | ||
|
|
e2c60aa45c | ||
|
|
56d2a74818 | ||
|
|
8a36b5ff15 | ||
|
|
7607645636 | ||
|
|
cbb84accfe | ||
|
|
3e70cf7b5f | ||
|
|
1a7deef735 | ||
|
|
748771ab72 | ||
|
|
6ef279dd2f | ||
|
|
abcf37dc72 | ||
|
|
690b7bf9c1 | ||
|
|
71cec5155a | ||
|
|
d2b0873a95 | ||
|
|
4cecdbb93e | ||
|
|
2abca7d244 | ||
|
|
c26b467e86 | ||
|
|
19514b09b0 | ||
|
|
ab98577deb | ||
|
|
aae5f00dbd | ||
|
|
04706d48b9 | ||
|
|
c7df60c78d | ||
|
|
f03a4503eb | ||
|
|
a6951fe5e3 | ||
|
|
6def48a0d1 | ||
|
|
8b5d1e07ce | ||
|
|
3182c39280 | ||
|
|
e0b5dc2f02 | ||
|
|
6e5181e405 | ||
|
|
75f4f23144 | ||
|
|
bc1402f66a | ||
|
|
fc5ffcb404 | ||
|
|
bd20a021ce | ||
|
|
dfd12107de | ||
|
|
6743cb9456 | ||
|
|
4aa93325e9 | ||
|
|
f2a06ede62 | ||
|
|
a36752b8ce | ||
|
|
3b347f2ba5 | ||
|
|
47296e5c11 | ||
|
|
a24c530ec6 | ||
|
|
7ebe0608ae | ||
|
|
2a3021c021 | ||
|
|
4d313aa72b | ||
|
|
7906a39647 | ||
|
|
86254958f0 | ||
|
|
0089c1af61 | ||
|
|
6b5a3ddef7 | ||
|
|
42c2fd69a2 | ||
|
|
bcb9b831db | ||
|
|
f6483cbb30 | ||
|
|
f742707699 | ||
|
|
aee02d86ab | ||
|
|
dfbf34daf6 | ||
|
|
494cbbecf0 | ||
|
|
a1513777f1 | ||
|
|
9784a16d47 | ||
|
|
a8648e0cc1 | ||
|
|
3f8e93ad7a | ||
|
|
b040bc411f | ||
|
|
ae8c3e5300 | ||
|
|
01d390c3e9 | ||
|
|
56e4cda76c | ||
|
|
c59d585c22 | ||
|
|
81c97682a7 | ||
|
|
a432628df6 | ||
|
|
d16effb4c5 | ||
|
|
6279f98bb5 | ||
|
|
3cbc474e76 | ||
|
|
c80fb7bebe | ||
|
|
68788a6fb8 | ||
|
|
fd3cb50249 | ||
|
|
7e0bd8414d | ||
|
|
70de571dc8 | ||
|
|
cc6da8941c | ||
|
|
d27c448a94 | ||
|
|
06a1590645 | ||
|
|
652653af0b | ||
|
|
c520b7d0be | ||
|
|
4f4605befb | ||
|
|
3f84f54d65 | ||
|
|
bf49b8e933 | ||
|
|
1edb204ec6 | ||
|
|
dd5c9ac8ad | ||
|
|
32b6f82249 | ||
|
|
44b3895698 | ||
|
|
5ce6ccde3d | ||
|
|
ee64e068f9 | ||
|
|
8d89e7c958 | ||
|
|
ef74f8eb55 | ||
|
|
a7749e944f | ||
|
|
18bf06ff5f | ||
|
|
b27f490acb | ||
|
|
e84fa859c6 | ||
|
|
4c57ca69bc | ||
|
|
b0d2557ea1 | ||
|
|
82906e03e9 | ||
|
|
1859868838 | ||
|
|
4ab3a3605b | ||
|
|
279b46b4e2 | ||
|
|
17950c5fe5 | ||
|
|
45b94c8abc | ||
|
|
a98ebd3b20 | ||
|
|
cb7cd1ac67 | ||
|
|
9a41faf40a | ||
|
|
8c44362f74 | ||
|
|
548c0c0c61 | ||
|
|
607221f480 | ||
|
|
160c76361b | ||
|
|
2fadad0c8d | ||
|
|
4d4973abcc | ||
|
|
f8ae9eb677 | ||
|
|
de825203cf | ||
|
|
4f865176d3 | ||
|
|
cb4b43e2e8 | ||
|
|
89b6e1aac0 | ||
|
|
daeaa242b8 | ||
|
|
100af17328 | ||
|
|
7527bfec85 | ||
|
|
f73d25c92d | ||
|
|
9080f5d52f | ||
|
|
6beb142bbe | ||
|
|
9b8b93288a | ||
|
|
6a2a549ec5 | ||
|
|
468b7e7a0c | ||
|
|
fd640e9232 | ||
|
|
d13d7feae3 | ||
|
|
17f69326e2 | ||
|
|
273fcd51b6 | ||
|
|
f4b9185ceb | ||
|
|
b722227b39 | ||
|
|
3d7e2f5c6b | ||
|
|
9369530068 | ||
|
|
4e968c3777 | ||
|
|
9a5302ac19 | ||
|
|
8216ef0f7b | ||
|
|
b897027021 | ||
|
|
6095cf8610 | ||
|
|
e917ac5663 | ||
|
|
2b44892aad | ||
|
|
294e45c7e1 | ||
|
|
467acfdd10 | ||
|
|
d3823951b5 | ||
|
|
cc33079d43 | ||
|
|
78d0bfb286 | ||
|
|
b2f5ae6917 | ||
|
|
9c723da768 | ||
|
|
70c3932f6e | ||
|
|
92bddcaab4 | ||
|
|
79a8401d75 | ||
|
|
570473e465 | ||
|
|
990b7b02d7 | ||
|
|
0b301d1cea | ||
|
|
f35db79792 | ||
|
|
dc1f163716 | ||
|
|
4d6bb407ee | ||
|
|
37cef298c6 | ||
|
|
0396d1f648 |
No files matched your search
+71
-16
@@ -1,6 +1,6 @@
|
||||
name: C/C++ CI
|
||||
|
||||
on: [push]
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -11,35 +11,90 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make
|
||||
run: make
|
||||
- name: make check
|
||||
run: make check
|
||||
- name: make check C99
|
||||
run: make clean check CC="cc -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C11
|
||||
working-directory: ./tests
|
||||
run: make clean check CC="cc -std=c11 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C++
|
||||
working-directory: ./tests
|
||||
run: make clean check CC="c++ -std=c++11"
|
||||
|
||||
build_linux32:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: update package list
|
||||
run: sudo apt-get update
|
||||
- name: install multilib
|
||||
run: sudo apt-get install gcc-multilib
|
||||
- name: make check C99 (32bits)
|
||||
working-directory: ./tests
|
||||
run: make clean check CC="gcc -m32 -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C11 (32bits)
|
||||
working-directory: ./tests
|
||||
run: make clean check CC="gcc -m32 -std=c11 -Wno-unknown-warning-option -Werror"
|
||||
|
||||
build_linux_tcc:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Clone TCC
|
||||
shell: bash
|
||||
run: git clone https://repo.or.cz/tinycc.git
|
||||
- name: Configure, build & install TCC
|
||||
shell: bash
|
||||
run: cd tinycc && ./configure --prefix=/tmp/tcc && make && make install
|
||||
- name: make depend
|
||||
shell: bash
|
||||
run: make depend
|
||||
- name: make check
|
||||
shell: bash
|
||||
run: make CC="/tmp/tcc/bin/tcc -std=c99" check
|
||||
|
||||
build_windows_mingw:
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [windows-latest]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install MINGW
|
||||
run: choco install mingw --no-progress
|
||||
- name: make check
|
||||
shell: bash
|
||||
run: mingw32-make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
|
||||
build_windows_msys2:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
update: true
|
||||
install: git mingw-w64-x86_64-toolchain make
|
||||
- name: make check
|
||||
run: make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
|
||||
build_windows_visual:
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [windows-latest]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make check
|
||||
shell: cmd
|
||||
working-directory: ./tests
|
||||
run: Make-check-cl.bat
|
||||
run: Make-check-cl.bat cl
|
||||
|
||||
build_windows_clang_cl:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make check
|
||||
shell: cmd
|
||||
working-directory: ./tests
|
||||
run: Make-check-cl.bat clang-cl
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Override automatic language detection by changing the below list
|
||||
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||
language: ['cpp']
|
||||
# Learn more...
|
||||
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
- name: Autobuild
|
||||
working-directory: ./tests
|
||||
run: make exe
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
+3
-1
@@ -38,5 +38,7 @@ depend
|
||||
other/
|
||||
a*.dat
|
||||
config
|
||||
fail*.log
|
||||
*.log
|
||||
.vscode
|
||||
.vs
|
||||
tmp-serial.*
|
||||
@@ -1,6 +1,6 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017-2020, Patrick Pelissier
|
||||
Copyright (c) 2017-2021, Patrick Pelissier
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,6 +1,29 @@
|
||||
# Copyright (c) 2017-2021, 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.
|
||||
|
||||
# Environnement variable. To customize if needed.
|
||||
RM=rm -f
|
||||
MKDIR=mkdir -p
|
||||
RMDIR=rmdir
|
||||
INSTALL=install
|
||||
INSTALL_PROGRAM=${INSTALL}
|
||||
INSTALL_DATA=${INSTALL} -m 644
|
||||
@@ -11,14 +34,14 @@ DESTDIR=
|
||||
|
||||
# Package name & version.
|
||||
PACKAGE=m_lib-$(VERSION)
|
||||
VERSION=0.4.0
|
||||
VERSION=0.5.0
|
||||
|
||||
# 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-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.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-tuple.h m-variant.h m-worker.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
|
||||
EXAMPLE=example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.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-json01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-rbtree01.c example/ex-section.c example/Makefile
|
||||
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/wip-mregister.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt
|
||||
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/ex-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
|
||||
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/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt
|
||||
|
||||
.PHONY: all test check doc clean distclean depend install uninstall dist
|
||||
|
||||
@@ -74,8 +97,13 @@ distcheck: dist
|
||||
cd '$(PACKAGE)' && make check
|
||||
|
||||
install:
|
||||
$(MKDIR) $(DESTDIR)$(PREFIX)/include
|
||||
$(INSTALL_DATA) $(HEADER) $(DESTDIR)$(PREFIX)/include
|
||||
$(MKDIR) $(DESTDIR)$(PREFIX)/include/m-lib
|
||||
$(INSTALL_DATA) $(HEADER) $(DESTDIR)$(PREFIX)/include/m-lib
|
||||
|
||||
uninstall:
|
||||
for i in $(HEADER) ; do $(RM) $(DESTDIR)$(PREFIX)/include/$$i ; done
|
||||
for i in $(HEADER) ; do $(RM) $(DESTDIR)$(PREFIX)/include/m-lib/$$i ; done
|
||||
$(RMDIR) $(DESTDIR)$(PREFIX)/include/m-lib/
|
||||
|
||||
format:
|
||||
cd example && $(MAKE) ex-string01.exe
|
||||
for i in $(HEADER) ; do ./example/ex-string01.exe $$i > tmp.h && mv tmp.h $$i ; done
|
||||
+65
-8
@@ -1,3 +1,25 @@
|
||||
# Copyright (c) 2017-2021, 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.
|
||||
|
||||
CC=cc -std=c11
|
||||
CXX=c++ -std=c++11
|
||||
CFLAGS=-O2 -march=native -Wall
|
||||
@@ -7,7 +29,7 @@ N=4
|
||||
BENCH_DEF=
|
||||
RM=rm -rf
|
||||
|
||||
.PHONY: all pgo container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain
|
||||
.PHONY: all pgo container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain bench-rigtorp-mpmc-queue bench-cmc
|
||||
|
||||
all: container queue mempool string plain
|
||||
|
||||
@@ -17,10 +39,10 @@ pgo:
|
||||
|
||||
#########################################################################
|
||||
|
||||
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-densehashmap bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-uthash bench-qlibc bench-libsrt bench-nedtries bench-rigtorp-hashmap
|
||||
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-cmc bench-sparsepp bench-densehashmap bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-uthash bench-qlibc bench-libsrt bench-nedtries bench-rigtorp-hashmap
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost
|
||||
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-rigtorp-mpmc-queue
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
mempool: bench-mempool
|
||||
@@ -130,6 +152,16 @@ bench-klib0:
|
||||
@./bench-klib.exe 41
|
||||
@./bench-klib.exe 50
|
||||
|
||||
# CMC shall point to the directory where the CMC main header is
|
||||
bench-cmc:
|
||||
@if test -n "$${CMC}" ; then $(MAKE) bench-cmc0 ; else echo "Nothing to be done for CMC." ; fi
|
||||
|
||||
bench-cmc0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${CMC} bench-cmc.c common.c -o bench-cmc.exe
|
||||
@./bench-cmc.exe 20
|
||||
@./bench-cmc.exe 30
|
||||
@./bench-cmc.exe 40
|
||||
|
||||
# LIBDYNAMIC shall point to the the directory containing the file libdynamic.pc
|
||||
bench-libdynamic:
|
||||
@if test -n "$${LIBDYNAMIC}" ; then $(MAKE) bench-libdynamic0 ; else echo "Nothing to be done for LIBDYNAMIC." ; fi
|
||||
@@ -300,6 +332,28 @@ bench-rigtorp-hashmap0:
|
||||
@./bench-rigtorp-hashmap.exe 41
|
||||
@./bench-rigtorp-hashmap.exe 43
|
||||
|
||||
# RIGTORP_MPMC_QUEUE shall point to the directory where the headers are
|
||||
bench-rigtorp-mpmc-queue:
|
||||
@if test -n "$${RIGTORP_MPMC_QUEUE}" ; then $(MAKE) bench-rigtorp-mpmc-queue0 ; else echo "Nothing to be done for RIGTORP_MPMC_QUEUE." ; fi
|
||||
bench-rigtorp-mpmc-queue0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RIGTORP_MPMC_QUEUE}" bench-rigtorp-mpmcqueue.cpp common.c -DMULTI_THREAD_MEASURE -o bench-mpmcqueue.exe -lpthread
|
||||
@./bench-mpmcqueue.exe 60
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-mlib-json: bench-mlib
|
||||
@./bench-mlib.exe 110
|
||||
@./bench-mlib.exe 111
|
||||
@./bench-mlib.exe 112
|
||||
|
||||
bench-rapidjson:
|
||||
@if test -n "$${RAPIDJSON}" ; then $(MAKE) bench-rapidjson0 ; else echo "Nothing to be done for RAPIDJSON." ; fi
|
||||
bench-rapidjson0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RAPIDJSON}/" bench-rapidjson.cpp common.c -o bench-rapidjson.exe
|
||||
@./bench-rapidjson.exe 110
|
||||
@./bench-rapidjson.exe 111
|
||||
@./bench-rapidjson.exe 112
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-plain:
|
||||
@@ -332,10 +386,7 @@ bench-string-step1:
|
||||
|
||||
#NOTE: Need to build by hand sds.o since it is not build by default and sds.c is not compatible with C++
|
||||
bench-string-step2:
|
||||
@if test -n "$${SDS}" ; then $(MAKE) bench-string-step3 BENCH_DEF="$(BENCH_DEF) -fpermissive -DBENCH_CAN_USE_SDS -I$${SDS}/ $${SDS}/sds.o" ; else $(MAKE) bench-string-step3 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
bench-string-step3:
|
||||
@if test -n "$${RAPIDSTRING}" ; then $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_RAPIDSTRING -I$${RAPIDSTRING}/ " ; else $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
@if test -n "$${SDS}" ; then $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF) -fpermissive -DBENCH_CAN_USE_SDS -I$${SDS}/ $${SDS}/sds.o" ; else $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
bench-string-step4:
|
||||
@if test -n "$${GLIB}" ; then $(MAKE) bench-string-step5 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_GLIB $$(pkg-config --cflags --libs glib-2.0)" ; else $(MAKE) bench-string-step5 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
@@ -347,7 +398,6 @@ bench-string-step5:
|
||||
@./bench-string-2.exe 2000000 0
|
||||
@./bench-string-2.exe 2000000 1
|
||||
@./bench-string-2.exe 2000000 2
|
||||
@./bench-string-2.exe 2000000 3
|
||||
@./bench-string-2.exe 2000000 4
|
||||
|
||||
bench-string-pgo:
|
||||
@@ -356,11 +406,18 @@ bench-string-pgo:
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-find-sort:
|
||||
g++ bench-find-sort.cpp -O2 -march=native -std=c++11 -I.. -g common.c -o bench-find-sort.exe
|
||||
./bench-find-sort.exe 10000000
|
||||
|
||||
############################################################################
|
||||
|
||||
clean:
|
||||
$(RM) *.o bench-*.exe
|
||||
$(RM) bench-*.s *~ massif.out.*
|
||||
$(RM) plot-*.dat
|
||||
$(RM) pgo
|
||||
$(RM) tmp-serial.*
|
||||
cd nucleotide && $(MAKE) clean
|
||||
|
||||
############################################################################
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "macro_collections.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
// CMC list are dynamic array
|
||||
#define MY_LIST_PARAMS (list_uint, list_uint_s, , , unsigned int)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, LIST, MY_LIST_PARAMS, (STR))
|
||||
|
||||
struct list_uint_s_fval list_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
struct list_uint_s *a1 = list_uint_new(1, &list_fval);
|
||||
struct list_uint_s *a2 = list_uint_new(1, &list_fval);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
list_uint_push_back(a1, rand_get() );
|
||||
list_uint_push_back(a2, rand_get() );
|
||||
}
|
||||
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += list_uint_get(a1, i ) * list_uint_get(a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
list_uint_free(a1);
|
||||
list_uint_free(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define my_cmp(a,b) ( (a) < (b) ? -1 : (a) > (b) )
|
||||
|
||||
#define MY_TMAP_PARAMS (tree_ulong, tree_ulong_s, , unsigned long, bool)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, TREEMAP, MY_TMAP_PARAMS, (STR))
|
||||
|
||||
int cmp_ulong(unsigned long a, unsigned long b) { return my_cmp(a,b); }
|
||||
|
||||
struct tree_ulong_s_fkey tree_fkey = { .cmp = cmp_ulong,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
struct tree_ulong_s_fval tree_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
struct tree_ulong_s *tree;
|
||||
tree = tree_ulong_new(&tree_fkey, &tree_fval);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
tree_ulong_insert(tree, j, true);
|
||||
}
|
||||
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
if (tree_ulong_get_ref(tree, j) != 0)
|
||||
s+= j;
|
||||
}
|
||||
g_result = s;
|
||||
tree_ulong_free(tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
#define hash_func(a) kh_int64_hash_func(a)
|
||||
size_t hash_ulong(unsigned long a)
|
||||
{
|
||||
return ( (a) >> 33 ) ^ (a) ^ ((a) << 11);
|
||||
}
|
||||
|
||||
#define MY_DICT_PARAMS (hmap, hmap_s, , unsigned long, unsigned long)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, HASHMAP, MY_DICT_PARAMS, (STR))
|
||||
|
||||
struct hmap_s_fkey hmap_fkey = { .cmp = cmp_ulong,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = hash_ulong,
|
||||
.pri = NULL };
|
||||
|
||||
struct hmap_s_fval hmap_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
struct hmap_s *dict = hmap_new(16, 0.7, &hmap_fkey, &hmap_fval);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
hmap_insert(dict, rand_get(), rand_get());
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long *val = hmap_get_ref(dict, rand_get());
|
||||
if (val != 0)
|
||||
s += *val;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
hmap_free(dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#if 0 // Not working issue in using not integer types
|
||||
|
||||
typedef struct {
|
||||
char a[256];
|
||||
} char_array_t;
|
||||
static inline int char_cmp (const char_array_t a, const char_array_t b) { return strcmp(a.a,b.a); }
|
||||
static inline size_t char_hash(const char_array_t a) {
|
||||
size_t hash = 0;
|
||||
const char *s = a.a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
#define MY_DICTB_PARAMS (bhmap, bhmap_s, , char_array_t, char_array_t)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, HASHMAP, MY_DICT_PARAMS, (STR))
|
||||
|
||||
struct bhmap_s_fkey bhmap_fkey = { .cmp = char_cmp,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = char_hash,
|
||||
.pri = NULL };
|
||||
|
||||
struct bhmap_s_fval bhmap_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
struct bhmap_s *dict = bhmap_new(16, 0.7, &bhmap_fkey, &bhmap_fval);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
bhmap_insert(dict, s1, s2);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1;
|
||||
sprintf(s1.a, "%u", rand_get() );
|
||||
char_array_t *val = bhmap_get_ref(dict, s1);
|
||||
if (val != 0)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
bhmap_free(dict);
|
||||
}
|
||||
#endif
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
//{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("CMC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
// program to find longest contiguous subsequence
|
||||
// based on https://www.geeksforgeeks.org/longest-consecutive-subsequence/
|
||||
#include <iostream>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Returns length of the longest contiguous subsequence
|
||||
int cpp_find_longest(int arr[], int n)
|
||||
{
|
||||
unordered_set<int> S;
|
||||
int ans = 0;
|
||||
|
||||
// Hash all the array elements
|
||||
for (int i = 0; i < n; i++)
|
||||
S.insert(arr[i]);
|
||||
|
||||
// check each possible sequence from
|
||||
// the start then update optimal length
|
||||
for (int i = 0; i < n; i++) {
|
||||
// if current element is the starting
|
||||
// element of a sequence
|
||||
if (S.find(arr[i] - 1) == S.end()) {
|
||||
// Then check for next elements
|
||||
// in the sequence
|
||||
int j = arr[i] + 1;
|
||||
while (S.find(j) != S.end())
|
||||
j++;
|
||||
|
||||
// update optimal length if
|
||||
// this length is more
|
||||
ans = max(ans, j - arr[i]);
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
static inline bool oor_equal_p(int a, unsigned char c) { return a == ((c == 0) ? INT_MIN : INT_MAX); }
|
||||
static inline void oor_set(int *a, unsigned char c) { *a = ((c == 0) ? INT_MIN : INT_MAX); }
|
||||
|
||||
DICT_OASET_DEF(dict_int, int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)))
|
||||
|
||||
// Returns length of the longest contiguous subsequence
|
||||
int mlib_find_longest(int arr[], int n)
|
||||
{
|
||||
dict_int_t S;
|
||||
int ans = 0;
|
||||
|
||||
dict_int_init(S);
|
||||
|
||||
// Hash all the array elements
|
||||
for (int i = 0; i < n; i++)
|
||||
dict_int_push(S, arr[i]);
|
||||
|
||||
// check each possible sequence from
|
||||
// the start then update optimal length
|
||||
for (int i = 0; i < n; i++) {
|
||||
// if current element is the starting
|
||||
// element of a sequence
|
||||
int *p = dict_int_get(S, arr[i]-1);
|
||||
if (p == NULL) {
|
||||
// Then check for next elements
|
||||
// in the sequence
|
||||
int j = arr[i] + 1;
|
||||
while (dict_int_get(S, j) != NULL)
|
||||
j++;
|
||||
|
||||
// update optimal length if
|
||||
// this length is more
|
||||
ans = M_MAX(ans, j - arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
dict_int_clear(S);
|
||||
return ans;
|
||||
}
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = argc == 1 ? 10000 : atoi(argv[1]);
|
||||
int *arr = (int*) malloc(n * sizeof(int));
|
||||
for(int i = 0; i < n; i++)
|
||||
arr[i] = rand_get();
|
||||
|
||||
unsigned long long t0 = cputime();
|
||||
cout << "Length of the Longest contiguous subsequence is "
|
||||
<< cpp_find_longest(arr, n) << endl;
|
||||
|
||||
unsigned long long t1 = cputime();
|
||||
|
||||
cout << "Length of the Longest contiguous subsequence is "
|
||||
<< mlib_find_longest(arr, n) << endl;
|
||||
unsigned long long t2 = cputime();
|
||||
|
||||
cout << "Time C++: " << (t1-t0) << " Time M*LIB: " << (t2-t1) << endl;
|
||||
return 0;
|
||||
}
|
||||
+221
-2
@@ -8,6 +8,7 @@
|
||||
#include "m-list.h"
|
||||
#include "m-rbtree.h"
|
||||
#include "m-bptree.h"
|
||||
#include "m-deque.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-mempool.h"
|
||||
@@ -16,6 +17,9 @@
|
||||
#include "m-mutex.h"
|
||||
#include "m-deque.h"
|
||||
#include "m-concurrent.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-serial-bin.h"
|
||||
#include "m-serial-json.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@@ -40,6 +44,30 @@ static void test_array(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
DEQUE_DEF(deque_uint, unsigned int)
|
||||
|
||||
static void test_deque(size_t n)
|
||||
{
|
||||
M_LET(a1, a2, DEQUE_OPLIST(deque_uint)) {
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
deque_uint_push_back(a1, rand_get() );
|
||||
deque_uint_push_back(a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
deque_uint_it_t it1, it2;
|
||||
deque_uint_it(it1, a1);
|
||||
deque_uint_it(it2, a2);
|
||||
while (!deque_uint_end_p(it1)) {
|
||||
s += *deque_uint_cref(it1 ) * *deque_uint_cref(it2 );
|
||||
deque_uint_next(it1);
|
||||
deque_uint_next(it2);
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
// Two benched mode: with or without mempool
|
||||
#ifdef USE_MEMPOOL
|
||||
LIST_DEF(list_uint, unsigned int, (MEMPOOL( list_mpool), MEMPOOL_LINKAGE(static)))
|
||||
@@ -719,7 +747,6 @@ static void test_queue_single_bulk(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
DEQUE_DEF(deque_uint, unsigned int)
|
||||
CONCURRENT_DEF(cdeque_uint, deque_uint_t, M_OPEXTEND(DEQUE_OPLIST(deque_uint, M_DEFAULT_OPLIST), PUSH(deque_uint_push_front)))
|
||||
|
||||
DEQUE_DEF(deque_ull, unsigned long long)
|
||||
@@ -837,12 +864,198 @@ static void test_core_hash(size_t n)
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
ARRAY_DEF(vector_string, string_t)
|
||||
|
||||
vector_string_t vstring;
|
||||
vector_string_t vstring2;
|
||||
|
||||
static void
|
||||
bench_vector_string_init(size_t n)
|
||||
{
|
||||
vector_string_init(vstring);
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
M_LET( (s, "%zu", i, i, i, i), string_t) {
|
||||
vector_string_push_back(vstring, s);
|
||||
}
|
||||
}
|
||||
vector_string_init(vstring2);
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_init_big(size_t n)
|
||||
{
|
||||
vector_string_init(vstring);
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
M_LET( (s, "%zu%zu%zu%zu%zu%zu", i, i, i, i, i, i), string_t) {
|
||||
vector_string_push_back(vstring, s);
|
||||
}
|
||||
}
|
||||
vector_string_init(vstring2);
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_bin_run(size_t n)
|
||||
{
|
||||
if (vector_string_size(vstring) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.dat", "wb");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_bin_write_t) {
|
||||
vector_string_out_serial(serial, vstring);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.dat", "rb");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_bin_read_t) {
|
||||
vector_string_in_serial(vstring2, serial);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vector_string_size(vstring2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_json_run(size_t n)
|
||||
{
|
||||
if (vector_string_size(vstring) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_json_write_t) {
|
||||
vector_string_out_serial(serial, vstring);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_json_read_t) {
|
||||
vector_string_in_serial(vstring2, serial);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vector_string_size(vstring2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_clear(void)
|
||||
{
|
||||
if (!vector_string_equal_p(vstring, vstring2)) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
}
|
||||
vector_string_clear(vstring);
|
||||
vector_string_clear(vstring2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
ARRAY_DEF(vector_ulong, unsigned long)
|
||||
|
||||
vector_ulong_t vulong;
|
||||
vector_ulong_t vulong2;
|
||||
|
||||
static void
|
||||
bench_vector_ulong_init(size_t n)
|
||||
{
|
||||
vector_ulong_init(vulong);
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
vector_ulong_push_back(vulong, i*i);
|
||||
}
|
||||
vector_ulong_init(vulong2);
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_bin_run(size_t n)
|
||||
{
|
||||
if (vector_ulong_size(vulong) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.dat", "wb");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_bin_write_t) {
|
||||
vector_ulong_out_serial(serial, vulong);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.dat", "rb");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_bin_read_t) {
|
||||
vector_ulong_in_serial(vulong2, serial);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vector_ulong_size(vulong2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_json_run(size_t n)
|
||||
{
|
||||
if (vector_ulong_size(vulong) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_json_write_t) {
|
||||
vector_ulong_out_serial(serial, vulong);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_json_read_t) {
|
||||
vector_ulong_in_serial(vulong2, serial);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vector_ulong_size(vulong2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_clear(void)
|
||||
{
|
||||
if (!vector_ulong_equal_p(vulong, vulong2)) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
}
|
||||
vector_ulong_clear(vulong);
|
||||
vector_ulong_clear(vulong2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 11, "DPList", 10000000, 0, test_dlist, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 21, "Deque", 100000000, 0, test_deque, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 31, "B+tree", 1000000, 0, test_bptree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
@@ -861,7 +1074,13 @@ const config_func_t table[] = {
|
||||
{ 65,"Queue Concurrent", 1000000, 0, test_queue_concurrent, 0},
|
||||
{ 66,"Queue SPSC(Bulk)", 1000000, 0, test_queue_single_bulk, 0},
|
||||
{ 70,"M_HASH", 100000000, test_hash_prepare, test_hash, test_hash_final},
|
||||
{ 71,"Core Hash", 100000000, test_hash_prepare, test_core_hash, test_hash_final}
|
||||
{ 71,"Core Hash", 100000000, test_hash_prepare, test_core_hash, test_hash_final},
|
||||
{100, "serial-bin STR", 10000000, bench_vector_string_init, bench_vector_string_bin_run, bench_vector_string_clear},
|
||||
{101, "serial-bin STR.big", 10000000, bench_vector_string_init_big, bench_vector_string_bin_run, bench_vector_string_clear},
|
||||
{102, "serial-bin INT", 10000000, bench_vector_ulong_init, bench_vector_ulong_bin_run, bench_vector_ulong_clear},
|
||||
{110, "serial-json STR", 10000000, bench_vector_string_init, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{111, "serial-json STR.big", 10000000, bench_vector_string_init_big, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{112, "serial-json INT", 10000000, bench_vector_ulong_init, bench_vector_ulong_json_run, bench_vector_ulong_clear}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
#define NDEBUG
|
||||
#define RAPIDJSON_HAS_STDSTRING 1
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
vector<string> vstring;
|
||||
vector<string> vstring2;
|
||||
|
||||
static void
|
||||
bench_vector_string_init(size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
char buff[100];
|
||||
snprintf(buff, sizeof(buff), "%zu", i);
|
||||
std::string s(buff);
|
||||
vstring.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_init_big(size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
char buff[100];
|
||||
snprintf(buff, sizeof(buff), "%zu%zu%zu%zu%zu%zu", i, i, i, i, i, i);
|
||||
std::string s(buff);
|
||||
vstring.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_json_run(size_t n)
|
||||
{
|
||||
if (vstring.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
{
|
||||
// Prepare writer and output stream.
|
||||
char writeBuffer[65536];
|
||||
typedef rapidjson::AutoUTFOutputStream<unsigned, rapidjson::FileWriteStream> OutputStream;
|
||||
rapidjson::FileWriteStream os(f, writeBuffer, sizeof(writeBuffer));
|
||||
OutputStream eos(os, rapidjson::kUTF8, false);
|
||||
rapidjson::PrettyWriter<OutputStream, rapidjson::UTF8<>, rapidjson::AutoUTF<unsigned> > writer(eos);
|
||||
|
||||
writer.StartArray();
|
||||
for(size_t i = 0; i < n; i++){
|
||||
writer.String(vstring[i]);
|
||||
}
|
||||
writer.EndArray();
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
{
|
||||
char readBuffer[65536];
|
||||
rapidjson::FileReadStream is(f, readBuffer, sizeof(readBuffer));
|
||||
rapidjson::Document d;
|
||||
d.ParseStream(is);
|
||||
for(size_t i = 0; i < d.Size(); i++) {
|
||||
rapidjson::Value& s = d[i];
|
||||
vstring2.push_back(s.GetString());
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vstring2.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_clear(void)
|
||||
{
|
||||
if (vstring != vstring2) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
vector<unsigned long> vulong;
|
||||
vector<unsigned long> vulong2;
|
||||
|
||||
static void
|
||||
bench_vector_ulong_init(size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
vulong.push_back(i*i);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_json_run(size_t n)
|
||||
{
|
||||
if (vulong.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
{
|
||||
// Prepare writer and output stream.
|
||||
char writeBuffer[65536];
|
||||
typedef rapidjson::AutoUTFOutputStream<unsigned, rapidjson::FileWriteStream> OutputStream;
|
||||
rapidjson::FileWriteStream os(f, writeBuffer, sizeof(writeBuffer));
|
||||
OutputStream eos(os, rapidjson::kUTF8, false);
|
||||
rapidjson::PrettyWriter<OutputStream, rapidjson::UTF8<>, rapidjson::AutoUTF<unsigned> > writer(eos);
|
||||
|
||||
writer.StartArray();
|
||||
for(size_t i = 0; i < n; i++){
|
||||
writer.Int64(vulong[i]);
|
||||
}
|
||||
writer.EndArray();
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
{
|
||||
char readBuffer[65536];
|
||||
rapidjson::FileReadStream is(f, readBuffer, sizeof(readBuffer));
|
||||
rapidjson::Document d;
|
||||
d.ParseStream(is);
|
||||
for(size_t i = 0; i < d.Size(); i++) {
|
||||
rapidjson::Value& s = d[i];
|
||||
vulong2.push_back(s.GetInt64());
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vulong2.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_clear(void)
|
||||
{
|
||||
if (vulong != vulong2) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{110, "serial-json STR", 10000000, bench_vector_string_init, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{111, "serial-json STR.big", 10000000, bench_vector_string_init_big, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{112, "serial-json INT", 10000000, bench_vector_ulong_init, bench_vector_ulong_json_run, bench_vector_ulong_clear}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("RAPIDJSON", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <rigtorp/MPMCQueue.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
rigtorp::MPMCQueue<unsigned int> g_buff(4*64);
|
||||
rigtorp::MPMCQueue<unsigned long long> g_final(4*64);
|
||||
|
||||
static void final(void *arg)
|
||||
{
|
||||
size_t *p_n = (size_t*) arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long j, s = 0;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
g_final.pop(j);
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
size_t *p_n = (size_t*)arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long s = 0;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
g_buff.pop(j);
|
||||
s += j;
|
||||
}
|
||||
g_final.push(s);
|
||||
}
|
||||
|
||||
static void prod(void *arg)
|
||||
{
|
||||
size_t *p_n = (size_t*)arg;
|
||||
size_t n = *p_n;
|
||||
size_t r = n;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
g_buff.push(r);
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_queue(size_t n)
|
||||
{
|
||||
const int cpu_count = get_cpu_count();
|
||||
const int prod_count = cpu_count/2;
|
||||
const int conso_count = cpu_count - prod_count;
|
||||
if (cpu_count < 2) {
|
||||
fprintf(stderr, "WARNING: Can not measure Buffer performance.\n");
|
||||
return;
|
||||
}
|
||||
rand_get();
|
||||
// Create thread
|
||||
m_thread_t idx_p[prod_count];
|
||||
m_thread_t idx_c[conso_count];
|
||||
m_thread_t idx_final;
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_create (idx_p[i], prod, &n);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
m_thread_create(idx_final, final, &n2);
|
||||
|
||||
// Wait for jobs to be done.
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_join(idx_p[i]);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_join(idx_c[i]);
|
||||
}
|
||||
m_thread_join(idx_final);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("RIGTORP-MPMC-QUEUE", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
@@ -53,6 +54,23 @@ static void test_array(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_deque(size_t n)
|
||||
{
|
||||
deque<unsigned int> a1, a2;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
a2.push_back(rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(auto it1 = a1.cbegin(), it2 = a2.cbegin();
|
||||
it1 != a1.cend() ;it1++, it2++) {
|
||||
s += *it1 * *it2;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
set<unsigned long> tree;
|
||||
@@ -241,6 +259,7 @@ static void test_stable_sort(size_t n)
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 21, "Deque", 100000000, 0, test_deque, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict(m)", 1000000, 0, test_dict1, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
|
||||
+46
-126
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - String Bench
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -37,10 +37,6 @@ extern "C" {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_RAPIDSTRING
|
||||
#include "rapidstring.h"
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
#include "bstrlib.h"
|
||||
#include "bstrwrap.h"
|
||||
@@ -77,6 +73,17 @@ void random_permutation(unsigned n)
|
||||
|
||||
using namespace std;
|
||||
|
||||
static void replace_all_stl(string &str, const char pattern[], const char replace[])
|
||||
{
|
||||
size_t pos = 0;
|
||||
do {
|
||||
pos = str.find(pattern, pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, strlen(pattern), replace);
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
}
|
||||
|
||||
size_t bench_stl(unsigned n)
|
||||
{
|
||||
vector<string> tab;
|
||||
@@ -89,21 +96,8 @@ size_t bench_stl(unsigned n)
|
||||
str += tab[permutation_tab[i]];
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
do {
|
||||
pos = str.find("1234", pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, 4, "WELL");
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
|
||||
pos = 0;
|
||||
do {
|
||||
pos = str.find("56789", pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, 5, "DONE");
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
replace_all_stl(str, "1234", "WELL");
|
||||
replace_all_stl(str, "56789", "DONE");
|
||||
|
||||
return str.length();
|
||||
}
|
||||
@@ -124,15 +118,8 @@ size_t bench_mlib(unsigned n)
|
||||
string_cat(str, tab[permutation_tab[i]]);
|
||||
}
|
||||
// P3
|
||||
size_t i = 0;
|
||||
do {
|
||||
i = string_replace_str(str, "1234", "WELL", i);
|
||||
} while (i != STRING_FAILURE);
|
||||
// P4
|
||||
i = 0;
|
||||
do {
|
||||
i = string_replace_str(str, "56789", "DONE", i);
|
||||
} while (i != STRING_FAILURE);
|
||||
string_replace_all_str(str, "1234", "WELL");
|
||||
string_replace_all_str(str, "56789", "DONE");
|
||||
size_t length = string_size(str);
|
||||
// Clean
|
||||
string_clear(str);
|
||||
@@ -145,6 +132,18 @@ size_t bench_mlib(unsigned n)
|
||||
|
||||
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
|
||||
static void replace_all_bstrlib(CBString &str, const char pattern[], const char replace[])
|
||||
{
|
||||
size_t pos = 0;
|
||||
do {
|
||||
pos = str.find(pattern, pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, strlen(pattern), replace);
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
}
|
||||
|
||||
size_t bench_bstrlib(unsigned n)
|
||||
{
|
||||
vector<CBString> tab;
|
||||
@@ -160,21 +159,8 @@ size_t bench_bstrlib(unsigned n)
|
||||
str += tab[permutation_tab[i]];
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
do {
|
||||
pos = str.find("1234", pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, 4, "WELL");
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
|
||||
pos = 0;
|
||||
do {
|
||||
pos = str.find("56789", pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, 5, "DONE");
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
replace_all_bstrlib(str, "1234", "WELL");
|
||||
replace_all_bstrlib(str, "56789", "DONE");
|
||||
|
||||
return str.length();
|
||||
}
|
||||
@@ -191,6 +177,19 @@ sds SDS_replace_at(sds str, size_t pos, size_t len, const char str2[])
|
||||
return a;
|
||||
}
|
||||
|
||||
sds replace_all_sds(sds str, const char pattern[], const char replace[])
|
||||
{
|
||||
size_t pos = 0;
|
||||
do {
|
||||
char *p = strstr(&str[pos], pattern);
|
||||
pos = p == NULL ? -1U : (p - str);
|
||||
if (pos != -1U) {
|
||||
str = SDS_replace_at(str, pos, strlen(pattern), replace);
|
||||
}
|
||||
} while (pos != -1U);
|
||||
return str;
|
||||
}
|
||||
|
||||
size_t bench_sds(unsigned n)
|
||||
{
|
||||
sds *tab = (sds*) malloc (n * sizeof (sds));
|
||||
@@ -205,25 +204,10 @@ size_t bench_sds(unsigned n)
|
||||
str = sdscat(str, tab[permutation_tab[i]]);
|
||||
}
|
||||
// P3
|
||||
size_t pos = 0;
|
||||
do {
|
||||
char *p = strstr(&str[pos], "1234");
|
||||
pos = p == NULL ? -1U : (p - str);
|
||||
if (pos != -1U) {
|
||||
str = SDS_replace_at(str, pos, 4, "WELL");
|
||||
}
|
||||
} while (pos != -1U);
|
||||
// P4
|
||||
pos = 0;
|
||||
do {
|
||||
char *p = strstr(&str[pos], "56789");
|
||||
pos = p == NULL ? -1U : (p - str);
|
||||
if (pos != -1U) {
|
||||
str = SDS_replace_at(str, pos, 5, "DONE");
|
||||
}
|
||||
} while (pos != -1U);
|
||||
size_t length = sdslen(str);
|
||||
str = replace_all_sds(str, "1234", "WELL");
|
||||
str = replace_all_sds(str, "56789", "DONE");
|
||||
// Clean
|
||||
size_t length = sdslen(str);
|
||||
sdsfree(str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
sdsfree(tab[i]);
|
||||
@@ -233,63 +217,6 @@ size_t bench_sds(unsigned n)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_RAPIDSTRING
|
||||
void RAPIDSTRING_replace_at(rapidstring *str, size_t pos, size_t len, const char str2[])
|
||||
{
|
||||
// simple implementation as replace is not available
|
||||
rapidstring a;
|
||||
|
||||
rs_init_w_n(&a, rs_data(str), pos);
|
||||
rs_cat(&a, str2);
|
||||
rs_cat(&a, &rs_data(str)[pos+len] );
|
||||
rs_free(str);
|
||||
*str = a;
|
||||
}
|
||||
|
||||
size_t bench_rapidstring(unsigned n)
|
||||
{
|
||||
rapidstring *tab = (rapidstring*) malloc (n * sizeof (rapidstring));
|
||||
assert (tab != 0);
|
||||
// P1
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
char tmp[10];
|
||||
sprintf(tmp, "%u", rand_get());
|
||||
rs_init_w(&tab[i], tmp);
|
||||
}
|
||||
// P2
|
||||
rapidstring str;
|
||||
rs_init(&str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
rs_cat_rs(&str, &tab[permutation_tab[i]]);
|
||||
}
|
||||
// P3
|
||||
size_t pos = 0;
|
||||
do {
|
||||
char *p = strstr(&rs_data(&str)[pos], "1234");
|
||||
pos = p == NULL ? -1U : (p - rs_data(&str));
|
||||
if (pos != -1U) {
|
||||
RAPIDSTRING_replace_at(&str, pos, 4, "WELL");
|
||||
}
|
||||
} while (pos != -1U);
|
||||
// P4
|
||||
pos = 0;
|
||||
do {
|
||||
char *p = strstr(&rs_data(&str)[pos], "56789");
|
||||
pos = p == NULL ? -1U : (p - rs_data(&str));
|
||||
if (pos != -1U) {
|
||||
RAPIDSTRING_replace_at(&str, pos, 5, "DONE");
|
||||
}
|
||||
} while (pos != -1U);
|
||||
size_t length = rs_len(&str);
|
||||
// Clean
|
||||
rs_free(&str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
rs_free(&tab[i]);
|
||||
}
|
||||
free(tab);
|
||||
return length;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
@@ -315,12 +242,6 @@ int main(int argc, const char *argv[])
|
||||
name = "SDS";
|
||||
break;
|
||||
#endif
|
||||
#ifdef BENCH_CAN_USE_RAPIDSTRING
|
||||
case 3:
|
||||
length = bench_rapidstring(n);
|
||||
name = "RAPID";
|
||||
break;
|
||||
#endif
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
case 4:
|
||||
length = bench_bstrlib(n);
|
||||
@@ -335,4 +256,3 @@ int main(int argc, const char *argv[])
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+2
-153
@@ -35,8 +35,8 @@
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Update of integrating M*LIB, LIBSRT, SDS, RAPIDSTRING & GLIB
|
||||
Copyright (c) 2018-2019 Patrick Pelissier
|
||||
/* Update of integrating M*LIB, LIBSRT, SDS & GLIB
|
||||
Copyright (c) 2018-2021 Patrick Pelissier
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -79,11 +79,6 @@ extern "C" {
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#if defined (BENCH_CAN_USE_RAPIDSTRING)
|
||||
#include "rapidstring.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(BENCH_CAN_USE_GLIB)
|
||||
#include "gmodule.h"
|
||||
#endif
|
||||
@@ -682,121 +677,6 @@ int testSDS_replace (int count) {
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_RAPIDSTRING
|
||||
int testRAPIDSTRING_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
rapidstring b;
|
||||
rs_init(&b);
|
||||
BARRIER(&b);
|
||||
c += rs_len(&b) ^i;
|
||||
rs_free(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testRAPIDSTRING_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
rapidstring b;
|
||||
rs_init_w(&b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += rs_len(&b) ^i;
|
||||
rs_free(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testRAPIDSTRING_smallnonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
rapidstring b;
|
||||
rs_init_w(&b, SMALLTESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += rs_len(&b) ^i;
|
||||
rs_free(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testRAPIDSTRING_cstrAssignment (int count) {
|
||||
int i, c = 0;
|
||||
rapidstring b;
|
||||
rs_init(&b);
|
||||
for (c=i=0; i < count; i++) {
|
||||
rs_cpy(&b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += rs_len(&b) ^i;
|
||||
}
|
||||
rs_free(&b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testRAPIDSTRING_extraction (int count) {
|
||||
int i, c = 0;
|
||||
|
||||
rapidstring b;
|
||||
rs_init_w(&b, TESTSTRING1);
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += rs_data_c(&b)[i & 7];
|
||||
c += rs_data_c(&b)[(i & 7) ^ 8];
|
||||
c += rs_data_c(&b)[(i & 7) ^ 4] ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
rs_free(&b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testRAPIDSTRING_concat (int count) {
|
||||
int i, j, c = 0;
|
||||
rapidstring a, accum;
|
||||
rs_init_w(&a, TESTSTRING1);
|
||||
rs_init (&accum);
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
rs_cpy(&accum, "");
|
||||
for (i=0; i < 250; i++) {
|
||||
rs_cat_rs(&accum, &a);
|
||||
rs_cat(&accum, "!!");
|
||||
BARRIER(&accum);
|
||||
c += rs_len(&accum) ^i;
|
||||
}
|
||||
}
|
||||
rs_free(&a);
|
||||
rs_free(&accum);
|
||||
return c;
|
||||
}
|
||||
|
||||
void RAPIDSTRING_replace_at(rapidstring *str, size_t pos, size_t len, const char str2[])
|
||||
{
|
||||
// simple implementation as replace is not available
|
||||
rapidstring a;
|
||||
|
||||
rs_init_w_n(&a, rs_data(str), pos);
|
||||
rs_cat(&a, str2);
|
||||
rs_cat(&a, &rs_data(str)[pos+len] );
|
||||
rs_free(str);
|
||||
*str = a;
|
||||
}
|
||||
|
||||
int testRAPIDSTRING_replace (int count) {
|
||||
int j, c = 0;
|
||||
rapidstring a;
|
||||
rs_init_w(&a, TESTSTRING1);
|
||||
for (j=0; j < count; j++) {
|
||||
RAPIDSTRING_replace_at(&a, 11, 4, "XXXXXX");
|
||||
RAPIDSTRING_replace_at(&a, 23, 2, "XXXXXX");
|
||||
RAPIDSTRING_replace_at(&a, 4, 8, "XX");
|
||||
BARRIER(&a);
|
||||
c += rs_len(&a) ^j;
|
||||
}
|
||||
rs_free(&a);
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef BENCH_CAN_USE_GLIB
|
||||
int testGLIB_emptyCtor (int count) {
|
||||
@@ -1088,37 +968,6 @@ int benchTest (const struct flags * runflags) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_RAPIDSTRING
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_emptyCtor, 100000);
|
||||
print ("RAPIDSTRING", "empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_nonemptyCtor, 100000);
|
||||
print ("RAPIDSTRING", "non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_smallnonemptyCtor, 100000);
|
||||
print ("RAPIDSTRING", "small non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_cstrAssignment, 100000);
|
||||
print ("RAPIDSTRING", "char * assignment", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_extraction, 100000);
|
||||
print ("RAPIDSTRING", "char extraction", cps);
|
||||
}
|
||||
if (runflags->runtest[6]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_concat, 10);
|
||||
print ("RAPIDSTRING", "concatenation", cps * 250);
|
||||
}
|
||||
if (runflags->runtest[7]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_replace, 10);
|
||||
print ("RAPIDSTRING", "replace", cps);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_GLIB
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testGLIB_emptyCtor, 100000);
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MLIB - TEST module
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
|
||||
+12
@@ -45,3 +45,15 @@ V0.3.*: * Remove B+TREE _remove method as it has been deprecated (use _erase ins
|
||||
The _it_ref method is still defined and can be used, so you can still modify the values
|
||||
but it won't be automatically used anymore (as the keys CANNOT be modified).
|
||||
(Previously it generates incorrect algorithm when used with m-dict).
|
||||
|
||||
V0.4.*: * The order of a list initialized using M_LET is reversed
|
||||
to match what is done for ARRAY (and the C++ forward_list).
|
||||
* Rename M_SKIP, M_KEEP & M_MID into M_SKIP_ARGS, M_KEEP_ARGS & M_MID_ARGS
|
||||
due to conflict with glibc malloc.h (that defines M_KEEP for compatibility).
|
||||
* Method write_string of m_serial expects a new argument (number of characters).
|
||||
* Method _init_set2 of m-i-shared is removed.
|
||||
* Operator _it_insert updates it_insertion iterator to reference the inserted element.
|
||||
* Dereference Type of an iterator of a dict / B+Tree is suffixed by _itref_t instead of _type_t.
|
||||
* Rename TUPLE _init_set2 in _init_emplace & _set2 in _emplace.
|
||||
* Rename Priority Queue method _update_further in _update.
|
||||
|
||||
Binary file not shown.
+10
@@ -30,6 +30,16 @@ List of tested systems
|
||||
* clang 3.8 on linux/armv7l
|
||||
|
||||
|
||||
Atomic library
|
||||
==============
|
||||
|
||||
For target, armel m68k mips mipsel powerpc powerpcspe sh4, you may need to run the test suite:
|
||||
|
||||
make check LDFLAGS="-pthread -latomic"
|
||||
|
||||
since 'atomic' library is not automatically included for 32 bits systems.
|
||||
|
||||
|
||||
Cross compilation
|
||||
=================
|
||||
|
||||
|
||||
+58
-12
@@ -1,4 +1,3 @@
|
||||
|
||||
*Long term issues*
|
||||
------------------
|
||||
|
||||
@@ -6,39 +5,85 @@
|
||||
|
||||
Specialize Hashmap for huge objects on supported hardware:
|
||||
|
||||
|
||||
based on OA hash map of taggued pointer (needs space for tagging)
|
||||
based on OA hash map with taggued pointer (needs space for tagging):
|
||||
low bits = low bits of hash
|
||||
pointer to object { key, hash, value }
|
||||
|
||||
Can detect collision without dereferencing object with 1/2^lowbits chances.
|
||||
Reduce cache usage ==> Shall be faster.
|
||||
Reduce cache usage ==> Should be faster.
|
||||
|
||||
Use of pointer to avoid moving object on GC.
|
||||
|
||||
On AMD64, only 48 bits of 64 bits are really used for addressing data.
|
||||
|
||||
|
||||
* TODO #25 : Support of error code model for error handling. :ENHANCEMENT:
|
||||
|
||||
Find a way to support error return code for the API in case of allocation
|
||||
failure.
|
||||
|
||||
==> Any service that returns void shall return a "int".
|
||||
==> In case of allocation failure, it shall return an error.
|
||||
==> M_CALL macro shall stop its execution if the service returns an error code
|
||||
Any service that returns void shall return a "int".
|
||||
In case of allocation failure, it shall return an error.
|
||||
M_CALL macro shall stop its execution if the service returns an error code
|
||||
and the error code represents an error (avoid rewritting everything)
|
||||
and throw back the error code (stopping the execution flow).
|
||||
|
||||
services returning already something shall not be modified.
|
||||
Services returning already something shall not be modified.
|
||||
|
||||
This model should be applied at the container level only and not globally.
|
||||
Different containers may need different levels of error handling.
|
||||
4 combinaison to take into account:
|
||||
|
||||
New operator: ERROR_MODEL which value is 0 (abort on error), 1 (throw on error)
|
||||
or 2 (return code on error).
|
||||
==> ABORT on container / ABORT on used type: The current model
|
||||
==> ABORT on container / RETCODE on used type: Needs to abort on reported error.
|
||||
==> RETCODE on container / ABORT on used type: Nothing particular to note.
|
||||
==> RETCODE on container / RETCODE on used type: Forward retcode to caller.
|
||||
|
||||
Find a way to make it while not making the code too complex
|
||||
(try to keep as simple as possible).
|
||||
|
||||
Using a specialized oplist for such containers (_OPLIST_RETCODE)
|
||||
using a specialized API for retcode:
|
||||
|
||||
API_RET_*: that expands to
|
||||
|
||||
if (func(args) == 0) goto handler_exit_failure;
|
||||
|
||||
Adding at the end of each service:
|
||||
M_END_FUNCTION(cleanup_code) that expands to different cases:
|
||||
M_END_FUNCTION_VALUE(cleanup_code, return_success, return_failure) that expands to different cases:
|
||||
|
||||
ABORT/ABORT:
|
||||
handler_exit_success:
|
||||
handler_exit_failure:
|
||||
return;
|
||||
|
||||
ABORT/RETCODE:
|
||||
handler_exit_success:
|
||||
return;
|
||||
handler_exit_failure:
|
||||
RAISE_FATAL_ERROR
|
||||
|
||||
RETCODE/ABORT
|
||||
handler_exit_success:
|
||||
return SUCESS;
|
||||
handler_exit_failure:
|
||||
cleanup_code
|
||||
return FAILURE;
|
||||
|
||||
RETCODE/RETCODE
|
||||
handler_exit_success:
|
||||
return SUCESS;
|
||||
handler_exit_failure:
|
||||
cleanup_code
|
||||
return FAILURE;
|
||||
|
||||
If really needed, the macro can be avoided and code can be hand written.
|
||||
|
||||
Open points:
|
||||
- How to handle warnings on unused labels?
|
||||
- What about M_LET/ M_EACH?
|
||||
|
||||
|
||||
* TODO #24 : Add MIN-MAX-HEAP container :ENHANCEMENT:
|
||||
|
||||
@@ -186,8 +231,9 @@ then unstack all to push instead the root object (which recursively remove them)
|
||||
|
||||
See also http://freetype.sourceforge.net/david/reliable-c.html#cseh
|
||||
|
||||
How to handle like allocation of the object?
|
||||
How to avoid calling the destructor multiple times? (It is needed?)
|
||||
- How to handle like allocation of the object?
|
||||
- How to avoid calling the destructor multiple times? (It is needed?)
|
||||
- How the code can be factorized with RETCODE needs?
|
||||
|
||||
|
||||
* TODO #14: Memory allocation enhancement :ENHANCEMENT:
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 102 KiB |
@@ -1,3 +1,25 @@
|
||||
# Copyright (c) 2017-2021, 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.
|
||||
|
||||
CC=cc -std=c99
|
||||
CFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -g
|
||||
GMP_DIR=
|
||||
|
||||
+20
-5
@@ -4,33 +4,49 @@
|
||||
|
||||
/* Define a dynamic array of int */
|
||||
ARRAY_DEF(vector_int, int)
|
||||
/* Register the oplist of this dynamic array globally */
|
||||
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
|
||||
/* Define some standards algorithms on this dynamic array */
|
||||
ALGO_DEF(vector_int, vector_int_t)
|
||||
|
||||
/* Define a dynamic array of bool */
|
||||
ARRAY_DEF(vector_bool, bool)
|
||||
#define M_OPL_vector_bool_t() ARRAY_OPLIST(vector_bool)
|
||||
ARRAY_DEF(vector_bool, bool, M_BOOL_OPLIST)
|
||||
/* Register the oplist of this dynamic array globally */
|
||||
#define M_OPL_vector_bool_t() ARRAY_OPLIST(vector_bool, M_BOOL_OPLIST)
|
||||
/* Define some standards algorithms on this dynamic array */
|
||||
ALGO_DEF(vector_bool, vector_bool_t)
|
||||
|
||||
/* ID function */
|
||||
static bool id(bool x) { return x ; }
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Define, init (& later clear) myvector & tmp as vector_int_t
|
||||
M_LET(myvector, tmp, vector_int_t) {
|
||||
// Fill myvector with 3 int equal to 20
|
||||
vector_int_fill_n(myvector, 3, 20);
|
||||
// Fill tmp with 3 int equal to 33
|
||||
vector_int_fill_n(tmp, 3, 33);
|
||||
// Append all tmp in myvector
|
||||
vector_int_splice(myvector, tmp);
|
||||
// Fill tmp with 2 int equal to 10
|
||||
vector_int_fill_n(tmp, 2, 10);
|
||||
// Append all tmp in myvector
|
||||
vector_int_splice(myvector, tmp);
|
||||
// Display the result
|
||||
printf("myvector contains:");
|
||||
// In C11, the for loop can be simplified as :
|
||||
// ALGO_FOR_EACH(myvector, vector_int_t, M_PRINT, " ");
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
|
||||
ALGO_FOR_EACH(myvector, vector_int_t, M_PRINT, " ");
|
||||
#else
|
||||
for M_EACH(it, myvector, vector_int_t) {
|
||||
printf(" %d", *it);
|
||||
}
|
||||
#endif
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Same thing but with booleans
|
||||
M_LET(myvector, tmp, vector_bool_t) {
|
||||
vector_bool_fill_n(myvector, 3, false);
|
||||
vector_bool_fill_n(tmp, 3, true);
|
||||
@@ -38,8 +54,6 @@ int main(void)
|
||||
vector_bool_fill_n(tmp, 2, false);
|
||||
vector_bool_splice(myvector, tmp);
|
||||
printf("myvector contains:");
|
||||
// In C11, the for loop can be simplified as :
|
||||
// ALGO_FOR_EACH(myvector, vector_bool_t, M_PRINT, " ");
|
||||
for M_EACH(it, myvector, vector_bool_t) {
|
||||
printf(" %d", (int)*it);
|
||||
}
|
||||
@@ -49,5 +63,6 @@ int main(void)
|
||||
vector_bool_any_of_p(myvector, id),
|
||||
vector_bool_none_of_p(myvector, id) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3,20 +3,31 @@
|
||||
#include "m-algo.h"
|
||||
#include "m-string.h"
|
||||
|
||||
/* Define a dictionnary (or hash_map or undordered_map)
|
||||
* from a string_t to int */
|
||||
DICT_DEF2(dict, string_t, int)
|
||||
/* Register the oplist of this dictionnary globally */
|
||||
#define M_OPL_dict_t() DICT_OPLIST(dict, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
/* Define an array of integer */
|
||||
ARRAY_DEF(vector_int, int)
|
||||
/* Register the oplist of this array of integer globally */
|
||||
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
|
||||
|
||||
/* Micro macro to detect if a string starts with the given pattern */
|
||||
#define start_with(pattern, item) \
|
||||
string_start_with_str_p((item).key, (pattern))
|
||||
|
||||
/* Micro macro to get the value of a pair of (key, value) */
|
||||
#define get_value(out, item) ((out) = (item).value)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int s;
|
||||
// Init keys as a vector_int_t, initialize it (and prepare its destruction)
|
||||
M_LET(keys, vector_int_t)
|
||||
// Initialize m as a dictionnary and initialize it with the given database
|
||||
// Initialize tmp as a dictionanry
|
||||
M_LET( (m, (STRING_CTE("foo"), 1), (STRING_CTE("bar"), 42), (STRING_CTE("bluez"), 7), (STRING_CTE("stop"), 789) ), tmp, dict_t) {
|
||||
|
||||
/* Extract all elements of 'm' that starts with 'b' */
|
||||
|
||||
@@ -2,20 +2,31 @@
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
/* Define an array of int */
|
||||
ARRAY_DEF(vector_int, int)
|
||||
/* Register the oplist of this array of int globally */
|
||||
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
|
||||
|
||||
/* Set s (string_t) to the integer i */
|
||||
#define str_ui(s, i) string_printf(s, "%d", i)
|
||||
|
||||
/* Concat two strings by insertion a '-' within them */
|
||||
#define str_cat(s1, s2) (string_cat_str(s1, "-"), string_cat(s1, s2))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Let s be a string_t and initilize it.
|
||||
M_LET(s, string_t)
|
||||
// Let v be a vector of integer and initialize it.
|
||||
M_LET( (v, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), vector_int_t) {
|
||||
int sum, product;
|
||||
|
||||
// Compute the sum of theses integers.
|
||||
ALGO_REDUCE(sum, v, vector_int_t, add);
|
||||
|
||||
// Compute the product of theses integers.
|
||||
ALGO_REDUCE(product, v, vector_int_t, mul);
|
||||
|
||||
/* Example of reduction with a transformation of the type from int to string_t */
|
||||
ALGO_REDUCE( (s, string_t), v, vector_int_t, str_cat, str_ui);
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#include <stdlib.h>
|
||||
#include "m-array.h"
|
||||
|
||||
// Let's define an array of 'int' named 'int'
|
||||
// Let's define an array of 'int' named 'array_int'
|
||||
ARRAY_DEF(array_int, int)
|
||||
|
||||
const int n = 100000;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Declare and initilize the array
|
||||
// Declare and initialize the array
|
||||
array_int_t x;
|
||||
array_int_init(x);
|
||||
|
||||
|
||||
+12
-7
@@ -1,12 +1,16 @@
|
||||
#include "m-bptree.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Define a map int -> string
|
||||
// Define a map int -> string named map_employee_id
|
||||
// The number 5 is the number of elements in a node of the B+TREE
|
||||
BPTREE_DEF2(map_employee_id, 5, int, string_t)
|
||||
// Register the oplist of this map globally.
|
||||
#define M_OPL_map_employee_id_t() BPTREE_OPLIST2(map_employee_id, M_DEFAULT_OPLIST, STRING_OPLIST)
|
||||
|
||||
// Define a map string -> int
|
||||
// Define a map string -> int named map_employee_name
|
||||
// The number 5 is the number of elements in a node of the B+TREE
|
||||
BPTREE_DEF2(map_employee_name, 5, string_t, int)
|
||||
// Register the oplist of this map globally.
|
||||
#define M_OPL_map_employee_name_t() BPTREE_OPLIST2(map_employee_name, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
int main(void)
|
||||
@@ -14,7 +18,7 @@ int main(void)
|
||||
map_employee_id_t Employees;
|
||||
map_employee_id_init(Employees);
|
||||
|
||||
// Assign
|
||||
// Assign the map with some data
|
||||
map_employee_id_set_at(Employees, 17425, STRING_CTE("Mike"));
|
||||
map_employee_id_set_at(Employees, 7147, STRING_CTE("Tango"));
|
||||
map_employee_id_set_at(Employees, 841, STRING_CTE("Charlie"));
|
||||
@@ -30,11 +34,13 @@ int main(void)
|
||||
map_employee_id_it_t it;
|
||||
for(map_employee_id_it(it, Employees); !map_employee_id_end_p(it); map_employee_id_next(it)) {
|
||||
// Get a pointer to this employee from the iterator
|
||||
const map_employee_id_type_t *e = map_employee_id_cref(it);
|
||||
const map_employee_id_itref_t *e = map_employee_id_cref(it);
|
||||
// Print it
|
||||
printf ("%d: %s\n", *(e->key_ptr), string_get_cstr(*(e->value_ptr)));
|
||||
}
|
||||
|
||||
// Now, let's go using some macros!
|
||||
|
||||
// Let's create a reverse map
|
||||
M_LET(Employees_r, map_employee_name_t) {
|
||||
|
||||
@@ -51,9 +57,8 @@ int main(void)
|
||||
}
|
||||
|
||||
// Print
|
||||
printf("\nElisabeth has id = %d\n", *map_employee_name_get(Employees_r, STRING_CTE("Elisabeth")));
|
||||
|
||||
}
|
||||
printf("\nElisabeth has id = %d\n", *map_employee_name_get(Employees_r, STRING_CTE("Elisabeth")));
|
||||
} /* Employees_r is cleared beyond this point */
|
||||
|
||||
map_employee_id_clear(Employees);
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#include "m-core.h"
|
||||
|
||||
// Stubs defined for the example. Real code will use soundio library.
|
||||
struct SoundIo { int x; };
|
||||
struct SoundIoDevice { int x; };
|
||||
struct SoundIoOutStream { int x; };
|
||||
|
||||
static struct SoundIo *soundio_create(void) { return (struct SoundIo *) malloc(sizeof(struct SoundIo)); }
|
||||
static void soundio_destroy(struct SoundIo *s) { free(s); }
|
||||
|
||||
static struct SoundIoDevice *soundio_get_device(struct SoundIo *io, int def) { (void) io; (void) def; return (struct SoundIoDevice *) malloc(sizeof(struct SoundIoDevice)); }
|
||||
static void soundio_device_unref(struct SoundIoDevice *s) { free(s); }
|
||||
|
||||
static struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device) { (void) device ; return (struct SoundIoOutStream *) malloc(sizeof(struct SoundIoOutStream)); }
|
||||
static void soundio_outstream_destroy(struct SoundIoOutStream *s) { free(s); }
|
||||
|
||||
static bool soundio_wait_events(struct SoundIo *s) { (void) s; return false; }
|
||||
// End of stubs
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int err = 1;
|
||||
|
||||
/* Example of using M_LET_IF macro to simplify writing error handling code.
|
||||
The following code creates some object, test if the object creation succeeds, register the destructor, and print an error if something went wrong
|
||||
*/
|
||||
M_LET_IF( struct SoundIo *soundio = soundio_create(), soundio != 0 , soundio_destroy(soundio) , fprintf(stderr, "out of memory for soundio\n") )
|
||||
M_LET_IF(struct SoundIoDevice *device = soundio_get_device(soundio, -1), device != 0, soundio_device_unref(device), fprintf(stderr, "out of memory for device\n"))
|
||||
M_LET_IF(struct SoundIoOutStream *outstream = soundio_outstream_create(device), outstream != 0, soundio_outstream_destroy(outstream), fprintf(stderr, "out of memory for stream\n")) {
|
||||
err = 0;
|
||||
bool cont = true;
|
||||
while (cont)
|
||||
cont = soundio_wait_events(soundio);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
#include "m-string.h"
|
||||
|
||||
// Define a dictionnary of string --> int
|
||||
// named 'str'
|
||||
// named 'dict_str'
|
||||
DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
|
||||
int main(void)
|
||||
|
||||
+5
-4
@@ -5,8 +5,9 @@
|
||||
#include "m-dict.h"
|
||||
#include "m-string.h"
|
||||
|
||||
DICT_DEF2(dict_map, char, M_DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
|
||||
// Define a dictionary (hashmap) from 'char' to 'int'
|
||||
DICT_DEF2(dict_map, char, int)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
dict_map_t mp;
|
||||
@@ -81,7 +82,7 @@ int main(void)
|
||||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
case 6:
|
||||
dict_map_clear(mp);
|
||||
string_clear (str);
|
||||
exit(0);
|
||||
@@ -89,7 +90,7 @@ int main(void)
|
||||
|
||||
default:
|
||||
printf("Wrong Choice\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-2
@@ -5,14 +5,23 @@
|
||||
/* program that reads text from standard-input,
|
||||
and prints the total number of distinct words found in the text.
|
||||
*/
|
||||
|
||||
/* Definition of a set (hashset) of unique string_t */
|
||||
DICT_SET_DEF(dict_str, string_t, STRING_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Define word as a string_t
|
||||
M_LET(word, STRING_OPLIST)
|
||||
M_LET(wordcount, DICT_SET_OPLIST(dict_str, STRING_OPLIST)) {
|
||||
while (string_fget_word(word, " \t\n,.!;:?", stdin))
|
||||
// Define wordcount as a set of string_t
|
||||
M_LET(wordcount, DICT_SET_OPLIST(dict_str, STRING_OPLIST)) {
|
||||
// Read a word from the standard input
|
||||
while (string_fget_word(word, " \t\n,.!;:?", stdin)) {
|
||||
// Push this word in the set.
|
||||
// Do nothing if it already exists.
|
||||
dict_str_push(wordcount, word);
|
||||
}
|
||||
// Print the number of words of the standard input.
|
||||
printf ("Words: %zu\n", dict_str_size(wordcount));
|
||||
}
|
||||
}
|
||||
+42
-18
@@ -3,30 +3,54 @@
|
||||
#include "m-array.h"
|
||||
#include "m-dict.h"
|
||||
|
||||
// Define an array of size_t
|
||||
ARRAY_DEF(array_size, size_t)
|
||||
// Register the oplist of this array globaly
|
||||
#define M_OPL_array_size_t() ARRAY_OPLIST(array_size)
|
||||
|
||||
// Define a dictionary (hashmap) of string_t to array of size_t
|
||||
DICT_DEF2(map_pos, string_t, array_size_t)
|
||||
// Register the oplist of this dictionary (hashmap)
|
||||
#define M_OPL_map_pos_t() DICT_OPLIST(map_pos, STRING_OPLIST, ARRAY_OPLIST(array_size))
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
if (argc == 2) {
|
||||
M_LET(word, string_t)
|
||||
M_LET(positions, map_pos_t) {
|
||||
FILE *f = fopen(argv[1], "rt");
|
||||
if (!f) return 1;
|
||||
while (string_fget_word(word, " \t\n\r\"(),=", f)) {
|
||||
array_size_t *array = map_pos_get_at(positions, word);
|
||||
array_size_push_back(*array, (size_t)ftell(f) - string_size(word));
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
for M_EACH(pair, positions, map_pos_t) {
|
||||
string_fputs(stdout, pair->key);
|
||||
for M_EACH(pos, pair->value, array_size_t)
|
||||
printf(" %zu", *pos);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
if (argc != 2) {
|
||||
printf("USAGE: %s filename\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Define word as a string_t
|
||||
M_LET(word, string_t)
|
||||
// Define positions as a map of string_t-->array of size_t
|
||||
M_LET(positions, map_pos_t) {
|
||||
// Open the file
|
||||
FILE *f = fopen(argv[1], "rt");
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s.\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// While it reads some word from the file
|
||||
while (string_fget_word(word, " \t\n\r\"(),=", f)) {
|
||||
// Get the reference to the array of this word in the dictionnary (or create it if needed)
|
||||
array_size_t *array = map_pos_get_at(positions, word);
|
||||
// Push the new offset to this word in the associated array
|
||||
array_size_push_back(*array, (size_t)ftell(f) - string_size(word));
|
||||
}
|
||||
|
||||
// Close the file
|
||||
fclose(f);
|
||||
|
||||
// Print the words and where they are:
|
||||
for M_EACH(pair, positions, map_pos_t) {
|
||||
string_fputs(stdout, pair->key);
|
||||
for M_EACH(pos, pair->value, array_size_t) {
|
||||
printf(" %zu", *pos);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
} // All created objects are destroyed beyond this point
|
||||
|
||||
return 0;
|
||||
}
|
||||
+17
-8
@@ -24,22 +24,25 @@
|
||||
|
||||
/* Define the needed data structure : */
|
||||
|
||||
// Define a dictionnary of constant string --> integer
|
||||
// Define a dictionnary of constant string --> integer and register it.
|
||||
DICT_DEF2(dict_mph, const char *, M_CSTR_OPLIST, uint32_t, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_dict_mph_t() DICT_OPLIST(dict_mph, M_CSTR_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
// Defin an array of integer
|
||||
// Define an array of integer to store the value and register it.
|
||||
ARRAY_DEF(array_value, uint32_t) // Start from 1. 0 is 'None'
|
||||
#define M_OPL_array_value_t() ARRAY_OPLIST(array_value)
|
||||
|
||||
// Defin an array of integer
|
||||
// Define an array of integer to store the seed and register it.
|
||||
ARRAY_DEF(array_seed, int32_t)
|
||||
#define M_OPL_array_seed_t() ARRAY_OPLIST(array_seed)
|
||||
// Define algorithms on array_seed
|
||||
ALGO_DEF(array_seed, array_seed_t)
|
||||
|
||||
// Define an array of constant string that are ordered by their size.
|
||||
ARRAY_DEF(array_cstr, const char *, M_CSTR_OPLIST)
|
||||
// Register it globally but with a custom CMP operator
|
||||
static inline int array_cstr_cmp(const array_cstr_t a, const array_cstr_t b) {
|
||||
// We compare only the size
|
||||
size_t sa = array_cstr_size(a);
|
||||
size_t sb = array_cstr_size(b);
|
||||
return (sa > sb) ? -1 : (sa < sb);
|
||||
@@ -191,7 +194,11 @@ static void
|
||||
dict_read_from_file(dict_mph_t dict, array_string_t arr, const char filename[])
|
||||
{
|
||||
FILE *f = fopen(filename, "rt");
|
||||
if (!f) abort();
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s\n", filename);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
uint32_t line = 1;
|
||||
M_LET(str, string_t) {
|
||||
while (!feof(f) && !ferror(f)) {
|
||||
@@ -234,12 +241,14 @@ test(array_seed_t seed, array_value_t value, dict_mph_t dict)
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
// Create arr as array_string_t, dict as dist_mph_t and seed as array_seed_t
|
||||
M_LET(arr, array_string_t) M_LET(dict, dict_mph_t) M_LET(seed, array_seed_t)
|
||||
// and value as array_value_t
|
||||
M_LET(value, array_value_t) {
|
||||
const char *filename = (argc > 1) ? argv[1] :"/usr/share/dict/words";
|
||||
dict_read_from_file(dict, arr, filename);
|
||||
CreateMinimalPerfectHash(seed, value, dict);
|
||||
test(seed, value, dict);
|
||||
const char *filename = (argc > 1) ? argv[1] :"/usr/share/dict/words";
|
||||
dict_read_from_file(dict, arr, filename);
|
||||
CreateMinimalPerfectHash(seed, value, dict);
|
||||
test(seed, value, dict);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Define an array of integer
|
||||
ARRAY_DEF(array_int, int)
|
||||
|
||||
typedef struct {
|
||||
@@ -25,7 +26,7 @@ static void tape_devance(tape_t tape) { if (tape->pos > 0) tape->pos--; }
|
||||
|
||||
typedef struct {
|
||||
string_t code;
|
||||
array_int_t bracket_map; // Should use map when possible.
|
||||
array_int_t bracket_map;
|
||||
} program_t[1];
|
||||
|
||||
static void program_init(program_t p, string_t text) {
|
||||
@@ -98,7 +99,11 @@ static void program_run(program_t p){
|
||||
|
||||
static void read_file(string_t str, const string_t filename) {
|
||||
FILE *f = fopen(string_get_cstr(filename), "rt");
|
||||
if (!f) abort();
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s\n", string_get_cstr(filename));
|
||||
exit(2);
|
||||
}
|
||||
// Read the full FILE in the string
|
||||
string_fgets (str, f, STRING_READ_FILE);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
@@ -51,6 +51,9 @@ TUPLE_DEF2(mlib_points, (first_ref, mlib_point_ptr, M_PTR_OPLIST),
|
||||
|
||||
static void let2(void)
|
||||
{
|
||||
// Initialize p1 as mlib_point_t with (4,4)
|
||||
// and p2 as mlib_point_t with (5,5)
|
||||
// and pair as mlib_point_t with default value
|
||||
M_LET((p1, 4, 4), (p2, 5, 5), mlib_point_t) {
|
||||
M_LET(pair, mlib_points_t) {
|
||||
pair->first_ref = p1;
|
||||
@@ -68,6 +71,7 @@ static void let2(void)
|
||||
|
||||
static void let(void)
|
||||
{
|
||||
// Let's initialize all the declared types
|
||||
M_LET(s, symbol_t)
|
||||
M_LET(l, symbol_list_t)
|
||||
M_LET(r,record_t)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "m-string.h"
|
||||
|
||||
#define MAX_COLUMN 80
|
||||
|
||||
static void format(FILE *f)
|
||||
{
|
||||
string_t s;
|
||||
string_init(s);
|
||||
while (string_fgets(s, f, STRING_READ_PURE_LINE) == true)
|
||||
{
|
||||
size_t n = string_size(s);
|
||||
if (n > 0 && string_get_char(s, n-1) == '\\' && n < MAX_COLUMN) {
|
||||
string_left(s, n-1);
|
||||
while (n < MAX_COLUMN-1) {
|
||||
string_push_back(s, ' ');
|
||||
n++;
|
||||
}
|
||||
string_push_back(s, '\\');
|
||||
}
|
||||
if (n >= MAX_COLUMN && string_get_char(s, n-1) == '\\') {
|
||||
n--;
|
||||
string_left(s, n);
|
||||
while (n >= MAX_COLUMN-2 && string_get_char(s, n-1) == ' ') {
|
||||
n--;
|
||||
string_left(s, n);
|
||||
}
|
||||
string_push_back(s, ' ');
|
||||
string_push_back(s, '\\');
|
||||
}
|
||||
printf("%s\n", string_get_cstr(s));
|
||||
}
|
||||
string_clear(s);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Missing argument filename.\nUSAGE: %s filename.h\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
FILE *f = fopen(argv[1], "rt");
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open filename '%s' .h\n", argv[1]);
|
||||
exit(2);
|
||||
}
|
||||
format(f);
|
||||
fclose(f);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Define an array of string_t. Since the oplist of string_t is registered globaly
|
||||
// there is no need to give it to this definition.
|
||||
ARRAY_DEF(str_array, string_t)
|
||||
|
||||
// First the verbose way and (nearly) macro free:
|
||||
static void main_macrofree(void)
|
||||
{
|
||||
str_array_t tab_name;
|
||||
str_array_init(tab_name);
|
||||
|
||||
// Push some elements in the array (long way)
|
||||
str_array_push_back(tab_name, STRING_CTE("My"));
|
||||
str_array_push_back(tab_name, STRING_CTE("CD"));
|
||||
str_array_push_back(tab_name, STRING_CTE("IS"));
|
||||
str_array_push_back(tab_name, STRING_CTE("OUT"));
|
||||
|
||||
// Overwrite element 1 of the array.
|
||||
str_array_set_at(tab_name, 1, STRING_CTE("DVD"));
|
||||
|
||||
// Format some strings and push them back in the array
|
||||
string_t format;
|
||||
string_init_printf(format, "There are %d elements", str_array_size(tab_name));
|
||||
str_array_push_back(tab_name, format);
|
||||
string_printf(format, "There is a capacty of %d", str_array_capacity(tab_name));
|
||||
string_replace_all_str(format, "capacty", "capacity");
|
||||
str_array_push_back(tab_name, format);
|
||||
string_printf(format, "The third element is '%s'", string_get_cstr(*str_array_get(tab_name, 2)));
|
||||
str_array_push_back(tab_name, format);
|
||||
string_clear(format);
|
||||
|
||||
// Display the content of the array.
|
||||
str_array_it_t it;
|
||||
int i = 0;
|
||||
for (str_array_it(it, tab_name) ; !str_array_end_p(it); str_array_next(it)) {
|
||||
printf("item[%d] = '%s'\n", i, string_get_cstr(*str_array_cref(it)) );
|
||||
i++;
|
||||
}
|
||||
|
||||
// Clear the array
|
||||
str_array_clear(tab_name);
|
||||
}
|
||||
|
||||
// Then the short version with macros.
|
||||
// For this we need to register the oplist of the array of string globally.
|
||||
#define M_OPL_str_array_t() ARRAY_OPLIST(str_array, STRING_OPLIST)
|
||||
|
||||
static void main_macro(void)
|
||||
{
|
||||
// Define and fill an array of string with some elements in it:
|
||||
M_LET( (tab_name, STRING_CTE("My"), STRING_CTE("CD"), STRING_CTE("IS"), STRING_CTE("OUT")), str_array_t) {
|
||||
// Overwrite element 1 of the array.
|
||||
str_array_set_at(tab_name, 1, STRING_CTE("DVD"));
|
||||
|
||||
// Format some strings and push them back in the array
|
||||
M_LET(format, string_t) {
|
||||
string_printf(format, "There are %d elements", str_array_size(tab_name));
|
||||
str_array_push_back(tab_name, format);
|
||||
string_printf(format, "There is a capacty of %d", str_array_capacity(tab_name));
|
||||
string_replace_all_str(format, "capacty", "capacity");
|
||||
str_array_push_back(tab_name, format);
|
||||
string_printf(format, "The third element is '%s'", string_get_cstr(*str_array_get(tab_name, 2)));
|
||||
str_array_push_back(tab_name, format);
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
// Set format to a formated string
|
||||
// In C11, we can mix string_t and char *.
|
||||
// We can also use M_CSTR to create a printf formated string.
|
||||
string_sets(format, "FILE=", getenv("PWD"), "/", *str_array_get(tab_name, 2), M_CSTR("-%d.txt", str_array_size(tab_name) ));
|
||||
str_array_push_back(tab_name, format);
|
||||
#endif
|
||||
} // beyond this point format is cleared
|
||||
|
||||
// Display the content of the array.
|
||||
int i = 0;
|
||||
for M_EACH(item, tab_name, str_array_t) {
|
||||
printf("item[%d] = '%s'\n", i, string_get_cstr(*item) );
|
||||
i++;
|
||||
}
|
||||
} // beyond this point tab_name is cleared
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("Version macrofree:\n");
|
||||
main_macrofree();
|
||||
printf("Version macro:\n");
|
||||
main_macro();
|
||||
return 0;
|
||||
}
|
||||
+19
-5
@@ -17,10 +17,14 @@ ARRAY_DEF(vector_employee, employee_t)
|
||||
#define M_OPL_vector_employee_t() ARRAY_OPLIST(vector_employee, M_OPL_employee_t())
|
||||
ALGO_DEF(vector_employee, vector_employee_t)
|
||||
|
||||
/* Define the function object to select the sort order */
|
||||
FUNC_OBJ_INS_DEF(compare_by,
|
||||
vector_employee_cmp_obj,
|
||||
(a, b), {
|
||||
/* Define the function object to select the sort order
|
||||
* named 'compare_by' which is an instance of the interface
|
||||
* 'vector_employee_cmp_obj' created by ALGO_DEF.
|
||||
*/
|
||||
FUNC_OBJ_INS_DEF(compare_by /* name of the instance */,
|
||||
vector_employee_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 (string_equal_str_p(self->sort_field, "name"))
|
||||
return string_cmp(a->name, b->name);
|
||||
else if (string_equal_str_p(self->sort_field, "age"))
|
||||
@@ -28,6 +32,7 @@ FUNC_OBJ_INS_DEF(compare_by,
|
||||
else
|
||||
return a->idnum < b->idnum ? -1 : a->idnum > b->idnum;
|
||||
},
|
||||
/* Additional fields stored in the function object */
|
||||
(sort_field, string_t) )
|
||||
#define M_OPL_compare_by_t() FUNC_OBJ_INS_OPLIST(compare_by, STRING_OPLIST)
|
||||
|
||||
@@ -39,19 +44,25 @@ static void read(vector_employee_t base, const char filename[])
|
||||
// Open the file
|
||||
FILE *f = fopen(filename, "rt");
|
||||
if (!f) {
|
||||
// Handle errors
|
||||
fprintf(stderr, "ERROR: Cannot open file '%s'.\n", filename);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
// Initialize the JSON serializer with this file
|
||||
M_LET( (in,f), m_serial_json_read_t)
|
||||
// Read the JSON file and fill in 'base' with it.
|
||||
ret = vector_employee_in_serial(base, in);
|
||||
// Let's handle errors
|
||||
|
||||
// Let's handle serialization error
|
||||
if (ret != M_SERIAL_OK_DONE) {
|
||||
fprintf(stderr, "ERROR: Cannot read JSON data from file '%s'.\nParsing stops at:\n", filename);
|
||||
while (!feof(f)) { fputc(fgetc(f), stdout); }
|
||||
fclose(f);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
// Close the FILE
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
@@ -67,11 +78,14 @@ int main(void)
|
||||
printf("Employees sorted by idnum are: ");
|
||||
vector_employee_out_str(stdout, emps);
|
||||
|
||||
// Sort the database by employee name
|
||||
M_LET( (cmp, STRING_CTE("name")), compare_by_t )
|
||||
vector_employee_sort_fo(emps, compare_by_as_interface(cmp));
|
||||
printf("\nEmployees sorted by name are: ");
|
||||
vector_employee_out_str(stdout, emps);
|
||||
printf("\n");
|
||||
|
||||
// End
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -2,19 +2,18 @@
|
||||
#include "m-tuple.h"
|
||||
#include "m-array.h"
|
||||
|
||||
// Serial json is not supported for standard types if not C11
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
|
||||
// Let's define a 'person' composed of several fields.
|
||||
TUPLE_DEF2(person,
|
||||
(surname, string_t),
|
||||
(age, int),
|
||||
(present, bool)
|
||||
)
|
||||
// Register the oplist of this tuple globaly
|
||||
#define M_OPL_person_t() TUPLE_OPLIST(person, M_DEFAULT_OPLIST, STRING_OPLIST, M_DEFAULT_OPLIST )
|
||||
|
||||
// Let's define an array of person
|
||||
ARRAY_DEF(base, person_t)
|
||||
// Register the oplist of this array globaly
|
||||
#define M_OPL_base_t() ARRAY_OPLIST(base, M_OPL_person_t())
|
||||
|
||||
// Let's read an array of person from the given JSON file
|
||||
@@ -29,6 +28,7 @@ static void read(base_t base, const char filename[])
|
||||
fprintf(stderr, "ERROR: Cannot open file '%s'.\n", filename);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
// Initialize the serializer with the file
|
||||
m_serial_json_read_init(in, f);
|
||||
// Read the array
|
||||
@@ -44,21 +44,17 @@ static void read(base_t base, const char filename[])
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Let's have base as a base_t
|
||||
M_LET(base, base_t) {
|
||||
read(base, "ex-json01.json");
|
||||
// Read the JSON file and fill-in base
|
||||
read(base, "ex11-json01.json");
|
||||
// Print the contents of base:
|
||||
printf ("List of presents:\n");
|
||||
for M_EACH(el, base, base_t) {
|
||||
if ((*el)->present) {
|
||||
printf("%s\n", string_get_cstr((*el)->surname));
|
||||
}
|
||||
if ((*el)->present) {
|
||||
printf("%s\n", string_get_cstr((*el)->surname));
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void)
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
File renamed without changes.
@@ -1,5 +1,3 @@
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m-array.h"
|
||||
@@ -7,12 +5,15 @@
|
||||
#include "m-dict.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Let's define a tuple composed of (offset, value) and register it
|
||||
TUPLE_DEF2(symbol, (offset, long), (value, long))
|
||||
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
// Let's define an array of such tuple and register it
|
||||
ARRAY_DEF(array_symbol, symbol_t)
|
||||
#define M_OPL_array_symbol_t() ARRAY_OPLIST(array_symbol, M_OPL_symbol_t())
|
||||
|
||||
// Let's define a dictionnary associating a string_t to such an array and register it
|
||||
DICT_DEF2(sections, string_t, array_symbol_t)
|
||||
#define M_OPL_sections_t() DICT_OPLIST(sections, STRING_OPLIST, M_OPL_array_symbol_t())
|
||||
|
||||
@@ -20,13 +21,21 @@ int main(int argc, const char *argv[])
|
||||
{
|
||||
if (argc < 2) abort();
|
||||
FILE *f = fopen(argv[1], "rt");
|
||||
if (!f) abort();
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s\n", argv[1]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Create & initialize sc as sections_t
|
||||
M_LET(sc, sections_t) {
|
||||
// Read the section from the FILE
|
||||
sections_in_str(sc, f);
|
||||
// Get the section named .text
|
||||
array_symbol_t *a = sections_get(sc, STRING_CTE(".text"));
|
||||
if (a == NULL) {
|
||||
printf("There is no .text section.");
|
||||
} else {
|
||||
// Print its content
|
||||
printf("Section .text is :");
|
||||
array_symbol_out_str(stdout, *a);
|
||||
printf("\n");
|
||||
@@ -34,7 +43,3 @@ int main(int argc, const char *argv[])
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void) { return 0; }
|
||||
#endif
|
||||
+82
-56
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin stdatomic wrapper for C++ compatibility
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -26,14 +26,17 @@
|
||||
#define MSTARLIB_ATOMIC_H
|
||||
|
||||
/* NOTE: Due to the C++ not having recognized stdatomic.h officialy,
|
||||
it is hard to use this header directly with a C++ compiler like
|
||||
g++ or MSVC.
|
||||
(See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932 ).
|
||||
clang has no issue with this header.
|
||||
GCC 4.9 doesn't have a working implementation of 'atomic'
|
||||
it is hard to use this header directly with a C++ compiler.
|
||||
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932
|
||||
clang++ has no issue with this header but if someone includes
|
||||
atomic from C++, there is incompatibility between atomic & stdatomic.
|
||||
Moreover some compilers lack a working stdatomic header.
|
||||
GCC 4.9 doesn't have a working implementation of 'atomic'.
|
||||
APPLE Clang defines __GNUC__ to be only 4 despite having full support
|
||||
for atomic.
|
||||
*/
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L \
|
||||
&& !defined(__clang__) && !(defined(__GNUC__) && __GNUC__ < 5)
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L \
|
||||
&& !(defined(__GNUC__) && __GNUC__ < 5 && !defined(__APPLE__))
|
||||
|
||||
/* NOTE: This is what the stdatomic.h header shall do in C++ mode. */
|
||||
#include <atomic>
|
||||
@@ -96,20 +99,38 @@ using std::memory_order_release;
|
||||
using std::memory_order_acq_rel;
|
||||
using std::memory_order_seq_cst;
|
||||
|
||||
/* CLANG provides a warning on defining _Atomic as it sees it
|
||||
* as a reserved system macro. It is true. However, the goal of this
|
||||
* header is to provide stdatomic semantic, so it needs to define
|
||||
* _Atomic macro.
|
||||
*
|
||||
* So, this warning has to be ignored.
|
||||
*
|
||||
* It cannot use M_BEGIN_PROTECTED_CODE as this header is normally
|
||||
* independent of m-core.h
|
||||
*/
|
||||
#if defined(__clang__) && __clang_major__ >= 4
|
||||
_Pragma("clang diagnostic push")
|
||||
_Pragma("clang diagnostic ignored \"-Wreserved-id-macro\"")
|
||||
#endif
|
||||
|
||||
#define _Atomic(T) std::atomic< T >
|
||||
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
|
||||
|| ( defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|
||||
|| (defined(__clang__) && __clang_major__ >= 4) \
|
||||
|| (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1800)
|
||||
#if defined(__clang__) && __clang_major__ >= 4
|
||||
_Pragma("clang diagnostic pop")
|
||||
#endif
|
||||
|
||||
/* C11 has mandatory working stdatomic
|
||||
STDATOMIC doesn't work with C++ except for clang
|
||||
/* C11 with working stdatomic
|
||||
STDATOMIC doesn't work with C++ except for clang but is incompatible with atomic.
|
||||
GCC < 4.9 doesn't provide a compliant stdatomic.h
|
||||
CLANG 3.5 has issues with GCC's stdatomic.h
|
||||
and doesn't provide its own stdatomic.h
|
||||
CLANG 3.5 has issues with GCC's stdatomic.h and doesn't provide its own
|
||||
ICC < 18 doesn't provide a compliant stdatomic.h
|
||||
*/
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) ) \
|
||||
|| (defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|
||||
|| (defined(__clang__) && (__clang_major__ * 100 + __clang_minor__) >= 308) \
|
||||
|| (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1800)
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
/* MSYS2 has a conflict between cdefs.h which defines a _Atomic macro (if not C11)
|
||||
@@ -124,16 +145,19 @@ using std::memory_order_seq_cst;
|
||||
# undef _Atomic
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/* Non working atomic.h, nor working stdatomic.h found.
|
||||
/* Non working C++ atomic header, nor working stdatomic.h found.
|
||||
Write a compatible layer using mutex as slin as possible.
|
||||
Supports only up to 64-bits atomic (sizeof long long to be more precise).
|
||||
The locks are never properly cleared and remain active until
|
||||
the end of the program.
|
||||
We also assume that the call to the atomic_* interface is "clean".
|
||||
We also assume that the call to the atomic_* interface is "macro clean".
|
||||
*/
|
||||
#else
|
||||
|
||||
#include "m-mutex.h"
|
||||
#include "m-core.h"
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* _Atomic qualifier for a type (emulation).
|
||||
The structure is quite large:
|
||||
@@ -143,12 +167,12 @@ using std::memory_order_seq_cst;
|
||||
_lock : the mutex lock.
|
||||
Support up to sizeof (long long) type.
|
||||
*/
|
||||
#define _Atomic(T) \
|
||||
struct { \
|
||||
T volatile _val; \
|
||||
T _zero; \
|
||||
T _previous; \
|
||||
m_mutex_t _lock; \
|
||||
#define _Atomic(T) \
|
||||
struct { \
|
||||
T volatile _val; \
|
||||
T _zero; \
|
||||
T _previous; \
|
||||
m_mutex_t _lock; \
|
||||
}
|
||||
|
||||
/* Define the supported memory order.
|
||||
@@ -193,8 +217,8 @@ typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
|
||||
#endif
|
||||
|
||||
/* Detect if stdint.h was included */
|
||||
#if (defined (INTMAX_C) && defined (UINTMAX_C) && !defined(__cplusplus)) || \
|
||||
defined (_STDINT_H) || defined (_STDINT_H_) || defined (_STDINT) || \
|
||||
#if (defined (INTMAX_C) && defined (UINTMAX_C) && !defined(__cplusplus)) || \
|
||||
defined (_STDINT_H) || defined (_STDINT_H_) || defined (_STDINT) || \
|
||||
defined (_SYS_STDINT_H_)
|
||||
/* Define additional atomic types */
|
||||
typedef _Atomic(intmax_t) atomic_intmax_t;
|
||||
@@ -217,11 +241,11 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
The trick is computing _val - _zero within the lock, then
|
||||
returns retvalue + _zero after the release of the lock.
|
||||
*/
|
||||
#define atomic_fetch_op(ptr, val, op) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
(ptr)->_val op (val), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (ptr)->_previous-(ptr)->_zero)+(ptr)->_zero)
|
||||
#define atomic_fetch_op(ptr, val, op) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
(ptr)->_val op (val), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (long long)((ptr)->_previous-(ptr)->_zero))+(ptr)->_zero)
|
||||
|
||||
/* Perform an atomic add (EMULATION) */
|
||||
#define atomic_fetch_add(ptr, val) atomic_fetch_op(ptr, val, +=)
|
||||
@@ -240,49 +264,49 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
#define ATOMIC_VAR_INIT(val) { val, 0, 0, M_MUTEXI_INIT_VALUE }
|
||||
|
||||
/* Initialize an atomic variable */
|
||||
#define atomic_init(ptr, val) \
|
||||
#define atomic_init(ptr, val) \
|
||||
(m_mutex_init((ptr)->_lock), (ptr)->_val = val, (ptr)->_zero = 0)
|
||||
|
||||
/* (INTERNAL) Load an atomic variable within a lock
|
||||
(needed for variable greater than CPU atomic size) */
|
||||
#define atomic_load_lock(ptr) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (ptr)->_previous-(ptr)->_zero)+(ptr)->_zero)
|
||||
#define atomic_load_lock(ptr) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (long long) ((ptr)->_previous-(ptr)->_zero))+(ptr)->_zero)
|
||||
|
||||
/* (INTERNAL) Store an atomic variable within a lock
|
||||
(needed for variable greater than CPU atomic size) */
|
||||
#define atomic_store_lock(ptr, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_val = (val), \
|
||||
#define atomic_store_lock(ptr, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_val = (val), \
|
||||
m_mutex_unlock((ptr)->_lock))
|
||||
|
||||
/* Atomic load of a variable (EMULATION)
|
||||
If the atomic type size is not greater than the CPU atomic size,
|
||||
we can perform a direct read of the variable (much faster) */
|
||||
#define atomic_load(ptr) \
|
||||
( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE \
|
||||
? (ptr)->_val \
|
||||
#define atomic_load(ptr) \
|
||||
( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE \
|
||||
? (ptr)->_val \
|
||||
: atomic_load_lock(ptr))
|
||||
|
||||
/* Atomic store of a variable (EMULATION)
|
||||
If the atomic type size is not greater than the CPU atomic size,
|
||||
we can perform a direct write of the variable (much faster) */
|
||||
#define atomic_store(ptr, val) do { \
|
||||
if ( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE) { \
|
||||
(ptr)->_val = (val); \
|
||||
} else { \
|
||||
long long _offset = (val) - (ptr)->_zero; \
|
||||
atomic_store_lock(ptr, (ptr)->_zero + _offset); \
|
||||
} \
|
||||
#define atomic_store(ptr, val) do { \
|
||||
if ( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE) { \
|
||||
(ptr)->_val = (val); \
|
||||
} else { \
|
||||
long long _offset = (long long) ((val) - (ptr)->_zero); \
|
||||
atomic_store_lock(ptr, (ptr)->_zero + _offset); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Perform a CAS (Compare and swap) operation (EMULATION) */
|
||||
#define atomic_compare_exchange_strong(ptr, exp, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, \
|
||||
(ptr)->_val == *(exp) \
|
||||
? ((ptr)->_val = (val), true) \
|
||||
#define atomic_compare_exchange_strong(ptr, exp, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, \
|
||||
(ptr)->_val == *(exp) \
|
||||
? ((ptr)->_val = (val), true) \
|
||||
: (*(exp) = (ptr)->_val, false)))
|
||||
|
||||
|
||||
@@ -304,6 +328,8 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
|
||||
/* TODO: Missing atomic_flag. Problem: it is supposed to be lock free! */
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+200
-114
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - BITSET module
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -30,10 +30,12 @@
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
// Define the limb of a bitset
|
||||
typedef uint64_t bitset_limb;
|
||||
// And its size
|
||||
#define BITSET_LIMB_BIT (sizeof(bitset_limb) * CHAR_BIT)
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
// Define the basic limb of a bitset
|
||||
typedef uint64_t bitset_limb_ct;
|
||||
// And its size in bits
|
||||
#define BITSET_LIMB_BIT (sizeof(bitset_limb_ct) * CHAR_BIT)
|
||||
|
||||
// bitset grow policy. n is limb size
|
||||
#define BITSETI_INC_ALLOC_SIZE(n) ((n) < 4 ? 4 : (n) * 2)
|
||||
@@ -45,43 +47,51 @@ typedef uint64_t bitset_limb;
|
||||
#define BITSETI_FROM_ALLOC(n) ((n) * BITSET_LIMB_BIT)
|
||||
|
||||
// Contract of a bitset
|
||||
#define BITSETI_CONTRACT(t) do { \
|
||||
assert (t != NULL); \
|
||||
assert (t->size <= BITSETI_FROM_ALLOC (t->alloc)); \
|
||||
assert (t->alloc <= ((size_t)-1) / BITSET_LIMB_BIT); \
|
||||
assert (t->size < ((size_t)-1) - BITSET_LIMB_BIT); \
|
||||
assert (t->size == 0 || t->ptr != NULL); \
|
||||
#define BITSETI_CONTRACT(t) do { \
|
||||
M_ASSERT (t != NULL); \
|
||||
M_ASSERT (t->size <= BITSETI_FROM_ALLOC (t->alloc)); \
|
||||
M_ASSERT (t->alloc <= ((size_t)-1) / BITSET_LIMB_BIT); \
|
||||
M_ASSERT (t->size < ((size_t)-1) - BITSET_LIMB_BIT); \
|
||||
M_ASSERT (t->size == 0 || t->ptr != NULL); \
|
||||
M_ASSERT (t->alloc == 0 || t->ptr != NULL); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/********************************** EXTERNAL ************************************/
|
||||
|
||||
/* Define a type of variable 'bits' or array of packed booleans */
|
||||
typedef struct bitset_s {
|
||||
size_t size; // Size is the number of bits
|
||||
size_t alloc; // Alloc is the number of allocated limbs
|
||||
bitset_limb *ptr; // Pointer to the allocated limbs
|
||||
bitset_limb_ct *ptr; // Pointer to the allocated limbs
|
||||
} bitset_t[1];
|
||||
|
||||
/* Pointer to a bitset_t */
|
||||
typedef struct bitset_s *bitset_ptr;
|
||||
|
||||
/* Constant Pointer to a bitset_t */
|
||||
typedef const struct bitset_s *bitset_srcptr;
|
||||
|
||||
/* Iterator on a bitset */
|
||||
typedef struct bitset_it_s {
|
||||
size_t index; // index to the array of bit
|
||||
bool value; // value used for _ref & _cref to store the value
|
||||
struct bitset_s *set; // the associated bitset
|
||||
} bitset_it_t[1];
|
||||
|
||||
/* Initialize a bitset (CONSTRUCTOR) */
|
||||
static inline void
|
||||
bitset_init(bitset_t t)
|
||||
{
|
||||
assert (t != NULL);
|
||||
assert (M_POWEROF2_P(BITSET_LIMB_BIT));
|
||||
M_ASSERT (t != NULL);
|
||||
M_STATIC_ASSERT (M_POWEROF2_P(BITSET_LIMB_BIT), MLIB_INTERNAL, "M*LIB: BITSET LIMB shall be a power of 2.");
|
||||
t->size = 0;
|
||||
t->alloc = 0;
|
||||
t->ptr = NULL;
|
||||
BITSETI_CONTRACT(t);
|
||||
}
|
||||
|
||||
/* Clean a bitset */
|
||||
static inline void
|
||||
bitset_clean(bitset_t t)
|
||||
{
|
||||
@@ -89,16 +99,20 @@ bitset_clean(bitset_t t)
|
||||
t->size = 0;
|
||||
}
|
||||
|
||||
/* Clear a bitset (DESTRUCTOR) */
|
||||
static inline void
|
||||
bitset_clear(bitset_t t)
|
||||
{
|
||||
bitset_clean(t);
|
||||
M_MEMORY_FREE(t->ptr);
|
||||
// This is not really needed, but is safer
|
||||
t->alloc = 0;
|
||||
// This representation is invalid and will be detected by the contract.
|
||||
// A C compiler should be able to optimize out theses initializations.
|
||||
t->alloc = 1;
|
||||
t->ptr = NULL;
|
||||
}
|
||||
|
||||
/* Set a bitset to another one */
|
||||
static inline void
|
||||
bitset_set(bitset_t d, const bitset_t s)
|
||||
{
|
||||
@@ -107,7 +121,7 @@ bitset_set(bitset_t d, const bitset_t s)
|
||||
if (M_UNLIKELY (d == s)) return;
|
||||
const size_t needAlloc = BITSETI_TO_ALLOC (s->size);
|
||||
if (s->size > BITSETI_FROM_ALLOC (d->alloc)) {
|
||||
bitset_limb *ptr = M_MEMORY_REALLOC (bitset_limb, d->ptr, needAlloc);
|
||||
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, d->ptr, needAlloc);
|
||||
if (M_UNLIKELY (ptr == NULL)) {
|
||||
M_MEMORY_FULL(needAlloc);
|
||||
return ;
|
||||
@@ -115,19 +129,21 @@ bitset_set(bitset_t d, const bitset_t s)
|
||||
d->ptr = ptr;
|
||||
d->alloc = needAlloc;
|
||||
}
|
||||
memcpy (d->ptr, s->ptr, needAlloc * sizeof(bitset_limb) );
|
||||
memcpy (d->ptr, s->ptr, needAlloc * sizeof(bitset_limb_ct) );
|
||||
d->size = s->size;
|
||||
BITSETI_CONTRACT(d);
|
||||
}
|
||||
|
||||
/* Initialize & set a bitset to another one (CONSTRUCTOR) */
|
||||
static inline void
|
||||
bitset_init_set(bitset_t d, const bitset_t s)
|
||||
{
|
||||
assert (d != s);
|
||||
M_ASSERT (d != s);
|
||||
bitset_init(d);
|
||||
bitset_set(d, s);
|
||||
}
|
||||
|
||||
/* Initialize & move a bitset (CONSTRUCTOR) from another one (DESTRUCTOR) */
|
||||
static inline void
|
||||
bitset_init_move(bitset_t d, bitset_t s)
|
||||
{
|
||||
@@ -140,6 +156,7 @@ bitset_init_move(bitset_t d, bitset_t s)
|
||||
BITSETI_CONTRACT(d);
|
||||
}
|
||||
|
||||
/* Move a bitset from another one (DESTRUCTOR) */
|
||||
static inline void
|
||||
bitset_move(bitset_t d, bitset_t s)
|
||||
{
|
||||
@@ -147,46 +164,52 @@ bitset_move(bitset_t d, bitset_t s)
|
||||
bitset_init_move (d, s);
|
||||
}
|
||||
|
||||
/* Set the bit 'i' in the bitset to the value 'x' */
|
||||
static inline void
|
||||
bitset_set_at(bitset_t v, size_t i, bool x)
|
||||
{
|
||||
BITSETI_CONTRACT(v);
|
||||
assert (i < v->size && v->ptr != NULL);
|
||||
M_ASSERT (v->ptr != NULL);
|
||||
M_ASSERT_INDEX(i, v->size);
|
||||
const size_t offset = i / BITSET_LIMB_BIT;
|
||||
const size_t index = i % BITSET_LIMB_BIT;
|
||||
// This is a branchless version as x can only be 0 or 1 with only one variable shift.
|
||||
const bitset_limb mask = ((bitset_limb)1)<<index;
|
||||
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (-(bitset_limb)x));
|
||||
const bitset_limb_ct mask = ((bitset_limb_ct)1)<<index;
|
||||
v->ptr[offset] = (v->ptr[offset] & ~mask) | (mask & (0-(bitset_limb_ct)x));
|
||||
BITSETI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Flip the bit 'i' in the bitset */
|
||||
static inline void
|
||||
bitset_flip_at(bitset_t v, size_t i)
|
||||
{
|
||||
BITSETI_CONTRACT(v);
|
||||
assert (i < v->size && v->ptr != NULL);
|
||||
M_ASSERT (v->ptr != NULL);
|
||||
M_ASSERT_INDEX(i, v->size);
|
||||
size_t offset = i / BITSET_LIMB_BIT;
|
||||
size_t index = i % BITSET_LIMB_BIT;
|
||||
v->ptr[offset] ^= ((bitset_limb)1)<<index;
|
||||
v->ptr[offset] ^= ((bitset_limb_ct)1)<<index;
|
||||
BITSETI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Push back the boolean 'x' in the bitset (increasing the bitset) */
|
||||
static inline void
|
||||
bitset_push_back (bitset_t v, bool x)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
if (v->size >= BITSETI_FROM_ALLOC (v->alloc)) {
|
||||
// Compute the needed allocation.
|
||||
const size_t needAlloc = BITSETI_INC_ALLOC_SIZE(v->alloc);
|
||||
// Check for integer overflow
|
||||
if (M_UNLIKELY (needAlloc <= v->alloc)) {
|
||||
M_MEMORY_FULL(needAlloc * sizeof(bitset_limb));
|
||||
M_MEMORY_FULL(needAlloc * sizeof(bitset_limb_ct));
|
||||
return;
|
||||
}
|
||||
// Alloc memory
|
||||
bitset_limb *ptr = M_MEMORY_REALLOC (bitset_limb, v->ptr, needAlloc);
|
||||
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, v->ptr, needAlloc);
|
||||
// Check if success
|
||||
if (M_UNLIKELY (ptr == NULL) ) {
|
||||
M_MEMORY_FULL(needAlloc * sizeof(bitset_limb));
|
||||
M_MEMORY_FULL(needAlloc * sizeof(bitset_limb_ct));
|
||||
return;
|
||||
}
|
||||
// Clear allocated memory
|
||||
@@ -196,11 +219,12 @@ bitset_push_back (bitset_t v, bool x)
|
||||
v->ptr = ptr;
|
||||
v->alloc = needAlloc;
|
||||
}
|
||||
assert(v->ptr != NULL);
|
||||
M_ASSERT(v->ptr != NULL);
|
||||
v->size ++;
|
||||
bitset_set_at (v, v->size - 1, x);
|
||||
}
|
||||
|
||||
/* Resize the bitset to have exactly 'size' bits */
|
||||
static inline void
|
||||
bitset_resize (bitset_t v, size_t size)
|
||||
{
|
||||
@@ -210,18 +234,19 @@ bitset_resize (bitset_t v, size_t size)
|
||||
M_MEMORY_FULL((size_t) -1);
|
||||
return;
|
||||
}
|
||||
// Compute the needed allocation.
|
||||
size_t newAlloc = BITSETI_TO_ALLOC (size);
|
||||
if (newAlloc > v->alloc) {
|
||||
bitset_limb *ptr = M_MEMORY_REALLOC (bitset_limb, v->ptr, newAlloc);
|
||||
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, v->ptr, newAlloc);
|
||||
if (M_UNLIKELY (ptr == NULL) ) {
|
||||
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb));
|
||||
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb_ct));
|
||||
return;
|
||||
}
|
||||
v->ptr = ptr;
|
||||
v->alloc = newAlloc;
|
||||
}
|
||||
//FIXME: Last bit are not cleared. if new size is lower than org size
|
||||
//TODO: More efficient!
|
||||
//FIXME: Last bit are not cleared if new size is lower than org size. Needed?
|
||||
//TODO: Implement a more efficient version when needed.
|
||||
size_t i = v->size;
|
||||
v->size = size;
|
||||
for( ; i < size; i++)
|
||||
@@ -229,6 +254,7 @@ bitset_resize (bitset_t v, size_t size)
|
||||
BITSETI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Reserve allocation in the bitset to accomodate at least 'size' bits without reallocation */
|
||||
static inline void
|
||||
bitset_reserve (bitset_t v, size_t size)
|
||||
{
|
||||
@@ -243,9 +269,9 @@ bitset_reserve (bitset_t v, size_t size)
|
||||
v->size = v->alloc = 0;
|
||||
v->ptr = NULL;
|
||||
} else {
|
||||
bitset_limb *ptr = M_MEMORY_REALLOC (bitset_limb, v->ptr, newAlloc);
|
||||
bitset_limb_ct *ptr = M_MEMORY_REALLOC (bitset_limb_ct, v->ptr, newAlloc);
|
||||
if (M_UNLIKELY (ptr == NULL) ) {
|
||||
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb));
|
||||
M_MEMORY_FULL(newAlloc * sizeof(bitset_limb_ct));
|
||||
return;
|
||||
}
|
||||
v->ptr = ptr;
|
||||
@@ -254,24 +280,30 @@ bitset_reserve (bitset_t v, size_t size)
|
||||
BITSETI_CONTRACT (v);
|
||||
}
|
||||
|
||||
// NOTE: Interface is a little bit different:
|
||||
// It doesn't return a pointer to the data, but the data itself.
|
||||
/* Return the value of the boolean at index 'i'.
|
||||
* NOTE: Interface is a little bit different:
|
||||
* It doesn't return a pointer to the data, but the data itself.
|
||||
*/
|
||||
static inline bool
|
||||
bitset_get(const bitset_t v, size_t i)
|
||||
{
|
||||
BITSETI_CONTRACT(v);
|
||||
assert (v->ptr != NULL && i < v->size);
|
||||
M_ASSERT (v->ptr != NULL);
|
||||
M_ASSERT_INDEX(i, v->size);
|
||||
size_t offset = i / BITSET_LIMB_BIT;
|
||||
size_t index = i % BITSET_LIMB_BIT;
|
||||
return ( v->ptr[offset] & (((bitset_limb)1) << index) ) != 0;
|
||||
return ( v->ptr[offset] & (((bitset_limb_ct)1) << index) ) != 0;
|
||||
}
|
||||
|
||||
/* bitset_cget is the exact same service than bitset_get */
|
||||
#define bitset_cget bitset_get
|
||||
|
||||
/* Pop back the last bit in the bitset */
|
||||
static inline void
|
||||
bitset_pop_back(bool *dest, bitset_t v)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
assert (v->size > 0);
|
||||
M_ASSERT_INDEX (0, v->size);
|
||||
if (dest) {
|
||||
*dest = bitset_get (v, v->size - 1);
|
||||
}
|
||||
@@ -280,22 +312,25 @@ bitset_pop_back(bool *dest, bitset_t v)
|
||||
BITSETI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Return the front bit value in the bitset */
|
||||
static inline bool
|
||||
bitset_front(bitset_t v)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
assert(v->size > 0);
|
||||
M_ASSERT_INDEX (0, v->size);
|
||||
return bitset_get(v, 0);
|
||||
}
|
||||
|
||||
/* Return the back bit value in the bitset */
|
||||
static inline bool
|
||||
bitset_back(bitset_t v)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
assert(v->size > 0);
|
||||
M_ASSERT_INDEX (0, v->size);
|
||||
return bitset_get(v, v->size-1);
|
||||
}
|
||||
|
||||
/* Test if the bitset is empty (no bits stored)*/
|
||||
static inline bool
|
||||
bitset_empty_p(bitset_t v)
|
||||
{
|
||||
@@ -303,6 +338,7 @@ bitset_empty_p(bitset_t v)
|
||||
return v->size == 0;
|
||||
}
|
||||
|
||||
/* Return the number of bits of the bitset */
|
||||
static inline size_t
|
||||
bitset_size(bitset_t v)
|
||||
{
|
||||
@@ -310,6 +346,7 @@ bitset_size(bitset_t v)
|
||||
return v->size;
|
||||
}
|
||||
|
||||
/* Return the capacity in limbs of the bitset */
|
||||
static inline size_t
|
||||
bitset_capacity(bitset_t v)
|
||||
{
|
||||
@@ -317,11 +354,14 @@ bitset_capacity(bitset_t v)
|
||||
return BITSETI_FROM_ALLOC (v->alloc);
|
||||
}
|
||||
|
||||
/* Swap the bit at index i and j of the bitset */
|
||||
static inline void
|
||||
bitset_swap_at (bitset_t v, size_t i, size_t j)
|
||||
{
|
||||
BITSETI_CONTRACT (v);
|
||||
assert (i < v->size && j < v->size);
|
||||
M_ASSERT_INDEX(i, v->size);
|
||||
M_ASSERT_INDEX(j, v->size);
|
||||
|
||||
bool i_val = bitset_get(v, i);
|
||||
bool j_val = bitset_get(v, j);
|
||||
bitset_set_at (v, i, j_val);
|
||||
@@ -329,6 +369,7 @@ bitset_swap_at (bitset_t v, size_t i, size_t j)
|
||||
BITSETI_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Swap the bitsets */
|
||||
static inline void
|
||||
bitset_swap (bitset_t v1, bitset_t v2)
|
||||
{
|
||||
@@ -336,59 +377,74 @@ bitset_swap (bitset_t v1, bitset_t v2)
|
||||
BITSETI_CONTRACT (v2);
|
||||
M_SWAP (size_t, v1->size, v2->size);
|
||||
M_SWAP (size_t, v1->alloc, v2->alloc);
|
||||
M_SWAP (bitset_limb *, v1->ptr, v2->ptr);
|
||||
M_SWAP (bitset_limb_ct *, v1->ptr, v2->ptr);
|
||||
}
|
||||
|
||||
static inline bitset_limb
|
||||
bitseti_lshift(bitset_limb ptr[], size_t n, bitset_limb carry)
|
||||
/* (INTERNAL) Left shift of the bitset (ptr+size) by 1 bit,
|
||||
* integrating the carry in the lowest position.
|
||||
* Return the new carry.
|
||||
*/
|
||||
static inline bitset_limb_ct
|
||||
bitseti_lshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
bitset_limb v = ptr[i];
|
||||
bitset_limb_ct v = ptr[i];
|
||||
ptr[i] = (v << 1) | carry;
|
||||
carry = (v >> (BITSET_LIMB_BIT-1) );
|
||||
}
|
||||
return carry;
|
||||
}
|
||||
|
||||
static inline bitset_limb
|
||||
bitseti_rshift(bitset_limb ptr[], size_t n, bitset_limb carry)
|
||||
/* (INTERNAL) Right shift of the bitset (ptr+size) by 1 bit,
|
||||
* integrating the carry in the lowest position.
|
||||
* Return the new carry.
|
||||
*/
|
||||
static inline bitset_limb_ct
|
||||
bitseti_rshift(bitset_limb_ct ptr[], size_t n, bitset_limb_ct carry)
|
||||
{
|
||||
for(size_t i = n - 1; i < n; i--) {
|
||||
bitset_limb v = ptr[i];
|
||||
bitset_limb_ct v = ptr[i];
|
||||
v = (v >> 1) | (carry << (BITSET_LIMB_BIT-1) );
|
||||
carry = v & 1;
|
||||
}
|
||||
return carry;
|
||||
}
|
||||
|
||||
/* Insert a new bit at position 'key' of value 'value' in the bitset */
|
||||
static inline void
|
||||
bitset_push_at(bitset_t set, size_t key, bool value)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
// First push another value to extend the array to the right size
|
||||
bitset_push_back(set, false);
|
||||
assert (set->ptr != NULL && key < set->size);
|
||||
M_ASSERT (set->ptr != NULL);
|
||||
M_ASSERT_INDEX(key, set->size);
|
||||
|
||||
// Then shift it
|
||||
size_t offset = key / BITSET_LIMB_BIT;
|
||||
size_t index = key % BITSET_LIMB_BIT;
|
||||
bitset_limb v = set->ptr[offset];
|
||||
bitset_limb mask = (((bitset_limb)1)<<index)-1;
|
||||
bitset_limb carry = (v >> (BITSET_LIMB_BIT-1) );
|
||||
v = (v & mask) | (value << index) | ((v & ~mask) << 1);
|
||||
bitset_limb_ct v = set->ptr[offset];
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1)<<index)-1;
|
||||
bitset_limb_ct carry = (v >> (BITSET_LIMB_BIT-1) );
|
||||
v = (v & mask) | ((unsigned int) value << index) | ((v & ~mask) << 1);
|
||||
set->ptr[offset] = v;
|
||||
size_t size = (set->size + BITSET_LIMB_BIT - 1) / BITSET_LIMB_BIT;
|
||||
assert (size >= offset + 1);
|
||||
M_ASSERT (size >= offset + 1);
|
||||
v = bitseti_lshift(&set->ptr[offset+1], size - offset - 1, carry);
|
||||
// v is unused.
|
||||
(void) v;
|
||||
BITSETI_CONTRACT (set);
|
||||
}
|
||||
|
||||
/* Pop a new bit at position 'key' in the bitset
|
||||
* and return in *dest its value if *dest exists */
|
||||
static inline void
|
||||
bitset_pop_at(bool *dest, bitset_t set, size_t key)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
assert (set->ptr != NULL && key < set->size);
|
||||
M_ASSERT (set->ptr != NULL);
|
||||
M_ASSERT_INDEX(key, set->size);
|
||||
|
||||
if (dest) {
|
||||
*dest = bitset_get (set, key);
|
||||
}
|
||||
@@ -396,10 +452,10 @@ bitset_pop_at(bool *dest, bitset_t set, size_t key)
|
||||
size_t offset = key / BITSET_LIMB_BIT;
|
||||
size_t index = key % BITSET_LIMB_BIT;
|
||||
size_t size = (set->size + BITSET_LIMB_BIT - 1) / BITSET_LIMB_BIT;
|
||||
bitset_limb v, mask, carry;
|
||||
bitset_limb_ct v, mask, carry;
|
||||
carry = bitseti_rshift(&set->ptr[offset+1], size - offset - 1, false);
|
||||
v = set->ptr[offset];
|
||||
mask = (((bitset_limb)1)<<index)-1;
|
||||
mask = (((bitset_limb_ct)1)<<index)-1;
|
||||
v = (v & mask) | ((v>>1) & ~mask) | (carry << (BITSET_LIMB_BIT-1)) ;
|
||||
set->ptr[offset] = v;
|
||||
// Decrease size
|
||||
@@ -407,6 +463,7 @@ bitset_pop_at(bool *dest, bitset_t set, size_t key)
|
||||
BITSETI_CONTRACT (set);
|
||||
}
|
||||
|
||||
/* Test if two bitsets are equal */
|
||||
static inline bool
|
||||
bitset_equal_p (const bitset_t set1, const bitset_t set2)
|
||||
{
|
||||
@@ -423,13 +480,14 @@ bitset_equal_p (const bitset_t set1, const bitset_t set2)
|
||||
/* Compare the last limb if needed */
|
||||
const size_t index = set1->size % BITSET_LIMB_BIT;
|
||||
if (index > 0) {
|
||||
const bitset_limb mask = (((bitset_limb)1) << index) - 1;
|
||||
const bitset_limb_ct mask = (((bitset_limb_ct)1) << index) - 1;
|
||||
if ((set1->ptr[limbSize] & mask) != (set2->ptr[limbSize] & mask))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Initialize an iterator to the first bit of the biset */
|
||||
static inline void
|
||||
bitset_it(bitset_it_t it, bitset_t set)
|
||||
{
|
||||
@@ -438,14 +496,16 @@ bitset_it(bitset_it_t it, bitset_t set)
|
||||
it->set = set;
|
||||
}
|
||||
|
||||
/* Initialize an iterator to reference the same bit as the given one*/
|
||||
static inline void
|
||||
bitset_it_set(bitset_it_t it, const bitset_it_t itorg)
|
||||
{
|
||||
assert (it != NULL && itorg != NULL);
|
||||
M_ASSERT (it != NULL && itorg != NULL);
|
||||
it->index = itorg->index;
|
||||
it->set = itorg->set;
|
||||
}
|
||||
|
||||
/* Initialize an iterator to reference the last bit of the bitset*/
|
||||
static inline void
|
||||
bitset_it_last(bitset_it_t it, bitset_t set)
|
||||
{
|
||||
@@ -454,6 +514,7 @@ bitset_it_last(bitset_it_t it, bitset_t set)
|
||||
it->set = set;
|
||||
}
|
||||
|
||||
/* Initialize an iterator to reference no valid bit of the bitset*/
|
||||
static inline void
|
||||
bitset_it_end(bitset_it_t it, bitset_t set)
|
||||
{
|
||||
@@ -462,55 +523,66 @@ bitset_it_end(bitset_it_t it, bitset_t set)
|
||||
it->set = set;
|
||||
}
|
||||
|
||||
/* Test if an iterator references no valid bit of the bitset anymore */
|
||||
static inline bool
|
||||
bitset_end_p(const bitset_it_t it)
|
||||
{
|
||||
assert (it != NULL && it->set != NULL);
|
||||
M_ASSERT (it != NULL && it->set != NULL);
|
||||
return (it->index) >= (it->set->size);
|
||||
}
|
||||
|
||||
/* Test if an iterator references the last (or end) bit of the bitset anymore */
|
||||
static inline bool
|
||||
bitset_last_p(const bitset_it_t it)
|
||||
{
|
||||
assert (it != NULL && it->set != NULL);
|
||||
return (it->index) >= (it->set->size)-1;
|
||||
M_ASSERT (it != NULL && it->set != NULL);
|
||||
/* NOTE: Can not compute 'size-1' due to potential overflow
|
||||
if size is 0 */
|
||||
return (it->index+1) >= (it->set->size);
|
||||
}
|
||||
|
||||
/* Test if both iterators reference the same bit */
|
||||
static inline bool
|
||||
bitset_it_equal_p(const bitset_it_t it1, const bitset_it_t it2)
|
||||
{
|
||||
assert (it1 != NULL && it2 != NULL);
|
||||
M_ASSERT (it1 != NULL && it2 != NULL);
|
||||
return it1->index == it2->index && it1->set == it2->set;
|
||||
}
|
||||
|
||||
/* Move the iterator to the next bit */
|
||||
static inline void
|
||||
bitset_next(bitset_it_t it)
|
||||
{
|
||||
assert (it != NULL && it->set != NULL);
|
||||
M_ASSERT (it != NULL && it->set != NULL);
|
||||
it->index++;
|
||||
}
|
||||
|
||||
/* Move the iterator to the previous bit */
|
||||
static inline void
|
||||
bitset_previous(bitset_it_t it)
|
||||
{
|
||||
assert (it != NULL && it->set != NULL);
|
||||
M_ASSERT (it != NULL && it->set != NULL);
|
||||
it->index--;
|
||||
}
|
||||
|
||||
// There is no _ref as it is not possible to modify the value using the IT interface
|
||||
|
||||
/* Return a pointer to the bit referenced by the iterator
|
||||
* Only one reference is possible at a time per iterator */
|
||||
static inline const bool *
|
||||
bitset_cref(bitset_it_t it)
|
||||
{
|
||||
assert (it != NULL && it->set != NULL);
|
||||
M_ASSERT (it != NULL && it->set != NULL);
|
||||
it->value = bitset_get(it->set, it->index);
|
||||
return &it->value;
|
||||
}
|
||||
|
||||
/* Output the bitset as a formatted text in a FILE */
|
||||
static inline void
|
||||
bitset_out_str(FILE *file, const bitset_t set)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
assert(file != NULL);
|
||||
M_ASSERT(file != NULL);
|
||||
fputc ('[', file);
|
||||
for(size_t i = 0; i < set->size; i++) {
|
||||
const bool b = bitset_get (set, i);
|
||||
@@ -520,11 +592,12 @@ bitset_out_str(FILE *file, const bitset_t set)
|
||||
fputc (']', file);
|
||||
}
|
||||
|
||||
/* Input the bitset from a formatted text in a FILE */
|
||||
static inline bool
|
||||
bitset_in_str(bitset_t set, FILE *file)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
assert(file != NULL);
|
||||
M_ASSERT(file != NULL);
|
||||
bitset_clean(set);
|
||||
int c = fgetc(file);
|
||||
if (c != '[') return false;
|
||||
@@ -538,11 +611,12 @@ bitset_in_str(bitset_t set, FILE *file)
|
||||
return c == ']';
|
||||
}
|
||||
|
||||
/* Parse the bitset from a formatted text in a C string */
|
||||
static inline bool
|
||||
bitset_parse_str(bitset_t set, const char str[], const char **endptr)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
assert(str != NULL);
|
||||
M_ASSERT(str != NULL);
|
||||
bool success = false;
|
||||
bitset_clean(set);
|
||||
char c = *str++;
|
||||
@@ -561,12 +635,15 @@ bitset_parse_str(bitset_t set, const char str[], const char **endptr)
|
||||
return success;
|
||||
}
|
||||
|
||||
/* Set the bitset from a formatted text in a C string */
|
||||
static inline bool
|
||||
bitset_set_str(bitset_t dest, const char str[])
|
||||
{
|
||||
return bitset_parse_str(dest, str, NULL);
|
||||
}
|
||||
|
||||
/* Perform an AND operation between the bitsets,
|
||||
* up to the minimum size of both bitsets */
|
||||
static inline void
|
||||
bitset_and(bitset_t dest, const bitset_t src)
|
||||
{
|
||||
@@ -578,13 +655,15 @@ bitset_and(bitset_t dest, const bitset_t src)
|
||||
for(size_t i = 0 ; i < n; i++)
|
||||
dest->ptr[i] &= src->ptr[i];
|
||||
if (m) {
|
||||
bitset_limb mask = (((bitset_limb)1) << m) - 1;
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
dest->ptr[n] = (dest->ptr[n] & src->ptr[n]) & mask;
|
||||
}
|
||||
dest->size = s;
|
||||
BITSETI_CONTRACT(dest);
|
||||
}
|
||||
|
||||
/* Perform an OR operation between the bitsets,
|
||||
* up to the minimum size of both bitsets */
|
||||
static inline void
|
||||
bitset_or(bitset_t dest, const bitset_t src)
|
||||
{
|
||||
@@ -596,13 +675,15 @@ bitset_or(bitset_t dest, const bitset_t src)
|
||||
for(size_t i = 0 ; i < n; i++)
|
||||
dest->ptr[i] |= src->ptr[i];
|
||||
if (m) {
|
||||
bitset_limb mask = (((bitset_limb)1) << m) - 1;
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
dest->ptr[n] = (dest->ptr[n] | src->ptr[n]) & mask;
|
||||
}
|
||||
dest->size = s;
|
||||
BITSETI_CONTRACT(dest);
|
||||
}
|
||||
|
||||
/* Perform an XOR operation between the bitsets,
|
||||
* up to the minimum size of both bitsets */
|
||||
static inline void
|
||||
bitset_xor(bitset_t dest, const bitset_t src)
|
||||
{
|
||||
@@ -614,13 +695,14 @@ bitset_xor(bitset_t dest, const bitset_t src)
|
||||
for(size_t i = 0 ; i < n; i++)
|
||||
dest->ptr[i] ^= src->ptr[i];
|
||||
if (m) {
|
||||
bitset_limb mask = (((bitset_limb)1) << m) - 1;
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
dest->ptr[n] = (dest->ptr[n] ^ src->ptr[n]) & mask;
|
||||
}
|
||||
dest->size = s;
|
||||
BITSETI_CONTRACT(dest);
|
||||
}
|
||||
|
||||
/* Perform a NOT operation of the bitset */
|
||||
static inline void
|
||||
bitset_not(bitset_t dest)
|
||||
{
|
||||
@@ -631,13 +713,14 @@ bitset_not(bitset_t dest)
|
||||
for(size_t i = 0 ; i < n; i++)
|
||||
dest->ptr[i] = ~ (dest->ptr[i]);
|
||||
if (m) {
|
||||
bitset_limb mask = (((bitset_limb)1) << m) - 1;
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
dest->ptr[n] = (~ dest->ptr[n]) & mask;
|
||||
}
|
||||
dest->size = s;
|
||||
BITSETI_CONTRACT(dest);
|
||||
}
|
||||
|
||||
/* Copute a hash of the bitset */
|
||||
static inline size_t
|
||||
bitset_hash(const bitset_t set)
|
||||
{
|
||||
@@ -649,23 +732,24 @@ bitset_hash(const bitset_t set)
|
||||
for(size_t i = 0 ; i < n; i++)
|
||||
M_HASH_UP(hash, set->ptr[i]);
|
||||
if (m) {
|
||||
bitset_limb mask = (((bitset_limb)1) << m) - 1;
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
M_HASH_UP(hash, (set->ptr[n] & mask));
|
||||
}
|
||||
return M_HASH_FINAL (hash);
|
||||
}
|
||||
|
||||
/* Count the number of leading zero */
|
||||
static inline size_t
|
||||
bitset_clz(const bitset_t set)
|
||||
{
|
||||
BITSETI_CONTRACT(set);
|
||||
size_t s = set->size;
|
||||
assert (s > 0);
|
||||
M_ASSERT_INDEX (0, s); // TBC: Special case to handle?
|
||||
size_t n = (s -1) / BITSET_LIMB_BIT;
|
||||
size_t m = s % BITSET_LIMB_BIT;
|
||||
bitset_limb limb = set->ptr[n];
|
||||
bitset_limb_ct limb = set->ptr[n];
|
||||
if (m) {
|
||||
bitset_limb mask = (((bitset_limb)1) << m) - 1;
|
||||
bitset_limb_ct mask = (((bitset_limb_ct)1) << m) - 1;
|
||||
limb &= mask;
|
||||
} else {
|
||||
m = BITSET_LIMB_BIT;
|
||||
@@ -680,39 +764,40 @@ bitset_clz(const bitset_t set)
|
||||
return s;
|
||||
}
|
||||
|
||||
#define BITSET_OPLIST \
|
||||
(INIT(bitset_init) \
|
||||
,INIT_SET(bitset_init_set) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
,SET(bitset_set) \
|
||||
,CLEAR(bitset_clear) \
|
||||
,INIT_MOVE(bitset_init_move) \
|
||||
,MOVE(bitset_move) \
|
||||
,SWAP(bitset_swap) \
|
||||
,TYPE(bitset_t) \
|
||||
,SUBTYPE(bool) \
|
||||
,TEST_EMPTY(bitset_empty_p), \
|
||||
,GET_SIZE(bitset_size) \
|
||||
,IT_TYPE(bitset_it_t) \
|
||||
,IT_FIRST(bitset_it) \
|
||||
,IT_SET(bitset_it_set) \
|
||||
,IT_LAST(bitset_it_last) \
|
||||
,IT_END(bitset_it_end) \
|
||||
,IT_END_P(bitset_end_p) \
|
||||
,IT_LAST_P(bitset_last_p) \
|
||||
,IT_EQUAL_P(bitset_it_equal_p) \
|
||||
,IT_NEXT(bitset_next) \
|
||||
,IT_PREVIOUS(bitset_previous) \
|
||||
,IT_CREF(bitset_cref) \
|
||||
,CLEAN(bitset_clean) \
|
||||
,PUSH(bitset_push_back) \
|
||||
,POP(bitset_pop_back) \
|
||||
,HASH(bitset_hash) \
|
||||
,GET_STR(bitset_get_str) \
|
||||
,OUT_STR(bitset_out_str) \
|
||||
,PARSE_STR(bitset_parse_str) \
|
||||
,IN_STR(bitset_in_str) \
|
||||
,EQUAL(bitset_equal_p) \
|
||||
/* Oplist for a bitset */
|
||||
#define BITSET_OPLIST \
|
||||
(INIT(bitset_init) \
|
||||
,INIT_SET(bitset_init_set) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
,SET(bitset_set) \
|
||||
,CLEAR(bitset_clear) \
|
||||
,INIT_MOVE(bitset_init_move) \
|
||||
,MOVE(bitset_move) \
|
||||
,SWAP(bitset_swap) \
|
||||
,TYPE(bitset_t) \
|
||||
,SUBTYPE(bool) \
|
||||
,EMPTY_P(bitset_empty_p), \
|
||||
,GET_SIZE(bitset_size) \
|
||||
,IT_TYPE(bitset_it_t) \
|
||||
,IT_FIRST(bitset_it) \
|
||||
,IT_SET(bitset_it_set) \
|
||||
,IT_LAST(bitset_it_last) \
|
||||
,IT_END(bitset_it_end) \
|
||||
,IT_END_P(bitset_end_p) \
|
||||
,IT_LAST_P(bitset_last_p) \
|
||||
,IT_EQUAL_P(bitset_it_equal_p) \
|
||||
,IT_NEXT(bitset_next) \
|
||||
,IT_PREVIOUS(bitset_previous) \
|
||||
,IT_CREF(bitset_cref) \
|
||||
,CLEAN(bitset_clean) \
|
||||
,PUSH(bitset_push_back) \
|
||||
,POP(bitset_pop_back) \
|
||||
,HASH(bitset_hash) \
|
||||
,GET_STR(bitset_get_str) \
|
||||
,OUT_STR(bitset_out_str) \
|
||||
,PARSE_STR(bitset_parse_str) \
|
||||
,IN_STR(bitset_in_str) \
|
||||
,EQUAL(bitset_equal_p) \
|
||||
)
|
||||
|
||||
/* Register the OPLIST as a global one */
|
||||
@@ -723,15 +808,15 @@ bitset_clz(const bitset_t set)
|
||||
#endif
|
||||
|
||||
// NOTE: Define this function only if m-string has been included
|
||||
#ifndef MSTARLIB_BITSET_STRING_H
|
||||
#ifdef MSTARLIB_STRING_H
|
||||
#if !defined(MSTARLIB_BITSET_STRING_H) && defined(MSTARLIB_STRING_H)
|
||||
#define MSTARLIB_BITSET_STRING_H
|
||||
|
||||
/* Output to a string_t the formatted text representation of a bitset */
|
||||
static inline void
|
||||
bitset_get_str(string_t str, const bitset_t set, bool append)
|
||||
{
|
||||
BITSETI_CONTRACT (set);
|
||||
assert(str != NULL);
|
||||
M_ASSERT(str != NULL);
|
||||
(append ? string_cat_str : string_set_str) (str, "[");
|
||||
for(size_t i = 0; i < set->size; i++) {
|
||||
const bool b = bitset_get (set, i);
|
||||
@@ -741,5 +826,6 @@ bitset_get_str(string_t str, const bitset_t set, bool append)
|
||||
string_push_back (str, ']');
|
||||
}
|
||||
|
||||
#endif
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
+1314
-1228
File diff suppressed because it is too large.
Load diff
+993
-911
File diff suppressed because it is too large.
Load diff
+471
-466
File diff suppressed because it is too large.
Load diff
+781
-685
File diff suppressed because it is too large.
Load diff
+240
-183
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Function Object module
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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,21 +32,34 @@
|
||||
* USAGE:
|
||||
* FUNC_OBJ_ITF_DEF(name, retcode type, type of param1, type of param 2, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_ITF_DEF(name, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, __VA_ARGS__)
|
||||
#define FUNC_OBJ_ITF_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, M_C(name, _t), __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define a function object interface of name 'name'
|
||||
* as the given name name_t
|
||||
* USAGE:
|
||||
* FUNC_OBJ_ITF_DEF_AS(name, name_t, retcode type, type of param1, type of param 2, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_ITF_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, name_t, __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define a function object instance of name 'name' based on the interface 'base_name'
|
||||
* The function is defined as per :
|
||||
* The function is defined using:
|
||||
* - the prototype of the inherited interface
|
||||
* - the parameters of the function are named as per the list param_list
|
||||
* - the core of the function shall be defined in callback_core
|
||||
* - the core of the function given in 'callback_core'
|
||||
* - optionals member attributes of the function object can be defined after the core
|
||||
* (just like for tuple & variant: (name, type [, oplist])
|
||||
*
|
||||
* In the core of the function, parameters are accessible just like a normal like
|
||||
* and a special variable 'self' which refers to the function object itself
|
||||
* can be used to access member attributes.
|
||||
* In the core of the function, parameters are accessible just like a normal function.
|
||||
* A special variable named 'self' that refers to the function object itself
|
||||
* can be used to access member attributes using the syntax self->param1, ...
|
||||
*
|
||||
* There shall be **exactly** the same number of parameters in 'param_list' than
|
||||
* the number of parameters of the interface 'base_name'
|
||||
@@ -54,15 +67,30 @@
|
||||
* USAGE/EXAMPLE:
|
||||
* FUNC_OBJ_INS_DEF(name, base_name, (param1, ...), { return param1 * self->member1 }, (member1, int), ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_DEF(name, base_name, param_list, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, base_name, param_list, __VA_ARGS__)
|
||||
#define FUNC_OBJ_INS_DEF(name, base_name, param_list, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, M_C(name, _t), base_name, param_list, __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define a function object instance of name 'name' based on the interface 'base_name'
|
||||
* as the given name name_t.
|
||||
* See FUNC_OBJ_INS_DEF for additional details.
|
||||
*
|
||||
* USAGE/EXAMPLE:
|
||||
* FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, (param1, ...), { return param1 * self->member1 }, (member1, int), ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, param_list, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, name_t, base_name, param_list, __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* OPLIST of the instanced function object
|
||||
* USAGE:
|
||||
* FUNC_OBJ_INS_OPLIST(name, oplist of the attr1, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_OPLIST(...) \
|
||||
#define FUNC_OBJ_INS_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_OPLIST, FUNCOBJI_INS_ATTR_OPLIST_P1)( __VA_ARGS__)
|
||||
|
||||
|
||||
@@ -71,7 +99,7 @@
|
||||
/********************************** INTERNAL ************************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/* To be used by M_IF_FUNCOBJ macro.
|
||||
/* To be used by M_IF_FUNCOBJ macro defined in m-core.
|
||||
NOTE: It is reversed (0 instead of 1) so that it can be used in M_IF reliabely.
|
||||
*/
|
||||
#define M_FUNCOBJ_IS_NOT_DEFINED 0
|
||||
@@ -85,75 +113,97 @@
|
||||
*/
|
||||
|
||||
/* Specialization of the OPLIST in function if there is at least one member or not */
|
||||
#define FUNCOBJI_INS_NO_ATTR_OPLIST(name) \
|
||||
(NAME(name), TYPE(M_C(name, _t)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT(M_C(name,_init)) \
|
||||
)
|
||||
#define FUNCOBJI_INS_NO_ATTR_OPLIST(name) ( \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT(M_C(name,_init)) \
|
||||
)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_P1(name, ...) \
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_P1(name, ...) \
|
||||
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(FUNCOBJI_INS_ATTR_OPLIST_P3, FUNCOBJI_INS_ATTR_OPLIST_FAILURE)(name, __VA_ARGS__)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_FAILURE(name, ...) \
|
||||
M_LIB_ERROR(ONE_ARGUMENT_OF_FUNC_OBJ_INS_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_FAILURE(name, ...) \
|
||||
((M_LIB_ERROR(ONE_ARGUMENT_OF_FUNC_OBJ_INS_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
|
||||
|
||||
/* Define at least the oplist */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_P3(name, ...) \
|
||||
(NAME(name), TYPE(M_C(name, _t)), \
|
||||
INIT_WITH(M_C(name, _init_with)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
|
||||
)
|
||||
/* Define the oplist of the instance */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_P3(name, ...) ( \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
INIT_WITH(M_C(name, _init_with)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
|
||||
)
|
||||
|
||||
|
||||
/* Specialization of the definition a function object interface of name 'name'
|
||||
* with a function like retcode () that doesn't have any input parameters.
|
||||
* with a function like "retcode (void)" that doesn't have any input parameters.
|
||||
* Define the following types to be used by instance:
|
||||
* - M_C(name, _retcode_ct): internal type of the return code
|
||||
* - M_C(name, _callback_ct): internal type of the callback.
|
||||
* - M_C(name, _ct): synonym of main type used by oplist.
|
||||
*/
|
||||
#define FUNCOBJI_ITF_NO_PARAM_DEF(name, retcode) \
|
||||
typedef retcode M_C(name, _retcode_t); \
|
||||
\
|
||||
struct M_C(name, _s); \
|
||||
\
|
||||
/* No parameters to the callback */ \
|
||||
typedef retcode(*M_C(name, _callback_t))(struct M_C(name, _s) *); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _callback_t) callback; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(M_C(name, _t) funcobj) \
|
||||
{ \
|
||||
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
|
||||
funcobj->callback(funcobj); \
|
||||
#define FUNCOBJI_ITF_NO_PARAM_DEF(name, interface_t, retcode) \
|
||||
\
|
||||
/* Forward declaration */ \
|
||||
struct M_C(name, _s); \
|
||||
\
|
||||
/* Internal type for instance */ \
|
||||
typedef retcode M_C(name, _retcode_ct); \
|
||||
/* No parameters to the callback */ \
|
||||
typedef retcode(*M_C(name, _callback_ct))(struct M_C(name, _s) *); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _callback_ct) callback; \
|
||||
} interface_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist & instance */ \
|
||||
typedef interface_t M_C(name, _ct); \
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(interface_t funcobj) \
|
||||
{ \
|
||||
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
|
||||
funcobj->callback(funcobj); \
|
||||
}
|
||||
|
||||
|
||||
/* Specialization of the definition a function object interface of name 'name'
|
||||
* with a function like retcode, type of param1, type of param 2, ...
|
||||
* with mandatory input parameters.
|
||||
* Define the following types to be used by instance:
|
||||
* - M_C(name, _retcode_ct): internal type of the return code
|
||||
* - M_C(name, _callback_ct): internal type of the callback.
|
||||
* - M_C4(name, _param_, num, _ct) for each parameter defined
|
||||
* - M_C(name, _ct): synonym of main type used by oplist.
|
||||
*/
|
||||
#define FUNCOBJI_ITF_PARAM_DEF(name, retcode, ...) \
|
||||
typedef retcode M_C(name, _retcode_t); \
|
||||
\
|
||||
/* Define types for all paremeters */ \
|
||||
M_MAP3(FUNCOBJI_BASE_TYPE, name, __VA_ARGS__) \
|
||||
\
|
||||
struct M_C(name, _s); \
|
||||
\
|
||||
typedef retcode(*M_C(name, _callback_t))(struct M_C(name, _s) *, __VA_ARGS__); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _callback_t) callback; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(M_C(name, _t) funcobj \
|
||||
M_MAP3(FUNCOBJI_BASE_ARGLIST, name, __VA_ARGS__) ) \
|
||||
{ \
|
||||
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
|
||||
#define FUNCOBJI_ITF_PARAM_DEF(name, interface_t, retcode, ...) \
|
||||
\
|
||||
/* Forward declaration */ \
|
||||
struct M_C(name, _s); \
|
||||
\
|
||||
/* Internal types for instance */ \
|
||||
typedef retcode M_C(name, _retcode_ct); \
|
||||
/* Define types for all parameters */ \
|
||||
M_MAP3(FUNCOBJI_BASE_TYPE, name, __VA_ARGS__) \
|
||||
/* Define callback type with all parameters */ \
|
||||
typedef retcode(*M_C(name, _callback_ct))(struct M_C(name, _s) *, __VA_ARGS__); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _callback_ct) callback; \
|
||||
} interface_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist & instance */ \
|
||||
typedef interface_t M_C(name, _ct); \
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(interface_t funcobj \
|
||||
M_MAP3(FUNCOBJI_BASE_ARGLIST, name, __VA_ARGS__) ) \
|
||||
{ \
|
||||
/* If the retcode is 'void', don't return the value of the callback */ \
|
||||
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
|
||||
funcobj->callback(funcobj M_MAP3(FUNCOBJI_BASE_ARGCALL, name, __VA_ARGS__) ); \
|
||||
}
|
||||
|
||||
@@ -161,184 +211,191 @@
|
||||
/* Specialization of the definition a function object instance of name 'name'
|
||||
* with no member attribute.
|
||||
*/
|
||||
#define FUNCOBJI_INS_NO_ATTR_DEF(name, base_name, param_list, callback_core) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(base_name, _callback_t) callback; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
static inline M_C(base_name, _retcode_t) \
|
||||
M_C(name, _callback)(M_C(base_name, _t) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list)\
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_with)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
(void) obj; /* nothing to do */ \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
M_C(name, _as_interface)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
} \
|
||||
#define FUNCOBJI_INS_NO_ATTR_DEF(name, instance_t, base_name, param_list, callback_core) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(base_name, _callback_ct) callback; \
|
||||
} instance_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef instance_t M_C(name, _ct); \
|
||||
\
|
||||
static inline M_C(base_name, _retcode_ct) \
|
||||
M_C(name, _callback)(M_C(base_name, _ct) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list) \
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_with)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(instance_t obj) \
|
||||
{ \
|
||||
(void) obj; /* nothing to do */ \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
M_C(name, _as_interface)(instance_t obj) \
|
||||
{ \
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
} \
|
||||
|
||||
|
||||
/* Specialization of the definition a function object instance of name 'name'
|
||||
* with mandatory member attribute.
|
||||
* First inject oplist in member attributes.
|
||||
*/
|
||||
#define FUNCOBJI_INS_ATTR_DEF(name, base_name, param_list, callback_core, ...) \
|
||||
FUNCOBJI_INS_ATTR_DEF_P2(name, base_name, param_list, callback_core, FUNCOBJI_INJECT_GLOBAL(__VA_ARGS__) )
|
||||
#define FUNCOBJI_INS_ATTR_DEF(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
FUNCOBJI_INS_ATTR_DEF_P2(name, instance_t, base_name, param_list, callback_core, FUNCOBJI_INJECT_GLOBAL(__VA_ARGS__) )
|
||||
|
||||
/* Inject the oplist within the list of arguments */
|
||||
#define FUNCOBJI_INJECT_GLOBAL(...) \
|
||||
#define FUNCOBJI_INJECT_GLOBAL(...) \
|
||||
M_MAP_C(FUNCOBJI_INJECT_OPLIST_A, __VA_ARGS__)
|
||||
|
||||
/* Transform (x, type) into (x, type, oplist) if there is global registered oplist
|
||||
or (x, type, M_DEFAULT_OPLIST) if there is no global one,
|
||||
or keep (x, type, oplist) if oplist was already present */
|
||||
#define FUNCOBJI_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
#define FUNCOBJI_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
FUNCOBJI_INJECT_OPLIST_B duo_or_trio
|
||||
#define FUNCOBJI_INJECT_OPLIST_B( f, ... ) \
|
||||
#define FUNCOBJI_INJECT_OPLIST_B( f, ... ) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
|
||||
|
||||
// Test if all third argument of all arguments is an oplist
|
||||
#define FUNCOBJI_IF_ALL_OPLIST(...) \
|
||||
#define FUNCOBJI_IF_ALL_OPLIST(...) \
|
||||
M_IF(M_REDUCE(FUNCOBJI_IS_OPLIST_P, M_AND, __VA_ARGS__))
|
||||
// Test if the third argument is an oplist
|
||||
#define FUNCOBJI_IS_OPLIST_P(a) \
|
||||
// Test if the third argument is an oplist. a is a trio (name, type, oplist)
|
||||
#define FUNCOBJI_IS_OPLIST_P(a) \
|
||||
M_OPLIST_P(M_RET_ARG3 a)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define FUNCOBJI_INS_ATTR_DEF_P2(name, base_name, param_list, callback_core, ...) \
|
||||
FUNCOBJI_IF_ALL_OPLIST(__VA_ARGS__)(FUNCOBJI_INS_ATTR_DEF_P3, FUNCOBJI_INS_ATTR_DEF_FAILURE)(name, base_name, param_list, callback_core, __VA_ARGS__)
|
||||
#define FUNCOBJI_INS_ATTR_DEF_P2(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
FUNCOBJI_IF_ALL_OPLIST(__VA_ARGS__)(FUNCOBJI_INS_ATTR_DEF_P3, FUNCOBJI_INS_ATTR_DEF_FAILURE)(name, instance_t, base_name, param_list, callback_core, __VA_ARGS__)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define FUNCOBJI_INS_ATTR_DEF_FAILURE(name, base_name, param_list, callback_core, ...) \
|
||||
#define FUNCOBJI_INS_ATTR_DEF_FAILURE(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(FUNC_OBJ_INS_DEF): at least one of the given argument is not a valid oplist: " #__VA_ARGS__)
|
||||
|
||||
/* Expand the Function Object with members */
|
||||
#define FUNCOBJI_INS_ATTR_DEF_P3(name, base_name, param_list, callback_core, ...) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
/* Callback is the mandatory first argument */ \
|
||||
M_C(base_name, _callback_t) callback; \
|
||||
/* All the member attribute of the Function Object */ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_STRUCT, __VA_ARGS__) \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
FUNCOBJI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
\
|
||||
static inline M_C(base_name, _retcode_t) \
|
||||
M_C(name, _callback)(M_C(base_name, _t) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list)\
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_with)(M_C(name, _t) obj M_MAP(FUNCOBJI_INS_ATTR_LIST, __VA_ARGS__)) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT_SET, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_CLEAR, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
M_C(name, _as_interface)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
M_IF(FUNCOBJI_TEST_METHOD_P(INIT, __VA_ARGS)) \
|
||||
( \
|
||||
static inline void \
|
||||
M_C(name, _init)(M_C(name, _t) obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT, __VA_ARGS__); \
|
||||
} \
|
||||
, /* END OF INIT METHOD */ ) \
|
||||
#define FUNCOBJI_INS_ATTR_DEF_P3(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
/* Callback is the mandatory first argument */ \
|
||||
M_C(base_name, _callback_ct) callback; \
|
||||
/* All the member attribute of the Function Object */ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_STRUCT, __VA_ARGS__) \
|
||||
} instance_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef instance_t M_C(name, _ct); \
|
||||
\
|
||||
FUNCOBJI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
\
|
||||
static inline M_C(base_name, _retcode_ct) \
|
||||
M_C(name, _callback)(M_C(base_name, _ct) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list) \
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)(void*)_self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_with)(instance_t obj M_MAP(FUNCOBJI_INS_ATTR_LIST, __VA_ARGS__)) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT_SET, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(instance_t obj) \
|
||||
{ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_CLEAR, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
M_C(name, _as_interface)(instance_t obj) \
|
||||
{ \
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
M_IF(FUNCOBJI_TEST_METHOD_P(INIT, __VA_ARGS)) \
|
||||
( \
|
||||
static inline void \
|
||||
M_C(name, _init)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT, __VA_ARGS__); \
|
||||
} \
|
||||
, /* END OF INIT METHOD */ ) \
|
||||
|
||||
|
||||
|
||||
/* Define a numbered type of a parameter of the callback*/
|
||||
#define FUNCOBJI_BASE_TYPE(name, num, type) \
|
||||
typedef type M_C4(name, _param_, num, _t);
|
||||
#define FUNCOBJI_BASE_TYPE(name, num, type) \
|
||||
typedef type M_C4(name, _param_, num, _ct);
|
||||
|
||||
/* Define a list of the type of arguments for a function definition */
|
||||
#define FUNCOBJI_BASE_ARGLIST(name, num, type) \
|
||||
#define FUNCOBJI_BASE_ARGLIST(name, num, type) \
|
||||
M_DEFERRED_COMMA type M_C(param_, num)
|
||||
|
||||
/* Define a list of arguments for a function call */
|
||||
#define FUNCOBJI_BASE_ARGCALL(name, num, type) \
|
||||
#define FUNCOBJI_BASE_ARGCALL(name, num, type) \
|
||||
M_DEFERRED_COMMA M_C(param_, num)
|
||||
|
||||
|
||||
/* Helper macros */
|
||||
/* arg = (name, type [, oplist]) */
|
||||
#define FUNCOBJI_INS_ATTR_STRUCT(arg) \
|
||||
#define FUNCOBJI_INS_ATTR_STRUCT(arg) \
|
||||
M_RET_ARG2 arg M_RET_ARG1 arg;
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_LIST(arg) \
|
||||
#define FUNCOBJI_INS_ATTR_LIST(arg) \
|
||||
M_DEFERRED_COMMA M_RET_ARG2 arg const M_RET_ARG1 arg
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_INIT(arg) \
|
||||
#define FUNCOBJI_INS_ATTR_INIT(arg) \
|
||||
M_CALL_INIT(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg);
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_INIT_SET(arg) \
|
||||
#define FUNCOBJI_INS_ATTR_INIT_SET(arg) \
|
||||
M_CALL_INIT_SET(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg, M_RET_ARG1 arg);
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_CLEAR(arg) \
|
||||
#define FUNCOBJI_INS_ATTR_CLEAR(arg) \
|
||||
M_CALL_CLEAR(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg);
|
||||
|
||||
/* Define the list of arguments of the instance of the callback */
|
||||
#define FUNCOBJI_INS_ARGLIST(name, num, param) \
|
||||
M_DEFERRED_COMMA M_C4(name, _param_, num, _t) param
|
||||
#define FUNCOBJI_INS_ARGLIST(name, num, param) \
|
||||
M_DEFERRED_COMMA M_C4(name, _param_, num, _ct) param
|
||||
|
||||
|
||||
/* Macros for testing for a method presence in all the attributes */
|
||||
#define FUNCOBJI_TEST_METHOD2_P(method, op) \
|
||||
#define FUNCOBJI_TEST_METHOD2_P(method, op) \
|
||||
M_TEST_METHOD_P(method, op)
|
||||
#define FUNCOBJI_TEST_METHOD1_P(method, arg) \
|
||||
#define FUNCOBJI_TEST_METHOD1_P(method, arg) \
|
||||
M_APPLY(FUNCOBJI_TEST_METHOD2_P, method, M_RET_ARG3 arg)
|
||||
#define FUNCOBJI_TEST_METHOD_P(method, ...) \
|
||||
#define FUNCOBJI_TEST_METHOD_P(method, ...) \
|
||||
M_IF(M_REDUCE2(FUNCOBJI_TEST_METHOD1_P, M_AND, method, __VA_ARGS__))
|
||||
|
||||
/* Macro for checking compatible type and oplist for all the attributes */
|
||||
#define FUNCOBJI_CONTROL_ALL_OPLIST(name, ...) \
|
||||
#define FUNCOBJI_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(FUNCOBJI_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
#define FUNCOBJI_CONTROL_OPLIST(name, a) \
|
||||
#define FUNCOBJI_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, M_RET_ARG1 a, M_RET_ARG2 a, M_RET_ARG3 a)
|
||||
|
||||
|
||||
|
||||
+83
-56
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - GENINT module
|
||||
* M*LIB - Integer Generator (GENINT) module
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,70 +28,87 @@
|
||||
#include "m-core.h"
|
||||
#include "m-atomic.h"
|
||||
|
||||
/* GENINT is a container of integers with the following properties:
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* GENINT is a container providing unique integers.
|
||||
It has the following properties:
|
||||
- it stores integer from [0..N) (N is fixed).
|
||||
- an integer can have only one occurrence in the container.
|
||||
- you can atomically push in / pop out integer from this container
|
||||
provided that they were not already in the container.
|
||||
provided that it is not already in the container.
|
||||
- there are no order (like FIFO or stack)
|
||||
|
||||
This can be used to map integers to index of resources in a table.
|
||||
At most we can support N = GENINT_LIMBSIZE * GENINT_LIMBSIZE >= 4096
|
||||
due to the master trick. For the typical usage of this container
|
||||
At most we can support N = 2048 with the master limb usage.
|
||||
For the typical usage of this container
|
||||
(mapping hardware or software limited resources), this should be
|
||||
enough.
|
||||
*/
|
||||
|
||||
// TO DO: We may want a specialization with constant N value.
|
||||
|
||||
// Define the limb size
|
||||
typedef unsigned long long genint_limb_t;
|
||||
// Define the limb size used by genint
|
||||
typedef unsigned long long genint_limb_ct;
|
||||
|
||||
/* Define a generator of unique integer (Lock Free) */
|
||||
typedef struct genint_s {
|
||||
unsigned int n; // size of the container
|
||||
unsigned int max; // number of allocated limb - 1
|
||||
genint_limb_t mask0; // mask of the last limb
|
||||
genint_limb_t mask_master; // mask of master
|
||||
genint_limb_ct mask0; // mask of the last limb (constant)
|
||||
genint_limb_ct mask_master; // mask of the master limb that controls others (constant)
|
||||
atomic_ullong master; // master bitfield (which informs if a limb is full or not)
|
||||
atomic_ullong *data; // the bitfield which informs if an integer
|
||||
atomic_ullong *data; // the bitfield which informs if an integer is used or not
|
||||
} genint_t[1];
|
||||
|
||||
// Define the max supported value
|
||||
// Define the max absolute supported value
|
||||
#define GENINT_MAX_ALLOC (GENINT_LIMBSIZE * (GENINT_LIMBSIZE - GENINT_ABA_CPT))
|
||||
|
||||
// Define the size of a limb in bits.
|
||||
#define GENINT_LIMBSIZE (sizeof(genint_limb_t) * CHAR_BIT)
|
||||
#define GENINT_LIMBSIZE ((unsigned)(sizeof(genint_limb_ct) * CHAR_BIT))
|
||||
|
||||
#define GENINT_CONTRACT(s) do { \
|
||||
assert (s != NULL); \
|
||||
assert (s->n > 0 && s->n <= GENINT_MAX_ALLOC); \
|
||||
assert ((s->max+1) * GENINT_LIMBSIZE >= s->n); \
|
||||
assert (s->data != NULL); \
|
||||
// Define the contract of a genint
|
||||
#define GENINT_CONTRACT(s) do { \
|
||||
M_ASSERT (s != NULL); \
|
||||
M_ASSERT (s->n > 0 && s->n <= GENINT_MAX_ALLOC); \
|
||||
M_ASSERT ((s->max+1) * GENINT_LIMBSIZE >= s->n); \
|
||||
M_ASSERT (s->data != NULL); \
|
||||
} while (0)
|
||||
|
||||
#define GENINT_ONE ((genint_limb_t)1)
|
||||
// Define the limb one
|
||||
#define GENINT_ONE ((genint_limb_ct)1)
|
||||
|
||||
// Value returned in case of error.
|
||||
#define GENINT_ERROR (-1U)
|
||||
#define GENINT_FULL_MASK ULLONG_MAX
|
||||
|
||||
// 32 bits of master are kept for handling the ABA problems.
|
||||
// Value returned in case of error (not integer available).
|
||||
#define GENINT_ERROR (UINT_MAX)
|
||||
|
||||
/* 32 bits of the master mask are kept for handling the ABA problem.
|
||||
* NOTE: May be too much. 16 bits should be more than enough. TBC
|
||||
*/
|
||||
#define GENINT_ABA_CPT 32
|
||||
#define GENINT_ABA_CPT_T uint32_t
|
||||
|
||||
// Set the bit i of master
|
||||
#define GENINT_MASTER_SET(master, i) \
|
||||
// Set the bit 'i' of the master limb, and increase ABA counter.
|
||||
#define GENINT_MASTER_SET(master, i) \
|
||||
((((master)& (~((GENINT_ONE<< GENINT_ABA_CPT)-1))) | (GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
|
||||
|((GENINT_ABA_CPT_T)((master) + 1)))
|
||||
|
||||
// Reset the bit i of master
|
||||
#define GENINT_MASTER_RESET(master, i) \
|
||||
(((master) & (~((GENINT_ONE<< GENINT_ABA_CPT)-1)) & ~(GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
|
||||
// Reset the bit i of the master limb, and increase ABA counter.
|
||||
#define GENINT_MASTER_RESET(master, i) \
|
||||
(((master) & (~((GENINT_ONE<< GENINT_ABA_CPT)-1)) & ~(GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
|
||||
|((GENINT_ABA_CPT_T)((master) + 1)))
|
||||
|
||||
static inline void genint_init(genint_t s, unsigned int n)
|
||||
/* Initialize an integer generator (CONSTRUCTOR).
|
||||
* Initialy, the container is full of all the integers up to 'n-1'
|
||||
* The typical sequence is to initialize the container, and pop
|
||||
* the integer from it. Each pop integer is **unique** for all threads,
|
||||
* meaning it can be used to index global unique resources shared
|
||||
* for all threads.
|
||||
*/
|
||||
static inline void
|
||||
genint_init(genint_t s, unsigned int n)
|
||||
{
|
||||
assert (s != NULL && n > 0 && n <= GENINT_MAX_ALLOC);
|
||||
M_ASSERT (s != NULL && n > 0 && n <= GENINT_MAX_ALLOC);
|
||||
const size_t alloc = (n + GENINT_LIMBSIZE - 1) / GENINT_LIMBSIZE;
|
||||
const unsigned int index = n % GENINT_LIMBSIZE;
|
||||
atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, alloc);
|
||||
@@ -101,55 +118,61 @@ static inline void genint_init(genint_t s, unsigned int n)
|
||||
}
|
||||
s->n = n;
|
||||
s->data = ptr;
|
||||
s->max = alloc-1;
|
||||
s->mask0 = (index == 0) ? -GENINT_ONE : ~((GENINT_ONE<<(GENINT_LIMBSIZE-index))-1);
|
||||
s->max = (unsigned int) (alloc-1);
|
||||
s->mask0 = (index == 0) ? GENINT_FULL_MASK : ~((GENINT_ONE<<(GENINT_LIMBSIZE-index))-1);
|
||||
s->mask_master = (((GENINT_ONE << alloc) - 1) << (GENINT_LIMBSIZE-alloc)) >> GENINT_ABA_CPT;
|
||||
atomic_init (&s->master, (genint_limb_t)0);
|
||||
atomic_init (&s->master, (genint_limb_ct)0);
|
||||
for(unsigned int i = 0; i < alloc; i++)
|
||||
atomic_init(&s->data[i], (genint_limb_t)0);
|
||||
atomic_init(&s->data[i], (genint_limb_ct)0);
|
||||
GENINT_CONTRACT(s);
|
||||
}
|
||||
|
||||
static inline void genint_clear(genint_t s)
|
||||
/* Clear an integer generator (Destructor) */
|
||||
static inline void
|
||||
genint_clear(genint_t s)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
M_MEMORY_FREE(s->data);
|
||||
s->data = NULL;
|
||||
}
|
||||
|
||||
static inline size_t genint_size(genint_t s)
|
||||
/* Return the maximum integer that the generator will provide */
|
||||
static inline size_t
|
||||
genint_size(genint_t s)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
return s->n;
|
||||
}
|
||||
|
||||
// For a typical case, the amortized cost is one CAS per pop.
|
||||
static inline unsigned int genint_pop(genint_t s)
|
||||
/* Get an unique integer from the integer generator.
|
||||
* NOTE: For a typical case, the amortized cost is one CAS per pop. */
|
||||
static inline unsigned int
|
||||
genint_pop(genint_t s)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
// First read master to see which limb is not full.
|
||||
genint_limb_t master = atomic_load(&s->master);
|
||||
genint_limb_ct master = atomic_load(&s->master);
|
||||
// While master is not full
|
||||
while ((master >> GENINT_ABA_CPT) != s->mask_master) {
|
||||
// Let's get the index i of the first not full limb according to master.
|
||||
unsigned int i = m_core_clz64(~master);
|
||||
assert (i < GENINT_LIMBSIZE);
|
||||
M_ASSERT (i < GENINT_LIMBSIZE);
|
||||
// Let's compute the mask of this limb representing the limb as being full
|
||||
genint_limb_t mask = s->mask0;
|
||||
mask = (i == s->max) ? mask : -GENINT_ONE;
|
||||
genint_limb_ct mask = s->mask0;
|
||||
mask = (i == s->max) ? mask : GENINT_FULL_MASK;
|
||||
unsigned int bit;
|
||||
// Let's load this limb,
|
||||
genint_limb_t next, org = atomic_load(&s->data[i]);
|
||||
genint_limb_ct next, org = atomic_load(&s->data[i]);
|
||||
do {
|
||||
// If it is now full, we have been preempted by another.
|
||||
if (M_UNLIKELY (org == mask))
|
||||
goto next_element;
|
||||
assert (org != -GENINT_ONE);
|
||||
M_ASSERT (org != GENINT_FULL_MASK);
|
||||
// At least one bit is free in the limb. Find one.
|
||||
bit = GENINT_LIMBSIZE - 1 - m_core_clz64(~org);
|
||||
assert (bit < GENINT_LIMBSIZE);
|
||||
assert ((org & (GENINT_ONE<<bit)) == 0);
|
||||
assert (i * GENINT_LIMBSIZE + GENINT_LIMBSIZE - 1 - bit < s->n);
|
||||
M_ASSERT (bit < GENINT_LIMBSIZE);
|
||||
M_ASSERT ((org & (GENINT_ONE<<bit)) == 0);
|
||||
M_ASSERT (i * GENINT_LIMBSIZE + GENINT_LIMBSIZE - 1 - bit < s->n);
|
||||
// Set the integer as being used.
|
||||
next = org | (GENINT_ONE << bit);
|
||||
// Try to reserve the integer
|
||||
@@ -158,7 +181,7 @@ static inline unsigned int genint_pop(genint_t s)
|
||||
// If the limb is now full, try to update master
|
||||
if (M_UNLIKELY(next == mask)) {
|
||||
while (true) {
|
||||
genint_limb_t newMaster;
|
||||
genint_limb_ct newMaster;
|
||||
if (next == mask) {
|
||||
newMaster = GENINT_MASTER_SET(master, i);
|
||||
} else {
|
||||
@@ -181,30 +204,32 @@ static inline unsigned int genint_pop(genint_t s)
|
||||
return GENINT_ERROR; // No more resource available
|
||||
}
|
||||
|
||||
// For a typical case, the amortized cost is one CAS per pop.
|
||||
static inline void genint_push(genint_t s, unsigned int n)
|
||||
/* Restore a used integer in the integer generator.
|
||||
* NOTE: For a typical case, the amortized cost is one CAS per pop */
|
||||
static inline void
|
||||
genint_push(genint_t s, unsigned int n)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
assert (n < s->n);
|
||||
M_ASSERT (n < s->n);
|
||||
const unsigned int i = n / GENINT_LIMBSIZE;
|
||||
const unsigned int bit = GENINT_LIMBSIZE - 1 - (n % GENINT_LIMBSIZE);
|
||||
genint_limb_t master = atomic_load(&s->master);
|
||||
genint_limb_ct master = atomic_load(&s->master);
|
||||
// Load the limb
|
||||
genint_limb_t next, org = atomic_load(&s->data[i]);
|
||||
genint_limb_ct next, org = atomic_load(&s->data[i]);
|
||||
do {
|
||||
assert ((org & (GENINT_ONE << bit)) != 0);
|
||||
M_ASSERT ((org & (GENINT_ONE << bit)) != 0);
|
||||
// Reset it
|
||||
next = org & (~(GENINT_ONE << bit));
|
||||
// Try to unreserve it.
|
||||
} while (!atomic_compare_exchange_weak (&s->data[i], &org, next));
|
||||
// if the limb was marked as full by master
|
||||
genint_limb_t mask = s->mask0;
|
||||
mask = (i == s->max) ? mask : -GENINT_ONE;
|
||||
genint_limb_ct mask = s->mask0;
|
||||
mask = (i == s->max) ? mask : GENINT_FULL_MASK;
|
||||
if (M_UNLIKELY (next != mask)) {
|
||||
// Let's compute the mask of this limb representing the limb as being full
|
||||
// Let's try to update master to say that this limb is not full
|
||||
while (true) {
|
||||
genint_limb_t newMaster;
|
||||
genint_limb_ct newMaster;
|
||||
if (next == mask) {
|
||||
newMaster = GENINT_MASTER_SET(master, i);
|
||||
} else {
|
||||
@@ -219,4 +244,6 @@ static inline void genint_push(genint_t s, unsigned int n)
|
||||
GENINT_CONTRACT(s);
|
||||
}
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
+566
-516
File diff suppressed because it is too large.
Load diff
+171
-103
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - INTRUSIVE SHARED PTR Module
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,27 +28,52 @@
|
||||
#include "m-core.h"
|
||||
#include "m-atomic.h"
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a intrusive shared pointer.
|
||||
USAGE: ISHARED_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define ISHARED_PTR_OPLIST(...) \
|
||||
ISHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
#define ISHARED_PTR_OPLIST(...) \
|
||||
ISHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Interface to add to a structure to allow intrusive support.
|
||||
name: name of the intrusive shared pointer.
|
||||
type: name of the type of the structure (aka. struct test_s) - not used currently.
|
||||
NOTE: There can be only one interface of this kind in a type! */
|
||||
#define ISHARED_PTR_INTERFACE(name, type) \
|
||||
#define ISHARED_PTR_INTERFACE(name, type) \
|
||||
atomic_int M_C(name, _cpt)
|
||||
|
||||
|
||||
/* Value of the interface field for static intialization (Uses C99 designated element). */
|
||||
#define ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
|
||||
.M_C(name, _cpt) = ATOMIC_VAR_INIT(0)
|
||||
|
||||
/* Value of the interface field for static intialization (Uses C89 designated element). */
|
||||
#define ISHARED_PTR_STATIC_INIT(name, type) \
|
||||
ATOMIC_VAR_INIT(0)
|
||||
|
||||
|
||||
/* Define the intrusive shared pointer type and its static inline functions.
|
||||
USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define ISHARED_PTR_DEF(name, ...) \
|
||||
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
|
||||
(name, __VA_ARGS__ )))
|
||||
#define ISHARED_PTR_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the intrusive shared pointer type and its static inline functions
|
||||
as the name name_t
|
||||
USAGE: ISHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
|
||||
#define ISHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__ , name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
@@ -57,114 +82,157 @@
|
||||
#define ISHAREDI_PTR_OPLIST_P1(arg) ISHAREDI_PTR_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define ISHAREDI_PTR_OPLIST_P2(name, oplist) \
|
||||
#define ISHAREDI_PTR_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(ISHAREDI_PTR_OPLIST_P3, ISHAREDI_PTR_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define ISHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_ISHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
#define ISHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_ISHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
// Define the oplist
|
||||
#define ISHAREDI_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_INIT_DEFAULT), \
|
||||
INIT_SET(M_C(name, _init_set2) M_IPTR), \
|
||||
SET(M_C(name, _set) M_IPTR), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
CLEAN(M_C(name, _clean) M_IPTR), \
|
||||
TYPE(M_C(name, _t)), \
|
||||
OPLIST(oplist), \
|
||||
SUBTYPE(M_C(name, _type_t)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
#define ISHAREDI_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_INIT_DEFAULT), \
|
||||
INIT_SET(API_4(M_C(name, _init_set))), \
|
||||
SET(M_C(name, _set) M_IPTR), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
CLEAN(M_C(name, _clean) M_IPTR), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
OPLIST(oplist), \
|
||||
SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
)
|
||||
|
||||
// Deferred evaluatioin
|
||||
#define ISHAREDI_PTR_DEF_P1(arg) ISHAREDI_PTR_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define ISHAREDI_PTR_DEF_P2(name, type, oplist) \
|
||||
M_IF_OPLIST(oplist)(ISHAREDI_PTR_DEF_P3, ISHAREDI_PTR_DEF_FAILURE)(name, type, oplist)
|
||||
#define ISHAREDI_PTR_DEF_P2(name, type, oplist, shared_t) \
|
||||
M_IF_OPLIST(oplist)(ISHAREDI_PTR_DEF_P3, ISHAREDI_PTR_DEF_FAILURE)(name, type, oplist, shared_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define ISHAREDI_PTR_DEF_FAILURE(name, type, oplist) \
|
||||
#define ISHAREDI_PTR_DEF_FAILURE(name, type, oplist, shared_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ISHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
#define ISHAREDI_PTR_DEF_P3(name, type, oplist) \
|
||||
\
|
||||
typedef type *M_C(name,_t); \
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline M_C(name,_t) \
|
||||
M_C(name, _init)(type *ptr) \
|
||||
{ \
|
||||
if (M_LIKELY (ptr != NULL)) \
|
||||
atomic_init(&ptr->M_C(name, _cpt), 1); \
|
||||
return ptr; \
|
||||
} \
|
||||
\
|
||||
static inline M_C(name,_t) \
|
||||
M_C(name, _init_set)(M_C(name,_t) shared) \
|
||||
{ \
|
||||
if (M_LIKELY (shared != NULL)) { \
|
||||
int n = atomic_fetch_add(&(shared->M_C(name, _cpt)), 1); \
|
||||
(void) n; \
|
||||
} \
|
||||
return shared; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set2)(M_C(name,_t) *ptr, M_C(name,_t) shared) \
|
||||
{ \
|
||||
assert (ptr != NULL); \
|
||||
*ptr = M_C(name, _init_set)(shared); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD2(INIT, NEW, oplist)( \
|
||||
static inline M_C(name,_t) \
|
||||
M_C(name, _init_new)(void) \
|
||||
{ \
|
||||
type *ptr = M_CALL_NEW(oplist, type); \
|
||||
if (ptr == NULL) { \
|
||||
M_MEMORY_FULL(sizeof(type)); \
|
||||
return NULL; \
|
||||
} \
|
||||
M_CALL_INIT(oplist, *ptr); \
|
||||
atomic_init (&ptr->M_C(name, _cpt), 1); \
|
||||
return ptr; \
|
||||
} \
|
||||
, /* End of INIT/NEW */) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name,_t) shared) \
|
||||
{ \
|
||||
if (shared != NULL) { \
|
||||
if (atomic_fetch_sub(&(shared->M_C(name, _cpt)), 1) == 1) { \
|
||||
M_CALL_CLEAR(oplist, *shared); \
|
||||
M_IF_DISABLED_METHOD(DEL, oplist)(, M_CALL_DEL(oplist, shared);) \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(M_C(name,_t) *shared) \
|
||||
{ \
|
||||
M_C(name, _clear)(*shared); \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(M_C(name,_t) *ptr, M_C(name,_t)shared) \
|
||||
{ \
|
||||
assert (ptr != NULL); \
|
||||
if (M_LIKELY (*ptr != shared)) { \
|
||||
M_C(name, _clear)(*ptr); \
|
||||
*ptr = M_C(name, _init_set)(shared); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
#define ISHAREDI_PTR_DEF_P3(name, type, oplist, shared_t) \
|
||||
\
|
||||
/* The shared pointer is only a pointer to the type */ \
|
||||
typedef type *shared_t; \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
typedef shared_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline shared_t \
|
||||
M_C(name, _init)(type *ptr) \
|
||||
{ \
|
||||
/* Initialize the type referenced by the pointer */ \
|
||||
if (M_LIKELY (ptr != NULL)) { \
|
||||
atomic_init(&ptr->M_C(name, _cpt), 2); \
|
||||
} \
|
||||
return ptr; \
|
||||
} \
|
||||
\
|
||||
static inline shared_t \
|
||||
M_C(name, _init_set)(shared_t shared) \
|
||||
{ \
|
||||
if (M_LIKELY (shared != NULL)) { \
|
||||
int n = atomic_fetch_add(&(shared->M_C(name, _cpt)), 2); \
|
||||
(void) n; \
|
||||
} \
|
||||
return shared; \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
M_IF_DISABLED_METHOD(NEW, oplist) \
|
||||
( \
|
||||
/* This function is only for static object */ \
|
||||
static inline shared_t \
|
||||
M_C(name, _init_once)(type *shared) \
|
||||
{ \
|
||||
if (M_LIKELY (shared != NULL)) { \
|
||||
/* Pretty much like atomic_add, except the first one increment by 1, others by 2 */ \
|
||||
int o = atomic_load(&(shared->M_C(name, _cpt))); \
|
||||
int n; \
|
||||
do { \
|
||||
n = o + 1 + (o != 0); \
|
||||
} while (!atomic_compare_exchange_strong(&(shared->M_C(name, _cpt)), &o, n)); \
|
||||
if (o == 0) { \
|
||||
/* Partial initialization: _cpt is odd */ \
|
||||
/* Call the INIT function once */ \
|
||||
M_CALL_INIT(oplist, *shared); \
|
||||
/* Finish initialization: _cpt is even */ \
|
||||
atomic_fetch_add(&(shared->M_C(name, _cpt)), 1); \
|
||||
} else if ( (o&1) != 0) { \
|
||||
/* Not fully initialized yet: wait for initialization */ \
|
||||
m_core_backoff_ct bkoff; \
|
||||
m_core_backoff_init(bkoff); \
|
||||
/* Wait for _cpt to be _even */ \
|
||||
while ((atomic_load(&(shared->M_C(name, _cpt)))&1) != 0 ) { \
|
||||
m_core_backoff_wait(bkoff); \
|
||||
} \
|
||||
} \
|
||||
M_ASSERT( (atomic_load(&(shared->M_C(name, _cpt)))&1) == 0); \
|
||||
} \
|
||||
return shared; \
|
||||
} \
|
||||
, \
|
||||
/* This function is only for dynamic object */ \
|
||||
static inline shared_t \
|
||||
M_C(name, _init_new)(void) \
|
||||
{ \
|
||||
type *ptr = M_CALL_NEW(oplist, type); \
|
||||
if (ptr == NULL) { \
|
||||
M_MEMORY_FULL(sizeof(type)); \
|
||||
return NULL; \
|
||||
} \
|
||||
M_CALL_INIT(oplist, *ptr); \
|
||||
atomic_init (&ptr->M_C(name, _cpt), 2); \
|
||||
return ptr; \
|
||||
} \
|
||||
/* End of NEW */) \
|
||||
, /* End of INIT */) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t shared) \
|
||||
{ \
|
||||
if (shared != NULL) { \
|
||||
if (atomic_fetch_sub(&(shared->M_C(name, _cpt)), 2) == 2) { \
|
||||
M_CALL_CLEAR(oplist, *shared); \
|
||||
M_IF_DISABLED_METHOD(DEL, oplist)(, M_CALL_DEL(oplist, shared);) \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear_ptr)(shared_t *shared) \
|
||||
{ \
|
||||
M_ASSERT(shared != NULL); \
|
||||
M_C(name, _clear)(*shared); \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(shared_t *shared) \
|
||||
{ \
|
||||
M_C(name, _clear)(*shared); \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(shared_t *ptr, shared_t shared) \
|
||||
{ \
|
||||
M_ASSERT (ptr != NULL); \
|
||||
if (M_LIKELY (*ptr != shared)) { \
|
||||
M_C(name, _clear)(*ptr); \
|
||||
*ptr = M_C(name, _init_set)(shared); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
|
||||
+127
-95
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - MEMPOOL module
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -37,113 +37,145 @@
|
||||
*ptr = 17;
|
||||
mempool_uint_free(m, ptr);
|
||||
mempool_uint_clear(m); // Give back memory to system
|
||||
NOTE: Can not use m-list since it may be expanded from LIST_DEF
|
||||
*/
|
||||
// NOTE: Can not use m-list since it may be expanded from LIST_DEF
|
||||
#define MEMPOOL_DEF(name, type) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
MEMPOOL_DEF_P2(name, type, M_C(name, _t) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Fast Fixed Size thread unsafe allocator based on memory region.
|
||||
USAGE:
|
||||
MEMPOOL_DEF_AS(memppol_uint, name_t, unsigned int)
|
||||
*/
|
||||
#define MEMPOOL_DEF_AS(name, name_t, type) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
MEMPOOL_DEF_P2(name, type, name_t ) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#define MEMPOOL_DEF(name, type) \
|
||||
\
|
||||
typedef union M_C(name,_union_s) { \
|
||||
type t; \
|
||||
union M_C(name,_union_s) *next; \
|
||||
} M_C(name,_union_t); \
|
||||
\
|
||||
typedef struct M_C(name,_segment_s) { \
|
||||
unsigned int count; \
|
||||
struct M_C(name,_segment_s) *next; \
|
||||
M_C(name,_union_t) tab[MEMPOOL_MAX_PER_SEGMENT(type)]; \
|
||||
} M_C(name,_segment_t); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name,_union_t) *free_list; \
|
||||
M_C(name,_segment_t) *current_segment; \
|
||||
} M_C(name,_t)[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_init)(M_C(name,_t) mem) \
|
||||
{ \
|
||||
mem->free_list = NULL; \
|
||||
mem->current_segment = M_MEMORY_ALLOC(M_C(name,_segment_t)); \
|
||||
if (mem->current_segment == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (M_C(name,_segment_t))); \
|
||||
return; \
|
||||
} \
|
||||
mem->current_segment->next = NULL; \
|
||||
mem->current_segment->count = 0; \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_clear)(M_C(name,_t) mem) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_C(name,_segment_t) *segment = mem->current_segment; \
|
||||
while (segment != NULL) { \
|
||||
M_C(name,_segment_t) *next = segment->next; \
|
||||
M_MEMORY_DEL (segment); \
|
||||
segment = next; \
|
||||
} \
|
||||
/* Clean pointers to be safer */ \
|
||||
mem->free_list = NULL; \
|
||||
mem->current_segment = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name,_alloc)(M_C(name,_t) mem) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_C(name,_union_t) *ret = mem->free_list; \
|
||||
if (ret != NULL) { \
|
||||
mem->free_list = ret->next; \
|
||||
return &ret->t; \
|
||||
} \
|
||||
M_C(name,_segment_t) *segment = mem->current_segment; \
|
||||
assert(segment != NULL); \
|
||||
unsigned int count = segment->count; \
|
||||
if (M_UNLIKELY (count >= MEMPOOL_MAX_PER_SEGMENT(type))) { \
|
||||
M_C(name,_segment_t) *new_segment = M_MEMORY_ALLOC (M_C(name,_segment_t)); \
|
||||
if (M_UNLIKELY (new_segment == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (M_C(name,_segment_t))); \
|
||||
return NULL; \
|
||||
} \
|
||||
new_segment->next = segment; \
|
||||
new_segment->count = 0; \
|
||||
mem->current_segment = new_segment; \
|
||||
segment = new_segment; \
|
||||
count = 0; \
|
||||
} \
|
||||
ret = &segment->tab[count]; \
|
||||
segment->count = count + 1; \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
return &ret->t; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_free)(M_C(name,_t) mem, type *ptr) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
/* NOTE: Unsafe cast: suppose that the given pointer \
|
||||
was allocated by the previous alloc function. */ \
|
||||
M_C(name,_union_t) *ret = (M_C(name,_union_t) *)(uintptr_t)ptr; \
|
||||
ret->next = mem->free_list; \
|
||||
mem->free_list = ret; \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
} \
|
||||
|
||||
/* User shall be able to cutomize the size of the segment and/or
|
||||
the minimun number of elements.
|
||||
The default is the number of elements that fits in 16KB.
|
||||
*/
|
||||
#ifndef MEMPOOL_MAX_PER_SEGMENT
|
||||
#define MEMPOOL_MAX_PER_SEGMENT(type) \
|
||||
#define MEMPOOL_MAX_PER_SEGMENT(type) \
|
||||
M_MAX((16*1024-sizeof(unsigned int) - 2*sizeof(void*)) / sizeof (type), 256U)
|
||||
#endif
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
#define MEMPOOL_DEF_P2(name, type, name_t) \
|
||||
\
|
||||
/* Define the type of element in a segment of the mempool. \
|
||||
Either it is the basic type or a pointer to another one. */ \
|
||||
typedef union M_C(name,_union_s) { \
|
||||
type t; \
|
||||
union M_C(name,_union_s) *next; \
|
||||
} M_C(name,_union_ct); \
|
||||
\
|
||||
/* Define a segment of a mempool. \
|
||||
It is an array of basic type, each segment is in a linked list */ \
|
||||
typedef struct M_C(name,_segment_s) { \
|
||||
unsigned int count; \
|
||||
struct M_C(name,_segment_s) *next; \
|
||||
M_C(name,_union_ct) tab[MEMPOOL_MAX_PER_SEGMENT(type)]; \
|
||||
} M_C(name,_segment_ct); \
|
||||
\
|
||||
/* Define a mempool. \
|
||||
It is a pointer to the first free object within the segments \
|
||||
and the segments themselves */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name,_union_ct) *free_list; \
|
||||
M_C(name,_segment_ct) *current_segment; \
|
||||
} name_t[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_init)(name_t mem) \
|
||||
{ \
|
||||
mem->free_list = NULL; \
|
||||
mem->current_segment = M_MEMORY_ALLOC(M_C(name,_segment_ct)); \
|
||||
if (mem->current_segment == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (M_C(name,_segment_ct))); \
|
||||
return; \
|
||||
} \
|
||||
mem->current_segment->next = NULL; \
|
||||
mem->current_segment->count = 0; \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_clear)(name_t mem) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_C(name,_segment_ct) *segment = mem->current_segment; \
|
||||
while (segment != NULL) { \
|
||||
M_C(name,_segment_ct) *next = segment->next; \
|
||||
M_MEMORY_DEL (segment); \
|
||||
segment = next; \
|
||||
} \
|
||||
/* Clean pointers to be safer */ \
|
||||
mem->free_list = NULL; \
|
||||
mem->current_segment = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name,_alloc)(name_t mem) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
/* Test if one object is in the free list */ \
|
||||
M_C(name,_union_ct) *ret = mem->free_list; \
|
||||
if (ret != NULL) { \
|
||||
/* Yes, so return it, and pop it from the free list */ \
|
||||
mem->free_list = ret->next; \
|
||||
return &ret->t; \
|
||||
} \
|
||||
/* No cheap free object exist. Test within a segment */ \
|
||||
M_C(name,_segment_ct) *segment = mem->current_segment; \
|
||||
M_ASSERT(segment != NULL); \
|
||||
unsigned int count = segment->count; \
|
||||
/* If segment is full, allocate a new one from the system */ \
|
||||
if (M_UNLIKELY (count >= MEMPOOL_MAX_PER_SEGMENT(type))) { \
|
||||
M_C(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (M_C(name,_segment_ct)); \
|
||||
if (M_UNLIKELY (new_segment == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (M_C(name,_segment_ct))); \
|
||||
return NULL; \
|
||||
} \
|
||||
new_segment->next = segment; \
|
||||
new_segment->count = 0; \
|
||||
mem->current_segment = new_segment; \
|
||||
segment = new_segment; \
|
||||
count = 0; \
|
||||
} \
|
||||
/* Return the object as the last element of the current segment */ \
|
||||
ret = &segment->tab[count]; \
|
||||
segment->count = count + 1; \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
return &ret->t; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_free)(name_t mem, type *ptr) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
/* NOTE: Unsafe cast: suppose that the given pointer \
|
||||
was allocated by the previous alloc function. */ \
|
||||
M_C(name,_union_ct) *ret = (M_C(name,_union_ct) *)(uintptr_t)ptr; \
|
||||
/* Add the object back in the free list */ \
|
||||
ret->next = mem->free_list; \
|
||||
mem->free_list = ret; \
|
||||
/* NOTE: the objects are NOT given back to the system until the mempool \
|
||||
is fully cleared */ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
} \
|
||||
|
||||
#define MEMPOOLI_CONTRACT(mempool, type) do { \
|
||||
assert((mempool) != NULL); \
|
||||
assert((mempool)->current_segment != NULL); \
|
||||
assert((mempool)->current_segment->count <= MEMPOOL_MAX_PER_SEGMENT(type)); \
|
||||
/* MEMPOOL contract */
|
||||
#define MEMPOOLI_CONTRACT(mempool, type) do { \
|
||||
M_ASSERT((mempool) != NULL); \
|
||||
M_ASSERT((mempool)->current_segment != NULL); \
|
||||
M_ASSERT((mempool)->current_segment->count <= MEMPOOL_MAX_PER_SEGMENT(type)); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin Mutex & Thread wrapper
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -25,16 +25,29 @@
|
||||
#ifndef MSTARLIB_MUTEX_H
|
||||
#define MSTARLIB_MUTEX_H
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \
|
||||
/* Auto-detect the thread backend to use if the user has not override it */
|
||||
#ifndef M_USE_THREAD_BACKEND
|
||||
# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \
|
||||
&& !defined(__STDC_NO_THREADS__)
|
||||
# define M_USE_THREAD_BACKEND 1
|
||||
# elif defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
|
||||
# define M_USE_THREAD_BACKEND 2
|
||||
# else
|
||||
# define M_USE_THREAD_BACKEND 3
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/****************************** C11 version ********************************/
|
||||
#if M_USE_THREAD_BACKEND == 1
|
||||
|
||||
#include <threads.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include "m-core.h"
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a mutex type based on C11 definition */
|
||||
typedef mtx_t m_mutex_t[1];
|
||||
|
||||
@@ -116,7 +129,7 @@ static inline void m_thread_create(m_thread_t t, void (*func)(void*), void* arg)
|
||||
static inline void m_thread_join(m_thread_t t)
|
||||
{
|
||||
int rc = thrd_join(*t, NULL);
|
||||
assert (rc == thrd_success);
|
||||
M_ASSERT (rc == thrd_success);
|
||||
// Avoid warning about variable unused.
|
||||
(void) rc;
|
||||
}
|
||||
@@ -133,20 +146,20 @@ static inline void m_thread_yield(void)
|
||||
static inline bool m_thread_sleep(unsigned long long usec)
|
||||
{
|
||||
struct timespec tv;
|
||||
tv.tv_sec = usec / 1000000ULL;
|
||||
tv.tv_nsec = (usec % 1000000ULL) * 1000UL;
|
||||
tv.tv_sec = (long) (usec / 1000000ULL);
|
||||
tv.tv_nsec = (long) ((usec % 1000000ULL) * 1000UL);
|
||||
int retval = thrd_sleep(&tv, NULL);
|
||||
return retval == 0;
|
||||
}
|
||||
|
||||
// Internal type, not exported.
|
||||
typedef once_flag m_oncei_t[1];
|
||||
typedef once_flag m_once_ct[1];
|
||||
|
||||
// Initial value for m_oncei_t
|
||||
// Initial value for m_once_ct
|
||||
#define M_ONCEI_INIT_VALUE { ONCE_FLAG_INIT }
|
||||
|
||||
// Call the function exactly once
|
||||
static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
|
||||
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
|
||||
{
|
||||
call_once(o,func);
|
||||
}
|
||||
@@ -154,11 +167,31 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
|
||||
// Attribute to use to allocate a global variable to a thread.
|
||||
#define M_THREAD_ATTR _Thread_local
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
// MSYS2 doesn't define _WIN32 by default.
|
||||
#elif defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
|
||||
|
||||
/****************************** WIN32 version ******************************/
|
||||
#elif M_USE_THREAD_BACKEND == 2
|
||||
|
||||
/* CLANG provides some useless and wrong warnings:
|
||||
* - _WIN32_WINNT starts with '_' which is reserved by the standard
|
||||
* as per the MSVC compiler, it is needed to be defined by the user
|
||||
* to define which version of windows it want to be compatible with.
|
||||
* - windows.h may be different than the case used by the file sytem
|
||||
* there is however no normalized case.
|
||||
*
|
||||
* So, theses warnings have to be ignored and are disabled.
|
||||
*
|
||||
* We cannot add theses warnings in M_BEGIN_PROTECTED_CODE
|
||||
* as they need to be disabled **BEFORE** including any system header
|
||||
* and m-core includes some system headers.
|
||||
* So we need to disable them explictly here.
|
||||
*/
|
||||
#if defined(__clang__) && __clang_major__ >= 4
|
||||
_Pragma("clang diagnostic push")
|
||||
_Pragma("clang diagnostic ignored \"-Wreserved-id-macro\"")
|
||||
_Pragma("clang diagnostic ignored \"-Wnonportable-system-include-path\"")
|
||||
#endif
|
||||
|
||||
/* CriticalSection & ConditionVariable are available from Windows Vista */
|
||||
#ifndef WINVER
|
||||
@@ -167,11 +200,19 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
#endif
|
||||
|
||||
/* Include system headers */
|
||||
#include <windows.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include "m-core.h"
|
||||
|
||||
#if defined(__clang__) && __clang_major__ >= 4
|
||||
_Pragma("clang diagnostic pop")
|
||||
#endif
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a thread type based on WINDOWS definition */
|
||||
typedef HANDLE m_thread_t[1];
|
||||
|
||||
@@ -247,7 +288,7 @@ static inline void m_thread_join(m_thread_t t)
|
||||
{
|
||||
DWORD dwWaitResult = WaitForSingleObject(*t, INFINITE);
|
||||
(void) dwWaitResult;
|
||||
assert (dwWaitResult == WAIT_OBJECT_0);
|
||||
M_ASSERT (dwWaitResult == WAIT_OBJECT_0);
|
||||
CloseHandle(*t);
|
||||
}
|
||||
|
||||
@@ -263,7 +304,8 @@ static inline void m_thread_yield(void)
|
||||
static inline bool m_thread_sleep(unsigned long long usec)
|
||||
{
|
||||
LARGE_INTEGER ft;
|
||||
ft.QuadPart = -(10ULL*usec);
|
||||
M_ASSERT (usec <= LLONG_MAX);
|
||||
ft.QuadPart = -(10LL*(long long) usec);
|
||||
HANDLE hd = CreateWaitableTimer(NULL, TRUE, NULL);
|
||||
M_ASSERT_INIT (hd != NULL, "timer");
|
||||
SetWaitableTimer(hd, &ft, 0, NULL, NULL, 0);
|
||||
@@ -274,7 +316,7 @@ static inline bool m_thread_sleep(unsigned long long usec)
|
||||
|
||||
|
||||
// Internal type, not exported.
|
||||
typedef INIT_ONCE m_oncei_t[1];
|
||||
typedef INIT_ONCE m_once_ct[1];
|
||||
#define M_ONCEI_INIT_VALUE { INIT_ONCE_STATIC_INIT }
|
||||
static inline BOOL CALLBACK m_oncei_callback( PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext)
|
||||
{
|
||||
@@ -285,7 +327,7 @@ static inline BOOL CALLBACK m_oncei_callback( PINIT_ONCE InitOnce, PVOID Paramet
|
||||
(*func)();
|
||||
return TRUE;
|
||||
}
|
||||
static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
|
||||
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
|
||||
{
|
||||
InitOnceExecuteOnce(o, m_oncei_callback, (void*)(intptr_t)func, NULL);
|
||||
}
|
||||
@@ -298,9 +340,11 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
|
||||
# define M_THREAD_ATTR __thread
|
||||
#endif
|
||||
|
||||
#else
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/**************************** PTHREAD version ******************************/
|
||||
#else
|
||||
|
||||
#include <pthread.h>
|
||||
#ifdef _POSIX_PRIORITY_SCHEDULING
|
||||
@@ -313,6 +357,8 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
|
||||
#include <stdbool.h>
|
||||
#include "m-core.h"
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a mutex type based on PTHREAD definition */
|
||||
typedef pthread_mutex_t m_mutex_t[1];
|
||||
|
||||
@@ -403,7 +449,7 @@ static inline void m_thread_join(m_thread_t t)
|
||||
{
|
||||
int _rc = pthread_join(*t, NULL);
|
||||
(void)_rc; // Avoid warning about variable unused.
|
||||
assert (_rc == 0);
|
||||
M_ASSERT (_rc == 0);
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
@@ -422,25 +468,26 @@ static inline bool m_thread_sleep(unsigned long long usec)
|
||||
struct timeval tv;
|
||||
/* We don't want to use usleep or nanosleep so that
|
||||
we remain compatible with strict C99 build */
|
||||
tv.tv_sec = usec / 1000000ULL;
|
||||
tv.tv_usec = usec % 1000000ULL;
|
||||
tv.tv_sec = (time_t) (usec / 1000000ULL);
|
||||
tv.tv_usec = (suseconds_t) (usec % 1000000ULL);
|
||||
int retval = select(1, NULL, NULL, NULL, &tv);
|
||||
return retval == 0;
|
||||
}
|
||||
|
||||
// Internal type, not exported.
|
||||
typedef pthread_once_t m_oncei_t[1];
|
||||
typedef pthread_once_t m_once_ct[1];
|
||||
#define M_ONCEI_INIT_VALUE { PTHREAD_ONCE_INIT }
|
||||
static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
|
||||
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
|
||||
{
|
||||
pthread_once(o,func);
|
||||
}
|
||||
|
||||
#define M_THREAD_ATTR __thread
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
|
||||
// TODO: m_thread_sleep doesn't yield thread during waiting, making it a poor choice for active waiting.
|
||||
// TODO: Obsolete M_LOCK macro.
|
||||
|
||||
/* M_LOCK macro. Allow simple locking encapsulation.
|
||||
@@ -456,25 +503,25 @@ static inline void m_oncei_call(m_oncei_t o, void (*func)(void))
|
||||
or using C11's ONCE mechanism */
|
||||
#ifdef M_MUTEXI_INIT_VALUE
|
||||
# define M_LOCK_DECL(name) m_mutex_t name = M_MUTEXI_INIT_VALUE
|
||||
# define M_LOCK(name) \
|
||||
# define M_LOCK(name) \
|
||||
M_LOCKI_DO(name, M_C(local_cont_, __LINE__), m_mutexi_lazy_lock, m_mutex_unlock)
|
||||
#else
|
||||
# define M_LOCK_DECL(name) \
|
||||
m_mutex_t name; \
|
||||
static void M_C(m_mutex_init_, name)(void) { \
|
||||
m_mutex_init(name); \
|
||||
} \
|
||||
m_oncei_t M_C(m_once_, name) = M_ONCEI_INIT_VALUE
|
||||
# define M_LOCKI_BY_ONCE(name) \
|
||||
(m_oncei_call(M_C(m_once_, name), M_C(m_mutex_init_, name)), \
|
||||
# define M_LOCK_DECL(name) \
|
||||
m_mutex_t name; \
|
||||
static void M_C(m_mutex_init_, name)(void) { \
|
||||
m_mutex_init(name); \
|
||||
} \
|
||||
m_once_ct M_C(m_once_, name) = M_ONCEI_INIT_VALUE
|
||||
# define M_LOCKI_BY_ONCE(name) \
|
||||
(m_oncei_call(M_C(m_once_, name), M_C(m_mutex_init_, name)), \
|
||||
m_mutex_lock(name), (void) 0 )
|
||||
# define M_LOCK(name) \
|
||||
# define M_LOCK(name) \
|
||||
M_LOCKI_DO(name, M_C(local_cont_, __LINE__), M_LOCKI_BY_ONCE, m_mutex_unlock)
|
||||
#endif
|
||||
|
||||
#define M_LOCKI_DO(name, cont, lock_func, unlock_func) \
|
||||
for(bool cont = true \
|
||||
; cont && (lock_func (name), true); \
|
||||
#define M_LOCKI_DO(name, cont, lock_func, unlock_func) \
|
||||
for(bool cont = true \
|
||||
; cont && (lock_func (name), true); \
|
||||
(unlock_func (name), cont = false))
|
||||
|
||||
#endif
|
||||
+361
-306
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - dynamic priority queue module
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -26,23 +26,36 @@
|
||||
#define MSTARLIB_PRIOQUEUE_H
|
||||
|
||||
#include "m-core.h"
|
||||
#include "m-array.h"
|
||||
#include "m-array.h" /* Priority queue are built upon array */
|
||||
|
||||
/* Priority queue based on binary heap implementation */
|
||||
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
USAGE: PRIOQUEUE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define PRIOQUEUE_DEF(name, ...) \
|
||||
PRIOQUEUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define PRIOQUEUE_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
PRIOQUEUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name,_it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t))))
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t)))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
as the name name_t with an iterator named it_t
|
||||
USAGE: PRIOQUEUE_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define PRIOQUEUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
PRIOQUEUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a prioqueue of type.
|
||||
USAGE: PRIOQUEUE_OPLIST(name[, oplist of the type]) */
|
||||
#define PRIOQUEUE_OPLIST(...) \
|
||||
PRIOQUEUEI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
#define PRIOQUEUE_OPLIST(...) \
|
||||
PRIOQUEUEI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -54,31 +67,40 @@
|
||||
#define PRIOQUEUEI_OPLIST_P1(arg) PRIOQUEUEI_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define PRIOQUEUEI_OPLIST_P2(name, oplist) \
|
||||
#define PRIOQUEUEI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(PRIOQUEUEI_OPLIST_P3, PRIOQUEUEI_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define PRIOQUEUEI_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_PRIOQUEUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
#define PRIOQUEUEI_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_PRIOQUEUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
/* Define oplist of a priority queue */
|
||||
#define PRIOQUEUEI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
,SET(M_C(name, _set)) \
|
||||
,CLEAR(M_C(name, _clear)) \
|
||||
,INIT_MOVE(M_C(name, _init_move)) \
|
||||
,MOVE(M_C(name, _move)) \
|
||||
,SWAP(M_C(name, _swap)) \
|
||||
,TYPE(M_C(name,_t)) \
|
||||
,SUBTYPE(M_C(name, _type_t)) \
|
||||
,CLEAN(M_C(name,_clean)) \
|
||||
,PUSH(M_C(name,_push)) \
|
||||
,POP(M_C(name,_pop)) \
|
||||
,OPLIST(oplist) \
|
||||
,TEST_EMPTY(M_C(name, _empty_p)), \
|
||||
,GET_SIZE(M_C(name, _size)) \
|
||||
#define PRIOQUEUEI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
,SET(M_C(name, _set)) \
|
||||
,CLEAR(M_C(name, _clear)) \
|
||||
,INIT_MOVE(M_C(name, _init_move)) \
|
||||
,MOVE(M_C(name, _move)) \
|
||||
,SWAP(M_C(name, _swap)) \
|
||||
,TYPE(M_C(name,_ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,CLEAN(M_C(name,_clean)) \
|
||||
,PUSH(M_C(name,_push)) \
|
||||
,POP(M_C(name,_pop)) \
|
||||
,OPLIST(oplist) \
|
||||
,EMPTY_P(M_C(name, _empty_p)), \
|
||||
,GET_SIZE(M_C(name, _size)) \
|
||||
,IT_TYPE(M_C(name, _it_ct)), \
|
||||
IT_FIRST(M_C(name,_it)), \
|
||||
IT_END(M_C(name,_it_end)), \
|
||||
IT_SET(M_C(name,_it_set)), \
|
||||
IT_END_P(M_C(name,_end_p)), \
|
||||
IT_EQUAL_P(M_C(name,_it_equal_p)), \
|
||||
IT_LAST_P(M_C(name,_last_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
)
|
||||
|
||||
|
||||
@@ -87,11 +109,11 @@
|
||||
#define PRIOQUEUEI_DEF_P1(arg) PRIOQUEUEI_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define PRIOQUEUEI_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
|
||||
#define PRIOQUEUEI_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(PRIOQUEUEI_DEF_P3, PRIOQUEUEI_DEF_FAILURE)(name, type, oplist, prioqueue_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define PRIOQUEUEI_DEF_FAILURE(name, type, oplist, prioqueue_t, it_t) \
|
||||
#define PRIOQUEUEI_DEF_FAILURE(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(PRIOQUEUE_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Define the priority queue:
|
||||
@@ -101,283 +123,316 @@
|
||||
- prioqueue_t: type of the container,
|
||||
- it_t: iterator of the container
|
||||
*/
|
||||
#define PRIOQUEUEI_DEF_P3(name, type, oplist, prioqueue_t, it_t) \
|
||||
ARRAY_DEF(M_C(name, _array), type, oplist) \
|
||||
\
|
||||
typedef type M_C(name, _type_t); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _array_t) array; \
|
||||
} prioqueue_t[1]; \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
\
|
||||
typedef M_C(name, _array_it_t) it_t; \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_init)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(prioqueue_t p, prioqueue_t const o) \
|
||||
{ \
|
||||
M_C(name, _array_init_set)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(prioqueue_t p, prioqueue_t const o) \
|
||||
{ \
|
||||
M_C(name, _array_set)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_clear)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_init_move)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_move)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_swap)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_clean)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_parent)(size_t i) \
|
||||
{ \
|
||||
assert (i > 0); \
|
||||
return (i - 1) / 2; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_lchild)(size_t i) \
|
||||
{ \
|
||||
assert(i <= ((-(size_t)1)-2)/2); \
|
||||
return 2*i + 1; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_rchild)(size_t i) \
|
||||
{ \
|
||||
assert(i <= ((-(size_t)1)-2)/2); \
|
||||
return 2*i + 2; \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
M_C(name, _i_cmp)(const prioqueue_t p, size_t i, size_t j) \
|
||||
{ \
|
||||
return M_CALL_CMP(oplist, *M_C(name, _array_cget)(p->array, i), \
|
||||
*M_C(name, _array_cget)(p->array, j)); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_empty_p)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_size)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push)(prioqueue_t p, type const x) \
|
||||
{ \
|
||||
M_C(name, _array_push_back)(p->array, x); \
|
||||
\
|
||||
size_t i = M_C(name, _array_size)(p->array)-1; \
|
||||
while (i > 0) { \
|
||||
size_t j = M_C(name, _i_parent)(i); \
|
||||
if (M_C(name, _i_cmp)(p, j, i) <= 0) \
|
||||
break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, j); \
|
||||
i = j; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _front)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_cget)(p->array, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _pop)(type *x, prioqueue_t p) \
|
||||
{ \
|
||||
size_t size = M_C(name, _array_size)(p->array)-1; \
|
||||
M_C(name, _array_swap_at) (p->array, 0, size); \
|
||||
M_C(name, _array_pop_back)(x, p->array); \
|
||||
\
|
||||
size_t i = 0; \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
if (child >= size) break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it_last)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it_end)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t it, const it_t org) \
|
||||
{ \
|
||||
M_C(name, _array_it_set)(it, org); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_end_p)(it); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _last_p)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_last_p)(it); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_equal_p)(const it_t it1, \
|
||||
const it_t it2) \
|
||||
{ \
|
||||
return M_C(name, _array_it_equal_p)(it1, it2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _next)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _array_next)(it); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _previous)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _array_previous)(it); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_cref)(it); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(EQUAL, oplist) \
|
||||
( \
|
||||
/* EQUAL & CMP may be uncorrelated */ \
|
||||
static inline bool \
|
||||
M_C(name, _erase)(prioqueue_t p, type x) \
|
||||
{ \
|
||||
/* First pass: search for an item EQUAL to x */ \
|
||||
/* NOTE: An HASHMAP may be a good idea to optimize this pass. */ \
|
||||
size_t size = M_C(name, _array_size)(p->array); \
|
||||
size_t i = 0; \
|
||||
for(i = 0; i < size; i++) { \
|
||||
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), x)) \
|
||||
break; \
|
||||
} \
|
||||
/* If x is not found, then stop */ \
|
||||
if (i >= size) \
|
||||
return false; \
|
||||
/* Swap the found item and the last element */ \
|
||||
size--; \
|
||||
M_C(name, _array_swap_at) (p->array, i, size); \
|
||||
M_C(name, _array_pop_back)(NULL, p->array); \
|
||||
#define PRIOQUEUEI_DEF_P3(name, type, oplist, prioqueue_t, it_t) \
|
||||
\
|
||||
/* Definition of the internal array used to construct the priority queue */ \
|
||||
ARRAY_DEF(M_C(name, _array), type, oplist) \
|
||||
\
|
||||
/* Define the priority queue over the defined array */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _array_t) array; \
|
||||
} prioqueue_t[1]; \
|
||||
/* Define the pointer references to the priority queue */ \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
\
|
||||
/* The iterator is the same one as the one of the internal array */ \
|
||||
typedef M_C(name, _array_it_t) it_t; \
|
||||
\
|
||||
/* Definition of the internal types used by the oplist */ \
|
||||
typedef prioqueue_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
typedef it_t M_C(name, _it_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_init)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(prioqueue_t p, prioqueue_t const o) \
|
||||
{ \
|
||||
M_C(name, _array_init_set)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(prioqueue_t p, prioqueue_t const o) \
|
||||
{ \
|
||||
M_C(name, _array_set)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_clear)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_init_move)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_move)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_swap)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_clean)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_parent)(size_t i) \
|
||||
{ \
|
||||
M_ASSERT (i > 0); \
|
||||
return (i - 1) / 2; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_lchild)(size_t i) \
|
||||
{ \
|
||||
M_ASSERT(i <= ((SIZE_MAX)-2)/2); \
|
||||
return 2*i + 1; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_rchild)(size_t i) \
|
||||
{ \
|
||||
M_ASSERT(i <= ((SIZE_MAX)-2)/2); \
|
||||
return 2*i + 2; \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
M_C(name, _i_cmp)(const prioqueue_t p, size_t i, size_t j) \
|
||||
{ \
|
||||
return M_CALL_CMP(oplist, *M_C(name, _array_cget)(p->array, i), \
|
||||
*M_C(name, _array_cget)(p->array, j)); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_empty_p)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_size)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push)(prioqueue_t p, type const x) \
|
||||
{ \
|
||||
/* Push back the new element at the end of the array */ \
|
||||
M_C(name, _array_push_back)(p->array, x); \
|
||||
\
|
||||
/* Reorder the array by swapping with its parent \
|
||||
* until it reaches the right position */ \
|
||||
size_t i = M_C(name, _array_size)(p->array)-1; \
|
||||
while (i > 0) { \
|
||||
size_t j = M_C(name, _i_parent)(i); \
|
||||
if (M_C(name, _i_cmp)(p, j, i) <= 0) \
|
||||
break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, j); \
|
||||
i = j; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _front)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_cget)(p->array, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _pop)(type *x, prioqueue_t p) \
|
||||
{ \
|
||||
/* Swap the front element with the last element */ \
|
||||
size_t size = M_C(name, _array_size)(p->array)-1; \
|
||||
M_C(name, _array_swap_at) (p->array, 0, size); \
|
||||
/* Swap the new last element */ \
|
||||
M_C(name, _array_pop_back)(x, p->array); \
|
||||
\
|
||||
/* Reorder the heap */ \
|
||||
size_t i = 0; \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
if (child >= size) \
|
||||
break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) \
|
||||
break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Define iterators over the array iterator */ \
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it_last)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it_end)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t it, const it_t org) \
|
||||
{ \
|
||||
M_C(name, _array_it_set)(it, org); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_end_p)(it); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _last_p)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_last_p)(it); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_equal_p)(const it_t it1, \
|
||||
const it_t it2) \
|
||||
{ \
|
||||
return M_C(name, _array_it_equal_p)(it1, it2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _next)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _array_next)(it); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _previous)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _array_previous)(it); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_cref)(it); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(EQUAL, oplist) \
|
||||
( \
|
||||
/* EQUAL & CMP may be uncorrelated */ \
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(prioqueue_t const p, prioqueue_t const q) \
|
||||
{ \
|
||||
return M_C(name, _array_equal_p)(p->array, q->array); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _erase)(prioqueue_t p, type x) \
|
||||
{ \
|
||||
/* First pass: search for an item EQUAL to x */ \
|
||||
/* NOTE: An HASHMAP may be a good idea to optimize this pass. */ \
|
||||
size_t size = M_C(name, _array_size)(p->array); \
|
||||
size_t i = 0; \
|
||||
for(i = 0; i < size; i++) { \
|
||||
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), x)) \
|
||||
break; \
|
||||
} \
|
||||
/* If x is not found, then stop */ \
|
||||
if (i >= size) \
|
||||
return false; \
|
||||
/* Swap the found item and the last element */ \
|
||||
size--; \
|
||||
M_C(name, _array_swap_at) (p->array, i, size); \
|
||||
M_C(name, _array_pop_back)(NULL, p->array); \
|
||||
/* Move back the last swapped element to its right position in the heap */ \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
if (child >= size) break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _update_further)(prioqueue_t p, type xold, type xnew) \
|
||||
{ \
|
||||
/* This update assumes that the new position is further in the heap */ \
|
||||
assert (M_CALL_CMP(oplist, xold, xnew) > 0); \
|
||||
/* First pass: search for an item EQUAL to x */ \
|
||||
size_t size = M_C(name, _array_size)(p->array); \
|
||||
size_t i = 0; \
|
||||
for(i = 0; i < size; i++) { \
|
||||
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), xold)) \
|
||||
break; \
|
||||
} \
|
||||
/* We shall have found the item */ \
|
||||
assert (i < size); \
|
||||
/* Set the found item to the new element */ \
|
||||
M_C(name, _array_set_at) (p->array, i, xnew); \
|
||||
/* Move back the updated element to its right position in the heap */ \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
if (child >= size) break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
, /* No EQUAL */ ) \
|
||||
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
if (child >= size) break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _update)(prioqueue_t p, type const xold, type const xnew) \
|
||||
{ \
|
||||
/* NOTE: xold can be the same pointer than xnew */ \
|
||||
/* First pass: search for an item EQUAL to x */ \
|
||||
size_t size = M_C(name, _array_size)(p->array); \
|
||||
size_t i = 0; \
|
||||
for(i = 0; i < size; i++) { \
|
||||
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), xold)) \
|
||||
break; \
|
||||
} \
|
||||
/* We shall have found the item */ \
|
||||
M_ASSERT (i < size); \
|
||||
/* Test if the position of the old data is further or nearer than the new */ \
|
||||
int cmp = M_CALL_CMP(oplist, *M_C(name, _array_cget)(p->array, i), xnew); \
|
||||
/* Set the found item to the new element */ \
|
||||
M_C(name, _array_set_at) (p->array, i, xnew); \
|
||||
if (cmp < 0) { \
|
||||
/* Move back the updated element to its new position, further in the heap */ \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
if (child >= size) break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
} else { \
|
||||
/* Move back the updated element to its new position, nearest in the heap */ \
|
||||
while (i > 0) { \
|
||||
size_t parent = M_C(name, _i_parent)(i); \
|
||||
if (M_C(name, _i_cmp)(p, parent, i) <= 0) break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, parent); \
|
||||
i = parent; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
, /* No EQUAL */ ) \
|
||||
|
||||
|
||||
// TODO: set all & remove all function
|
||||
|
||||
|
||||
+1043
-1027
File diff suppressed because it is too large.
Load diff
+138
-41
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Serial BIN
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -30,6 +30,80 @@
|
||||
#include "m-core.h"
|
||||
#include "m-string.h"
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Internal service:
|
||||
* Write size_t in the stream in a compact form to reduce consumption
|
||||
* (and I/O bandwidth)
|
||||
*/
|
||||
static inline bool
|
||||
m_serial_bin_write_size(FILE *f, const size_t size)
|
||||
{
|
||||
bool b;
|
||||
if (M_LIKELY(size < 253))
|
||||
{
|
||||
b = EOF != fputc((unsigned char) size, f);
|
||||
} else if (size < 1ULL << 16) {
|
||||
b = EOF != fputc(253, f); // Save 16 bits encoding
|
||||
b &= EOF != fputc((unsigned char) (size >> 8), f);
|
||||
b &= EOF != fputc((unsigned char) size, f);
|
||||
}
|
||||
// For 32 bits systems, don't encode a 64 bits size_t
|
||||
#if SIZE_MAX < 1ULL<< 32
|
||||
else {
|
||||
b = EOF != fputc(254, f); // Save 32 bits encoding
|
||||
b &= EOF != fputc((unsigned char) (size >> 24), f);
|
||||
b &= EOF != fputc((unsigned char) (size >> 16), f);
|
||||
b &= EOF != fputc((unsigned char) (size >> 8), f);
|
||||
b &= EOF != fputc((unsigned char) size, f);
|
||||
}
|
||||
#else
|
||||
else if (size < 1ULL<< 32) {
|
||||
b = EOF != fputc(254, f); // Save 32 bits encoding
|
||||
b &= EOF != fputc((unsigned char) (size >> 24), f);
|
||||
b &= EOF != fputc((unsigned char) (size >> 16), f);
|
||||
b &= EOF != fputc((unsigned char) (size >> 8), f);
|
||||
b &= EOF != fputc((unsigned char) size, f);
|
||||
} else {
|
||||
b = EOF != fputc(255, f); // Save 64 bits encoding
|
||||
b &= EOF != fputc((unsigned char) (size >> 56), f);
|
||||
b &= EOF != fputc((unsigned char) (size >> 48), f);
|
||||
b &= EOF != fputc((unsigned char) (size >> 40), f);
|
||||
b &= EOF != fputc((unsigned char) (size >> 32), f);
|
||||
b &= EOF != fputc((unsigned char) (size >> 24), f);
|
||||
b &= EOF != fputc((unsigned char) (size >> 16), f);
|
||||
b &= EOF != fputc((unsigned char) (size >> 8), f);
|
||||
b &= EOF != fputc((unsigned char) size, f);
|
||||
}
|
||||
#endif
|
||||
return b;
|
||||
}
|
||||
|
||||
/* Internal service:
|
||||
* Read size_t in the stream from a compact form to reduce consumption
|
||||
* (and I/O bandwidth)
|
||||
*/
|
||||
static inline bool
|
||||
m_serial_bin_read_size(FILE *f, size_t *size)
|
||||
{
|
||||
int c;
|
||||
c = fgetc(f);
|
||||
if (M_UNLIKELY(c == EOF)) return false;
|
||||
if (M_LIKELY(c < 253)) {
|
||||
*size = (size_t) c;
|
||||
return true;
|
||||
}
|
||||
size_t s = 0;
|
||||
int l = (c = 255) ? 8 : (c == 254) ? 4 : 2;
|
||||
for(int i = 0; i < l; i++) {
|
||||
c = fgetc(f);
|
||||
if (M_UNLIKELY(c == EOF)) return false;
|
||||
s = (s << 8) | (size_t) c;
|
||||
}
|
||||
*size = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Write the boolean 'data' into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
@@ -37,7 +111,7 @@ m_serial_bin_write_boolean(m_serial_write_t serial, const bool data)
|
||||
{
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
size_t n = fwrite (M_ASSIGN_CAST(const void*, &data), sizeof (bool), 1, f);
|
||||
return n == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'.
|
||||
@@ -54,26 +128,26 @@ m_serial_bin_write_integer(m_serial_write_t serial,const long long data, const s
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
switch (size_of_type) {
|
||||
case 1:
|
||||
i8 = data;
|
||||
i8 = (int8_t) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &i8), sizeof i8, 1, f);
|
||||
break;
|
||||
case 2:
|
||||
i16 = data;
|
||||
i16 = (int16_t) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &i16), sizeof i16, 1, f);
|
||||
break;
|
||||
case 4:
|
||||
i32 = data;
|
||||
i32 = (int32_t) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &i32), sizeof i32, 1, f);
|
||||
break;
|
||||
case 8:
|
||||
i64 = data;
|
||||
i64 = (int64_t) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &i64), sizeof i64, 1, f);
|
||||
break;
|
||||
default:
|
||||
M_ASSERT_INIT(false, "an integer of suitable size");
|
||||
M_ASSERT_INIT(false, "an integer of suitable size (8/16/32/64)");
|
||||
break;
|
||||
}
|
||||
return n == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'.
|
||||
@@ -88,29 +162,34 @@ m_serial_bin_write_float(m_serial_write_t serial, const long double data, const
|
||||
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
if (size_of_type == sizeof f1) {
|
||||
f1 = data;
|
||||
f1 = (float) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &f1), sizeof f1, 1, f);
|
||||
} else if (size_of_type == sizeof f2) {
|
||||
f2 = data;
|
||||
f2 = (double) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &f2), sizeof f2, 1, f);
|
||||
} else if (size_of_type == sizeof f3) {
|
||||
f3 = data;
|
||||
f3 = (long double) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &f3), sizeof f3, 1, f);
|
||||
} else {
|
||||
M_ASSERT_INIT(false, "a float of suitable size");
|
||||
}
|
||||
return n == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write the null-terminated string 'data'into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_string(m_serial_write_t serial, const char data[])
|
||||
m_serial_bin_write_string(m_serial_write_t serial, const char data[], size_t length)
|
||||
{
|
||||
M_ASSERT_SLOW(length == strlen(data) );
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
size_t l = strlen(data);
|
||||
size_t n = fwrite (M_ASSIGN_CAST(const void*, data), 1, l+1, f);
|
||||
return n == l+1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
M_ASSERT(f != NULL && data != NULL);
|
||||
// Write first the number of (non null) characters
|
||||
if (m_serial_bin_write_size(f, length) != true) return m_core_serial_fail();
|
||||
// Write the characters (excluding the final null char)
|
||||
// NOTE: fwrite supports length == 0.
|
||||
size_t n = fwrite (M_ASSIGN_CAST(const void*, data), 1, length, f);
|
||||
return (n == length) ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start writing an array of 'number_of_elements' objects into the serial stream 'serial'.
|
||||
@@ -125,7 +204,7 @@ m_serial_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial,
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
size_t n = fwrite (M_ASSIGN_CAST(const void*, &number_of_elements), sizeof number_of_elements, 1, f);
|
||||
local->data[0].b = (number_of_elements == 0);
|
||||
return n == 1 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
|
||||
return n == 1 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write an array separator between elements of an array into the serial stream 'serial' if needed.
|
||||
@@ -138,7 +217,7 @@ m_serial_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
if (local->data[0].b) {
|
||||
size_t n = 0xABCDEF;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &n), sizeof n, 1, f);
|
||||
return n == 1 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
|
||||
return n == 1 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
} else {
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
@@ -154,7 +233,7 @@ m_serial_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
if (local->data[0].b) {
|
||||
size_t n = 0x12345678;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &n), sizeof n, 1, f);
|
||||
return n == 1 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
|
||||
return n == 1 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
} else {
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
@@ -218,7 +297,7 @@ m_serial_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial
|
||||
(void) local;
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
size_t n = fwrite (M_ASSIGN_CAST(const void*, &index), sizeof index, 1, f);
|
||||
return n == 1 ? ((index < 0) ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE) : M_SERIAL_FAIL;
|
||||
return n == 1 ? ((index < 0) ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE) : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* End Writing a variant into the serial stream 'serial'.
|
||||
@@ -263,6 +342,12 @@ static inline void m_serial_bin_write_clear(m_serial_write_t serial)
|
||||
}
|
||||
|
||||
|
||||
/* Define a synonym of m_serial_read_t to the BIN serializer with its proper OPLIST */
|
||||
typedef m_serial_write_t m_serial_bin_write_t;
|
||||
#define M_OPL_m_serial_bin_write_t() \
|
||||
(INIT_WITH(m_serial_bin_write_init), CLEAR(m_serial_bin_write_clear), TYPE(m_serial_bin_write_t) )
|
||||
|
||||
|
||||
/* Read from the stream 'serial' a boolean.
|
||||
Set '*b' with the boolean value if succeeds
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
@@ -270,7 +355,7 @@ static inline m_serial_return_code_t
|
||||
m_serial_bin_read_boolean(m_serial_read_t serial, bool *b){
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
size_t n = fread (M_ASSIGN_CAST(void*, b), sizeof (bool), 1, f);
|
||||
return n == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Read from the stream 'serial' an integer that can be represented with 'size_of_type' bytes.
|
||||
@@ -305,7 +390,7 @@ m_serial_bin_read_integer(m_serial_read_t serial, long long *i, const size_t siz
|
||||
M_ASSERT_INIT(false, "an integer of suitable size");
|
||||
break;
|
||||
}
|
||||
return n == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Read from the stream 'serial' a float that can be represented with 'size_of_type' bytes.
|
||||
@@ -330,7 +415,7 @@ m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
|
||||
} else {
|
||||
M_ASSERT_INIT(false, "a float of suitable size");
|
||||
}
|
||||
return n == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Read from the stream 'serial' a string.
|
||||
@@ -339,14 +424,19 @@ m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
string_clean(s);
|
||||
int c;
|
||||
c = fgetc(f);
|
||||
while (c != 0 && c != EOF) {
|
||||
string_push_back(s, c);
|
||||
c = fgetc(f);
|
||||
}
|
||||
return c != EOF ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
M_ASSERT(f != NULL && s != NULL);
|
||||
// First read the number of non null characters
|
||||
size_t length;
|
||||
if (m_serial_bin_read_size(f, &length) != true) return m_core_serial_fail();
|
||||
// Use of internal string interface to dimension the string
|
||||
char *p = stringi_fit2size(s, length + 1);
|
||||
stringi_set_size(s, length);
|
||||
// Read the characters excluding the final null one.
|
||||
// NOTE: fread supports length == 0.
|
||||
size_t n = fread(M_ASSIGN_CAST(void*, p), 1, length, f);
|
||||
// Force the final null character
|
||||
p[length] = 0;
|
||||
return (n == length) ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start reading from the stream 'serial' an array.
|
||||
@@ -362,7 +452,7 @@ m_serial_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, si
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
size_t n = fread (M_ASSIGN_CAST(void*, num), sizeof *num, 1, f);
|
||||
if (n != 1)
|
||||
return M_SERIAL_FAIL;
|
||||
return m_core_serial_fail();
|
||||
local->data[0].b = (*num == 0);
|
||||
local->data[1].s = *num;
|
||||
if (local->data[0].b) {
|
||||
@@ -370,8 +460,8 @@ m_serial_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, si
|
||||
size_t p;
|
||||
n = fread (M_ASSIGN_CAST(void*, &p), sizeof p, 1, f);
|
||||
if (n != 1)
|
||||
return M_SERIAL_FAIL;
|
||||
return p == 0xABCDEF ? M_SERIAL_OK_CONTINUE : p == 0x12345678 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return m_core_serial_fail();
|
||||
return p == 0xABCDEF ? M_SERIAL_OK_CONTINUE : p == 0x12345678 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
@@ -389,10 +479,10 @@ m_serial_bin_read_array_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
size_t p, n;
|
||||
n = fread (M_ASSIGN_CAST(void*, &p), sizeof p, 1, f);
|
||||
if (n != 1)
|
||||
return M_SERIAL_FAIL;
|
||||
return p == 0xABCDEF ? M_SERIAL_OK_CONTINUE : p == 0x12345678 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return m_core_serial_fail();
|
||||
return p == 0xABCDEF ? M_SERIAL_OK_CONTINUE : p == 0x12345678 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
} else {
|
||||
assert(local->data[1].s > 0);
|
||||
M_ASSERT(local->data[1].s > 0);
|
||||
local->data[1].s --;
|
||||
return local->data[1].s == 0 ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
@@ -417,7 +507,7 @@ static inline m_serial_return_code_t
|
||||
m_serial_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) serial;
|
||||
local->data[1].s = 0;
|
||||
local->data[1].i = 0;
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
@@ -433,8 +523,8 @@ m_serial_bin_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const
|
||||
(void) serial;
|
||||
(void) field_name;
|
||||
(void) max;
|
||||
*id = local->data[1].s;
|
||||
local->data[1].s ++;
|
||||
*id = local->data[1].i;
|
||||
local->data[1].i ++;
|
||||
return (*id == max) ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
@@ -452,7 +542,7 @@ m_serial_bin_read_variant_start(m_serial_local_t local, m_serial_read_t serial,
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
size_t n = fread (M_ASSIGN_CAST(void*, id), sizeof *id, 1, f);
|
||||
return n == 1 ? ((*id < 0) ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE) : M_SERIAL_FAIL;
|
||||
return n == 1 ? ((*id < 0) ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE) : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* End reading a variant from the stream 'serial'.
|
||||
@@ -493,4 +583,11 @@ static inline void m_serial_bin_read_clear(m_serial_read_t serial)
|
||||
(void) serial; // Nothing to do
|
||||
}
|
||||
|
||||
/* Define a synonym of m_serial_read_t to the BIN serializer with its proper OPLIST */
|
||||
typedef m_serial_read_t m_serial_bin_read_t;
|
||||
#define M_OPL_m_serial_bin_read_t() \
|
||||
(INIT_WITH(m_serial_bin_read_init), CLEAR(m_serial_bin_read_clear), TYPE(m_serial_bin_read_t) )
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
+85
-63
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Serial JSON
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "m-core.h"
|
||||
#include "m-string.h"
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Write the boolean 'data' into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
@@ -35,7 +37,7 @@ m_serial_json_write_boolean(m_serial_write_t serial, const bool data)
|
||||
{
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, "%s", data ? "true" : "false");
|
||||
return n > 0 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'.
|
||||
@@ -46,7 +48,7 @@ m_serial_json_write_integer(m_serial_write_t serial,const long long data, const
|
||||
(void) size_of_type; // Ignored
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, "%lld", data);
|
||||
return n > 0 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'.
|
||||
@@ -57,20 +59,22 @@ m_serial_json_write_float(m_serial_write_t serial, const long double data, const
|
||||
(void) size_of_type; // Ignored
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, "%Lf", data);
|
||||
return n > 0 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write the null-terminated string 'data'into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_json_write_string(m_serial_write_t serial, const char data[])
|
||||
m_serial_json_write_string(m_serial_write_t serial, const char data[], size_t length)
|
||||
{
|
||||
M_ASSERT_SLOW(length == strlen(data) );
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
/* Build dummy string to reuse string_out_str */
|
||||
M_ASSERT(f != NULL && data != NULL);
|
||||
/* HACK: Build dummy string to reuse string_out_str */
|
||||
string_t v2;
|
||||
uintptr_t ptr = (uintptr_t) data;
|
||||
v2->u.heap.size = strlen(data);
|
||||
v2->u.heap.alloc = v2->u.heap.size + 1;
|
||||
v2->u.heap.size = length;
|
||||
v2->u.heap.alloc = length + 1;
|
||||
v2->ptr = (char*)ptr;
|
||||
string_out_str(f, v2);
|
||||
return M_SERIAL_OK_DONE;
|
||||
@@ -89,7 +93,7 @@ m_serial_json_write_array_start(m_serial_local_t local, m_serial_write_t serial,
|
||||
(void) number_of_elements; // Ignored
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, "[");
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write an array separator between elements of an array into the serial stream 'serial' if needed.
|
||||
@@ -100,7 +104,7 @@ m_serial_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, ",");
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* End the writing of an array into the serial stream 'serial'.
|
||||
@@ -111,7 +115,7 @@ m_serial_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, "]");
|
||||
return n > 0 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start writing a map of 'number_of_elements' pairs of objects into the serial stream 'serial'.
|
||||
@@ -127,7 +131,7 @@ m_serial_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, c
|
||||
(void) number_of_elements; // Ignored
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, "{");
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write a value separator between element of the same pair of a map into the serial stream 'serial' if needed.
|
||||
@@ -138,7 +142,7 @@ m_serial_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, ":");
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write a map separator between elements of a map into the serial stream 'serial' if needed.
|
||||
@@ -149,7 +153,7 @@ m_serial_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, ",");
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* End the writing of a map into the serial stream 'serial'.
|
||||
@@ -160,7 +164,7 @@ m_serial_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, "}");
|
||||
return n > 0 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start writing a tuple into the serial stream 'serial'.
|
||||
@@ -173,7 +177,7 @@ m_serial_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, "{");
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'.
|
||||
@@ -185,7 +189,7 @@ m_serial_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, co
|
||||
(void) max; // Ignored
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, "%c\"%s\":", index == 0 ? ' ' : ',', field_name[index]);
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* End the write of a tuple into the serial stream 'serial'.
|
||||
@@ -196,7 +200,7 @@ m_serial_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, "}");
|
||||
return n > 0 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start writing a variant into the serial stream 'serial'.
|
||||
@@ -212,12 +216,12 @@ m_serial_json_write_variant_start(m_serial_local_t local, m_serial_write_t seria
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n;
|
||||
if (index >= 0) {
|
||||
assert (index < max);
|
||||
M_ASSERT (index < max);
|
||||
n = fprintf(f, "{\"%s\":", field_name[index]);
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
} else {
|
||||
n = fprintf(f, "{}");
|
||||
return n > 0 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +233,7 @@ m_serial_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
int n = fprintf(f, "}");
|
||||
return n > 0 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* The internal exported interface of m_serial_write_json. */
|
||||
@@ -267,7 +271,7 @@ static inline void m_serial_json_write_clear(m_serial_write_t serial)
|
||||
|
||||
/* Define a synonym to the JSON serializer with a proper OPLIST */
|
||||
typedef m_serial_write_t m_serial_json_write_t;
|
||||
#define M_OPL_m_serial_json_write_t() \
|
||||
#define M_OPL_m_serial_json_write_t() \
|
||||
(INIT_WITH(m_serial_json_write_init), CLEAR(m_serial_json_write_clear), TYPE(m_serial_json_write_t) )
|
||||
|
||||
|
||||
@@ -293,25 +297,25 @@ m_serial_json_read_boolean(m_serial_read_t serial, bool *b){
|
||||
if (c == 't') {
|
||||
*b = true;
|
||||
c = fgetc(f);
|
||||
if (c != 'r') return M_SERIAL_FAIL;
|
||||
if (c != 'r') return m_core_serial_fail();
|
||||
c = fgetc(f);
|
||||
if (c != 'u') return M_SERIAL_FAIL;
|
||||
if (c != 'u') return m_core_serial_fail();
|
||||
c = fgetc(f);
|
||||
if (c != 'e') return M_SERIAL_FAIL;
|
||||
if (c != 'e') return m_core_serial_fail();
|
||||
return M_SERIAL_OK_DONE;
|
||||
} else if (c == 'f') {
|
||||
*b = false;
|
||||
c = fgetc(f);
|
||||
if (c != 'a') return M_SERIAL_FAIL;
|
||||
if (c != 'a') return m_core_serial_fail();
|
||||
c = fgetc(f);
|
||||
if (c != 'l') return M_SERIAL_FAIL;
|
||||
if (c != 'l') return m_core_serial_fail();
|
||||
c = fgetc(f);
|
||||
if (c != 's') return M_SERIAL_FAIL;
|
||||
if (c != 's') return m_core_serial_fail();
|
||||
c = fgetc(f);
|
||||
if (c != 'e') return M_SERIAL_FAIL;
|
||||
if (c != 'e') return m_core_serial_fail();
|
||||
return M_SERIAL_OK_DONE;
|
||||
} else {
|
||||
return M_SERIAL_FAIL;
|
||||
return m_core_serial_fail();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,7 +326,7 @@ static inline m_serial_return_code_t
|
||||
m_serial_json_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
|
||||
(void) size_of_type; // Ignored
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
return fscanf(f, " %lld", i) == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return m_core_fscanf(f, " %lld", i) == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Read from the stream 'serial' a float that can be represented with 'size_of_type' bytes.
|
||||
@@ -332,7 +336,7 @@ static inline m_serial_return_code_t
|
||||
m_serial_json_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
|
||||
(void) size_of_type; // Ignored
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
return fscanf(f, " %Lf", r) == 1 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
return m_core_fscanf(f, " %Lf", r) == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Read from the stream 'serial' a string.
|
||||
@@ -341,8 +345,9 @@ m_serial_json_read_float(m_serial_read_t serial, long double *r, const size_t si
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_json_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
fscanf(f, " "); // Skip any leading spaces.
|
||||
return string_in_str(s, f) ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
int n = m_core_fscanf(f, " "); // Skip any leading spaces.
|
||||
(void) n; // Unused return value.
|
||||
return string_in_str(s, f) ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start reading from the stream 'serial' an array.
|
||||
@@ -358,10 +363,12 @@ m_serial_json_read_array_start(m_serial_local_t local, m_serial_read_t serial, s
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
int final1 = -1, final2 = -1;
|
||||
fscanf(f, " [%n ]%n", &final1, &final2);
|
||||
int n = m_core_fscanf(f, " [%n ]%n", &final1, &final2);
|
||||
(void) n; // Unused. Parsing is checked through c (more robust)
|
||||
*num = 0; // don't know the size of the array.
|
||||
// Test how much the parsing succeed.
|
||||
return (final1 < 0) ? M_SERIAL_FAIL : (final2 < 0) ? M_SERIAL_OK_CONTINUE : M_SERIAL_OK_DONE;
|
||||
if (final1 < 0) m_core_serial_fail();
|
||||
return (final2 < 0) ? M_SERIAL_OK_CONTINUE : M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
/* Continue reading from the stream 'serial' an array.
|
||||
@@ -374,8 +381,9 @@ m_serial_json_read_array_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
char c = 0;
|
||||
fscanf(f, " %c", &c);
|
||||
return c == ',' ? M_SERIAL_OK_CONTINUE : c == ']' ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
int n = m_core_fscanf(f, " %c", m_core_arg_size(&c, 1) );
|
||||
(void) n; // Unused. Parsing is checked through c (more robust)
|
||||
return c == ',' ? M_SERIAL_OK_CONTINUE : c == ']' ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start reading from the stream 'serial' a map.
|
||||
@@ -384,17 +392,19 @@ m_serial_json_read_array_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
(local is an unique serialization object of the array).
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the map continue,
|
||||
M_SERIAL_OK_DONE if it succeeds and the map ends (the map is empty),
|
||||
M_SERIAL_FAIL otherwise */
|
||||
m_core_serial_fail() otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_json_read_map_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
int final1 = -1, final2 = -1;
|
||||
fscanf(f, " {%n }%n", &final1, &final2);
|
||||
int n = m_core_fscanf(f, " {%n }%n", &final1, &final2);
|
||||
(void) n; // Unused. Parsing is checked through final (more robust)
|
||||
*num = 0; // don't know the size of the map.
|
||||
// Test how much the parsing succeed.
|
||||
return (final1 < 0) ? M_SERIAL_FAIL : (final2 < 0) ? M_SERIAL_OK_CONTINUE : M_SERIAL_OK_DONE;
|
||||
if (final1 < 0) m_core_serial_fail();
|
||||
return (final2 < 0) ? M_SERIAL_OK_CONTINUE : M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
/* Continue reading from the stream 'serial' the value separator
|
||||
@@ -406,8 +416,9 @@ m_serial_json_read_map_value(m_serial_local_t local, m_serial_read_t serial)
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
int final = -1;
|
||||
fscanf(f, " :%n", &final);
|
||||
return final > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
|
||||
int n = m_core_fscanf(f, " :%n", &final);
|
||||
(void) n; // Unused. Parsing is checked through final (more robust)
|
||||
return final > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Continue reading from the stream 'serial' a map.
|
||||
@@ -420,8 +431,9 @@ m_serial_json_read_map_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
char c = 0;
|
||||
fscanf(f, " %c", &c);
|
||||
return c == ',' ? M_SERIAL_OK_CONTINUE : c == '}' ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
int n = m_core_fscanf(f, " %c", m_core_arg_size(&c, 1) );
|
||||
(void) n; // Unused. Parsing is checked through c (more robust)
|
||||
return c == ',' ? M_SERIAL_OK_CONTINUE : c == '}' ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start reading a tuple from the stream 'serial'.
|
||||
@@ -433,8 +445,9 @@ m_serial_json_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
int final = -1;
|
||||
fscanf(f, " {%n", &final);
|
||||
return final > 0 ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL;
|
||||
int n = m_core_fscanf(f, " {%n", &final);
|
||||
(void) n; // Unused. Parsing is checked through final (more robust)
|
||||
return final > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Continue reading a tuple from the stream 'serial'.
|
||||
@@ -449,21 +462,23 @@ m_serial_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, cons
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
int c = m_serial_json_read_skip(f);
|
||||
if (c == EOF) return M_SERIAL_FAIL;
|
||||
if (c == EOF) return m_core_serial_fail();
|
||||
if (c == '}') return M_SERIAL_OK_DONE;
|
||||
if (c == ',') {
|
||||
// If first call of read_tuple_id, it is a failure
|
||||
if (*id == -1) return M_SERIAL_FAIL;
|
||||
if (*id == -1) return m_core_serial_fail();
|
||||
} else {
|
||||
// c should be \" but let fscanf parse it.
|
||||
ungetc(c, f);
|
||||
}
|
||||
/* Read the field in the JSON */
|
||||
c = -1;
|
||||
char field[M_MAX_IDENTIFIER_LENGTH+1]; // TODO: fix error detection below.
|
||||
fscanf(f, " \"%" M_APPLY(M_AS_STR, M_MAX_IDENTIFIER_LENGTH) "[^ \t\n\"]\":%n", field, &c);
|
||||
char field[M_MAX_IDENTIFIER_LENGTH+1];
|
||||
int nn = m_core_fscanf(f, " \"%" M_APPLY(M_AS_STR, M_MAX_IDENTIFIER_LENGTH) "[^ \t\n\"]\":%n",
|
||||
m_core_arg_size(field, M_MAX_IDENTIFIER_LENGTH+1), &c);
|
||||
(void) nn ; // Unused. Check is done through 'c' (more robust).
|
||||
if (c <= 0)
|
||||
return M_SERIAL_FAIL;
|
||||
return m_core_serial_fail();
|
||||
/* Search for field in field_name */
|
||||
for(int n = 0; n < max; n++) {
|
||||
if (strcmp(field, field_name[n]) == 0) {
|
||||
@@ -471,7 +486,7 @@ m_serial_json_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, cons
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
}
|
||||
return M_SERIAL_FAIL;
|
||||
return m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Start reading a variant from the stream 'serial'.
|
||||
@@ -487,24 +502,28 @@ m_serial_json_read_variant_start(m_serial_local_t local, m_serial_read_t serial,
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
|
||||
int final1 = -1, final2 = -1;
|
||||
fscanf(f, " {%n }%n", &final1, &final2);
|
||||
int nn = m_core_fscanf(f, " {%n }%n", &final1, &final2);
|
||||
(void) nn ; // Unused. Check is done through final (more robust).
|
||||
// Test how much the parsing succeed.
|
||||
if (final1 <= 0) return M_SERIAL_FAIL;
|
||||
if (final1 <= 0) return m_core_serial_fail();
|
||||
if (final2 > 0) return M_SERIAL_OK_DONE;
|
||||
|
||||
/* Read the field in the JSON */
|
||||
char field[M_MAX_IDENTIFIER_LENGTH+1];
|
||||
fscanf(f, " \"%" M_APPLY(M_AS_STR, M_MAX_IDENTIFIER_LENGTH) "[^ \t\n\"]\":%n", field, &final2);
|
||||
if (final2 <= 0) return M_SERIAL_FAIL;
|
||||
nn = m_core_fscanf(f, " \"%" M_APPLY(M_AS_STR, M_MAX_IDENTIFIER_LENGTH) "[^ \t\n\"]\":%n",
|
||||
m_core_arg_size(field, M_MAX_IDENTIFIER_LENGTH+1), &final2);
|
||||
(void) nn ; // Unused. Check is done through final (more robust).
|
||||
if (final2 <= 0) return m_core_serial_fail();
|
||||
|
||||
/* Search for field in field_name */
|
||||
/* Linear Search for field in field_name */
|
||||
for(int n = 0; n < max; n++) {
|
||||
if (strcmp(field, field_name[n]) == 0) {
|
||||
*id = n;
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
}
|
||||
return M_SERIAL_FAIL;
|
||||
// Field not found
|
||||
return m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* End reading a variant from the stream 'serial'.
|
||||
@@ -516,8 +535,9 @@ m_serial_json_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
|
||||
(void) local; // argument not used
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
int final = -1;
|
||||
fscanf(f, " }%n", &final);
|
||||
return final > 0 ? M_SERIAL_OK_DONE : M_SERIAL_FAIL;
|
||||
int n = m_core_fscanf(f, " }%n", &final);
|
||||
(void) n ; // Unused. Check is done through final (more robust).
|
||||
return final > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
static const m_serial_read_interface_t m_serial_json_read_interface = {
|
||||
@@ -552,7 +572,9 @@ static inline void m_serial_json_read_clear(m_serial_read_t serial)
|
||||
/* Define a synonym of m_serial_read_t
|
||||
to the JSON serializer with its proper OPLIST */
|
||||
typedef m_serial_read_t m_serial_json_read_t;
|
||||
#define M_OPL_m_serial_json_read_t() \
|
||||
#define M_OPL_m_serial_json_read_t() \
|
||||
(INIT_WITH(m_serial_json_read_init), CLEAR(m_serial_json_read_clear), TYPE(m_serial_json_read_t) )
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
+406
-354
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SHARED Module
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,37 +29,79 @@
|
||||
#include "m-atomic.h"
|
||||
#include "m-genint.h"
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a shared pointer.
|
||||
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define SHARED_PTR_OPLIST(...) \
|
||||
SHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
#define SHARED_PTR_OPLIST(...) \
|
||||
SHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define shared pointer and its function.
|
||||
USAGE: SHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_DEF(name, ...) \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST)))
|
||||
#define SHARED_PTR_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST, M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST, M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define shared pointer and its function
|
||||
as the given name name_t
|
||||
USAGE: SHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
|
||||
#define SHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST, name_t ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST, name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define relaxed shared pointer and its function (thread unsafe).
|
||||
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_RELAXED_DEF(name, ...) \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_INTEGER_OPLIST)))
|
||||
#define SHARED_PTR_RELAXED_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST, M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__, SHAREDI_INTEGER_OPLIST, M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define relaxed shared pointer and its function (thread unsafe)
|
||||
as the given name name_t
|
||||
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_RELAXED_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST, name_t ), \
|
||||
(name, __VA_ARGS__, SHAREDI_INTEGER_OPLIST, name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define shared resource and its function.
|
||||
This is a bounded pool of resource shared by multiple owners.
|
||||
USAGE: SHARED_RESOURCE_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_RESOURCE_DEF(name, ...) \
|
||||
SHAREDI_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__) ), \
|
||||
(name, __VA_ARGS__)))
|
||||
#define SHARED_RESOURCE_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t), M_C(name, _it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name, _t), M_C(name, _it_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define shared resource and its function
|
||||
as the given name named_t and the iterator it_t
|
||||
This is a bounded pool of resource shared by multiple owners.
|
||||
USAGE: SHARED_RESOURCE_DEF_AS(name, name_t, it_t, type, [, oplist]) */
|
||||
#define SHARED_RESOURCE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
|
||||
@@ -68,41 +110,41 @@
|
||||
// deferred evaluation
|
||||
#define SHAREDI_PTR_OPLIST_P1(arg) SHAREDI_PTR_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define SHAREDI_PTR_OPLIST_P2(name, oplist) \
|
||||
/* Validation of the given, shared_t oplist */
|
||||
#define SHAREDI_PTR_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_PTR_OPLIST_P3, SHAREDI_PTR_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define SHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
M_LIB_ERROR(ARGUMENT_OF_SHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)
|
||||
#define SHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_SHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
#define SHAREDI_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_C(name, _init)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
SET(M_C(name, _set)) \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
CLEAN(M_C(name, _clean)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)) \
|
||||
,TYPE(M_C(name, _t)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
#define SHAREDI_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_C(name, _init)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
SET(M_C(name, _set)) \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
CLEAN(M_C(name, _clean)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)) \
|
||||
,TYPE(M_C(name, _ct)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
)
|
||||
|
||||
// OPLIST to handle a counter of atomic type
|
||||
#define SHAREDI_ATOMIC_OPLIST (TYPE(atomic_int), \
|
||||
INIT_SET(atomic_init), \
|
||||
ADD(atomic_fetch_add), \
|
||||
SUB(atomic_fetch_sub), \
|
||||
#define SHAREDI_ATOMIC_OPLIST (TYPE(atomic_int), \
|
||||
INIT_SET(atomic_init), \
|
||||
ADD(atomic_fetch_add), \
|
||||
SUB(atomic_fetch_sub), \
|
||||
IT_CREF(atomic_load))
|
||||
|
||||
// OPLIST to handle a counter of non-atomic type
|
||||
#define SHAREDI_INTEGER_OPLIST (TYPE(int), \
|
||||
INIT_SET(sharedi_integer_init_set), \
|
||||
ADD(sharedi_integer_add), \
|
||||
SUB(sharedi_integer_sub), \
|
||||
#define SHAREDI_INTEGER_OPLIST (TYPE(int), \
|
||||
INIT_SET(sharedi_integer_init_set), \
|
||||
ADD(sharedi_integer_add), \
|
||||
SUB(sharedi_integer_sub), \
|
||||
IT_CREF(sharedi_integer_cref))
|
||||
|
||||
/* Atomic like interface for basic integers */
|
||||
@@ -112,343 +154,353 @@ static inline int sharedi_integer_sub(int *p, int val) { int r = *p; *p -= val;
|
||||
static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
|
||||
/* Contract of a shared pointer */
|
||||
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
|
||||
assert(shared != NULL); \
|
||||
assert(*shared == NULL || M_CALL_IT_CREF(cpt_oplist, &(*shared)->cpt) >= 1); \
|
||||
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
|
||||
M_ASSERT(shared != NULL); \
|
||||
M_ASSERT(*shared == NULL || M_CALL_IT_CREF(cpt_oplist, &(*shared)->cpt) >= 1); \
|
||||
} while (0)
|
||||
|
||||
// deferred evaluation
|
||||
#define SHAREDI_PTR_DEF_P1(arg) SHAREDI_PTR_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SHAREDI_PTR_DEF_P2(name, type, oplist, cpt_oplist_t) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_PTR_DEF_P3, SHAREDI_PTR_DEF_FAILURE)(name, type, oplist, cpt_oplist_t)
|
||||
#define SHAREDI_PTR_DEF_P2(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_PTR_DEF_P3, SHAREDI_PTR_DEF_FAILURE)(name, type, oplist, cpt_oplist, shared_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SHAREDI_PTR_DEF_FAILURE(name, type, oplist, cpt_oplist) \
|
||||
#define SHAREDI_PTR_DEF_FAILURE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Code generation */
|
||||
#define SHAREDI_PTR_DEF_P3(name, type, oplist, cpt_oplist) \
|
||||
\
|
||||
typedef struct M_C(name, _s){ \
|
||||
type *data; /* Pointer to the data */ \
|
||||
M_GET_TYPE cpt_oplist cpt; /* Counter of how many points to the data */ \
|
||||
bool combineAlloc; /* Does the data and the ptr share the slot? */ \
|
||||
} *M_C(name, _t)[1]; \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
\
|
||||
typedef struct M_C(name, combine_s) { \
|
||||
type data; \
|
||||
struct M_C(name, _s) ptr; \
|
||||
} M_C(name, combine_t)[1]; \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(M_C(name, _t) shared) \
|
||||
{ \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init2)(M_C(name, _t) shared, type *data) \
|
||||
{ \
|
||||
assert (shared != NULL); \
|
||||
/* The shared ptr get exclusive access to data */ \
|
||||
struct M_C(name, _s) *ptr; \
|
||||
if (M_UNLIKELY (data == NULL)) { \
|
||||
*shared = NULL; \
|
||||
return; \
|
||||
} \
|
||||
ptr = M_CALL_NEW(oplist, struct M_C(name, _s)); \
|
||||
if (M_UNLIKELY (ptr == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_C(name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
ptr->data = data; \
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = false; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_new)(M_C(name, _t) shared) \
|
||||
{ \
|
||||
/* NOTE: Alloc 1 struct with both structures. */ \
|
||||
struct M_C(name, combine_s) *p = \
|
||||
M_CALL_NEW(oplist, struct M_C(name, combine_s)); \
|
||||
if (M_UNLIKELY (p == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_C(name, combine_s))); \
|
||||
return; \
|
||||
} \
|
||||
struct M_C(name, _s) *ptr = &p->ptr; \
|
||||
type *data = &p->data; \
|
||||
M_CALL_INIT( oplist, *data); \
|
||||
ptr->data = data; \
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = true; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _NULL_p)(const M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
return *shared == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(M_C(name, _t) dest, \
|
||||
const M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert (dest != shared); \
|
||||
*dest = *shared; \
|
||||
if (*dest != NULL) { \
|
||||
int n = M_CALL_ADD(cpt_oplist, &((*dest)->cpt), 1); \
|
||||
(void) n; /* unused return value */ \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name, _t) dest) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
if (*dest != NULL) { \
|
||||
if (M_CALL_SUB(cpt_oplist, &((*dest)->cpt), 1) == 1) { \
|
||||
bool combineAlloc = (*dest)->combineAlloc; \
|
||||
/* Note: if combineAlloc is true, the address of the slot \
|
||||
combining both data & ptr is the same as the address of the \
|
||||
first element, aka data itself. Static analyzer tools don't \
|
||||
seem to detect this and report error. */ \
|
||||
M_CALL_CLEAR(oplist, *(*dest)->data); \
|
||||
M_CALL_DEL(oplist, (*dest)->data); \
|
||||
if (combineAlloc == false) \
|
||||
M_CALL_DEL(oplist, *dest); \
|
||||
} \
|
||||
*dest = NULL; \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(M_C(name, _t) dest) \
|
||||
{ \
|
||||
/* NOTE: Clear will also set dest to NULL */ \
|
||||
M_C(name, _clear)(dest); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(M_C(name, _t) dest, \
|
||||
const M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_set)(dest, shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(M_C(name, _t) dest, \
|
||||
M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert (dest != NULL && dest != shared); \
|
||||
*dest = *shared; \
|
||||
*shared = NULL; \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(M_C(name, _t) dest, \
|
||||
M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert (dest != shared); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_move)(dest, shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(M_C(name, _t) p1, \
|
||||
M_C(name, _t) p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
M_SWAP (struct M_C(name, _s)*, *p1, *p2); \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(const M_C(name, _t) p1, \
|
||||
const M_C(name, _t) p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
return *p1 == *p2; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
assert (data != NULL); \
|
||||
return M_CONST_CAST (type, data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(M_C(name, _t) shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
assert (data != NULL); \
|
||||
return data; \
|
||||
} \
|
||||
#define SHAREDI_PTR_DEF_P3(name, type, oplist, cpt_oplist, shared_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s){ \
|
||||
type *data; /* Pointer to the data */ \
|
||||
M_GET_TYPE cpt_oplist cpt; /* Counter of how many refs the data */ \
|
||||
bool combineAlloc; /* Does the data and the ptr share the slot? */ \
|
||||
} *shared_t[1]; \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef shared_t M_C(name, _ct); \
|
||||
\
|
||||
typedef struct M_C(name, combine_s) { \
|
||||
type data; \
|
||||
struct M_C(name, _s) ptr; \
|
||||
} M_C(name, combine_ct)[1]; \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(shared_t shared) \
|
||||
{ \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init2)(shared_t shared, type *data) \
|
||||
{ \
|
||||
M_ASSERT (shared != NULL); \
|
||||
/* The shared ptr get exclusive access to data */ \
|
||||
struct M_C(name, _s) *ptr; \
|
||||
if (M_UNLIKELY (data == NULL)) { \
|
||||
*shared = NULL; \
|
||||
return; \
|
||||
} \
|
||||
ptr = M_CALL_NEW(oplist, struct M_C(name, _s)); \
|
||||
if (M_UNLIKELY (ptr == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_C(name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
ptr->data = data; \
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = false; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_new)(shared_t shared) \
|
||||
{ \
|
||||
/* NOTE: Alloc 1 struct with both structures. */ \
|
||||
struct M_C(name, combine_s) *p = \
|
||||
M_CALL_NEW(oplist, struct M_C(name, combine_s)); \
|
||||
if (M_UNLIKELY (p == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_C(name, combine_s))); \
|
||||
return; \
|
||||
} \
|
||||
struct M_C(name, _s) *ptr = &p->ptr; \
|
||||
type *data = &p->data; \
|
||||
M_CALL_INIT( oplist, *data); \
|
||||
ptr->data = data; \
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = true; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _NULL_p)(const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
return *shared == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(shared_t dest, \
|
||||
const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT (dest != shared); \
|
||||
*dest = *shared; \
|
||||
if (*dest != NULL) { \
|
||||
int n = M_CALL_ADD(cpt_oplist, &((*dest)->cpt), 1); \
|
||||
(void) n; /* unused return value */ \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t dest) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
if (*dest != NULL) { \
|
||||
if (M_CALL_SUB(cpt_oplist, &((*dest)->cpt), 1) == 1) { \
|
||||
bool combineAlloc = (*dest)->combineAlloc; \
|
||||
/* Note: if combineAlloc is true, the address of the slot \
|
||||
combining both data & ptr is the same as the address of the \
|
||||
first element, aka data itself. Static analyzer tools don't \
|
||||
seem to detect this and report error. */ \
|
||||
M_CALL_CLEAR(oplist, *(*dest)->data); \
|
||||
M_CALL_DEL(oplist, (*dest)->data); \
|
||||
if (combineAlloc == false) \
|
||||
M_CALL_DEL(oplist, *dest); \
|
||||
} \
|
||||
*dest = NULL; \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(shared_t dest) \
|
||||
{ \
|
||||
/* NOTE: Clear will also set dest to NULL */ \
|
||||
M_C(name, _clear)(dest); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(shared_t dest, \
|
||||
const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_set)(dest, shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(shared_t dest, \
|
||||
shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT (dest != NULL && dest != shared); \
|
||||
*dest = *shared; \
|
||||
*shared = NULL; \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(shared_t dest, \
|
||||
shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT (dest != shared); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_move)(dest, shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(shared_t p1, \
|
||||
shared_t p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
/* NOTE: SWAP is not atomic */ \
|
||||
M_SWAP (struct M_C(name, _s)*, *p1, *p2); \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(const shared_t p1, \
|
||||
const shared_t p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
return *p1 == *p2; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
M_ASSERT (data != NULL); \
|
||||
return M_CONST_CAST (type, data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
M_ASSERT (data != NULL); \
|
||||
return data; \
|
||||
} \
|
||||
|
||||
|
||||
|
||||
/********************************** SHARED RESOURCE ************************************/
|
||||
|
||||
#define SHAREDI_RESOURCE_CONTRACT(s) do { \
|
||||
assert (s != NULL); \
|
||||
assert (s->buffer != NULL); \
|
||||
#define SHAREDI_RESOURCE_CONTRACT(s) do { \
|
||||
M_ASSERT (s != NULL); \
|
||||
M_ASSERT (s->buffer != NULL); \
|
||||
} while (0)
|
||||
|
||||
// deferred
|
||||
#define SHAREDI_RESOURCE_DEF_P1(arg) SHAREDI_RESOURCE_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SHAREDI_RESOURCE_DEF_P2(name, type, oplist) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_RESOURCE_DEF_P3, SHAREDI_RESOURCE_DEF_FAILURE)(name, type, oplist)
|
||||
#define SHAREDI_RESOURCE_DEF_P2(name, type, oplist, shared_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_RESOURCE_DEF_P3, SHAREDI_RESOURCE_DEF_FAILURE)(name, type, oplist, shared_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SHAREDI_RESOURCE_DEF_FAILURE(name, type, oplist) \
|
||||
#define SHAREDI_RESOURCE_DEF_FAILURE(name, type, oplist, shared_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_RESOURCE_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
#define SHAREDI_RESOURCE_DEF_P3(name, type, oplist) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _atype_s) { \
|
||||
atomic_uint cpt; \
|
||||
type x; \
|
||||
M_CACHELINE_ALIGN(align, type, atomic_uint); \
|
||||
} M_C(name, _atype_t); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
genint_t core; \
|
||||
M_C(name, _atype_t) *buffer; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
unsigned int idx; \
|
||||
struct M_C(name, _s) *ref; \
|
||||
} M_C(name, _it_t)[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(M_C(name, _t) s, size_t n) \
|
||||
{ \
|
||||
assert(s != NULL); \
|
||||
assert (n > 0); \
|
||||
s->buffer = M_CALL_REALLOC(oplist, M_C(name, _atype_t), NULL, n); \
|
||||
if (M_UNLIKELY (s->buffer == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _atype_t)) * n); \
|
||||
return; \
|
||||
} \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_INIT(oplist, s->buffer[i].x); \
|
||||
atomic_init (&s->buffer[i].cpt, 0U); \
|
||||
} \
|
||||
genint_init(s->core, n); \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name, _t) s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
size_t n = genint_size(s->core); \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_CLEAR(oplist, s->buffer[i].x); \
|
||||
} \
|
||||
M_CALL_FREE(oplist, s->buffer); \
|
||||
s->buffer = NULL; \
|
||||
genint_clear(s->core); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(M_C(name, _it_t) it, M_C(name, _t) s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
assert (it != NULL); \
|
||||
unsigned int idx = genint_pop(s->core); \
|
||||
it->idx = idx; \
|
||||
it->ref = s; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
assert(atomic_load(&s->buffer[idx].cpt) == 0); \
|
||||
atomic_store(&s->buffer[idx].cpt, 1U); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(M_C(name, _it_t) it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return it->idx == GENINT_ERROR; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(M_C(name, _it_t) it) \
|
||||
{ \
|
||||
assert (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
return &it->ref->buffer[it->idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(M_C(name, _it_t) it) \
|
||||
{ \
|
||||
assert (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _end)(M_C(name, _it_t) it, M_C(name, _t) s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
assert (it != NULL); \
|
||||
assert (it->ref == s); \
|
||||
unsigned int idx = it->idx; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \
|
||||
if (c == 1) { \
|
||||
genint_push(it->ref->core, idx); \
|
||||
} \
|
||||
it->idx = GENINT_ERROR; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(M_C(name, _it_t) itd, M_C(name, _it_t) its) \
|
||||
{ \
|
||||
assert (itd != NULL && its != NULL); \
|
||||
SHAREDI_RESOURCE_CONTRACT(its->ref); \
|
||||
itd->ref = its->ref; \
|
||||
unsigned int idx = its->idx; \
|
||||
itd->idx = idx; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
|
||||
assert (c >= 1); \
|
||||
} \
|
||||
} \
|
||||
#define SHAREDI_RESOURCE_DEF_P3(name, type, oplist, shared_t, it_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _atype_s) { \
|
||||
atomic_uint cpt; \
|
||||
type x; \
|
||||
M_CACHELINE_ALIGN(align, type, atomic_uint); \
|
||||
} M_C(name, _atype_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
genint_t core; \
|
||||
M_C(name, _atype_ct) *buffer; \
|
||||
} shared_t[1]; \
|
||||
\
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
unsigned int idx; \
|
||||
struct M_C(name, _s) *ref; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
/* Internal Types for oplist */ \
|
||||
typedef shared_t M_C(name, _ct); \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(shared_t s, size_t n) \
|
||||
{ \
|
||||
M_ASSERT(s != NULL); \
|
||||
M_ASSERT (n > 0 && n < UINT_MAX); \
|
||||
s->buffer = M_CALL_REALLOC(oplist, M_C(name, _atype_ct), NULL, n); \
|
||||
if (M_UNLIKELY (s->buffer == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _atype_ct)) * n); \
|
||||
return; \
|
||||
} \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_INIT(oplist, s->buffer[i].x); \
|
||||
atomic_init (&s->buffer[i].cpt, 0U); \
|
||||
} \
|
||||
genint_init(s->core, (unsigned int) n); \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
size_t n = genint_size(s->core); \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_CLEAR(oplist, s->buffer[i].x); \
|
||||
} \
|
||||
M_CALL_FREE(oplist, s->buffer); \
|
||||
s->buffer = NULL; \
|
||||
genint_clear(s->core); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, shared_t s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
M_ASSERT (it != NULL); \
|
||||
unsigned int idx = genint_pop(s->core); \
|
||||
it->idx = idx; \
|
||||
it->ref = s; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
M_ASSERT(atomic_load(&s->buffer[idx].cpt) == 0); \
|
||||
atomic_store(&s->buffer[idx].cpt, 1U); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
return it->idx == GENINT_ERROR; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
return &it->ref->buffer[it->idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _end)(it_t it, shared_t s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
M_ASSERT (it != NULL); \
|
||||
M_ASSERT (it->ref == s); \
|
||||
unsigned int idx = it->idx; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \
|
||||
if (c == 1) { \
|
||||
genint_push(it->ref->core, idx); \
|
||||
} \
|
||||
it->idx = GENINT_ERROR; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t itd, it_t its) \
|
||||
{ \
|
||||
M_ASSERT (itd != NULL && its != NULL); \
|
||||
SHAREDI_RESOURCE_CONTRACT(its->ref); \
|
||||
itd->ref = its->ref; \
|
||||
unsigned int idx = its->idx; \
|
||||
itd->idx = idx; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
|
||||
M_ASSERT (c >= 1); \
|
||||
} \
|
||||
} \
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
+505
-390
File diff suppressed because it is too large.
Load diff
+846
-587
File diff suppressed because it is too large.
Load diff
+537
-464
File diff suppressed because it is too large.
Load diff
+83
-75
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB / WORKER - Extra worker interface
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -43,8 +43,8 @@
|
||||
/* Include needed system header for detection of how many core on the system */
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
#elif (defined(__APPLE__) && defined(__MACH__)) \
|
||||
|| defined(__DragonFly__) || defined(__FreeBSD__) \
|
||||
#elif (defined(__APPLE__) && defined(__MACH__)) \
|
||||
|| defined(__DragonFly__) || defined(__FreeBSD__) \
|
||||
|| defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# include <sys/param.h>
|
||||
# include <sys/sysctl.h>
|
||||
@@ -93,6 +93,8 @@
|
||||
# error M_USE_WORKER_CPP_FUNCTION and M_USE_WORKER_CLANG_BLOCK are both defined. This is not supported.
|
||||
#endif
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Definition of a work order */
|
||||
typedef struct work_order_s {
|
||||
struct worker_sync_s *block; // Reference to the shared Synchronization block
|
||||
@@ -104,7 +106,7 @@ typedef struct work_order_s {
|
||||
#if M_USE_WORKER_CPP_FUNCTION
|
||||
std::function<void(void*)> function; // The work order function (for C++)
|
||||
#endif
|
||||
} worker_order_t;
|
||||
} worker_order_ct;
|
||||
|
||||
/* Define the macros needed to initialize an order.
|
||||
* * MACRO to be used to send an empty order to stop the thread
|
||||
@@ -122,11 +124,11 @@ typedef struct work_order_s {
|
||||
is not sufficient for initialization of the structure.
|
||||
So let's use C++ constructor, destructor and copy constructor */
|
||||
#if M_USE_WORKER_CPP_FUNCTION
|
||||
# define WORKERI_CPP_INIT(x) (new (&(x)) worker_order_t())
|
||||
# define WORKERI_CPP_INIT_SET(x, y) (new (&(x)) worker_order_t(y))
|
||||
# define WORKERI_CPP_INIT(x) (new (&(x)) worker_order_ct())
|
||||
# define WORKERI_CPP_INIT_SET(x, y) (new (&(x)) worker_order_ct(y))
|
||||
# define WORKERI_CPP_SET(x, y) ((x) = (y))
|
||||
# define WORKERI_CPP_CLEAR(x) ((&(x))->~worker_order_t())
|
||||
# define WORKERI_CPP_INIT_MOVE(x,y) (new (&(x)) worker_order_t(y), ((&(y))->~worker_order_t()))
|
||||
# define WORKERI_CPP_CLEAR(x) ((&(x))->~worker_order_ct())
|
||||
# define WORKERI_CPP_INIT_MOVE(x,y) (new (&(x)) worker_order_ct(y), ((&(y))->~worker_order_ct()))
|
||||
# define WORKER_OPLIST \
|
||||
(INIT(WORKERI_CPP_INIT), INIT_SET(WORKERI_CPP_INIT_SET), \
|
||||
SET(WORKERI_CPP_SET), CLEAR(WORKERI_CPP_CLEAR), INIT_MOVE(WORKERI_CPP_INIT_MOVE) )
|
||||
@@ -137,19 +139,19 @@ typedef struct work_order_s {
|
||||
/* Definition of a worker (implemented by a thread) */
|
||||
typedef struct worker_thread_s {
|
||||
m_thread_t id;
|
||||
} worker_thread_t;
|
||||
} worker_thread_ct;
|
||||
|
||||
/* Definition of the queue that will record the work orders */
|
||||
BUFFER_DEF(worker_queue, worker_order_t, 0,
|
||||
BUFFER_DEF_AS(worker_queue, m_worker_queue_ct, worker_order_ct, 0,
|
||||
BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, WORKER_OPLIST)
|
||||
|
||||
/* Definition the global pool of workers */
|
||||
typedef struct worker_s {
|
||||
/* The work order queue */
|
||||
worker_queue_t queue_g;
|
||||
m_worker_queue_ct queue_g;
|
||||
|
||||
/* The table of available workers */
|
||||
worker_thread_t *worker;
|
||||
worker_thread_ct *worker;
|
||||
|
||||
/* Number of workers in the table */
|
||||
unsigned int numWorker_g;
|
||||
@@ -161,7 +163,7 @@ typedef struct worker_s {
|
||||
void (*clearFunc_g)(void);
|
||||
|
||||
m_mutex_t lock;
|
||||
m_cond_t a_thread_ends; // A worker has ended
|
||||
m_cond_t a_thread_ends; // EVENT: A worker has ended
|
||||
|
||||
} worker_t[1];
|
||||
|
||||
@@ -179,7 +181,8 @@ workeri_get_cpu_count(void)
|
||||
#if defined(_WIN32)
|
||||
SYSTEM_INFO sysinfo;
|
||||
GetSystemInfo(&sysinfo);
|
||||
return sysinfo.dwNumberOfProcessors;
|
||||
M_ASSERT(sysinfo.dwNumberOfProcessors <= INT_MAX);
|
||||
return (int) sysinfo.dwNumberOfProcessors;
|
||||
#elif defined(M_USE_WORKER_SYSCTL)
|
||||
int nm[2];
|
||||
int count = 0;
|
||||
@@ -189,7 +192,7 @@ workeri_get_cpu_count(void)
|
||||
sysctl(nm, 2, &count, &len, NULL, 0);
|
||||
return M_MAX(1, count);
|
||||
#elif defined (_SC_NPROCESSORS_ONLN)
|
||||
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||
return (int) sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
@@ -204,9 +207,9 @@ workeri_get_cpu_count(void)
|
||||
|
||||
/* Execute the registered work order **synchronously** */
|
||||
static inline void
|
||||
workeri_exec(worker_order_t *w)
|
||||
workeri_exec(worker_order_ct *w)
|
||||
{
|
||||
assert (w!= NULL && w->block != NULL);
|
||||
M_ASSERT (w!= NULL && w->block != NULL);
|
||||
WORKERI_DEBUG ("Starting thread with data %p\n", w->data);
|
||||
#if M_USE_WORKER_CLANG_BLOCK
|
||||
WORKERI_DEBUG ("Running %s f=%p b=%p\n", (w->func == NULL) ? "Blocks" : "Function", w->func, w->blockFunc);
|
||||
@@ -233,7 +236,7 @@ workeri_thread(void *arg)
|
||||
// Get back the given argument
|
||||
struct worker_s *g = M_ASSIGN_CAST(struct worker_s *, arg);
|
||||
while (true) {
|
||||
worker_order_t w;
|
||||
worker_order_ct w;
|
||||
// If needed, reset the global state of the worker
|
||||
if (g->resetFunc_g != NULL) {
|
||||
g->resetFunc_g();
|
||||
@@ -271,20 +274,22 @@ workeri_thread(void *arg)
|
||||
static inline void
|
||||
worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
|
||||
{
|
||||
assert (numWorker >= -1);
|
||||
M_ASSERT (numWorker >= -1);
|
||||
// Auto compute number of workers if the argument is 0
|
||||
if (numWorker <= 0)
|
||||
numWorker = (1 + (numWorker == -1))*workeri_get_cpu_count()-1;
|
||||
WORKERI_DEBUG ("Starting queue with: %d\n", numWorker + extraQueue);
|
||||
// Initialization
|
||||
size_t numWorker_st = numWorker;
|
||||
g->worker = M_MEMORY_REALLOC(worker_thread_t, NULL, numWorker_st);
|
||||
// numWorker can still be 0 if it is a single core cpu (no worker available)
|
||||
M_ASSERT(numWorker >= 0);
|
||||
size_t numWorker_st = (size_t) numWorker;
|
||||
g->worker = M_MEMORY_REALLOC(worker_thread_ct, NULL, numWorker_st);
|
||||
if (g->worker == NULL) {
|
||||
M_MEMORY_FULL(sizeof (worker_thread_t) * numWorker_st);
|
||||
M_MEMORY_FULL(sizeof (worker_thread_ct) * numWorker_st);
|
||||
return;
|
||||
}
|
||||
worker_queue_init(g->queue_g, numWorker + extraQueue);
|
||||
g->numWorker_g = numWorker_st;
|
||||
worker_queue_init(g->queue_g, numWorker_st + extraQueue);
|
||||
g->numWorker_g = (unsigned int) numWorker_st;
|
||||
g->resetFunc_g = resetFunc;
|
||||
g->clearFunc_g = clearFunc;
|
||||
m_mutex_init(g->lock);
|
||||
@@ -308,10 +313,10 @@ worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc
|
||||
static inline void
|
||||
worker_clear(worker_t g)
|
||||
{
|
||||
assert (worker_queue_empty_p (g->queue_g));
|
||||
M_ASSERT (worker_queue_empty_p (g->queue_g));
|
||||
// Push the terminate order on the queue
|
||||
for(unsigned int i = 0; i < g->numWorker_g; i++) {
|
||||
worker_order_t w = WORKERI_EMPTY_ORDER;
|
||||
worker_order_ct w = WORKERI_EMPTY_ORDER;
|
||||
// Normaly all worker threads shall be waiting at this
|
||||
// stage, so all push won't block as the queue is empty.
|
||||
// But for robustness, let's wait.
|
||||
@@ -346,7 +351,7 @@ worker_start(worker_sync_t block, worker_t g)
|
||||
static inline void
|
||||
worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
|
||||
{
|
||||
const worker_order_t w = { block, data, func WORKERI_EXTRA_ORDER };
|
||||
const worker_order_ct w = { block, data, func WORKERI_EXTRA_ORDER };
|
||||
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
|
||||
&& worker_queue_push (block->worker->queue_g, w) == true) {
|
||||
WORKERI_DEBUG ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
@@ -364,7 +369,7 @@ worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
|
||||
static inline void
|
||||
worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
|
||||
{
|
||||
const worker_order_t w = { block, data, NULL, func };
|
||||
const worker_order_ct w = { block, data, NULL, func };
|
||||
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
|
||||
&& worker_queue_push (block->worker->queue_g, w) == true) {
|
||||
WORKERI_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
@@ -383,7 +388,7 @@ worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
|
||||
static inline void
|
||||
worker_spawn_function(worker_sync_t block, std::function<void(void *data)> func, void *data)
|
||||
{
|
||||
const worker_order_t w = { block, data, NULL, func };
|
||||
const worker_order_ct w = { block, data, NULL, func };
|
||||
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
|
||||
&& worker_queue_push (block->worker->queue_g, w) == true) {
|
||||
WORKERI_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
@@ -425,7 +430,7 @@ worker_sync(worker_sync_t block)
|
||||
static inline void
|
||||
worker_flush(worker_t g)
|
||||
{
|
||||
worker_order_t w;
|
||||
worker_order_ct w;
|
||||
while (worker_queue_pop_blocking (&w, g->queue_g, false) == true) {
|
||||
workeri_exec(&w);
|
||||
worker_queue_pop_release(g->queue_g);
|
||||
@@ -445,81 +450,84 @@ worker_count(worker_t g)
|
||||
'block' shall be the initialised synchronised block for all threads.
|
||||
'input' is the list of input variables of the 'core' block within "( )"
|
||||
'output' is the list of output variables of the 'core' block within "( )"
|
||||
Output variables are only available after a synchronisation block. */
|
||||
Output variables are only available after a synchronisation block.
|
||||
TODO: Support oplist for input & outputs parameters
|
||||
*/
|
||||
#if M_USE_WORKER_CLANG_BLOCK
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
WORKER_DEF_DATA(_input, _output) \
|
||||
WORKER_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
WORKER_DEF_DATA(_input, _output) \
|
||||
WORKER_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
worker_spawn_block ((_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
|
||||
#elif M_USE_WORKER_CPP_FUNCTION
|
||||
// TODO: Explicit pass all arguments by reference.
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
worker_spawn_function ((_block), [&](void *param) {(void)param ; _core } , NULL)
|
||||
#else
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
WORKER_DEF_DATA(_input, _output) \
|
||||
WORKER_DEF_SUBFUNC(_input, _output, _core) \
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
WORKER_DEF_DATA(_input, _output) \
|
||||
WORKER_DEF_SUBFUNC(_input, _output, _core) \
|
||||
worker_spawn ((_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
|
||||
#endif
|
||||
|
||||
#define WORKER_SPAWN_STRUCT_NAME M_C(worker_data_s_, __LINE__)
|
||||
#define WORKER_SPAWN_DATA_NAME M_C(worker_data_, __LINE__)
|
||||
#define WORKER_SPAWN_SUBFUNC_NAME M_C(worker_subfunc_, __LINE__)
|
||||
#define WORKER_DEF_DATA(_input, _output) \
|
||||
struct WORKER_SPAWN_STRUCT_NAME { \
|
||||
WORKER_DEF_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_DEF_DATA_OUTPUT _output) \
|
||||
} WORKER_SPAWN_DATA_NAME = { \
|
||||
WORKER_INIT_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output (, WORKER_INIT_DATA_OUTPUT _output) \
|
||||
#define WORKER_DEF_DATA(_input, _output) \
|
||||
struct WORKER_SPAWN_STRUCT_NAME { \
|
||||
WORKER_DEF_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_DEF_DATA_OUTPUT _output) \
|
||||
} WORKER_SPAWN_DATA_NAME = { \
|
||||
WORKER_INIT_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output (, WORKER_INIT_DATA_OUTPUT _output) \
|
||||
};
|
||||
#define WORKER_DEF_SINGLE_INPUT(var) __typeof__(var) var;
|
||||
#define WORKER_DEF_DATA_INPUT(...) \
|
||||
#define WORKER_DEF_DATA_INPUT(...) \
|
||||
M_MAP(WORKER_DEF_SINGLE_INPUT, __VA_ARGS__)
|
||||
#define WORKER_DEF_SINGLE_OUTPUT(var) \
|
||||
#define WORKER_DEF_SINGLE_OUTPUT(var) \
|
||||
__typeof__(var) *M_C(var, _ptr);
|
||||
#define WORKER_DEF_DATA_OUTPUT(...) \
|
||||
#define WORKER_DEF_DATA_OUTPUT(...) \
|
||||
M_MAP(WORKER_DEF_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define WORKER_INIT_SINGLE_INPUT(var) \
|
||||
#define WORKER_INIT_SINGLE_INPUT(var) \
|
||||
.var = var,
|
||||
#define WORKER_INIT_DATA_INPUT(...) \
|
||||
#define WORKER_INIT_DATA_INPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_INPUT, __VA_ARGS__)
|
||||
#define WORKER_INIT_SINGLE_OUTPUT(var) \
|
||||
#define WORKER_INIT_SINGLE_OUTPUT(var) \
|
||||
.M_C(var, _ptr) = &var,
|
||||
#define WORKER_INIT_DATA_OUTPUT(...) \
|
||||
#define WORKER_INIT_DATA_OUTPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define WORKER_DEF_SUBFUNC(_input, _output, _core) \
|
||||
__extension__ auto void WORKER_SPAWN_SUBFUNC_NAME(void *) ; \
|
||||
__extension__ void WORKER_SPAWN_SUBFUNC_NAME(void *_data) \
|
||||
{ \
|
||||
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
WORKER_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
|
||||
do { _core } while (0); \
|
||||
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
#define WORKER_DEF_SUBFUNC(_input, _output, _core) \
|
||||
__extension__ auto void WORKER_SPAWN_SUBFUNC_NAME(void *) ; \
|
||||
__extension__ void WORKER_SPAWN_SUBFUNC_NAME(void *_data) \
|
||||
{ \
|
||||
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
WORKER_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
|
||||
do { _core } while (0); \
|
||||
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
};
|
||||
#define WORKER_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
void (^WORKER_SPAWN_SUBFUNC_NAME) (void *) = ^ void (void * _data) \
|
||||
{ \
|
||||
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
WORKER_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
|
||||
do { _core } while (0); \
|
||||
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
#define WORKER_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
void (^WORKER_SPAWN_SUBFUNC_NAME) (void *) = ^ void (void * _data) \
|
||||
{ \
|
||||
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
WORKER_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
|
||||
do { _core } while (0); \
|
||||
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
};
|
||||
#define WORKER_INIT_SINGLE_LOCAL_INPUT(var) \
|
||||
#define WORKER_INIT_SINGLE_LOCAL_INPUT(var) \
|
||||
__typeof__(var) var = _s_data->var;
|
||||
#define WORKER_INIT_LOCAL_INPUT(...) \
|
||||
#define WORKER_INIT_LOCAL_INPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_LOCAL_INPUT, __VA_ARGS__)
|
||||
#define WORKER_INIT_SINGLE_LOCAL_OUTPUT(var) \
|
||||
#define WORKER_INIT_SINGLE_LOCAL_OUTPUT(var) \
|
||||
__typeof__(var) var;
|
||||
#define WORKER_INIT_LOCAL_OUTPUT(...) \
|
||||
#define WORKER_INIT_LOCAL_OUTPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_LOCAL_OUTPUT, __VA_ARGS__)
|
||||
#define WORKER_PROPAGATE_SINGLE_OUTPUT(var) \
|
||||
#define WORKER_PROPAGATE_SINGLE_OUTPUT(var) \
|
||||
*(_s_data->M_C(var, _ptr)) = var;
|
||||
#define WORKER_PROPAGATE_LOCAL_OUTPUT(...) \
|
||||
#define WORKER_PROPAGATE_LOCAL_OUTPUT(...) \
|
||||
M_MAP(WORKER_PROPAGATE_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#else /* M_USE_WORKER */
|
||||
|
||||
|
||||
+45
-21
@@ -1,3 +1,25 @@
|
||||
REM Copyright (c) 2017-2021, Patrick Pelissier
|
||||
REM All rights reserved.
|
||||
REM
|
||||
REM Redistribution and use in source and binary forms, with or without
|
||||
REM modification, are permitted provided that the following conditions are met:
|
||||
REM + Redistributions of source code must retain the above copyright
|
||||
REM notice, this list of conditions and the following disclaimer.
|
||||
REM + Redistributions in binary form must reproduce the above copyright
|
||||
REM notice, this list of conditions and the following disclaimer in the
|
||||
REM documentation and/or other materials provided with the distribution.
|
||||
REM
|
||||
REM THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
REM EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
REM WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
REM DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
REM DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
REM (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
REM LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
REM ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
REM (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
REM SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
REM Execute the test suite for Microsoft Visual Studio
|
||||
REM
|
||||
REM Load Micosoft Visual Studio environement file.
|
||||
@@ -8,46 +30,48 @@ IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxi
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
)
|
||||
|
||||
REM Add clang-cl in the PATH. It is the default install of clang for MSVC:
|
||||
REM %VCINSTALLDIR%\Tools\Llvm\bin;%VCINSTALLDIR%\Tools\Llvm\x64\bin
|
||||
REM Adding x64 version
|
||||
REM See https://docs.microsoft.com/de-de/cpp/build/clang-support-msbuild?view=vs-2019
|
||||
SET PATH=%PATH%;%VCINSTALLDIR%\Tools\Llvm\x64\bin
|
||||
|
||||
REM Remove previous results
|
||||
DEL *.log *.dat
|
||||
|
||||
REM List the expected failure (compiler internal error)
|
||||
set "expectedFailure=test-msnapshot.c"
|
||||
REM Select compiler to use (either cl or clang-cl)
|
||||
set "compiler=%1"
|
||||
|
||||
echo "Compiler full version:"
|
||||
cl /Bv
|
||||
|
||||
echo " "
|
||||
echo "Disabled tests passed due to wrong errors C4002 C4003 preventing build"
|
||||
exit /B 0
|
||||
echo "Compiler full version (%compiler%):"
|
||||
%compiler% /Bv
|
||||
%compiler% -v
|
||||
|
||||
REM Perform for each test
|
||||
for %%f in (test-*.c) do (
|
||||
echo =================================================
|
||||
echo Testing %%f
|
||||
REM Copy the test file as a C++ file as CL.EXE only support C++ file
|
||||
copy %%f test.cpp
|
||||
if ERRORLEVEL 1 EXIT /B 1
|
||||
del test.exe
|
||||
copy %%f test.cpp || EXIT /B 1
|
||||
REM Compile the test suite
|
||||
REM /experimental:preprocessor is mandatory to have a compliant preprocessor
|
||||
REM /Zc:preprocessor is mandatory to have a compliant preprocessor
|
||||
REM /Zc:__cplusplus is needed to report the real value of __cplusplus, so that M*LIB uses the C++ atomic, and not its emulation.
|
||||
echo Compiling %%f
|
||||
cl.exe /I.. /O2 /std:c++14 /Zc:__cplusplus /experimental:preprocessor test.cpp > %%f.log 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
REM Enable warnings and basic optimization
|
||||
REM Inform M*LIB to use Annex K by defining __STDC_WANT_LIB_EXT1__
|
||||
echo Compiling %%f with %compiler%
|
||||
%compiler% /I.. /O2 /W3 /std:c++14 /Zc:__cplusplus /Zc:preprocessor /D__STDC_WANT_LIB_EXT1__ test.cpp > %%f.log 2>&1 || (
|
||||
echo *** BUILD ERROR for %%f *** >> %%f.log
|
||||
type %%f.log
|
||||
if /i "%%f" NEQ "%expectedFailure%" EXIT /B 1
|
||||
EXIT /B 1
|
||||
)
|
||||
REM Execute it
|
||||
echo Running %%f
|
||||
test.exe >> %%f.log 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
test.exe >> %%f.log 2>&1 && echo Test OK for %%f >> %%f.log || (
|
||||
echo *** RUNTIME ERROR for %%f *** >> %%f.log
|
||||
type %%f.log
|
||||
if /i "%%f" NEQ "%expectedFailure%" EXIT /B 1
|
||||
) ELSE (
|
||||
echo Test OK for %%f >> %%f.log
|
||||
EXIT /B 1
|
||||
)
|
||||
type %%f.log
|
||||
)
|
||||
echo "All tests passed (except %expectedFailure%)"
|
||||
echo "All tests passed"
|
||||
exit /B 0
|
||||
+62
-42
@@ -1,7 +1,29 @@
|
||||
# Copyright (c) 2017-2021, 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.
|
||||
|
||||
CC=cc -std=c99
|
||||
WCFLAGS_GCC=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -ftrapv
|
||||
WCFLAGS_CLANG=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -ftrapv
|
||||
WCFLAGS_CPP=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wstrict-overflow=5 -Winline -Wundef -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wno-unused-function -ftrapv
|
||||
WCFLAGS_GCC=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wunused-function -ftrapv -Wsign-conversion -Wdate-time -Wconversion -Wformat=2 -Winit-self -Wjump-misses-init -Wstack-protector -Wtrampolines -Wwrite-strings -Wformat-security -Wno-float-conversion -O
|
||||
WCFLAGS_CLANG=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wunused-function -ftrapv -Wsign-conversion -O
|
||||
WCFLAGS_CPP=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wstrict-overflow=5 -Winline -Wundef -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wunused-function -ftrapv -Wsign-conversion
|
||||
XCFLAGS=
|
||||
CFLAGS=$(WCFLAGS_GCC) $(XCFLAGS)
|
||||
CPPFLAGS=-I..
|
||||
@@ -20,9 +42,9 @@ all:
|
||||
#####################################################################################################
|
||||
|
||||
.POSIX:
|
||||
.PHONY: valgrind scan-build sanitize check clean *.log coverage synthesis
|
||||
.PHONY: scan-build sanitize check clean *.log coverage synthesis
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .exe .log .depend .valgrind .gcov
|
||||
.SUFFIXES: .c .exe .log .depend .gcov
|
||||
.SECONDARY:
|
||||
|
||||
.c.exe:
|
||||
@@ -34,9 +56,6 @@ all:
|
||||
.exe.log:
|
||||
$(LOG_COMPILER) ./$<
|
||||
|
||||
.exe.valgrind:
|
||||
valgrind ./$<
|
||||
|
||||
.c.gcov:
|
||||
awk '/START_COVERAGE/ { printit=1} (printit == 0) { print }' $< > $<.first.c
|
||||
awk ' printit { print } /END_COVERAGE/ { printit=1}' $< > $<.end.c
|
||||
@@ -63,13 +82,17 @@ depend:
|
||||
# Clean
|
||||
#####################################################################################################
|
||||
|
||||
exe: depend
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.exe/g'` CC="$(CC)" CFLAGS="$(CFLAGS)"
|
||||
@echo All executable generated
|
||||
|
||||
check: depend
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'` `ls fail-*.c|$(SED) 's/\.c/\.log/g'`
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'` `ls fail-*.c|$(SED) 's/\.c/\.log/g'` CC="$(CC)" CFLAGS="$(CFLAGS)"
|
||||
@echo All tests passed
|
||||
|
||||
clean:
|
||||
$(RM) *.exe *.s *~ *.o *.log a*.dat
|
||||
$(RM) *.valgrind *.gcda *.gcno *.gcov all.info test.tar *.synt clang_output_* *.c.c *.end.c *.first.c *.middle.c
|
||||
$(RM) *.gcda *.gcno *.gcov all.info test.tar *.synt clang_output_* *.c.c *.end.c *.first.c *.middle.c
|
||||
$(RMDIR) coverage coverage-dir mlib-report
|
||||
|
||||
distclean: clean
|
||||
@@ -85,13 +108,13 @@ FAIL_BASE=
|
||||
FAIL_SEQ=
|
||||
fail-generic.log:
|
||||
for i in `seq 1 $(FAIL_SEQ)` ; do \
|
||||
if $(CC) $(CFLAGS) $(CPPFLAGS) -g -c $(FAIL_BASE).c -o tmp.o -DTEST=$$i 2> $(FAIL_BASE)-$$i.log ; then echo $(FAIL_BASE) -- TEST $$i : ERROR; false; else echo $(FAIL_BASE) -- TEST $$i : OK ; fi \
|
||||
if $(CC) $(CFLAGS) $(CPPFLAGS) -g -c $(FAIL_BASE).c -o tmp.o -DTEST=$$i 2> $(FAIL_BASE)-$$i.log ; then echo "$(FAIL_BASE) -- TEST $$i : ERROR (compilation succeeded)" ; false ; elif grep -q "M_LIB_" $(FAIL_BASE)-$$i.log ; then echo "$(FAIL_BASE) -- TEST $$i : OK" ; else echo "$(FAIL_BASE) -- TEST $$i : WARNING (Not a M*LIB detected error)" ; fi \
|
||||
done
|
||||
|
||||
fail-no-oplist.log:
|
||||
@$(MAKE) fail-generic.log FAIL_BASE=fail-no-oplist FAIL_SEQ=44
|
||||
fail-chain-oplist.log:
|
||||
@$(MAKE) fail-generic.log FAIL_BASE=fail-chain-oplist FAIL_SEQ=23
|
||||
@$(MAKE) fail-generic.log FAIL_BASE=fail-chain-oplist FAIL_SEQ=24
|
||||
fail-incompatible.log:
|
||||
@$(MAKE) fail-generic.log FAIL_BASE=fail-incompatible FAIL_SEQ=24
|
||||
|
||||
@@ -122,7 +145,6 @@ gene-string:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -march=native -DNDEBUG -S tgen-mstring.c && less tgen-mstring.s
|
||||
|
||||
|
||||
#####################################################################################################
|
||||
# Coverage
|
||||
#####################################################################################################
|
||||
|
||||
@@ -131,39 +153,40 @@ coverage:
|
||||
$(MAKE) synthesis
|
||||
|
||||
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-BUFFER test-mbuffer.c.c test-mbuffer.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-BUFFER test-mbuffer.c.c test-mbuffer.synt \
|
||||
M-CONCURRENT test-mconcurrent.c.c test-mconcurrent.synt \
|
||||
M-CORE test-mcore.c.c test-mcore.synt \
|
||||
M-DEQUE test-mdeque.c.c test-mdeque.synt \
|
||||
M-DICT test-mdict.c.c test-mdict.synt \
|
||||
M-FUNCOBJ test-mfuncobj.c.c test-mfuncobj.synt \
|
||||
M-GENINT ../m-genint.h test-mgenint.synt \
|
||||
M-I-LIST test-milist.c.c test-milist.synt \
|
||||
M-LIST test-mlist.c.c test-mlist.synt \
|
||||
M-MEMPOOL test-mmempool.c.c test-mmempool.synt \
|
||||
M-MUTEX ../m-mutex.h test-mmutex.synt \
|
||||
M-CORE test-mcore.c.c test-mcore.synt \
|
||||
M-DEQUE test-mdeque.c.c test-mdeque.synt \
|
||||
M-DICT test-mdict.c.c test-mdict.synt \
|
||||
M-FUNCOBJ test-mfuncobj.c.c test-mfuncobj.synt \
|
||||
M-GENINT ../m-genint.h test-mgenint.synt \
|
||||
M-I-LIST test-milist.c.c test-milist.synt \
|
||||
M-I-SHARED test-mishared.c.c test-mishared.synt \
|
||||
M-LIST test-mlist.c.c test-mlist.synt \
|
||||
M-MEMPOOL test-mmempool.c.c test-mmempool.synt \
|
||||
M-MUTEX ../m-mutex.h test-mmutex.synt \
|
||||
M-PRIOQUEUE test-mprioqueue.c.c test-mprioqueue.synt \
|
||||
M-RBTREE test-mrbtree.c.c test-mrbtree.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 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-TUPLE test-mtuple.c.c test-mtuple.synt \
|
||||
M-VARIANT test-mvariant.c.c test-mvariant.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-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
|
||||
|
||||
synthesis:
|
||||
@printf "+-------------------------------+-------------------------------+\n"
|
||||
@for i in $(SYNTHESIS_DATA) ; do \
|
||||
if test "$$j" = "" ; then j=$$i ; continue ; fi; \
|
||||
if test "$$k" = "" ; then k=$$i ; continue ; fi; \
|
||||
@for i in $(SYNTHESIS_DATA) ; do \
|
||||
if test "$$j" = "" ; then j=$$i ; continue ; fi; \
|
||||
if test "$$k" = "" ; then k=$$i ; continue ; fi; \
|
||||
printf "|\t%16.16s\t|\t%16.16s\t|\n" "$$j" "`grep -v Creating $$i|grep $$k -F -A1 |tail -1|cut -f2 -d':'`"; \
|
||||
j=""; \
|
||||
k=""; \
|
||||
j=""; \
|
||||
k=""; \
|
||||
done
|
||||
@printf "+-------------------------------+-------------------------------+\n"
|
||||
|
||||
@@ -172,15 +195,12 @@ synthesis:
|
||||
# Code analyzer tools
|
||||
#####################################################################################################
|
||||
|
||||
valgrind:
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.valgrind/g'`
|
||||
|
||||
scan-build: clean
|
||||
$(RM) -rf ./mlib-report
|
||||
scan-build -o ./mlib-report $(MAKE) check XCFLAGS="-std=c99"
|
||||
scan-build -o ./mlib-report $(MAKE) exe XCFLAGS="-std=c99"
|
||||
|
||||
sanitize:
|
||||
$(MAKE) clean check XCFLAGS="-fsanitize=address,undefined"
|
||||
$(MAKE) clean check XCFLAGS="-fsanitize=address,undefined,leak"
|
||||
$(MAKE) clean check XCFLAGS="-fsanitize=thread -pie -fPIE"
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -221,6 +221,15 @@ int f(void) {
|
||||
return r;
|
||||
}
|
||||
|
||||
#elif TEST == 24
|
||||
|
||||
#include "m-tuple.h"
|
||||
#include "m-string.h"
|
||||
|
||||
TUPLE_DEF2(aggregate, (x, int), (z, string_t))
|
||||
#define M_OPL_aggregate_t() TUPLE_OPLIST(aggregate, int, string_t)
|
||||
TUPLE_DEF2(struct2, (a, aggregate_t))
|
||||
|
||||
#else
|
||||
# warning TEST variable is out of range.
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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,8 +40,10 @@ void f(int x, int y) {
|
||||
|
||||
#elif TEST == 2
|
||||
|
||||
#define OP (SWAP(0))
|
||||
|
||||
void f(int x, int y) {
|
||||
M_CALL_SET(M_VALID_OPLIST(DEFAULT_OPLIST), x, y);
|
||||
M_CALL_SWAP(OP, x, y);
|
||||
}
|
||||
|
||||
#elif TEST == 3
|
||||
|
||||
+48
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -48,6 +48,8 @@ DICT_DEF2(dict_obj, string_t, STRING_OPLIST, testobj_t, TESTOBJ_OPLIST)
|
||||
LIST_DUAL_PUSH_DEF(dlist_int, int)
|
||||
DICT_DEF2(dict_int, string_t, int)
|
||||
#define M_OPL_dict_int_t() DICT_OPLIST(dict_int, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
ARRAY_DEF(array_uint, unsigned int)
|
||||
#define M_OPL_array_uint_t() ARRAY_OPLIST(array_uint)
|
||||
|
||||
#include "coverage.h"
|
||||
START_COVERAGE
|
||||
@@ -153,7 +155,7 @@ static void test_list(void)
|
||||
assert(g_count == 101);
|
||||
assert(list_int_size(tmp) == 101);
|
||||
for(int i = 0; i < 100; i++) {
|
||||
assert(*list_int_get(tmp, i) == i * i);
|
||||
assert(*list_int_get(tmp, (size_t) i) == i * i);
|
||||
}
|
||||
assert(*list_int_get(tmp, 100) == 17 * 17);
|
||||
}
|
||||
@@ -215,6 +217,37 @@ static void test_list(void)
|
||||
assert (list_int_end_p (it1));
|
||||
|
||||
list_int_clear(l);
|
||||
|
||||
M_LET( (l1, 1, 3, 5), (l2, 1, 2, 4), (l3, 1, 2, 3, 4, 5), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
|
||||
algo_list_sort_union(l1, l2);
|
||||
assert(list_int_equal_p (l1, l3));
|
||||
}
|
||||
|
||||
M_LET( (l1, 1, 30, 31), (l2, 2, 4, 31, 32), (l3, 1, 2, 4, 30, 31, 32), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
|
||||
algo_list_sort_union(l1, l2);
|
||||
assert(list_int_equal_p (l1, l3));
|
||||
}
|
||||
|
||||
M_LET( (l1, 4, 28, 29, 30, 34), (l2, 1, 3, 31, 32, 33), (l3, 1, 3, 4, 28, 29, 30, 31, 32, 33, 34), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
|
||||
algo_list_sort_union(l1, l2);
|
||||
assert(list_int_equal_p (l1, l3));
|
||||
}
|
||||
|
||||
M_LET( (l1, 1, 4, 28, 29, 31, 34), (l2, 1, 3, 31, 32, 33), (l3, 1, 31), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
|
||||
algo_list_sort_intersect(l1, l2);
|
||||
assert(list_int_equal_p (l1, l3));
|
||||
}
|
||||
|
||||
M_LET( (l1, 4, 28, 29, 31, 34), (l2, 1, 3, 31, 32, 33), (l3, 31), LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
|
||||
algo_list_sort_intersect(l1, l2);
|
||||
assert(list_int_equal_p (l1, l3));
|
||||
}
|
||||
|
||||
M_LET( (l1, 1, 4, 28, 29, 31, 34), (l2, 3, 32, 33), l3, LIST_OPLIST(list_int, M_DEFAULT_OPLIST)) {
|
||||
algo_list_sort_intersect(l1, l2);
|
||||
assert(list_int_equal_p (l1, l3));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void test_array(void)
|
||||
@@ -282,8 +315,8 @@ static void test_array(void)
|
||||
assert(g_count == 101);
|
||||
assert(array_int_size(tmp) == 101);
|
||||
for(int i = 0; i < 100; i++) {
|
||||
assert(*array_int_get(l, i) == i);
|
||||
assert(*array_int_get(tmp, i) == i * i);
|
||||
assert(*array_int_get(l, (size_t) i) == i);
|
||||
assert(*array_int_get(tmp, (size_t) i) == i * i);
|
||||
}
|
||||
assert(*array_int_get(l, 100) == 17);
|
||||
assert(*array_int_get(tmp, 100) == 17 * 17);
|
||||
@@ -293,8 +326,8 @@ static void test_array(void)
|
||||
ALGO_TRANSFORM(tmp, array_int_t, l, array_int_t, FT);
|
||||
assert(array_int_size(tmp) == 101);
|
||||
for(int i = 0; i < 100; i++) {
|
||||
assert(*array_int_get(l, i) == i);
|
||||
assert(*array_int_get(tmp, i) == i + 1);
|
||||
assert(*array_int_get(l, (size_t) i) == i);
|
||||
assert(*array_int_get(tmp, (size_t) i) == i + 1);
|
||||
}
|
||||
|
||||
array_int_clean(tmp);
|
||||
@@ -302,8 +335,8 @@ static void test_array(void)
|
||||
ALGO_TRANSFORM(tmp, array_int_t, l, array_int_t, FT2, 17);
|
||||
assert(array_int_size(tmp) == 101);
|
||||
for(int i = 0; i < 100; i++) {
|
||||
assert(*array_int_get(l, i) == i);
|
||||
assert(*array_int_get(tmp, i) == i + 17);
|
||||
assert(*array_int_get(l, (size_t) i) == i);
|
||||
assert(*array_int_get(tmp, (size_t) i) == i + 17);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -510,7 +543,10 @@ static void test_extract(void)
|
||||
assert (dst == 127);
|
||||
|
||||
unsigned long long dst_l;
|
||||
ALGO_REDUCE( (dst_l, M_OPEXTEND(M_STANDARD_OPLIST, TYPE(unsigned long long))), a, array_int_t, sum);
|
||||
// To avoid warnings about sign conversion between int and unsigned long long
|
||||
#define my_set(a, b) do { (a) = (unsigned int) (b); } while (0)
|
||||
#define my_sum(a, b) do { (a) += (unsigned int) (b); } while (0)
|
||||
ALGO_REDUCE( (dst_l, M_OPEXTEND(M_STANDARD_OPLIST, SET(my_set), TYPE(unsigned long long))), a, array_int_t, my_sum);
|
||||
assert (dst_l == 100*99/2-10*11/2);
|
||||
|
||||
array_int_clean(a);
|
||||
@@ -559,11 +595,11 @@ static void test_insert(void)
|
||||
static void test_string_utf8(void)
|
||||
{
|
||||
M_LET( (s, "H€llo René Chaînôr¬"), string_t)
|
||||
M_LET( (ref, 72, 8364, 108, 108, 111, 32, 82, 101, 110, 233, 32, 67, 104, 97, 238, 110, 244, 114, 172), a, array_int_t) {
|
||||
M_LET( (ref, 72, 8364, 108, 108, 111, 32, 82, 101, 110, 233, 32, 67, 104, 97, 238, 110, 244, 114, 172), a, array_uint_t) {
|
||||
// Convert the string into an array of unicode.
|
||||
ALGO_EXTRACT(a, array_int_t, s, string_t);
|
||||
ALGO_EXTRACT(a, array_uint_t, s, string_t);
|
||||
// Compare the converted string into the reference array
|
||||
assert(array_int_equal_p(a, ref));
|
||||
assert(array_uint_equal_p(a, ref));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -636,8 +672,6 @@ FUNC_OBJ_INS_DEF(fol_cmp, algo_list_fo_cmp_obj,
|
||||
M_LET( (obj, 1), fol_cmp_t)
|
||||
algo_list_fo_sort_fo(tab, fol_cmp_as_interface(obj));
|
||||
M_LET ( (ref, -1, 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9), LIST_OPLIST(list_int)) {
|
||||
// NOTE: For a list, the order is revered by default
|
||||
list_int_reverse(ref);
|
||||
assert( list_int_equal_p(tab, ref));
|
||||
}
|
||||
}
|
||||
|
||||
+30
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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,6 +33,13 @@ END_COVERAGE
|
||||
|
||||
// Array with the minimum number of methods.
|
||||
ARRAY_DEF(array_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
|
||||
ARRAY_DEF(array_min2_z, testobj_t, (INIT(testobj_init), CLEAR(testobj_clear)))
|
||||
ARRAY_DEF(array_min3_z, testobj_t, (CLEAR(testobj_clear)))
|
||||
|
||||
ARRAY_DEF(array_ulong, uint64_t)
|
||||
|
||||
ARRAY_DEF_AS(array_double, ArrayDouble, ArrayDoubleIt, double)
|
||||
#define M_OPL_ArrayDouble() ARRAY_OPLIST(array_double, M_DEFAULT_OPLIST)
|
||||
|
||||
static void test_uint(void)
|
||||
{
|
||||
@@ -183,7 +190,7 @@ static void test_uint(void)
|
||||
assert (x == 1478963);
|
||||
assert (s == *array_uint_back(v));
|
||||
|
||||
s = array_uint_size (v);
|
||||
s = (unsigned int) array_uint_size (v);
|
||||
bool b = array_uint_erase (v, 12459);
|
||||
assert (b == false);
|
||||
assert (s == array_uint_size (v));
|
||||
@@ -205,12 +212,12 @@ static void test_mpz(void)
|
||||
testobj_init (z);
|
||||
|
||||
// Test empty
|
||||
FILE *f = fopen ("a-marray.dat", "wt");
|
||||
FILE *f = m_core_fopen ("a-marray.dat", "wt");
|
||||
if (!f) abort();
|
||||
array_mpz_out_str(f, array1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen ("a-marray.dat", "rt");
|
||||
f = m_core_fopen ("a-marray.dat", "rt");
|
||||
if (!f) abort();
|
||||
bool b = array_mpz_in_str (array2, f);
|
||||
assert (b == true);
|
||||
@@ -219,16 +226,16 @@ static void test_mpz(void)
|
||||
|
||||
// Test non empty
|
||||
for(int n = 0; n < 1000; n++) {
|
||||
testobj_set_ui (z, n);
|
||||
testobj_set_ui (z, (unsigned int) n);
|
||||
array_mpz_push_back (array1, z);
|
||||
}
|
||||
|
||||
f = fopen ("a-marray.dat", "wt");
|
||||
f = m_core_fopen ("a-marray.dat", "wt");
|
||||
if (!f) abort();
|
||||
array_mpz_out_str(f, array1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen ("a-marray.dat", "rt");
|
||||
f = m_core_fopen ("a-marray.dat", "rt");
|
||||
if (!f) abort();
|
||||
b = array_mpz_in_str (array2, f);
|
||||
assert (b == true);
|
||||
@@ -286,7 +293,7 @@ static void test_d(void)
|
||||
array_uint_move(a1, a2);
|
||||
assert (array_uint_empty_p (a1));
|
||||
for(int i = 0; i < 10; i++)
|
||||
array_uint_push_back (a1, i);
|
||||
array_uint_push_back (a1, (unsigned int) i);
|
||||
array_uint_set_at (a1, 0, 17);
|
||||
assert (*array_uint_get (a1, 0) == 17);
|
||||
assert (*array_uint_back(a1) == 9);
|
||||
@@ -295,10 +302,10 @@ static void test_d(void)
|
||||
*p = 10;
|
||||
assert (*array_uint_back(a1) == 10);
|
||||
for(int i = 0; i < 10; i++)
|
||||
array_uint_push_at (a1, 9, i);
|
||||
array_uint_push_at (a1, 9, (unsigned int) i);
|
||||
assert (*array_uint_back(a1) == 10);
|
||||
for(int i = 9; i < 19; i++)
|
||||
assert (*array_uint_get (a1, i) == 18U-i);
|
||||
assert (*array_uint_get (a1, (size_t) i) == 18U -(unsigned int) i);
|
||||
|
||||
*array_uint_get_at(a1, 100) = 100;
|
||||
assert (*array_uint_back(a1) == 100);
|
||||
@@ -310,7 +317,7 @@ static void test_d(void)
|
||||
array_uint_insert_v (a1, 10, 200);
|
||||
assert (array_uint_size(a1) == 300);
|
||||
for(int i = 10; i < 210; i++) {
|
||||
assert (*array_uint_get (a1, i) == 0);
|
||||
assert (*array_uint_get (a1, (size_t)i) == 0);
|
||||
}
|
||||
array_uint_it_t it;
|
||||
array_uint_it(it, a1);
|
||||
@@ -329,8 +336,6 @@ static void test_d(void)
|
||||
assert (*array_uint_ref(it2) == 0);
|
||||
array_uint_insert(a1, it2, 17);
|
||||
assert (array_uint_size(a1) == 300);
|
||||
assert (*array_uint_ref(it2) == 0);
|
||||
array_uint_next(it2);
|
||||
assert (*array_uint_ref(it2) == 17);
|
||||
|
||||
array_uint_init_set (a2, a1);
|
||||
@@ -348,10 +353,22 @@ static void test_d(void)
|
||||
array_uint_clear(a2);
|
||||
}
|
||||
|
||||
static void test_double(void)
|
||||
{
|
||||
M_LET( (tab, 0.0, 1.0, 2.0, 3.0), ArrayDouble) {
|
||||
double ref = 0.0;
|
||||
for M_EACH(i, tab, ArrayDouble) {
|
||||
assert (*i == ref);
|
||||
ref += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_uint();
|
||||
test_mpz();
|
||||
test_d();
|
||||
test_double();
|
||||
exit(0);
|
||||
}
|
||||
+22
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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,10 +33,10 @@ static void test1(void)
|
||||
assert(bitset_empty_p(set) == true);
|
||||
for(int i = 0; i < 100; i ++) {
|
||||
bitset_push_back(set, i%2);
|
||||
assert (bitset_back(set) == (i%2));
|
||||
assert (bitset_back(set) == M_ASSIGN_CAST(bool, i%2));
|
||||
}
|
||||
for(int i = 0; i < 100; i ++) {
|
||||
assert (bitset_get(set, i) == (i%2));
|
||||
assert (bitset_get(set, (size_t) i) == M_ASSIGN_CAST(bool, i%2));
|
||||
}
|
||||
assert(bitset_size(set) == 100);
|
||||
assert(bitset_empty_p(set) == false);
|
||||
@@ -56,7 +56,7 @@ static void test1(void)
|
||||
assert(bitset_size(set2) == 50);
|
||||
assert(bitset_empty_p(set2) == false);
|
||||
for(int i = 0; i < 50; i ++) {
|
||||
assert (bitset_get(set2, i) == (i%2));
|
||||
assert (bitset_get(set2, (size_t) i) == M_ASSIGN_CAST(bool, i%2));
|
||||
}
|
||||
bitset_reserve(set2, 100);
|
||||
assert(bitset_capacity(set2) >= 100); // rounded
|
||||
@@ -64,10 +64,10 @@ static void test1(void)
|
||||
assert(bitset_capacity(set2) >= 50 && bitset_capacity(set2) < 100); // rounded
|
||||
bitset_resize(set2, 100);
|
||||
for(int i = 0; i < 50; i ++) {
|
||||
assert (bitset_get(set2, i) == (i%2));
|
||||
assert (bitset_get(set2, (size_t) i) == M_ASSIGN_CAST(bool, i%2));
|
||||
}
|
||||
for(int i = 50; i < 100; i ++) {
|
||||
assert (bitset_get(set2, i) == false);
|
||||
assert (bitset_get(set2, (size_t) i) == false);
|
||||
}
|
||||
bitset_resize(set2, 50);
|
||||
|
||||
@@ -75,16 +75,16 @@ static void test1(void)
|
||||
bitset_push_at(set2, 0, 1);
|
||||
assert (bitset_get(set2, 0) == 1);
|
||||
for(int i = 1; i < 51; i ++) {
|
||||
assert (bitset_get(set2, i) == ((i-1)%2));
|
||||
assert (bitset_get(set2, (size_t) i) == M_ASSIGN_CAST(bool, (i-1)%2));
|
||||
}
|
||||
// Push from not aligned bit
|
||||
bitset_push_at(set2, 9, 1);
|
||||
for(int i = 1; i < 9; i ++) {
|
||||
assert (bitset_get(set2, i) == ((i-1)%2));
|
||||
assert (bitset_get(set2, (size_t) i) == M_ASSIGN_CAST(bool, (i-1)%2));
|
||||
}
|
||||
assert (bitset_get(set2, 9) == 1);
|
||||
for(int i = 10; i < 52; i ++) {
|
||||
assert (bitset_get(set2, i) == ((i)%2));
|
||||
assert (bitset_get(set2, (size_t) i) == M_ASSIGN_CAST(bool, i%2));
|
||||
}
|
||||
|
||||
bool b;
|
||||
@@ -94,7 +94,7 @@ static void test1(void)
|
||||
assert(bitset_size(set2) == 50);
|
||||
|
||||
for(int i = 0; i < 200; i++)
|
||||
bitset_push_back(set, (i%2));
|
||||
bitset_push_back(set, M_ASSIGN_CAST(bool, i%2));
|
||||
bitset_pop_at(&b, set, 0);
|
||||
assert (b == false);
|
||||
assert (bitset_size(set) == 199);
|
||||
@@ -123,11 +123,11 @@ static void test1(void)
|
||||
|
||||
bitset_clean(set);
|
||||
for(int i = 0; i < 200; i++)
|
||||
bitset_push_back(set, (i*17547854547UL)&1) ;
|
||||
bitset_push_back(set, ((size_t) i*17547854547UL)&1) ;
|
||||
bitset_it_t it;
|
||||
int n = 0;
|
||||
for(bitset_it(it, set); ! bitset_end_p(it); bitset_next(it)) {
|
||||
bool v = (n*17547854547UL)&1;
|
||||
bool v = ((size_t) n*17547854547UL)&1;
|
||||
bool c = *bitset_cref(it);
|
||||
assert (v == c);
|
||||
n++;
|
||||
@@ -135,7 +135,7 @@ static void test1(void)
|
||||
|
||||
n = 0;
|
||||
for M_EACH (item, set, BITSET_OPLIST) {
|
||||
bool v = (n*17547854547UL)&1;
|
||||
bool v = ((size_t) n*17547854547UL)&1;
|
||||
bool c = *item;
|
||||
assert (v == c);
|
||||
n++;
|
||||
@@ -202,7 +202,12 @@ static void test1(void)
|
||||
assert (bitset_end_p(it));
|
||||
|
||||
assert (bitset_hash(set) != 0);
|
||||
|
||||
|
||||
bitset_clean(set);
|
||||
bitset_it(it, set);
|
||||
assert(bitset_end_p(it));
|
||||
assert(bitset_last_p(it));
|
||||
|
||||
bitset_clear(set);
|
||||
bitset_clear(set2);
|
||||
}
|
||||
@@ -229,14 +234,14 @@ static void test_str(void)
|
||||
bitset_init(set2);
|
||||
|
||||
for(int i = 0; i < 200; i++)
|
||||
bitset_push_back(set1, (i*17547854547UL >> 4)&1) ;
|
||||
bitset_push_back(set1, ((size_t) i*17547854547UL >> 4)&1) ;
|
||||
|
||||
FILE *f = fopen ("a-mbitset.dat", "wt");
|
||||
FILE *f = m_core_fopen ("a-mbitset.dat", "wt");
|
||||
if (!f) abort();
|
||||
bitset_out_str(f, set1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen ("a-mbitset.dat", "rt");
|
||||
f = m_core_fopen ("a-mbitset.dat", "rt");
|
||||
if (!f) abort();
|
||||
bool b = bitset_in_str (set2, f);
|
||||
assert (b == true);
|
||||
|
||||
+72
-41
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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,7 +40,16 @@ BPTREE_DEF(btree_myset, 15, testobj_t, TESTOBJ_CMP_OPLIST)
|
||||
|
||||
BPTREE_MULTI_DEF2(multimap, 3, int, M_DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
BPTREE_MULTI_DEF(multiset, 6, int, M_DEFAULT_OPLIST)
|
||||
|
||||
|
||||
BPTREE_DEF2_AS(MapDouble, MapDouble, MapDoubleIt, MapDoubleItRef, 4, double, double)
|
||||
#define M_OPL_MapDouble() BPTREE_OPLIST2(MapDouble, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
BPTREE_DEF_AS(SetDouble, SetDouble, SetDoubleIt, 7, double)
|
||||
#define M_OPL_SetDouble() BPTREE_OPLIST(SetDouble, M_DEFAULT_OPLIST)
|
||||
BPTREE_MULTI_DEF2_AS(MultiMapDouble, MultiMapDouble, MultiMapDoubleIt, MultiMapDoubleItRef, 8, double, double)
|
||||
#define M_OPL_MultiMapDouble() BPTREE_OPLIST2(MultiMapDouble, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
BPTREE_MULTI_DEF_AS(MultiSetDouble, MultiSetDouble, MultiSetDoubleIt, 9, double)
|
||||
#define M_OPL_MultiSetDouble() BPTREE_OPLIST(MultiSetDouble, M_DEFAULT_OPLIST)
|
||||
|
||||
static void test1(void)
|
||||
{
|
||||
btree_t b;
|
||||
@@ -355,7 +364,7 @@ static void test5(void)
|
||||
btree_it_t it, it2;
|
||||
int i = 0;
|
||||
for(btree_it(it, b), btree_it_set(it2, it); !btree_end_p(it); btree_next(it)) {
|
||||
const btree_type_t *item = btree_cref(it);
|
||||
const btree_itref_t *item = btree_cref(it);
|
||||
assert (*item->key_ptr == i);
|
||||
assert (*item->value_ptr == 1000*i);
|
||||
i++;
|
||||
@@ -368,7 +377,7 @@ static void test5(void)
|
||||
|
||||
i = 500;
|
||||
for(btree_it_from(it, b, 500); !btree_it_until_p(it, 600); btree_next(it)) {
|
||||
const btree_type_t *item = btree_cref(it);
|
||||
const btree_itref_t *item = btree_cref(it);
|
||||
assert (*item->key_ptr == i);
|
||||
assert (*item->value_ptr == 1000*i);
|
||||
i++;
|
||||
@@ -378,7 +387,7 @@ static void test5(void)
|
||||
btree_erase (b, 500);
|
||||
i = 501;
|
||||
for(btree_it_from(it, b, 500); !btree_it_until_p(it, 600); btree_next(it)) {
|
||||
const btree_type_t *item = btree_cref(it);
|
||||
const btree_itref_t *item = btree_cref(it);
|
||||
assert (*item->key_ptr == i);
|
||||
assert (*item->value_ptr == 1000*i);
|
||||
i++;
|
||||
@@ -405,12 +414,12 @@ static void test_io(void)
|
||||
assert(*endp == 0);
|
||||
assert (btree_my_equal_p (tree1, tree2));
|
||||
|
||||
FILE *f = fopen ("a-mbptree.dat", "wt");
|
||||
FILE *f = m_core_fopen ("a-mbptree.dat", "wt");
|
||||
if (!f) abort();
|
||||
btree_my_out_str(f, tree1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen ("a-mbptree.dat", "rt");
|
||||
f = m_core_fopen ("a-mbptree.dat", "rt");
|
||||
if (!f) abort();
|
||||
b = btree_my_in_str (tree2, f);
|
||||
assert (b == true);
|
||||
@@ -431,12 +440,12 @@ static void test_io(void)
|
||||
assert(*endp == 0);
|
||||
assert (btree_my_equal_p (tree1, tree2));
|
||||
|
||||
f = fopen ("a-mbptree.dat", "wt");
|
||||
f = m_core_fopen ("a-mbptree.dat", "wt");
|
||||
if (!f) abort();
|
||||
btree_my_out_str(f, tree1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen ("a-mbptree.dat", "rt");
|
||||
f = m_core_fopen ("a-mbptree.dat", "rt");
|
||||
if (!f) abort();
|
||||
b = btree_my_in_str (tree2, f);
|
||||
assert (b == true);
|
||||
@@ -458,12 +467,12 @@ static void test_io_set(void)
|
||||
assert(*endp == 0);
|
||||
assert (btree_myset_equal_p (tree1, tree2));
|
||||
|
||||
FILE *f = fopen ("a-mbptree.dat", "wt");
|
||||
FILE *f = m_core_fopen ("a-mbptree.dat", "wt");
|
||||
if (!f) abort();
|
||||
btree_myset_out_str(f, tree1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen ("a-mbptree.dat", "rt");
|
||||
f = m_core_fopen ("a-mbptree.dat", "rt");
|
||||
if (!f) abort();
|
||||
b = btree_myset_in_str (tree2, f);
|
||||
assert (b == true);
|
||||
@@ -485,12 +494,12 @@ static void test_io_set(void)
|
||||
assert(*endp == 0);
|
||||
assert (btree_myset_equal_p (tree1, tree2));
|
||||
|
||||
f = fopen ("a-mbptree.dat", "wt");
|
||||
f = m_core_fopen ("a-mbptree.dat", "wt");
|
||||
if (!f) abort();
|
||||
btree_myset_out_str(f, tree1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen ("a-mbptree.dat", "rt");
|
||||
f = m_core_fopen ("a-mbptree.dat", "rt");
|
||||
if (!f) abort();
|
||||
b = btree_myset_in_str (tree2, f);
|
||||
assert (b == true);
|
||||
@@ -499,32 +508,6 @@ static void test_io_set(void)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Dump code for debug
|
||||
static void multimap_dump_node(multimap_node_t n)
|
||||
{
|
||||
while (n) {
|
||||
int num = n->num < 0 ? -n->num : n->num;
|
||||
printf ("[");
|
||||
for(int i = 0; i < num; i++)
|
||||
printf ("%d, ", n->key[i]);
|
||||
printf ("] ");
|
||||
n = n->next;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
static void
|
||||
multimap_dump(multimap_t b)
|
||||
{
|
||||
multimap_node_t n = b->root;
|
||||
while (n->num > 0) {
|
||||
multimap_dump_node(n);
|
||||
n = n->kind.node[0];
|
||||
}
|
||||
multimap_dump_node(n);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_multimap(void)
|
||||
{
|
||||
@@ -543,7 +526,7 @@ test_multimap(void)
|
||||
for(multimap_it_from(it, b, k);
|
||||
multimap_it_while_p(it, k);
|
||||
multimap_next(it)) {
|
||||
const multimap_type_t *ref = multimap_cref(it);
|
||||
const multimap_itref_t *ref = multimap_cref(it);
|
||||
assert(*ref->key_ptr == k);
|
||||
assert(*ref->value_ptr == j);
|
||||
j--;
|
||||
@@ -579,7 +562,7 @@ test_multiset(void)
|
||||
for(multiset_it_from(it, b, k);
|
||||
multiset_it_while_p(it, k);
|
||||
multiset_next(it)) {
|
||||
const multiset_type_t *ref = multiset_cref(it);
|
||||
const multiset_itref_t *ref = multiset_cref(it);
|
||||
assert(*ref == k);
|
||||
j++;
|
||||
}
|
||||
@@ -596,6 +579,53 @@ test_multiset(void)
|
||||
multiset_clear(b);
|
||||
}
|
||||
|
||||
static void test_double(void)
|
||||
{
|
||||
M_LET( (tree, (1.0, 2.0), (3.0, 4.0)), MapDouble) {
|
||||
double *r = MapDouble_get(tree, 1.0);
|
||||
assert( r != NULL);
|
||||
assert( *r == 2.0);
|
||||
r = MapDouble_get(tree, 3.0);
|
||||
assert( r != NULL);
|
||||
assert( *r == 4.0);
|
||||
r = MapDouble_get(tree, 4.0);
|
||||
assert( r == NULL);
|
||||
}
|
||||
|
||||
M_LET( (tree, 1.0, 3.0), SetDouble) {
|
||||
double *r = SetDouble_get(tree, 1.0);
|
||||
assert( r != NULL);
|
||||
assert( *r == 1.0);
|
||||
r = SetDouble_get(tree, 3.0);
|
||||
assert( r != NULL);
|
||||
assert( *r == 3.0);
|
||||
r = SetDouble_get(tree, 4.0);
|
||||
assert( r == NULL);
|
||||
}
|
||||
|
||||
M_LET( (tree, (1.0, 2.0), (3.0, 4.0)), MultiMapDouble) {
|
||||
double *r = MultiMapDouble_get(tree, 1.0);
|
||||
assert( r != NULL);
|
||||
assert( *r == 2.0);
|
||||
r = MultiMapDouble_get(tree, 3.0);
|
||||
assert( r != NULL);
|
||||
assert( *r == 4.0);
|
||||
r = MultiMapDouble_get(tree, 4.0);
|
||||
assert( r == NULL);
|
||||
}
|
||||
|
||||
M_LET( (tree, 1.0, 3.0), MultiSetDouble) {
|
||||
double *r = MultiSetDouble_get(tree, 1.0);
|
||||
assert( r != NULL);
|
||||
assert( *r == 1.0);
|
||||
r = MultiSetDouble_get(tree, 3.0);
|
||||
assert( r != NULL);
|
||||
assert( *r == 3.0);
|
||||
r = MultiSetDouble_get(tree, 4.0);
|
||||
assert( r == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test1();
|
||||
@@ -608,5 +638,6 @@ int main(void)
|
||||
test_io_set();
|
||||
test_multimap();
|
||||
test_multiset();
|
||||
test_double();
|
||||
exit(0);
|
||||
}
|
||||
+106
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -45,6 +45,14 @@ BUFFER_DEF(buffer_mpz, testobj_t, 32, BUFFER_QUEUE, TESTOBJ_OPLIST)
|
||||
QUEUE_MPMC_DEF(queue_z, testobj_t, BUFFER_QUEUE, TESTOBJ_OPLIST)
|
||||
QUEUE_SPSC_DEF(squeue_a, testobj_t, BUFFER_QUEUE, TESTOBJ_OPLIST)
|
||||
|
||||
// Define other buffers
|
||||
BUFFER_DEF_AS(BufferDouble1, BufferDouble1, double, 4, BUFFER_QUEUE)
|
||||
QUEUE_MPMC_DEF_AS(BufferDouble2, BufferDouble2, double, BUFFER_QUEUE)
|
||||
QUEUE_SPSC_DEF_AS(BufferDouble3, BufferDouble3, double, BUFFER_QUEUE)
|
||||
#define M_OPL_BufferDouble1() BUFFER_OPLIST(BufferDouble1, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_BufferDouble2() BUFFER_OPLIST(BufferDouble2, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_BufferDouble3() BUFFER_OPLIST(BufferDouble3, M_DEFAULT_OPLIST)
|
||||
|
||||
buffer_uint_t g_buff;
|
||||
buffer_uint_t g_buffB;
|
||||
|
||||
@@ -157,7 +165,7 @@ static void test_stack(void)
|
||||
buffer_floats_init(buff, 100);
|
||||
assert (buffer_floats_capacity(buff) == 100);
|
||||
for(unsigned int i = 0; i < 100; i++) {
|
||||
float f = i;
|
||||
float f = (float) i;
|
||||
buffer_floats_push(buff, f);
|
||||
assert (buffer_floats_empty_p(buff) == false);
|
||||
}
|
||||
@@ -165,7 +173,7 @@ static void test_stack(void)
|
||||
for(unsigned int i = 0; i < 100; i++) {
|
||||
float j;
|
||||
buffer_floats_pop(&j, buff);
|
||||
assert(j == 99-i);
|
||||
assert(j == (float) (99-i) );
|
||||
assert (buffer_floats_full_p(buff) == false);
|
||||
}
|
||||
assert (buffer_floats_empty_p(buff) == true);
|
||||
@@ -179,7 +187,7 @@ static void test_stack2(void)
|
||||
char c;
|
||||
buffer_char_init(buff, 10);
|
||||
for(int i = 0; i < 10; i++) {
|
||||
c = i;
|
||||
c = (char) i;
|
||||
b = buffer_char_push(buff, c);
|
||||
assert (b == true);
|
||||
assert (buffer_char_empty_p(buff) == false);
|
||||
@@ -234,19 +242,40 @@ static void test_no_thread(void)
|
||||
|
||||
/* Test intrusive shared pointer + buffer */
|
||||
#include "m-i-shared.h"
|
||||
|
||||
// Tiny test structure
|
||||
typedef struct test_s {
|
||||
ISHARED_PTR_INTERFACE(ishared_itest, struct test_s);
|
||||
char buffer[52];
|
||||
char bigbuffer[1000000];
|
||||
} test_t;
|
||||
|
||||
static void test_init(test_t *p) { memset(p->buffer, 0x00, 52); }
|
||||
static void test_clear(test_t *p) { memset(p->buffer, 0xFF, 52); }
|
||||
|
||||
ISHARED_PTR_DEF(ishared_itest, test_t,
|
||||
(INIT(test_init M_IPTR), CLEAR(test_clear M_IPTR), DEL(free)))
|
||||
|
||||
typedef struct test2_s {
|
||||
ISHARED_PTR_INTERFACE(ishared_itest2, struct test_s);
|
||||
char buffer[52];
|
||||
} test2_t;
|
||||
static inline void ishared_itest2_init_data(test2_t *d)
|
||||
{
|
||||
memset(d->buffer, 0, sizeof (d->buffer));
|
||||
}
|
||||
ISHARED_PTR_DEF(ishared_itest2, test2_t, (INIT(API_2(ishared_itest2_init_data)), CLEAR(M_NOTHING_DEFAULT)))
|
||||
|
||||
typedef struct test3_s {
|
||||
ISHARED_PTR_INTERFACE(ishared_itest3, struct test_s);
|
||||
char buffer[52];
|
||||
} test3_t;
|
||||
ISHARED_PTR_DEF(ishared_itest3, test3_t, (CLEAR(M_NOTHING_DEFAULT)))
|
||||
|
||||
typedef struct test4_s {
|
||||
ISHARED_PTR_INTERFACE(ishared_itest4, struct test_s);
|
||||
char buffer[52];
|
||||
} test4_t;
|
||||
ISHARED_PTR_DEF(ishared_itest4, test4_t, (INIT(0), DEL(0), INIT(M_MEMSET_DEFAULT), CLEAR(M_NOTHING_DEFAULT)))
|
||||
|
||||
static test_t *test_new(void)
|
||||
{
|
||||
test_t *p = M_ASSIGN_CAST(test_t*, malloc (sizeof (test_t)));
|
||||
@@ -290,8 +319,9 @@ static void test_prod(void *arg)
|
||||
assert (arg == NULL);
|
||||
for(unsigned int i = 0; i < 10;i++) {
|
||||
test_t *p = test_new();
|
||||
for(int j = 0; j < 52; j++)
|
||||
p->buffer[j] = (j * j * 17) + j * 42 + 1;
|
||||
for(int j = 0; j < 52; j++) {
|
||||
p->buffer[j] = (char) ((j * j * 17) + j * 42 + 1);
|
||||
}
|
||||
buffer_itest_push(comm1, p);
|
||||
buffer_itest_push(comm2, p);
|
||||
ishared_itest_clear(p);
|
||||
@@ -361,7 +391,7 @@ static void prod2(void *arg)
|
||||
size_t n = *p_n;
|
||||
size_t r = n;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
while (!queue_uint_push(g_buff2, r ));
|
||||
while (!queue_uint_push(g_buff2, (unsigned int) r ));
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
@@ -388,7 +418,7 @@ static void test_queue(size_t n, int cpu_count, unsigned long long ref)
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso2, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
size_t n2 = (size_t) conso_count;
|
||||
m_thread_create(idx_final, final2, &n2);
|
||||
|
||||
// Wait for jobs to be done.
|
||||
@@ -489,7 +519,65 @@ static void test_spsc(void)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
int main(void)
|
||||
static void test_double1(void)
|
||||
{
|
||||
bool b;
|
||||
M_LET(buffer, BufferDouble1) {
|
||||
b = BufferDouble1_push(buffer, 0.0);
|
||||
assert(b);
|
||||
b= BufferDouble1_push(buffer, 1.0);
|
||||
assert(b);
|
||||
double d;
|
||||
b = BufferDouble1_pop(&d, buffer);
|
||||
assert(b);
|
||||
assert(d == 0.0);
|
||||
b = BufferDouble1_pop(&d, buffer);
|
||||
assert(b);
|
||||
assert(d == 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_double2(void)
|
||||
{
|
||||
bool b;
|
||||
BufferDouble2 buffer;
|
||||
BufferDouble2_init(buffer, 2);
|
||||
b = BufferDouble2_push(buffer, 0.0);
|
||||
assert(b);
|
||||
b= BufferDouble2_push(buffer, 1.0);
|
||||
assert(b);
|
||||
double d;
|
||||
b = BufferDouble2_pop(&d, buffer);
|
||||
assert(b);
|
||||
assert(d == 0.0);
|
||||
b = BufferDouble2_pop(&d, buffer);
|
||||
assert(b);
|
||||
assert(d == 1.0);
|
||||
BufferDouble2_clear(buffer);
|
||||
}
|
||||
|
||||
static void test_double3(void)
|
||||
{
|
||||
bool b;
|
||||
BufferDouble3 buffer;
|
||||
BufferDouble3_init(buffer, 2);
|
||||
b = BufferDouble3_push(buffer, 0.0);
|
||||
assert(b);
|
||||
b= BufferDouble3_push(buffer, 1.0);
|
||||
assert(b);
|
||||
double d;
|
||||
b = BufferDouble3_pop(&d, buffer);
|
||||
assert(b);
|
||||
assert(d == 0.0);
|
||||
b = BufferDouble3_pop(&d, buffer);
|
||||
assert(b);
|
||||
assert(d == 1.0);
|
||||
BufferDouble3_clear(buffer);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_uint(void)
|
||||
{
|
||||
unsigned int x, y;
|
||||
buffer_uint_t v;
|
||||
@@ -511,7 +599,11 @@ int main(void)
|
||||
assert (y == 10);
|
||||
|
||||
buffer_uint_clear(v);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_uint();
|
||||
test_global();
|
||||
test_stack();
|
||||
test_stack2();
|
||||
@@ -519,5 +611,8 @@ int main(void)
|
||||
test_global_ishared();
|
||||
test_queue(1000000, 2, 2148371710223136ULL);
|
||||
test_spsc();
|
||||
test_double1();
|
||||
test_double2();
|
||||
test_double3();
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Test for Concurrent memory pool allocator
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -97,6 +97,9 @@ CONCURRENT_RP_DEF(rparray1, array1_t, ARRAY_OPLIST(array1))
|
||||
|
||||
CONCURRENT_RP_DEF(rpdict1, dict1_t, DICT_OPLIST(dict1))
|
||||
|
||||
CONCURRENT_DEF_AS(ConcurrentDouble, ConcurrentDouble, double)
|
||||
CONCURRENT_RP_DEF_AS(ConcurrentRpDouble, ConcurrentRpDouble, double)
|
||||
|
||||
/* OA dict needs more operators than the default ones to work */
|
||||
static inline bool int_oor_equal_p(int s, unsigned char n)
|
||||
{
|
||||
@@ -210,11 +213,23 @@ static void test_rp_basic(void)
|
||||
rpdict1_clear(dict);
|
||||
}
|
||||
|
||||
static void test_double(void)
|
||||
{
|
||||
ConcurrentDouble d;
|
||||
ConcurrentDouble_init(d);
|
||||
ConcurrentDouble_clear(d);
|
||||
|
||||
ConcurrentRpDouble r;
|
||||
ConcurrentRpDouble_init(r);
|
||||
ConcurrentRpDouble_clear(r);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_basic();
|
||||
test_rp_basic();
|
||||
test_thread();
|
||||
test_rp_thread();
|
||||
test_double();
|
||||
exit(0);
|
||||
}
|
||||
+166
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -149,6 +149,32 @@ static void test_empty(void)
|
||||
assert (M_EMPTY_P(()) == false);
|
||||
assert (M_EMPTY_P("123") == false);
|
||||
assert (M_EMPTY_P(,1,2,3) == false);
|
||||
assert (M_EMPTY_P(+2) == false);
|
||||
assert (M_EMPTY_P(-2) == false);
|
||||
assert (M_EMPTY_P( () ) == false);
|
||||
#define F0() int
|
||||
#define F1() (void)
|
||||
#define F2(x) x
|
||||
#define F3()
|
||||
#define F4() 1,2
|
||||
assert (M_EMPTY_P(F0) == false);
|
||||
#ifndef M_COMMA_P_WORKAROUND
|
||||
// Disable tests on platform with a non working preprocessor
|
||||
assert (M_EMPTY_P(F1) == false);
|
||||
assert (M_EMPTY_P(F2) == false);
|
||||
assert (M_EMPTY_P(F3) == false);
|
||||
#endif
|
||||
assert (M_EMPTY_P(F4) == false);
|
||||
#define G0 int
|
||||
#define G1 (void)
|
||||
#define G2 x
|
||||
#define G3
|
||||
#define G4 1,2
|
||||
assert (M_EMPTY_P(G0) == false);
|
||||
assert (M_EMPTY_P(G1) == false);
|
||||
assert (M_EMPTY_P(G2) == false);
|
||||
assert (M_EMPTY_P(G3) == true);
|
||||
assert (M_EMPTY_P(G4) == false);
|
||||
}
|
||||
|
||||
#define f(n) (n)*(n) +
|
||||
@@ -192,6 +218,49 @@ static void test_let(void)
|
||||
assert(0);
|
||||
}
|
||||
assert(b);
|
||||
|
||||
int c = 0;
|
||||
M_LET_IF( assert(c++ == 0), (assert(c++ == 1), true), assert(c++ == 3)) {
|
||||
assert(c++ == 2);
|
||||
}
|
||||
M_LET_IF( assert(c++ == 4), (assert(c++ == 5), false), assert(0)) {
|
||||
assert(0);
|
||||
}
|
||||
assert(c++ == 6);
|
||||
M_LET_IF(int *p = (int*) malloc(sizeof(int)), p!=0, free(p)) {
|
||||
assert(p != NULL);
|
||||
*p = 4;
|
||||
}
|
||||
|
||||
M_LET_IF( assert(c++ == 7), (assert(c++ == 8), true), assert(c++ == 10), assert(0) ) {
|
||||
assert(c++ == 9);
|
||||
}
|
||||
M_LET_IF( assert(c++ == 11), (assert(c++ == 12), false), assert(0), assert(c++ == 13) ) {
|
||||
assert(0);
|
||||
}
|
||||
assert(c++ == 14);
|
||||
|
||||
M_LET_IF( assert(c++ == 15), (assert(c++ == 16), true), assert(c++ == 18) ) {
|
||||
assert(c++ == 17);
|
||||
break;
|
||||
assert(0);
|
||||
}
|
||||
assert(c++ == 19);
|
||||
|
||||
c = 7;
|
||||
int *p = (int*)malloc(sizeof(int));
|
||||
assert(p != NULL);
|
||||
M_DEFER ( (assert(c++ == 8), free(p)) ) {
|
||||
*p = 4;
|
||||
assert(c++ == 7);
|
||||
}
|
||||
assert(c++ == 9);
|
||||
M_DEFER ( assert(c++ == 11) ) {
|
||||
assert(c++ == 10);
|
||||
break;
|
||||
assert(0);
|
||||
}
|
||||
assert(c++ == 12);
|
||||
}
|
||||
|
||||
static void test_va(void)
|
||||
@@ -231,6 +300,12 @@ static void test_test(void)
|
||||
assert(!M_PARENTHESIS_P(()x));
|
||||
}
|
||||
|
||||
static void test_list(void)
|
||||
{
|
||||
assert(M_KEEP_ARGS(1, 1, 0, 0, 0, 0));
|
||||
assert(M_SKIP_ARGS(4, 0, 0, 0, 0, 1));
|
||||
assert(M_MID_ARGS(2, 1, 0, 0, 1, 0));
|
||||
}
|
||||
|
||||
static void test_oplist(void)
|
||||
{
|
||||
@@ -329,6 +404,35 @@ static void test_reduce(void)
|
||||
== M_REDUCE(M_ID, add, M_SEQ(1, 10)));
|
||||
}
|
||||
|
||||
static void test_as_type(void)
|
||||
{
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
int i = 42;
|
||||
float f = 2.5;
|
||||
void *p = (void*) &i;
|
||||
struct as_type { int n; } n = { 17 };
|
||||
|
||||
assert (M_AS_TYPE(int, i) == 42);
|
||||
assert (M_AS_TYPE(float, i) == 0.0);
|
||||
assert (M_AS_TYPE(void *, i) == 0);
|
||||
assert (M_AS_TYPE(struct as_type, i).n == 0 );
|
||||
|
||||
assert (M_AS_TYPE(int, f) == 0);
|
||||
assert (M_AS_TYPE(float, f) == 2.5);
|
||||
assert (M_AS_TYPE(void *, f) == 0);
|
||||
assert (M_AS_TYPE(struct as_type, f).n == 0 );
|
||||
|
||||
assert (M_AS_TYPE(int, p) == 0);
|
||||
assert (M_AS_TYPE(float, p) == 0.0);
|
||||
assert (M_AS_TYPE(void *, p) == &i);
|
||||
assert (M_AS_TYPE(struct as_type, p).n == 0 );
|
||||
|
||||
assert (M_AS_TYPE(int, n) == 0);
|
||||
assert (M_AS_TYPE(float, n) == 0.0);
|
||||
assert (M_AS_TYPE(void *, n) == 0);
|
||||
assert (M_AS_TYPE(struct as_type, n).n == 17 );
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_parse_standard_c_type(void)
|
||||
{
|
||||
@@ -459,6 +563,62 @@ static void test_move_default(void)
|
||||
assert(x2.c == 0);
|
||||
}
|
||||
|
||||
static void test_builtin(void)
|
||||
{
|
||||
assert(m_core_clz32(0) == 32);
|
||||
for(unsigned i = 0; i < 31; i++) {
|
||||
assert(m_core_clz32((uint32_t) (1UL<<i)) == 31U - i);
|
||||
assert(m_core_clz32((uint32_t) ((1UL<<i) | 1)) == 31U - i);
|
||||
}
|
||||
|
||||
assert(m_core_clz64(0) == 64);
|
||||
for(unsigned i = 0; i < 63; i++) {
|
||||
assert(m_core_clz64((uint64_t) (1ULL<<i)) == 63U - i);
|
||||
assert(m_core_clz64((uint64_t) ((1ULL<<i) | 1)) == 63U - i);
|
||||
}
|
||||
|
||||
assert ( m_core_roundpow2(0) == 0);
|
||||
for(unsigned i = 0; i < 62; i++) {
|
||||
assert ( m_core_roundpow2(1ULL<<i) == 1ULL<<i);
|
||||
assert ( m_core_roundpow2((1ULL<<i)+1) == 1ULL<<(i+1) );
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < 3000; i++) {
|
||||
assert( m_core_rotl32a(i, 1) == i * 2);
|
||||
assert( m_core_rotl32a(i, 2) == i * 4);
|
||||
assert( m_core_rotl32a((uint32_t) ((1UL<<31) + i), 1) == i * 2 + 1);
|
||||
assert( m_core_rotl32a((uint32_t) ((1UL<<31) + i), 2) == i * 4 + 2);
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < 3000; i++) {
|
||||
assert( m_core_rotl64a(i, 1) == i * 2);
|
||||
assert( m_core_rotl64a(i, 2) == i * 4);
|
||||
assert( m_core_rotl64a((1ULL<<63) + i, 1) == i * 2 + 1);
|
||||
assert( m_core_rotl64a((1ULL<<63) + i, 2) == i * 4 + 2);
|
||||
}
|
||||
}
|
||||
|
||||
const char str1[] = "A";
|
||||
const char str2[] = "AB";
|
||||
const char str3[] = "Hello";
|
||||
|
||||
static void test_str_hash(void)
|
||||
{
|
||||
assert (M_CALL_HASH(M_CSTR_OPLIST, str1) != 0);
|
||||
assert (M_CALL_HASH(M_CSTR_OPLIST, str2) != 0);
|
||||
assert (M_CALL_HASH(M_CSTR_OPLIST, str3) != 0);
|
||||
}
|
||||
|
||||
static void test_M_CSTR(void)
|
||||
{
|
||||
assert ( strcmp(M_CSTR("Len=%d", 17), "Len=17") == 0);
|
||||
assert ( strcmp(M_CSTR("Hello %s %c", "World", '!'), "Hello World !") == 0);
|
||||
// Reduce allocation to test truncation
|
||||
#undef M_USE_CSTR_ALLOC
|
||||
#define M_USE_CSTR_ALLOC 8
|
||||
assert ( strcmp(M_CSTR("Hello %s %c", "World", '!'), "Hello W") == 0);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_cat();
|
||||
@@ -468,6 +628,7 @@ int main(void)
|
||||
test_invert();
|
||||
test_min();
|
||||
test_empty();
|
||||
test_list();
|
||||
test_map();
|
||||
test_let();
|
||||
test_va();
|
||||
@@ -476,7 +637,11 @@ int main(void)
|
||||
test_oplist();
|
||||
test_cast();
|
||||
test_reduce();
|
||||
test_as_type();
|
||||
test_parse_standard_c_type();
|
||||
test_move_default();
|
||||
test_builtin();
|
||||
test_str_hash();
|
||||
test_M_CSTR();
|
||||
exit(0);
|
||||
}
|
||||
+73
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -36,8 +36,17 @@ DEQUE_DEF(deque_mpz, testobj_t, TESTOBJ_OPLIST)
|
||||
// Deque with the minimum number of methods.
|
||||
DEQUE_DEF(deque_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
|
||||
|
||||
// Dequeue of an enumerate
|
||||
typedef enum {
|
||||
SUCCESS = 0, NULL_PARAM, INVALID_PARAM
|
||||
} ReturnCode_t;
|
||||
|
||||
DEQUE_DEF(deque_retcode, ReturnCode_t, M_ENUM_OPLIST(ReturnCode_t, SUCCESS))
|
||||
#define OPL DEQUE_OPLIST(deque)
|
||||
|
||||
DEQUE_DEF_AS(DequeDouble, DequeDouble, DequeDoubleIt, double)
|
||||
#define M_OPL_DequeDouble() DEQUE_OPLIST(DequeDouble, M_DEFAULT_OPLIST)
|
||||
|
||||
static void test_ti1(int n)
|
||||
{
|
||||
deque_t d;
|
||||
@@ -52,7 +61,7 @@ static void test_ti1(int n)
|
||||
assert(*deque_front(d) == i);
|
||||
}
|
||||
assert (!deque_empty_p(d));
|
||||
assert (deque_size(d) == (size_t)2*n);
|
||||
assert (deque_size(d) == (size_t)(2*n));
|
||||
int s = 0;
|
||||
for(int i =0; i < 2*n ;i++) {
|
||||
int z;
|
||||
@@ -102,7 +111,7 @@ static void test1(void)
|
||||
}
|
||||
assert (deque_size(d) == 99*2);
|
||||
for(int i = 0; i < 99*2; i++)
|
||||
assert (*deque_get(d, i) == (i < 99) ? i - 99 : i - 98);
|
||||
assert (*deque_get(d, (size_t) i) == (i < 99) ? i - 99 : i - 98);
|
||||
for(int i = 0; i < 98; i++) {
|
||||
deque_pop_back(NULL, d);
|
||||
assert (*deque_back(d) == i - 98);
|
||||
@@ -127,15 +136,15 @@ static void test1(void)
|
||||
static void test_it(void)
|
||||
{
|
||||
M_LET(d, OPL) {
|
||||
for(size_t i = 0; i < 1997; i ++) {
|
||||
for(int i = 0; i < 1997; i ++) {
|
||||
deque_push_back(d, 1997+i);
|
||||
deque_push_front(d, 1996-i);
|
||||
deque_it_t it;
|
||||
deque_it_last (it, d);
|
||||
assert (deque_last_p(it));
|
||||
assert (*deque_cref (it) == (int)(1997+i));
|
||||
assert (*deque_cref (it) == (1997+i));
|
||||
deque_it(it, d);
|
||||
assert (*deque_cref (it) == (int)(1996-i));
|
||||
assert (*deque_cref (it) == (1996-i));
|
||||
}
|
||||
int s = 0;
|
||||
for M_EACH(it, d, OPL) {
|
||||
@@ -188,7 +197,7 @@ static void test_set(void)
|
||||
{
|
||||
M_LET(e, d, OPL) {
|
||||
assert (deque_equal_p(d, e));
|
||||
for(size_t i = 0; i < 1997; i ++)
|
||||
for(int i = 0; i < 1997; i ++)
|
||||
deque_push_back(d, i);
|
||||
assert (!deque_equal_p(d, e));
|
||||
deque_set(e, d);
|
||||
@@ -222,9 +231,9 @@ static void test_set(void)
|
||||
deque_push_back(d, 10000);
|
||||
deque_push_front(d, -10000);
|
||||
assert (deque_size (d) == 1999);
|
||||
for(size_t i = 0; i < 1999; i ++)
|
||||
for(int i = 0; i < 1999; i ++)
|
||||
deque_pop_back(NULL, d);
|
||||
for(size_t i = 0; i < 3001; i ++)
|
||||
for(int i = 0; i < 3001; i ++)
|
||||
deque_push_back(d, i);
|
||||
deque_init (e);
|
||||
deque_move (e, d);
|
||||
@@ -276,12 +285,12 @@ static void test_io(void)
|
||||
M_LET(z, TESTOBJ_OPLIST)
|
||||
M_LET(str, STRING_OPLIST) {
|
||||
// Test empty
|
||||
FILE *f = fopen ("a-marray.dat", "wt");
|
||||
FILE *f = m_core_fopen ("a-mdeque.dat", "wt");
|
||||
if (!f) abort();
|
||||
deque_mpz_out_str(f, d1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen ("a-marray.dat", "rt");
|
||||
f = m_core_fopen ("a-mdeque.dat", "rt");
|
||||
if (!f) abort();
|
||||
bool b = deque_mpz_in_str (d2, f);
|
||||
assert (b == true);
|
||||
@@ -290,16 +299,16 @@ static void test_io(void)
|
||||
|
||||
// Test non empty
|
||||
for(int n = 0; n < 1000; n++) {
|
||||
testobj_set_ui (z, n);
|
||||
testobj_set_ui (z, (unsigned int) n);
|
||||
deque_mpz_push_back (d1, z);
|
||||
}
|
||||
|
||||
f = fopen ("a-marray.dat", "wt");
|
||||
f = m_core_fopen ("a-mdeque.dat", "wt");
|
||||
if (!f) abort();
|
||||
deque_mpz_out_str(f, d1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen ("a-marray.dat", "rt");
|
||||
f = m_core_fopen ("a-mdeque.dat", "rt");
|
||||
if (!f) abort();
|
||||
b = deque_mpz_in_str (d2, f);
|
||||
assert (b == true);
|
||||
@@ -340,6 +349,54 @@ static void test_io(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_io_enum(void)
|
||||
{
|
||||
deque_retcode_t d1, d2;
|
||||
string_t s;
|
||||
|
||||
string_init(s);
|
||||
deque_retcode_init(d1);
|
||||
deque_retcode_init(d2);
|
||||
|
||||
ReturnCode_t *ret = deque_retcode_push_back_new(d1);
|
||||
assert( *ret == SUCCESS);
|
||||
deque_retcode_push_front(d1, INVALID_PARAM);
|
||||
|
||||
FILE *f = m_core_fopen ("a-mdeque.dat", "wt");
|
||||
if (!f) abort();
|
||||
deque_retcode_out_str(f, d1);
|
||||
fclose (f);
|
||||
|
||||
f = m_core_fopen ("a-mdeque.dat", "rt");
|
||||
if (!f) abort();
|
||||
bool b = deque_retcode_in_str (d2, f);
|
||||
assert (b == true);
|
||||
assert (deque_retcode_equal_p (d1, d2));
|
||||
fclose(f);
|
||||
|
||||
deque_retcode_get_str(s, d1, false);
|
||||
assert (string_equal_str_p(s, "[2,0]"));
|
||||
|
||||
b = deque_retcode_parse_str(d2, string_get_cstr(s), NULL);
|
||||
assert(b == true);
|
||||
assert (deque_retcode_equal_p (d1, d2));
|
||||
|
||||
string_clear(s);
|
||||
deque_retcode_clear(d1);
|
||||
deque_retcode_clear(d2);
|
||||
}
|
||||
|
||||
static void test_double(void)
|
||||
{
|
||||
M_LET( (tab, 0.0, 1.0, 2.0, 3.0), DequeDouble) {
|
||||
double ref = 0.0;
|
||||
for M_EACH(i, tab, DequeDouble) {
|
||||
assert (*i == ref);
|
||||
ref += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test1();
|
||||
@@ -350,7 +407,9 @@ int main(void)
|
||||
test_it();
|
||||
test_set();
|
||||
test_io();
|
||||
test_io_enum();
|
||||
test_z();
|
||||
test_advance();
|
||||
test_double();
|
||||
exit(0);
|
||||
}
|
||||
+35
-26
@@ -1,5 +1,6 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -47,6 +48,14 @@ DICT_OA_DEF2(dict_oa_str, symbol_t, BOUNDED_STRING_OPLIST(symbol), int, M_DEFAUL
|
||||
DICT_OA_DEF2(dict_oa_bstr, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
DICT_OASET_DEF(dict_oa_setstr, string_t, STRING_OPLIST)
|
||||
|
||||
|
||||
DICT_DEF2_AS(dictas_int, DictInt, DictIntIt, DictIntItRef, int, M_DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
DICT_STOREHASH_DEF2_AS(dictas_str2, DictSInt, DictSIntIt, DictSIntItRef, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
|
||||
DICT_SET_DEF_AS(dictas_setstr, DictStr, DictStrIt, string_t, STRING_OPLIST)
|
||||
DICT_OA_DEF2_AS(dictas_oa_bstr, DictOAStr, DictOAStrIt, DictOAStrItRef, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
DICT_OASET_DEF_AS(dictas_oa_setstr, DictOASStr, DictOASStrIt, string_t, STRING_OPLIST)
|
||||
|
||||
|
||||
/* Helper structure */
|
||||
ARRAY_DEF(array_string, string_t, STRING_OPLIST)
|
||||
array_string_t v_str;
|
||||
@@ -58,10 +67,10 @@ static void init_data(int data_size)
|
||||
string_init (s);
|
||||
array_string_init(v_str);
|
||||
for (int i = 0; i < data_size; ++i) {
|
||||
int j = (unsigned)(data_size * ((double)x / UINT_MAX) / 4) * 271828183u;
|
||||
unsigned int j = (unsigned int)(data_size * ((double)x / UINT_MAX) / 4) * 271828183u;
|
||||
string_printf(s, "%x", j);
|
||||
array_string_push_back (v_str, s);
|
||||
x = 1664525L * x + 1013904223L;
|
||||
x = (uint32_t) (1664525L * x + 1013904223L);
|
||||
}
|
||||
string_clear(s);
|
||||
}
|
||||
@@ -79,7 +88,7 @@ static void test_data(void)
|
||||
dict_str_init (dict);
|
||||
assert(dict_str_empty_p(dict));
|
||||
for (int i = 0; i < data_size; ++i) {
|
||||
dict_str_set_at(dict, *array_string_cget(v_str, i), *array_string_cget(v_str, (i+1) % data_size));
|
||||
dict_str_set_at(dict, *array_string_cget(v_str, (size_t) i), *array_string_cget(v_str, (size_t) ((i+1) % data_size)));
|
||||
assert(!dict_str_empty_p(dict));
|
||||
}
|
||||
assert(dict_str_size(dict) == 1227176);
|
||||
@@ -118,11 +127,11 @@ static void check_io(void)
|
||||
assert (*sp == 0);
|
||||
assert (dict_str_equal_p(dict, dict2));
|
||||
|
||||
FILE *f = fopen ("a-mdict.dat", "wt");
|
||||
FILE *f = m_core_fopen ("a-mdict.dat", "wt");
|
||||
if (!f) abort();
|
||||
dict_str_out_str(f, dict);
|
||||
fclose (f);
|
||||
f = fopen ("a-mdict.dat", "rt");
|
||||
f = m_core_fopen ("a-mdict.dat", "rt");
|
||||
if (!f) abort();
|
||||
b = dict_str_in_str(dict2, f);
|
||||
assert (b == true);
|
||||
@@ -157,14 +166,14 @@ static void test_init(void)
|
||||
{
|
||||
M_LET(str1, str2, STRING_OPLIST)
|
||||
M_LET(d1, d2, DICT_OPLIST(dict_str, STRING_OPLIST, STRING_OPLIST)){
|
||||
for(size_t i = 0; i < 100; i++) {
|
||||
for(int i = 0; i < 100; i++) {
|
||||
string_printf(str1, "%d", 2*i);
|
||||
string_printf(str2, "%d", 2*i+1);
|
||||
dict_str_set_at (d1, str1, str2);
|
||||
}
|
||||
assert (dict_str_size (d1) == 100);
|
||||
|
||||
for(size_t i = 0; i < 100; i++) {
|
||||
for(int i = 0; i < 100; i++) {
|
||||
string_printf(str1, "%d", 2*i);
|
||||
string_printf(str2, "%d", 2*i+1);
|
||||
string_t *p = dict_str_get (d1, str1);
|
||||
@@ -191,7 +200,7 @@ static void test_init(void)
|
||||
assert (b);
|
||||
assert (!dict_str_equal_p (d2, d1));
|
||||
|
||||
for(size_t i = 1; i < 100; i++) {
|
||||
for(int i = 1; i < 100; i++) {
|
||||
string_printf(str1, "%d", 2*i);
|
||||
b = dict_str_erase (d1, str1);
|
||||
assert (b);
|
||||
@@ -205,7 +214,7 @@ static void test_init(void)
|
||||
|
||||
dict_str_init_move (d3, d1);
|
||||
assert (dict_str_size (d3) == 100);
|
||||
for(size_t i = 0; i < 100; i++) {
|
||||
for(int i = 0; i < 100; i++) {
|
||||
string_printf(str1, "%d", 2*i);
|
||||
string_printf(str2, "%d", 2*i+1);
|
||||
assert (string_equal_p (*dict_str_get (d3, str1), str2));
|
||||
@@ -218,12 +227,12 @@ static void test_init(void)
|
||||
assert (dict_str_size (d2) == 0);
|
||||
|
||||
assert (dict_str_size (d1) == 100);
|
||||
for(size_t i = 100; i < 200; i++) {
|
||||
for(int i = 100; i < 200; i++) {
|
||||
string_printf(str1, "%d", 2*i);
|
||||
string_printf(*dict_str_get_at (d1, str1), "%d", 2*i+1);
|
||||
}
|
||||
assert (dict_str_size (d1) == 200);
|
||||
for(size_t i = 100; i < 200; i++) {
|
||||
for(int i = 100; i < 200; i++) {
|
||||
string_printf(str1, "%d", 2*i);
|
||||
string_printf(str2, "%d", 2*i+1);
|
||||
string_t *p = dict_str_get (d1, str1);
|
||||
@@ -269,7 +278,7 @@ static void test1(void)
|
||||
string_init(key);
|
||||
string_init(ref);
|
||||
|
||||
FILE *f = fopen("dict.txt", "rt");
|
||||
FILE *f = m_core_fopen("dict.txt", "rt");
|
||||
if (!f) abort();
|
||||
dict_str_set_at(dict, STRING_CTE("LICENCE"), STRING_CTE("BSD3"));
|
||||
assert(string_equal_p(*dict_str_cget(dict, STRING_CTE("LICENCE")), STRING_CTE("BSD3")));
|
||||
@@ -285,7 +294,7 @@ static void test1(void)
|
||||
fclose(f);
|
||||
assert(dict_str_size(dict) == 19);
|
||||
|
||||
f = fopen("dict.txt", "rt");
|
||||
f = m_core_fopen("dict.txt", "rt");
|
||||
if (!f) abort();
|
||||
while (!feof(f) && !ferror(f)) {
|
||||
string_fgets(key, f, STRING_READ_PURE_LINE);
|
||||
@@ -332,28 +341,28 @@ static void test_oa(void)
|
||||
dict_oa_int_t d;
|
||||
dict_oa_int_init(d);
|
||||
|
||||
for(size_t i = 0 ; i < 150; i+= 3)
|
||||
for(int i = 0 ; i < 150; i+= 3)
|
||||
dict_oa_int_set_at(d, i, i*i);
|
||||
assert(dict_oa_int_size(d) == 50);
|
||||
for(size_t i = 0 ; i < 150; i++) {
|
||||
for(int i = 0 ; i < 150; i++) {
|
||||
int *p = dict_oa_int_get(d, i);
|
||||
if ((i % 3) == 0) {
|
||||
assert (p != NULL);
|
||||
assert (*p == M_ASSIGN_CAST(int, i*i));
|
||||
assert (*p == i*i);
|
||||
} else {
|
||||
assert (p == NULL);
|
||||
}
|
||||
}
|
||||
assert(dict_oa_int_size(d) == 50);
|
||||
|
||||
for(size_t i = 1 ; i < 150; i+= 3)
|
||||
for(int i = 1 ; i < 150; i+= 3)
|
||||
*dict_oa_int_get_at(d, i) = i*i;
|
||||
assert(dict_oa_int_size(d) == 100);
|
||||
for(size_t i = 0 ; i < 150; i++) {
|
||||
for(int i = 0 ; i < 150; i++) {
|
||||
int *p = dict_oa_int_get(d, i);
|
||||
if ((i % 3) != 2) {
|
||||
assert (p != NULL);
|
||||
assert (*p == M_ASSIGN_CAST(int, i*i));
|
||||
assert (*p == i*i);
|
||||
} else {
|
||||
assert (p == NULL);
|
||||
}
|
||||
@@ -366,7 +375,7 @@ static void test_oa(void)
|
||||
static void test_init_oa(void)
|
||||
{
|
||||
M_LET(d1, d2, DICT_OPLIST(dict_oa_int, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)){
|
||||
for(size_t i = 0; i < 100; i++) {
|
||||
for(int i = 0; i < 100; i++) {
|
||||
dict_oa_int_set_at (d1, 2*i, 2*i+1);
|
||||
}
|
||||
assert (dict_oa_int_size (d1) == 100);
|
||||
@@ -396,7 +405,7 @@ static void test_init_oa(void)
|
||||
assert (b);
|
||||
assert (!dict_oa_int_equal_p (d2, d1));
|
||||
|
||||
for(size_t i = 1; i < 100; i++) {
|
||||
for(int i = 1; i < 100; i++) {
|
||||
b = dict_oa_int_erase (d1, 2*i);
|
||||
assert (b);
|
||||
}
|
||||
@@ -409,7 +418,7 @@ static void test_init_oa(void)
|
||||
|
||||
dict_oa_int_init_move (d3, d1);
|
||||
assert (dict_oa_int_size (d3) == 100);
|
||||
for(size_t i = 0; i < 100; i++) {
|
||||
for(int i = 0; i < 100; i++) {
|
||||
assert (*dict_oa_int_get (d3, 2*i) == 2*(int)i+1);
|
||||
}
|
||||
dict_oa_int_init_set (d1, d3);
|
||||
@@ -426,7 +435,7 @@ static void test_init_oa(void)
|
||||
static void test_it_oa(void)
|
||||
{
|
||||
M_LET(d1, DICT_OPLIST(dict_oa_int, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)){
|
||||
for(size_t i = 0; i < 100; i++) {
|
||||
for(int i = 0; i < 100; i++) {
|
||||
dict_oa_int_set_at (d1, 2*i, 2*i+1);
|
||||
}
|
||||
assert (dict_oa_int_size (d1) == 100);
|
||||
@@ -434,7 +443,7 @@ static void test_it_oa(void)
|
||||
dict_oa_int_it_t it;
|
||||
size_t s = 0;
|
||||
for(dict_oa_int_it(it, d1); !dict_oa_int_end_p(it); dict_oa_int_next(it)) {
|
||||
dict_oa_int_pair_t *pair = dict_oa_int_ref(it);
|
||||
dict_oa_int_itref_t *pair = dict_oa_int_ref(it);
|
||||
assert (pair->key >= 0 && pair->key < 200);
|
||||
assert (pair->value == pair->key + 1);
|
||||
s++;
|
||||
@@ -460,7 +469,7 @@ static void test_it_oa(void)
|
||||
|
||||
s = 0;
|
||||
for(dict_oa_int_it_last(it, d1); !dict_oa_int_end_p(it); dict_oa_int_previous(it)) {
|
||||
dict_oa_int_pair_t *pair = dict_oa_int_ref(it);
|
||||
dict_oa_int_itref_t *pair = dict_oa_int_ref(it);
|
||||
assert (pair->key >= 0 && pair->key < 200);
|
||||
assert (pair->value == pair->key + 1);
|
||||
s++;
|
||||
|
||||
+21
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -69,6 +69,17 @@ END_COVERAGE
|
||||
|
||||
#define M_OPL_instance22_t() FUNC_OBJ_INS_OPLIST(instance22, M_DEFAULT_OPLIST)
|
||||
|
||||
FUNC_OBJ_ITF_DEF_AS(Interface, Interface, double, double)
|
||||
|
||||
FUNC_OBJ_INS_DEF_AS(Instance, Instance,
|
||||
Interface,
|
||||
(a), {
|
||||
return a * self->a + self->b;
|
||||
},
|
||||
(a, double),
|
||||
(b, double) )
|
||||
#define M_OPL_Instance() FUNC_OBJ_INS_OPLIST(Instance, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
static void test_instance11(void)
|
||||
{
|
||||
instance11_t cmp;
|
||||
@@ -117,11 +128,20 @@ static void test_instance22(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_double(void)
|
||||
{
|
||||
M_LET( (func, 2.0, 3.0), Instance) {
|
||||
double d = Interface_call(Instance_as_interface(func), 4.0);
|
||||
assert (d == 2.0 * 4.0 + 3.0);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_instance11();
|
||||
test_instance12();
|
||||
test_instance21();
|
||||
test_instance22();
|
||||
test_double();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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,7 +33,7 @@ static void test(size_t n)
|
||||
genint_t s;
|
||||
size_t i;
|
||||
|
||||
genint_init(s, n);
|
||||
genint_init(s, (unsigned int) n);
|
||||
for(int k = 0; k < 3; k++) {
|
||||
for(size_t j = 0; j< n ; j++) {
|
||||
i = genint_pop(s);
|
||||
@@ -44,7 +44,7 @@ static void test(size_t n)
|
||||
assert (genint_pop(s) == GENINT_ERROR);
|
||||
|
||||
for(size_t j = 0; j< n ; j++) {
|
||||
genint_push(s, (j+k) % n );
|
||||
genint_push(s, (unsigned int) ((j + (size_t) k) % n ));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ static void test2(size_t n)
|
||||
{
|
||||
m_thread_t idx[4];
|
||||
|
||||
genint_init(global, n);
|
||||
genint_init(global, (unsigned int) n);
|
||||
for(int i = 0; i < MAX_N; i++)
|
||||
atomic_init(&tab_g[i], false);
|
||||
|
||||
@@ -105,7 +105,7 @@ static void conso2(void *p)
|
||||
size_t n = *(size_t*)p;
|
||||
for(int i = 0; i < 1000000; i++) {
|
||||
unsigned int j = genint_pop(global);
|
||||
assert (j != -1U);
|
||||
assert (j != GENINT_ERROR);
|
||||
assert (j < n);
|
||||
genint_push(global, j);
|
||||
}
|
||||
@@ -116,7 +116,7 @@ static void test3(size_t n)
|
||||
m_thread_t idx[MAX_N];
|
||||
assert (n <= MAX_N);
|
||||
|
||||
genint_init(global, n);
|
||||
genint_init(global, (unsigned int) n);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
m_thread_create (idx[i], conso2, (void*)&n);
|
||||
}
|
||||
|
||||
+27
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MLIB - TEST module
|
||||
*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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,6 +40,14 @@ END_COVERAGE
|
||||
|
||||
ILIST_DEF(ilist_free, test_t, (DEL(free)))
|
||||
|
||||
typedef struct testd_s {
|
||||
double n;
|
||||
ILIST_INTERFACE (ListDouble, struct testd_s);
|
||||
} TestDouble;
|
||||
|
||||
ILIST_DEF_AS(ListDouble, ListDouble, ListDoubleIt, TestDouble, M_OPEXTEND(M_POD_OPLIST, DEL(0)))
|
||||
#define M_OPL_ListDouble() ILIST_OPLIST(ListDouble, M_POD_OPLIST)
|
||||
|
||||
static void test(void)
|
||||
{
|
||||
test_t x1, x2, x3;
|
||||
@@ -239,10 +247,28 @@ static void test_free(void)
|
||||
ilist_free_clear(list);
|
||||
}
|
||||
|
||||
static void test_double(void)
|
||||
{
|
||||
TestDouble base[5];
|
||||
M_LET( tab, ListDouble) {
|
||||
for(int i = 0; i < 5; i++) {
|
||||
base[i].n = (double) i;
|
||||
ListDouble_init_field(&base[i]);
|
||||
ListDouble_push_back(tab, &base[i]);
|
||||
}
|
||||
double ref = 0.0;
|
||||
for M_EACH(i, tab, ListDouble) {
|
||||
assert (i->n == ref);
|
||||
ref += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test();
|
||||
test2();
|
||||
test_free();
|
||||
test_double();
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, 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 <assert.h>
|
||||
#include "test-obj.h"
|
||||
|
||||
#include "m-i-shared.h"
|
||||
|
||||
#include "m-mutex.h"
|
||||
#include "coverage.h"
|
||||
|
||||
typedef struct ishared_s {
|
||||
ISHARED_PTR_INTERFACE(ishared1, struct ishared_s);
|
||||
ISHARED_PTR_INTERFACE(ishared2, struct ishared_s);
|
||||
int data[100];
|
||||
} ishared_t[1];
|
||||
|
||||
static void ishared_init_data(struct ishared_s *x)
|
||||
{
|
||||
for(int i = 0 ; i < 100; i++)
|
||||
x->data[i] = i * i;
|
||||
}
|
||||
|
||||
static void ishared_test(struct ishared_s *x)
|
||||
{
|
||||
for(int i = 0 ; i < 100; i++) {
|
||||
assert (x->data[i] == i*i);
|
||||
}
|
||||
}
|
||||
|
||||
START_COVERAGE
|
||||
ISHARED_PTR_DEF(ishared1, struct ishared_s, (INIT(API_2(ishared_init_data))))
|
||||
ISHARED_PTR_DEF(ishared2, struct ishared_s, (INIT(API_2(ishared_init_data)), NEW(0), DEL(0)) )
|
||||
END_COVERAGE
|
||||
|
||||
/*ISHARED_PTR_DEF_AS(SharedDouble, SharedDouble, double) */
|
||||
|
||||
static void test_single(void)
|
||||
{
|
||||
ishared1_t p1, p2;
|
||||
p1 = ishared1_init_new();
|
||||
ishared_test(p1);
|
||||
p2 = ishared1_init_set(p1);
|
||||
ishared_test(p2);
|
||||
ishared1_clear(p1);
|
||||
ishared_test(p2);
|
||||
|
||||
p1 = ishared1_init(NULL);
|
||||
ishared1_set(&p1, p2);
|
||||
ishared1_clean(&p2);
|
||||
assert(p2 == NULL);
|
||||
ishared_test(p1);
|
||||
ishared1_clear(p1);
|
||||
|
||||
p1 = ishared1_init_set(p2);
|
||||
assert(p1 == NULL);
|
||||
ishared1_clear(p1);
|
||||
|
||||
ishared1_clear(p2);
|
||||
|
||||
struct ishared_s *x = (struct ishared_s *) malloc(sizeof (struct ishared_s));
|
||||
assert(x != NULL);
|
||||
ishared_init_data(x);
|
||||
p1 = ishared1_init(x);
|
||||
ishared_test(p1);
|
||||
ishared1_clear(p1);
|
||||
}
|
||||
|
||||
static struct ishared_s g_var = {
|
||||
ISHARED_PTR_STATIC_INIT(ishared1, struct ishared_s),
|
||||
ISHARED_PTR_STATIC_INIT(ishared2, struct ishared_s),
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static void test_static(void)
|
||||
{
|
||||
ishared2_t p1, p2;
|
||||
|
||||
p1 = ishared2_init_once(NULL);
|
||||
assert(p1 == NULL);
|
||||
p1 = ishared2_init_once(&g_var);
|
||||
ishared_test(p1);
|
||||
p2 = ishared2_init_once(&g_var);
|
||||
ishared_test(p2);
|
||||
ishared2_clear(p1);
|
||||
ishared_test(p2);
|
||||
ishared2_clear(p2);
|
||||
}
|
||||
|
||||
#define MAX_THREAD 256
|
||||
#define MAX_VAR 5
|
||||
|
||||
#define VAL(x) { ISHARED_PTR_STATIC_INIT(ishared1, struct ishared_s), ISHARED_PTR_STATIC_INIT(ishared2, struct ishared_s), { 0 } }
|
||||
static struct ishared_s g_tab[MAX_VAR] = {
|
||||
M_MAP_C(VAL, M_SEQ(1, MAX_VAR))
|
||||
};
|
||||
|
||||
static void func(void *arg)
|
||||
{
|
||||
int id = (int)(intptr_t) arg;
|
||||
int v = id % MAX_VAR;
|
||||
ishared2_t p = ishared2_init_once(&g_tab[v]);
|
||||
for(int i = 0; i < 100; i++) {
|
||||
ishared_test(p);
|
||||
}
|
||||
ishared2_clear(p);
|
||||
}
|
||||
|
||||
static void test_shared(void)
|
||||
{
|
||||
m_thread_t id[MAX_THREAD];
|
||||
|
||||
for(int i = 0; i < MAX_THREAD; i++) {
|
||||
m_thread_create(id[i], func, (void*) (intptr_t) i);
|
||||
}
|
||||
for(int i = 0; i < MAX_THREAD; i++) {
|
||||
m_thread_join(id[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_single();
|
||||
test_static();
|
||||
test_shared();
|
||||
exit(0);
|
||||
}
|
||||
+33
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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,6 +40,12 @@ LIST_DEF(list_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), C
|
||||
LIST_DUAL_PUSH_DEF(list2_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
|
||||
|
||||
|
||||
LIST_DEF_AS(list_double, ListDouble, ListDoubleIt, double)
|
||||
#define M_OPL_ListDouble() LIST_OPLIST(list_double, M_DEFAULT_OPLIST)
|
||||
|
||||
LIST_DUAL_PUSH_DEF_AS(list_doubleDP, ListDoubleDP, ListDoubleDPIt, double)
|
||||
#define M_OPL_ListDoubleDP() LIST_OPLIST(list_doubleDP, M_DEFAULT_OPLIST)
|
||||
|
||||
static void test_uint(void)
|
||||
{
|
||||
list_uint_t v;
|
||||
@@ -251,14 +257,14 @@ static void test_mpz(void)
|
||||
}
|
||||
assert (testobj_get_ui(s) == 1000*999/2);
|
||||
|
||||
FILE *f = fopen ("a-mlist.dat", "wt");
|
||||
FILE *f = m_core_fopen ("a-mlist.dat", "wt");
|
||||
if (!f) abort();
|
||||
list_mpz_out_str(f, v);
|
||||
fclose (f);
|
||||
|
||||
list_mpz_t list2;
|
||||
list_mpz_init(list2);
|
||||
f = fopen ("a-mlist.dat", "rt");
|
||||
f = m_core_fopen ("a-mlist.dat", "rt");
|
||||
bool b = list_mpz_in_str (list2, f);
|
||||
assert (b == true);
|
||||
fclose(f);
|
||||
@@ -603,13 +609,13 @@ static void test_out_default_oplist(void)
|
||||
{
|
||||
M_LET(str, string_t)
|
||||
M_LET(list, l2, list_int_t) {
|
||||
FILE *f = fopen ("a-mlist.dat", "wt");
|
||||
FILE *f = m_core_fopen ("a-mlist.dat", "wt");
|
||||
if (!f) abort();
|
||||
list_int_push_back(list, 2);
|
||||
list_int_push_back(list, 3);
|
||||
list_int_out_str(f, list);
|
||||
fclose(f);
|
||||
f = fopen("a-mlist.dat", "rt");
|
||||
f = m_core_fopen("a-mlist.dat", "rt");
|
||||
if (!f) abort();
|
||||
char buffer[1024];
|
||||
assert (fgets(buffer, 1024, f) == buffer);
|
||||
@@ -617,7 +623,7 @@ static void test_out_default_oplist(void)
|
||||
fclose(f);
|
||||
list_int_get_str(str, list, false);
|
||||
assert (string_equal_str_p(str, "[3,2]"));
|
||||
f = fopen("a-mlist.dat", "rt");
|
||||
f = m_core_fopen("a-mlist.dat", "rt");
|
||||
if (!f) abort();
|
||||
assert (list_int_in_str(l2, f) == true);
|
||||
assert (list_int_equal_p(l2, list));
|
||||
@@ -626,7 +632,7 @@ static void test_out_default_oplist(void)
|
||||
M_LET(str, string_t)
|
||||
M_LET( (list, 1, 2, 3, 4, 5), list_int_t) {
|
||||
list_int_get_str(str, list, false);
|
||||
assert (string_equal_str_p(str, "[5,4,3,2,1]"));
|
||||
assert (string_equal_str_p(str, "[1,2,3,4,5]"));
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -635,6 +641,25 @@ static void test_out_default_oplist(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void test_double(void)
|
||||
{
|
||||
M_LET( (tab, 0.0, 1.0, 2.0, 3.0), ListDouble) {
|
||||
double ref = 0.0;
|
||||
for M_EACH(i, tab, ListDouble) {
|
||||
assert (*i == ref);
|
||||
ref += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
M_LET( (tab, 0.0, 1.0, 2.0, 3.0), ListDoubleDP) {
|
||||
double ref = 0.0;
|
||||
for M_EACH(i, tab, ListDoubleDP) {
|
||||
assert (*i == ref);
|
||||
ref += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_uint();
|
||||
@@ -642,6 +667,7 @@ int main(void)
|
||||
test_dual_push1();
|
||||
test_dual_it1();
|
||||
test_out_default_oplist();
|
||||
test_double();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
+38
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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,6 +31,8 @@ START_COVERAGE
|
||||
MEMPOOL_DEF(mempool_uint, unsigned int)
|
||||
END_COVERAGE
|
||||
|
||||
MEMPOOL_DEF_AS(MempoolDouble, MempoolDouble, unsigned int)
|
||||
|
||||
static void test(void)
|
||||
{
|
||||
mempool_uint_t m;
|
||||
@@ -65,8 +67,43 @@ static void test(void)
|
||||
mempool_uint_clear(m);
|
||||
}
|
||||
|
||||
static void test_double(void)
|
||||
{
|
||||
MempoolDouble m;
|
||||
MempoolDouble_init(m);
|
||||
|
||||
unsigned int *tab[100000];
|
||||
for(unsigned int i = 0; i < 100000; i++) {
|
||||
tab[i] = MempoolDouble_alloc(m);
|
||||
*tab[i] = i;
|
||||
}
|
||||
for(unsigned int i = 0; i < 100000; i++) {
|
||||
assert (*tab[i] == i);
|
||||
}
|
||||
for(unsigned int i = 0; i < 100000; i+=2) {
|
||||
MempoolDouble_free(m, tab[i]);
|
||||
tab[i] = NULL;
|
||||
}
|
||||
for(unsigned int i = 1; i < 100000; i+=2) {
|
||||
assert (*tab[i] == i);
|
||||
}
|
||||
for(unsigned int i = 0; i < 100000; i+=2) {
|
||||
tab[i] = MempoolDouble_alloc(m);
|
||||
*tab[i] = i;
|
||||
}
|
||||
for(unsigned int i = 0; i < 100000; i++) {
|
||||
assert (*tab[i] == i);
|
||||
}
|
||||
for(unsigned int i = 0; i < 100000; i++) {
|
||||
MempoolDouble_free(m, tab[i]);
|
||||
tab[i] = NULL;
|
||||
}
|
||||
MempoolDouble_clear(m);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test();
|
||||
test_double();
|
||||
exit(0);
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
|
||||
+234
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -29,7 +29,16 @@
|
||||
START_COVERAGE
|
||||
PRIOQUEUE_DEF(int_pqueue, int)
|
||||
END_COVERAGE
|
||||
PRIOQUEUE_DEF(mpz_pqueue, testobj_t, TESTOBJ_CMP_OPLIST)
|
||||
|
||||
static inline bool testobj_equal2_p(const testobj_t z1, const testobj_t z2)
|
||||
{
|
||||
return z1->a == z2->a;
|
||||
}
|
||||
|
||||
PRIOQUEUE_DEF(obj_pqueue, testobj_t, M_OPEXTEND(TESTOBJ_CMP_OPLIST, EQUAL(testobj_equal2_p) ))
|
||||
|
||||
PRIOQUEUE_DEF_AS(PrioDouble, PrioDouble, PrioDoubleIt, double)
|
||||
#define M_OPL_PrioDouble() PRIOQUEUE_OPLIST(PrioDouble, M_DEFAULT_OPLIST)
|
||||
|
||||
static void test1(void)
|
||||
{
|
||||
@@ -61,6 +70,7 @@ static void test1(void)
|
||||
assert (x == 60);
|
||||
assert (int_pqueue_empty_p(p));
|
||||
assert (int_pqueue_size(p) == 0);
|
||||
|
||||
int_pqueue_push(p, 10);
|
||||
int_pqueue_push(p, 30);
|
||||
int_pqueue_pop(&x, p);
|
||||
@@ -71,8 +81,29 @@ static void test1(void)
|
||||
int_pqueue_push(p, 17);
|
||||
bool b = int_pqueue_erase(p, 17);
|
||||
assert(b);
|
||||
assert (int_pqueue_size(p) == 1);
|
||||
b = int_pqueue_erase(p, 1742);
|
||||
assert(!b);
|
||||
b = int_pqueue_erase(p, 30);
|
||||
assert(b);
|
||||
assert (int_pqueue_size(p) == 0);
|
||||
|
||||
int_pqueue_push(p, 30);
|
||||
int_pqueue_push(p, 40);
|
||||
int_pqueue_push(p, 10);
|
||||
int_pqueue_push(p, 50);
|
||||
int_pqueue_push(p, 20);
|
||||
assert (int_pqueue_size(p) == 5);
|
||||
int_pqueue_erase(p, 30);
|
||||
int_pqueue_push(p, 30);
|
||||
assert (*int_pqueue_front(p) == 10);
|
||||
int_pqueue_update(p, 40, 15);
|
||||
assert (*int_pqueue_front(p) == 10);
|
||||
int_pqueue_update(p, 20, 5);
|
||||
assert (*int_pqueue_front(p) == 5);
|
||||
int_pqueue_update(p, 5, 25);
|
||||
assert (*int_pqueue_front(p) == 10);
|
||||
|
||||
int_pqueue_clear(p);
|
||||
}
|
||||
|
||||
@@ -98,12 +129,213 @@ static void test2(void)
|
||||
assert (x == i);
|
||||
}
|
||||
|
||||
assert (int_pqueue_size(p) == 0);
|
||||
for(int i = -100; i < 100; i++) {
|
||||
int_pqueue_push(p, i);
|
||||
}
|
||||
assert (int_pqueue_size(p) == 200);
|
||||
for(int i = -100; i < 100; i++) {
|
||||
bool b = int_pqueue_erase(p, i);
|
||||
assert (b);
|
||||
}
|
||||
assert (int_pqueue_size(p) == 0);
|
||||
|
||||
int_pqueue_clear(p);
|
||||
}
|
||||
|
||||
static void test_update(void)
|
||||
{
|
||||
obj_pqueue_t p;
|
||||
obj_pqueue_init(p);
|
||||
const testobj_t *front;
|
||||
M_LET( x, y, z, TESTOBJ_OPLIST) {
|
||||
testobj_set_ui(x, 7);
|
||||
testobj_set_id(x, 1);
|
||||
obj_pqueue_push(p, x);
|
||||
|
||||
testobj_set_ui(x, 30);
|
||||
testobj_set_id(x, 2);
|
||||
obj_pqueue_push(p, x);
|
||||
|
||||
testobj_set_ui(x, 40);
|
||||
testobj_set_id(x, 3);
|
||||
obj_pqueue_push(p, x);
|
||||
|
||||
testobj_set_ui(x, 10);
|
||||
testobj_set_id(x, 4);
|
||||
obj_pqueue_push(p, x);
|
||||
|
||||
testobj_set_ui(x, 20);
|
||||
testobj_set_id(x, 5);
|
||||
obj_pqueue_push(p, x);
|
||||
|
||||
testobj_set_ui(x, 3);
|
||||
testobj_set_id(x, 6);
|
||||
obj_pqueue_push(p, x);
|
||||
|
||||
testobj_set_ui(x, 35);
|
||||
testobj_set_id(x, 7);
|
||||
obj_pqueue_push(p, x);
|
||||
|
||||
front = obj_pqueue_front(p);
|
||||
assert ( (*front)->a == 6);
|
||||
|
||||
testobj_set_ui(y, 8);
|
||||
testobj_set_id(y, 5);
|
||||
obj_pqueue_update(p, y, y);
|
||||
|
||||
front = obj_pqueue_front(p);
|
||||
assert ( (*front)->a == 6);
|
||||
|
||||
testobj_set_ui(y, 1);
|
||||
testobj_set_id(y, 5);
|
||||
obj_pqueue_update(p, y, y);
|
||||
|
||||
front = obj_pqueue_front(p);
|
||||
assert ( (*front)->a == 5);
|
||||
|
||||
testobj_set_ui(y, 4);
|
||||
testobj_set_id(y, 5);
|
||||
obj_pqueue_update(p, y, y);
|
||||
|
||||
front = obj_pqueue_front(p);
|
||||
assert ( (*front)->a == 6);
|
||||
|
||||
testobj_set_ui(y, 4);
|
||||
testobj_set_id(y, 6);
|
||||
obj_pqueue_erase(p, y);
|
||||
|
||||
front = obj_pqueue_front(p);
|
||||
assert ( (*front)->a == 5);
|
||||
|
||||
testobj_set_ui(y, 100);
|
||||
testobj_set_id(y, 5);
|
||||
obj_pqueue_update(p, y, y);
|
||||
|
||||
front = obj_pqueue_front(p);
|
||||
assert ( (*front)->a == 1);
|
||||
|
||||
testobj_set_ui(y, 4);
|
||||
testobj_set_id(y, 2);
|
||||
obj_pqueue_erase(p, y);
|
||||
|
||||
front = obj_pqueue_front(p);
|
||||
assert ( (*front)->a == 1);
|
||||
|
||||
testobj_set_ui(y, 4);
|
||||
testobj_set_id(y, 3);
|
||||
obj_pqueue_erase(p, y);
|
||||
|
||||
front = obj_pqueue_front(p);
|
||||
assert ( (*front)->a == 1);
|
||||
|
||||
testobj_set_ui(y, 4);
|
||||
testobj_set_id(y, 4);
|
||||
obj_pqueue_erase(p, y);
|
||||
|
||||
front = obj_pqueue_front(p);
|
||||
assert ( (*front)->a == 1);
|
||||
|
||||
testobj_set_ui(y, 4);
|
||||
testobj_set_id(y, 1);
|
||||
obj_pqueue_erase(p, y);
|
||||
|
||||
front = obj_pqueue_front(p);
|
||||
assert ( (*front)->a == 7);
|
||||
|
||||
testobj_set_ui(y, 4);
|
||||
testobj_set_id(y, 7);
|
||||
obj_pqueue_erase(p, y);
|
||||
|
||||
front = obj_pqueue_front(p);
|
||||
assert ( (*front)->a == 5);
|
||||
}
|
||||
obj_pqueue_clear(p);
|
||||
}
|
||||
|
||||
static void test_it(void)
|
||||
{
|
||||
int_pqueue_t p, q;
|
||||
|
||||
int_pqueue_init(p);
|
||||
for(int i = -10; i < 10; i++) {
|
||||
int_pqueue_push(p, i*i);
|
||||
}
|
||||
assert(int_pqueue_size(p) == 20);
|
||||
|
||||
int_pqueue_init_set(q, p);
|
||||
assert(int_pqueue_equal_p(p, q));
|
||||
assert(int_pqueue_size(q) == 20);
|
||||
int_pqueue_push(q, 43);
|
||||
assert(int_pqueue_size(p) == 20);
|
||||
assert(int_pqueue_size(q) == 21);
|
||||
int_pqueue_swap(p, q);
|
||||
assert(int_pqueue_size(p) == 21);
|
||||
assert(int_pqueue_size(q) == 20);
|
||||
int_pqueue_swap(p, q);
|
||||
assert(int_pqueue_size(p) == 20);
|
||||
assert(int_pqueue_size(q) == 21);
|
||||
int_pqueue_clean(q);
|
||||
assert(!int_pqueue_equal_p(p, q));
|
||||
assert(int_pqueue_empty_p(q));
|
||||
assert(!int_pqueue_empty_p(p));
|
||||
|
||||
int_pqueue_set(q, p);
|
||||
assert(int_pqueue_equal_p(p, q));
|
||||
assert(int_pqueue_size(q) == 20);
|
||||
|
||||
int_pqueue_move(q, p);
|
||||
assert(int_pqueue_size(q) == 20);
|
||||
int_pqueue_init_move(p, q);
|
||||
assert(int_pqueue_size(p) == 20);
|
||||
|
||||
int_pqueue_it_t it, it2;
|
||||
int i = 0;
|
||||
const int tab[] = {0 , 1 , 1 , 16 , 4 , 4 , 9 , 25 , 49 , 64 , 9 , 81 , 25 , 36 , 16 , 100 , 36 , 49 , 64 , 81};
|
||||
assert (int_pqueue_size(p) == sizeof(tab)/sizeof(tab[0]) );
|
||||
for(int_pqueue_it(it, p) ;
|
||||
!int_pqueue_end_p(it) ;
|
||||
int_pqueue_next(it) ) {
|
||||
assert(tab[i] == *int_pqueue_cref(it) );
|
||||
i++;
|
||||
}
|
||||
|
||||
int_pqueue_it_end(it, p);
|
||||
assert(int_pqueue_end_p(it)) ;
|
||||
|
||||
int_pqueue_it_last(it, p);
|
||||
assert(!int_pqueue_end_p(it)) ;
|
||||
int_pqueue_next(it);
|
||||
assert(int_pqueue_end_p(it)) ;
|
||||
|
||||
int_pqueue_previous(it);
|
||||
int_pqueue_it_set(it2, it);
|
||||
assert(int_pqueue_last_p(it2));
|
||||
assert(int_pqueue_it_equal_p(it, it2));
|
||||
int_pqueue_previous(it2);
|
||||
assert(!int_pqueue_it_equal_p(it, it2));
|
||||
|
||||
int_pqueue_clear(p);
|
||||
}
|
||||
|
||||
static void test_double(void)
|
||||
{
|
||||
M_LET( (tab, 0.0, 1.0, 2.0, 3.0), PrioDouble) {
|
||||
double ref = 0.0;
|
||||
// NOTE: The binary heap is sorted in the same natural order that the sorted array
|
||||
for M_EACH(i, tab, PrioDouble) {
|
||||
assert (*i == ref);
|
||||
ref += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test1();
|
||||
test2();
|
||||
test_update();
|
||||
test_double();
|
||||
test_it();
|
||||
exit(0);
|
||||
}
|
||||
+26
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -27,14 +27,14 @@
|
||||
|
||||
static bool uint_in_str(unsigned int *u, FILE *f)
|
||||
{
|
||||
int n = fscanf(f, "%u", u);
|
||||
int n = m_core_fscanf(f, "%u", u);
|
||||
return n == 1;
|
||||
}
|
||||
|
||||
static bool uint_parse_str(unsigned int *u, const char str[], const char **endptr)
|
||||
{
|
||||
char *end;
|
||||
*u = strtol(str, &end, 0);
|
||||
*u = (unsigned int) strtol(str, &end, 0);
|
||||
if (endptr) { *endptr = (const char*) end; }
|
||||
return (uintptr_t) end != (uintptr_t) str;
|
||||
}
|
||||
@@ -60,6 +60,9 @@ RBTREE_DEF(rbtree_mpz, testobj_t, TESTOBJ_OPLIST)
|
||||
#define UINT_OPLIST RBTREE_OPLIST(rbtree_uint)
|
||||
#define FLOAT_OP RBTREE_OPLIST(rbtree_float)
|
||||
|
||||
RBTREE_DEF_AS(TreeDouble, TreeDouble, TreeDoubleIt, double, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_TreeDouble() RBTREE_OPLIST(TreeDouble, M_DEFAULT_OPLIST)
|
||||
|
||||
static void test_uint(void)
|
||||
{
|
||||
rbtree_uint_t tree, tree2, tree3;
|
||||
@@ -83,6 +86,7 @@ static void test_uint(void)
|
||||
}
|
||||
assert (k == 5);
|
||||
rbtree_uint_it_t it, it2;
|
||||
rbtree_uint_it(it2, tree);
|
||||
for (rbtree_uint_it_last(it, tree) ; !rbtree_uint_end_p(it) ; rbtree_uint_previous(it)) {
|
||||
k--;
|
||||
rbtree_uint_it_set(it2, it);
|
||||
@@ -176,8 +180,8 @@ static void test_uint_permut(void)
|
||||
for(unsigned int i = 0; i < num; i++)
|
||||
tab[i] = i;
|
||||
for(unsigned int i = 0; i < 2 * num; i++) {
|
||||
int j = rand() % num;
|
||||
int k = rand() % num;
|
||||
unsigned int j = (unsigned int) rand() % num;
|
||||
unsigned int k = (unsigned int) rand() % num;
|
||||
M_SWAP(unsigned int, tab[j], tab[k]);
|
||||
}
|
||||
for(unsigned int i = 0; i < num; i++)
|
||||
@@ -195,7 +199,7 @@ static void test_uint_permut(void)
|
||||
static void test_float(void)
|
||||
{
|
||||
M_LET(tree, FLOAT_OP) {
|
||||
for(float f = -17.42; f < 17.42; f+=0.01)
|
||||
for(float f = -17.42f; f < 17.42f; f+=0.01f)
|
||||
rbtree_float_push (tree, f);
|
||||
bool p = false;
|
||||
float g;
|
||||
@@ -214,12 +218,12 @@ static void test_io(void)
|
||||
M_LET(str, STRING_OPLIST)
|
||||
M_LET(tree1, tree2, UINT_OPLIST) {
|
||||
// Empty one
|
||||
FILE *f = fopen ("a-mrbtree.dat", "wt");
|
||||
FILE *f = m_core_fopen ("a-mrbtree.dat", "wt");
|
||||
if (!f) abort();
|
||||
rbtree_uint_out_str(f, tree1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen ("a-mrbtree.dat", "rt");
|
||||
f = m_core_fopen ("a-mrbtree.dat", "rt");
|
||||
if (!f) abort();
|
||||
bool b = rbtree_uint_in_str (tree2, f);
|
||||
assert (b == true);
|
||||
@@ -238,12 +242,12 @@ static void test_io(void)
|
||||
for(unsigned int i = 0 ; i < 10; i++)
|
||||
rbtree_uint_push(tree1, i);
|
||||
|
||||
f = fopen ("a-mrbtree.dat", "wt");
|
||||
f = m_core_fopen ("a-mrbtree.dat", "wt");
|
||||
if (!f) abort();
|
||||
rbtree_uint_out_str(f, tree1);
|
||||
fclose (f);
|
||||
|
||||
f = fopen ("a-mrbtree.dat", "rt");
|
||||
f = m_core_fopen ("a-mrbtree.dat", "rt");
|
||||
if (!f) abort();
|
||||
b = rbtree_uint_in_str (tree2, f);
|
||||
assert (b == true);
|
||||
@@ -256,8 +260,18 @@ static void test_io(void)
|
||||
assert(b);
|
||||
assert(*sp == 0);
|
||||
assert(rbtree_uint_equal_p(tree1, tree2));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_double(void)
|
||||
{
|
||||
M_LET( (tree, 0.0, 1.0, 2.0), TreeDouble) {
|
||||
double ref = 0.0;
|
||||
for M_EACH(i, tree, TreeDouble) {
|
||||
assert (*i == ref);
|
||||
ref += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(void)
|
||||
@@ -266,5 +280,6 @@ int main(void)
|
||||
test_uint_permut();
|
||||
test_float();
|
||||
test_io();
|
||||
test_double();
|
||||
exit(0);
|
||||
}
|
||||
+15
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -62,27 +62,25 @@ TUPLE_DEF2(my2,
|
||||
|
||||
static void test_out_empty(void)
|
||||
{
|
||||
m_serial_read_t in;
|
||||
m_serial_write_t out;
|
||||
m_serial_return_code_t ret;
|
||||
my2_t el1, el2;
|
||||
my2_init(el1);
|
||||
my2_init(el2);
|
||||
|
||||
FILE *f = fopen ("a-mbin.dat", "wt");
|
||||
FILE *f = m_core_fopen ("a-mbin.dat", "wt");
|
||||
if (!f) abort();
|
||||
m_serial_bin_write_init(out, f);
|
||||
ret = my2_out_serial(out, el1);
|
||||
assert (ret == M_SERIAL_OK_DONE);
|
||||
m_serial_bin_write_clear(out);
|
||||
M_LET( (serial, f), m_serial_bin_write_t) {
|
||||
ret = my2_out_serial(serial, el1);
|
||||
assert (ret == M_SERIAL_OK_DONE);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen ("a-mbin.dat", "rt");
|
||||
f = m_core_fopen ("a-mbin.dat", "rt");
|
||||
if (!f) abort();
|
||||
m_serial_bin_read_init(in, f);
|
||||
ret = my2_in_serial(el2, in);
|
||||
assert (ret == M_SERIAL_OK_DONE);
|
||||
m_serial_bin_read_clear(in);
|
||||
M_LET( (serial, f), m_serial_bin_read_t) {
|
||||
ret = my2_in_serial(el2, serial);
|
||||
assert (ret == M_SERIAL_OK_DONE);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
assert (my2_equal_p (el1, el2));
|
||||
@@ -104,7 +102,7 @@ static void test_out_fill(void)
|
||||
|
||||
el2->activated = true;
|
||||
el2->data->vala = 145788;
|
||||
el2->data->valb = -0.1;
|
||||
el2->data->valb = -0.1f;
|
||||
el2->data->valc = false;
|
||||
string_set_str(el2->data->vald, "This is a string test.");
|
||||
a2_push_back(el2->data->vale, 1);
|
||||
@@ -118,7 +116,7 @@ static void test_out_fill(void)
|
||||
d2_set_at(el2->data->valh, STRING_CTE("Paul"), 1);
|
||||
d2_set_at(el2->data->valh, STRING_CTE("Smith"), 2);
|
||||
|
||||
f = fopen ("a-mbin.dat", "wt");
|
||||
f = m_core_fopen ("a-mbin.dat", "wt");
|
||||
if (!f) abort();
|
||||
m_serial_bin_write_init(out, f);
|
||||
ret = my2_out_serial(out, el2);
|
||||
@@ -126,7 +124,7 @@ static void test_out_fill(void)
|
||||
m_serial_bin_write_clear(out);
|
||||
fclose(f);
|
||||
|
||||
f = fopen ("a-mbin.dat", "rt");
|
||||
f = m_core_fopen ("a-mbin.dat", "rt");
|
||||
if (!f) abort();
|
||||
m_serial_bin_read_init(in, f);
|
||||
ret = my2_in_serial(el1, in);
|
||||
@@ -142,7 +140,7 @@ static void test_out_fill(void)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
//test_out_empty();
|
||||
test_out_empty();
|
||||
test_out_fill();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
+29
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -43,7 +43,12 @@ VARIANT_DEF2(v2,
|
||||
(is_int, int),
|
||||
(is_bool, bool) )
|
||||
#define M_OPL_v2_t() VARIANT_OPLIST(v2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
|
||||
typedef enum {
|
||||
SUCCESS = 0, NULL_PARAM, INVALID_PARAM
|
||||
} my_return_code_t;
|
||||
#define M_OPL_my_return_code_t() M_ENUM_OPLIST(my_return_code_t, SUCCESS)
|
||||
|
||||
TUPLE_DEF2(my,
|
||||
(vala, int),
|
||||
(valb, float),
|
||||
@@ -52,9 +57,10 @@ TUPLE_DEF2(my,
|
||||
(vale, a2_t),
|
||||
(valf, v2_t),
|
||||
(valg, l2_t),
|
||||
(valh, d2_t)
|
||||
(valh, d2_t),
|
||||
(vali, my_return_code_t)
|
||||
)
|
||||
#define M_OPL_my_t() TUPLE_OPLIST(my, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST, STRING_OPLIST, M_OPL_a2_t(), M_OPL_v2_t(), M_OPL_l2_t(), M_OPL_d2_t() )
|
||||
#define M_OPL_my_t() TUPLE_OPLIST(my, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST, STRING_OPLIST, M_OPL_a2_t(), M_OPL_v2_t(), M_OPL_l2_t(), M_OPL_d2_t(), M_OPL_my_return_code_t() )
|
||||
|
||||
TUPLE_DEF2(my2,
|
||||
(activated, bool),
|
||||
@@ -69,7 +75,7 @@ static void test_out_empty(void)
|
||||
my2_init(el1);
|
||||
my2_init(el2);
|
||||
|
||||
FILE *f = fopen ("a-mjson.dat", "wt");
|
||||
FILE *f = m_core_fopen ("a-mjson.dat", "wt");
|
||||
if (!f) abort();
|
||||
m_serial_json_write_init(out, f);
|
||||
ret = my2_out_serial(out, el1);
|
||||
@@ -77,15 +83,15 @@ static void test_out_empty(void)
|
||||
m_serial_json_write_clear(out);
|
||||
fclose(f);
|
||||
|
||||
f = fopen ("a-mjson.dat", "rt");
|
||||
f = m_core_fopen ("a-mjson.dat", "rt");
|
||||
if (!f) abort();
|
||||
static const char expected[] = "{ \"activated\":false,\"data\":{ \"vala\":0,\"valb\":0.000000,\"valc\":false,\"vald\":\"\",\"vale\":[],\"valf\":{},\"valg\":[],\"valh\":{}}";
|
||||
static const char expected[] = "{ \"activated\":false,\"data\":{ \"vala\":0,\"valb\":0.000000,\"valc\":false,\"vald\":\"\",\"vale\":[],\"valf\":{},\"valg\":[],\"valh\":{},\"vali\":0}";
|
||||
char get[sizeof expected];
|
||||
fgets (get, sizeof expected , f);
|
||||
assert (strcmp(get, expected) == 0);
|
||||
char *unused = fgets (get, sizeof expected , f);
|
||||
assert (unused != NULL && strcmp(get, expected) == 0);
|
||||
fclose(f);
|
||||
|
||||
f = fopen ("a-mjson.dat", "rt");
|
||||
f = m_core_fopen ("a-mjson.dat", "rt");
|
||||
if (!f) abort();
|
||||
m_serial_json_read_init(in, f);
|
||||
ret = my2_in_serial(el2, in);
|
||||
@@ -108,7 +114,7 @@ static void test_out_fill(void)
|
||||
my2_init(el1);
|
||||
my2_init(el2);
|
||||
|
||||
FILE *f = fopen("a-mjson.dat", "wt");
|
||||
FILE *f = m_core_fopen("a-mjson.dat", "wt");
|
||||
if (!f) abort();
|
||||
fprintf(f,
|
||||
"{\n"
|
||||
@@ -121,10 +127,11 @@ static void test_out_fill(void)
|
||||
"\"valf\": { \"is_bool\": true },\n"
|
||||
" \"vala\":1742,\n"
|
||||
" \"vald\": \"This is a test\",\n"
|
||||
"\"vali\": 3,"
|
||||
" \"valc\": true } }\n");
|
||||
fclose(f);
|
||||
|
||||
f = fopen ("a-mjson.dat", "rt");
|
||||
f = m_core_fopen ("a-mjson.dat", "rt");
|
||||
if (!f) abort();
|
||||
m_serial_json_read_init(in, f);
|
||||
ret = my2_in_serial(el2, in);
|
||||
@@ -132,7 +139,7 @@ static void test_out_fill(void)
|
||||
m_serial_json_read_clear(in);
|
||||
fclose(f);
|
||||
|
||||
f = fopen ("a-mjson.dat", "wt");
|
||||
f = m_core_fopen ("a-mjson.dat", "wt");
|
||||
if (!f) abort();
|
||||
m_serial_json_write_init(out, f);
|
||||
ret = my2_out_serial(out, el2);
|
||||
@@ -140,16 +147,19 @@ static void test_out_fill(void)
|
||||
m_serial_json_write_clear(out);
|
||||
fclose(f);
|
||||
|
||||
f = fopen ("a-mjson.dat", "rt");
|
||||
f = m_core_fopen ("a-mjson.dat", "rt");
|
||||
if (!f) abort();
|
||||
static const char expected[] = "{ \"activated\":false,\"data\":{ \"vala\":1742,\"valb\":-2.300000,\"valc\":true,\"vald\":\"This is a test\",\"vale\":[1,2,3],\"valf\":{\"is_bool\":true},\"valg\":[1,2,3,4,5,6],\"valh\":{\"steeve\":-4,\"jane\":3}}}";
|
||||
static const char expected2[] = "{ \"activated\":false,\"data\":{ \"vala\":1742,\"valb\":-2.300000,\"valc\":true,\"vald\":\"This is a test\",\"vale\":[1,2,3],\"valf\":{\"is_bool\":true},\"valg\":[1,2,3,4,5,6],\"valh\":{\"jane\":3,\"steeve\":-4}}}";
|
||||
static const char expected[] = "{ \"activated\":false,\"data\":{ \"vala\":1742,\"valb\":-2.300000,\"valc\":true,\"vald\":\"This is a test\",\"vale\":[1,2,3],\"valf\":{\"is_bool\":true},\"valg\":[1,2,3,4,5,6],\"valh\":{\"steeve\":-4,\"jane\":3},\"vali\":3}}";
|
||||
static const char expected2[] = "{ \"activated\":false,\"data\":{ \"vala\":1742,\"valb\":-2.300000,\"valc\":true,\"vald\":\"This is a test\",\"vale\":[1,2,3],\"valf\":{\"is_bool\":true},\"valg\":[1,2,3,4,5,6],\"valh\":{\"jane\":3,\"steeve\":-4},\"vali\":3}}";
|
||||
char get[sizeof expected];
|
||||
fgets (get, sizeof expected , f);
|
||||
assert (strcmp(get, expected) == 0 || strcmp(get, expected2) == 0);
|
||||
char *unused2 = fgets (get, sizeof expected , f);
|
||||
assert(unused2 != NULL);
|
||||
// Workaround string literal of length 4350 exceeds maximum length 4095
|
||||
if (!(strcmp(get, expected) == 0 || strcmp(get, expected2) == 0))
|
||||
assert (0);
|
||||
fclose(f);
|
||||
|
||||
f = fopen ("a-mjson.dat", "rt");
|
||||
f = m_core_fopen ("a-mjson.dat", "rt");
|
||||
if (!f) abort();
|
||||
m_serial_json_read_init(in, f);
|
||||
ret = my2_in_serial(el1, in);
|
||||
|
||||
+50
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -30,9 +30,14 @@ START_COVERAGE
|
||||
SHARED_PTR_DEF(shared_int, int)
|
||||
SHARED_RESOURCE_DEF(shared_ressource, testobj_t, TESTOBJ_OPLIST)
|
||||
END_COVERAGE
|
||||
|
||||
SHARED_PTR_DEF(shared_mpz, testobj_t, TESTOBJ_OPLIST)
|
||||
SHARED_PTR_RELAXED_DEF(shared_relaxed_int, int)
|
||||
|
||||
SHARED_PTR_DEF_AS(SharedDouble, SharedDouble, double)
|
||||
SHARED_PTR_RELAXED_DEF_AS(SharedDouble2, SharedDouble2, double, M_DEFAULT_OPLIST)
|
||||
SHARED_RESOURCE_DEF_AS(SharedRessource, SharedRessource, SharedRessourceIt, double)
|
||||
|
||||
static int f(const shared_int_t p)
|
||||
{
|
||||
return *shared_int_cref(p);
|
||||
@@ -139,13 +144,13 @@ static void test_ressource(int n)
|
||||
shared_ressource_it_t copy[MAX_RESSOURCE];
|
||||
shared_ressource_it_t onemore;
|
||||
|
||||
shared_ressource_init (ressource, n);
|
||||
shared_ressource_init (ressource, (size_t) n);
|
||||
for(int i = 0; i < n ; i++) {
|
||||
shared_ressource_it (it[i], ressource);
|
||||
assert (!shared_ressource_end_p(it[i]));
|
||||
testobj_t *z = shared_ressource_ref(it[i]);
|
||||
assert (z != NULL);
|
||||
testobj_set_ui(*z, i);
|
||||
testobj_set_ui(*z, (unsigned int) i);
|
||||
}
|
||||
shared_ressource_it (onemore, ressource);
|
||||
assert (shared_ressource_end_p(onemore));
|
||||
@@ -154,7 +159,7 @@ static void test_ressource(int n)
|
||||
assert (!shared_ressource_end_p(copy[i]));
|
||||
const testobj_t *z = shared_ressource_cref(copy[i]);
|
||||
assert (z != NULL);
|
||||
assert (testobj_cmp_ui(*z, i) == 0);
|
||||
assert (testobj_cmp_ui(*z, (unsigned int) i) == 0);
|
||||
}
|
||||
shared_ressource_it (onemore, ressource);
|
||||
assert (shared_ressource_end_p(onemore));
|
||||
@@ -177,12 +182,52 @@ static void test_ressource(int n)
|
||||
shared_ressource_clear(ressource);
|
||||
}
|
||||
|
||||
static void test_double(void){
|
||||
SharedDouble p;
|
||||
SharedDouble_init_new(p);
|
||||
assert(*SharedDouble_ref(p) == 0.0);
|
||||
*SharedDouble_ref(p) = 5678.0;
|
||||
SharedDouble q;
|
||||
SharedDouble_init_set(q, p);
|
||||
assert(*SharedDouble_ref(q) == 5678.0);
|
||||
SharedDouble_clear(p);
|
||||
SharedDouble_clear(q);
|
||||
}
|
||||
|
||||
static void test_double2(void){
|
||||
SharedDouble2 p;
|
||||
SharedDouble2_init_new(p);
|
||||
assert(*SharedDouble2_ref(p) == 0.0);
|
||||
*SharedDouble2_ref(p) = 5678.0;
|
||||
SharedDouble2 q;
|
||||
SharedDouble2_init_set(q, p);
|
||||
assert(*SharedDouble2_ref(q) == 5678.0);
|
||||
SharedDouble2_clear(p);
|
||||
SharedDouble2_clear(q);
|
||||
}
|
||||
|
||||
static void test_double_res(void){
|
||||
SharedRessource r;
|
||||
SharedRessource_init(r, 4);
|
||||
SharedRessourceIt i;
|
||||
SharedRessource_it(i, r);
|
||||
assert(*SharedRessource_ref(i) == 0);
|
||||
*SharedRessource_ref(i) = 3456.0;
|
||||
SharedRessource_end(i, r);
|
||||
SharedRessource_it(i, r);
|
||||
assert(*SharedRessource_ref(i) == 3456.0);
|
||||
SharedRessource_clear(r);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test1();
|
||||
test2();
|
||||
for(int i = 1; i < MAX_RESSOURCE; i++)
|
||||
for(int i = 1; i < MAX_RESSOURCE; i++) {
|
||||
test_ressource(i);
|
||||
}
|
||||
test_double();
|
||||
test_double2();
|
||||
test_double_res();
|
||||
exit(0);
|
||||
}
|
||||
+72
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -37,9 +37,9 @@ typedef struct {
|
||||
void *v;
|
||||
} data_t;
|
||||
|
||||
static void data_crc(data_t *p) { p->p = -p->n; p->c = ~p->n; }
|
||||
static void data_crc(data_t *p) { p->p = 0-p->n; p->c = ~p->n; }
|
||||
static void data_init(data_t *p) { p->n = 0; p->spare1 = 0; p->spare2 = 0; data_crc(p); p->v = calloc(1, 1); assert(p->v); }
|
||||
static void data_valid_p(const data_t *p) { assert (p->n == -p->p && p->n == ~p->c); }
|
||||
static void data_valid_p(const data_t *p) { assert (p->n == (0-p->p) && p->n == ~p->c); }
|
||||
static void data_clear(data_t *p) { free(p->v); }
|
||||
static void data_set(data_t *p, data_t o) { p->n = o.n; data_crc(p); }
|
||||
static void data_init_set(data_t *p, data_t o) { data_init(p); data_set(p, o); }
|
||||
@@ -53,8 +53,12 @@ SNAPSHOT_SPSC_DEF(snapshot_mpz, testobj_t, TESTOBJ_OPLIST)
|
||||
SNAPSHOT_SPMC_DEF(snapshot_mrsw_data, data_t, DATA_OPLIST)
|
||||
SNAPSHOT_MPMC_DEF(snapshot_mrmw_data, data_t, DATA_OPLIST)
|
||||
END_COVERAGE
|
||||
|
||||
SNAPSHOT_SPSC_DEF(snapshot_data, data_t, DATA_OPLIST )
|
||||
|
||||
SNAPSHOT_SPSC_DEF_AS(SnapshotDouble, SnapshotDouble, double)
|
||||
SNAPSHOT_SPMC_DEF_AS(SnapshotDoubleSPMC, SnapshotDoubleSPMC, double)
|
||||
SNAPSHOT_MPMC_DEF_AS(SnapshotDoubleMPMC, SnapshotDoubleMPMC, double)
|
||||
|
||||
static void test_uint(void)
|
||||
{
|
||||
@@ -150,7 +154,7 @@ static void test_global(void)
|
||||
|
||||
static void test_mrsw_int1(void)
|
||||
{
|
||||
snapshot_mrsw_int_t idx;
|
||||
snapshot_mrsw_int_ct idx;
|
||||
snapshot_mrsw_int_init(idx, 1);
|
||||
|
||||
assert (snapshot_mrsw_int_get_write_idx(idx) == 1);
|
||||
@@ -180,7 +184,7 @@ static void test_mrsw_int1(void)
|
||||
|
||||
static void test_mrsw_int2(void)
|
||||
{
|
||||
snapshot_mrsw_int_t idx;
|
||||
snapshot_mrsw_int_ct idx;
|
||||
snapshot_mrsw_int_init(idx, 2);
|
||||
|
||||
assert (snapshot_mrsw_int_get_write_idx(idx) == 1);
|
||||
@@ -215,13 +219,20 @@ snapshot_mrsw_data_t global_mrsw;
|
||||
|
||||
static void conso2(void *arg)
|
||||
{
|
||||
assert (arg == NULL);
|
||||
unsigned int idx = (unsigned) (uintptr_t) arg;
|
||||
while (true) {
|
||||
const data_t *p = snapshot_mrsw_data_read_start(global_mrsw);
|
||||
assert (p != NULL);
|
||||
unsigned int n = p->n;
|
||||
data_valid_p(p);
|
||||
if (p->n == 0)
|
||||
return;
|
||||
break;
|
||||
if (idx > 0) {
|
||||
// Simulate slow readers if idx > 0
|
||||
m_thread_sleep(idx * 10);
|
||||
data_valid_p(p);
|
||||
assert (n == p->n);
|
||||
}
|
||||
snapshot_mrsw_data_read_end(global_mrsw, p);
|
||||
}
|
||||
}
|
||||
@@ -230,12 +241,21 @@ static void prod2(void *arg)
|
||||
{
|
||||
assert (arg == NULL);
|
||||
data_t *p = snapshot_mrsw_data_get_write_buffer(global_mrsw);
|
||||
for(unsigned int i = 1; i < 200000;i++) {
|
||||
for(unsigned int i = 1; i < 190000;i++) {
|
||||
assert (p != NULL);
|
||||
p->n = i * i;
|
||||
data_crc(p);
|
||||
p = snapshot_mrsw_data_write(global_mrsw);
|
||||
}
|
||||
for(unsigned int i = 190000; i < 200000;i++) {
|
||||
assert (p != NULL);
|
||||
p->n = i * i;
|
||||
data_crc(p);
|
||||
// Simulate slow writes
|
||||
m_thread_sleep(1);
|
||||
m_thread_yield();
|
||||
p = snapshot_mrsw_data_write(global_mrsw);
|
||||
}
|
||||
p->n = 0;
|
||||
data_crc(p);
|
||||
p = snapshot_mrsw_data_write(global_mrsw);
|
||||
@@ -250,7 +270,7 @@ static void test_mrsw_global(int reader)
|
||||
m_thread_t idx_w;
|
||||
m_thread_t idx[MAX_READER];
|
||||
|
||||
snapshot_mrsw_data_init(global_mrsw, reader);
|
||||
snapshot_mrsw_data_init(global_mrsw, (size_t) reader);
|
||||
data_t *p = snapshot_mrsw_data_write(global_mrsw);
|
||||
assert (p != NULL);
|
||||
p->n = 42;
|
||||
@@ -259,7 +279,7 @@ static void test_mrsw_global(int reader)
|
||||
assert (p != NULL);
|
||||
|
||||
for(int i = 0 ; i < reader; i++)
|
||||
m_thread_create (idx[i], conso2, NULL);
|
||||
m_thread_create (idx[i], conso2, (void*) (uintptr_t) i);
|
||||
m_thread_create (idx_w, prod2, NULL);
|
||||
|
||||
m_thread_join(idx_w);
|
||||
@@ -305,7 +325,7 @@ static void test_mrmw_global(int reader, int writer)
|
||||
m_thread_t idx_w[MAX_WRITER];
|
||||
m_thread_t idx[MAX_READER];
|
||||
|
||||
snapshot_mrmw_data_init(global_mrmw, reader, writer);
|
||||
snapshot_mrmw_data_init(global_mrmw, (size_t) reader, (size_t) writer);
|
||||
data_t *p = snapshot_mrmw_data_write_start(global_mrmw);
|
||||
assert (p != NULL);
|
||||
p->n = 42;
|
||||
@@ -325,6 +345,44 @@ static void test_mrmw_global(int reader, int writer)
|
||||
snapshot_mrmw_data_clear(global_mrmw);
|
||||
}
|
||||
|
||||
static void test_double(void)
|
||||
{
|
||||
SnapshotDouble s;
|
||||
SnapshotDouble_init(s);
|
||||
double *p = SnapshotDouble_get_write_buffer(s);
|
||||
*p = 42.0;
|
||||
p = SnapshotDouble_write(s);
|
||||
const double *q = SnapshotDouble_read(s);
|
||||
assert (*q == 42.0);
|
||||
SnapshotDouble_clear(s);
|
||||
}
|
||||
|
||||
static void test_doubleSPMC(void)
|
||||
{
|
||||
SnapshotDoubleSPMC s;
|
||||
SnapshotDoubleSPMC_init(s, 1);
|
||||
double *p = SnapshotDoubleSPMC_get_write_buffer(s);
|
||||
*p = 42.0;
|
||||
p = SnapshotDoubleSPMC_write(s);
|
||||
const double *q = SnapshotDoubleSPMC_read_start(s);
|
||||
assert (*q == 42.0);
|
||||
SnapshotDoubleSPMC_read_end(s, q);
|
||||
SnapshotDoubleSPMC_clear(s);
|
||||
}
|
||||
|
||||
static void test_doubleMPMC(void)
|
||||
{
|
||||
SnapshotDoubleMPMC s;
|
||||
SnapshotDoubleMPMC_init(s, 1, 1);
|
||||
double *p = SnapshotDoubleMPMC_write_start(s);
|
||||
*p = 42.0;
|
||||
SnapshotDoubleMPMC_write_end(s, p);
|
||||
const double *q = SnapshotDoubleMPMC_read_start(s);
|
||||
assert (*q == 42.0);
|
||||
SnapshotDoubleMPMC_read_end(s, q);
|
||||
SnapshotDoubleMPMC_clear(s);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_uint();
|
||||
@@ -337,6 +395,9 @@ int main(void)
|
||||
test_mrsw_global(MAX_READER);
|
||||
test_mrmw_global(1, 1);
|
||||
test_mrmw_global(MAX_READER/4, MAX_WRITER/4);
|
||||
test_double();
|
||||
test_doubleSPMC();
|
||||
test_doubleMPMC();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Loaded 100 of 111 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user