Initial import of libdpf.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ryan Henry 2026-09-24 14:08:32 -06:00
commit e4e666f459
4563 changed files with 1690372 additions and 0 deletions

View file

@ -0,0 +1,29 @@
environment:
matrix:
- GENERATOR: Visual Studio 14 2015 Win64
- GENERATOR: Visual Studio 14 2015
- GENERATOR: Visual Studio 12 2013 Win64
- GENERATOR: Visual Studio 11 2012
- GENERATOR: Visual Studio 10 2010 Win64
- GENERATOR: Visual Studio 9 2008
branches:
except:
- /^(wip\/)?(travis|osx|ipp)(\-.+)?$/
- /^master$/
before_build:
- ps: |
git submodule -q update --init --recursive
cd tests
mkdir build
cd build
cmake -G "$env:GENERATOR" .. -DENABLE_AGGRESSIVE_WARNINGS=yes -DFATAL_WARNINGS=yes
build_script:
- ps: |
cmake --build . --config Debug
test_script:
- ps: |
ctest --output-on-failure --interactive-debug-mode 0 -C Debug -V

View file

@ -0,0 +1,3 @@
*~
*#
*.bak

View file

@ -0,0 +1,3 @@
[submodule "tests/munit"]
path = tests/munit
url = https://github.com/nemequ/munit.git

193
thirdparty/portable-snippets/.travis.yml vendored Normal file
View file

@ -0,0 +1,193 @@
language: c
sudo: false
branches:
except:
- /^(wip\/)?(appveyor|msvc|mingw|windows)(\-.+)?$/
- /^master$/
matrix:
include:
###
## Linux builds using various versions of GCC.
###
- env: C_COMPILER=gcc-6
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- george-edison55-precise-backports
packages:
- gcc-6
- g++-6
- cmake
- cmake-data
- env: C_COMPILER=gcc-5
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- george-edison55-precise-backports
packages:
- gcc-5
- g++-5
- cmake
- cmake-data
# - env: C_COMPILER=gcc-4.9
# addons:
# apt:
# sources:
# - ubuntu-toolchain-r-test
# - george-edison55-precise-backports
# packages:
# - gcc-4.9
# - g++-4.9
# - cmake
# - cmake-data
- env: C_COMPILER=gcc-4.8
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- george-edison55-precise-backports
packages:
- gcc-4.8
- g++-4.8
- cmake
- cmake-data
# - env: C_COMPILER=gcc-4.7
# addons:
# apt:
# sources:
# - ubuntu-toolchain-r-test
# - george-edison55-precise-backports
# packages:
# - gcc-4.7
# - g++-4.7
# - cmake
# - cmake-data
- env: C_COMPILER=gcc-4.6
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- george-edison55-precise-backports
packages:
- gcc-4.6
- g++-4.6
- cmake
- cmake-data
# - os: linux
# env: C_COMPILER=gcc-4.5
# addons:
# apt:
# sources:
# - ubuntu-toolchain-r-test
# - george-edison55-precise-backports
# packages:
# - gcc-4.5
# - g++-4.5
# - cmake
# - cmake-data
- env: C_COMPILER=gcc-4.4
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- george-edison55-precise-backports
packages:
- gcc-4.4
- g++-4.4
- cmake
- cmake-data
###
## clang on Linux
###
- env: C_COMPILER=clang-3.9
addons:
apt:
sources:
- llvm-toolchain-precise-3.9
- ubuntu-toolchain-r-test
- george-edison55-precise-backports
packages:
- clang-3.9
- cmake
- cmake-data
# - env: C_COMPILER=clang-3.8
# addons:
# apt:
# sources:
# - llvm-toolchain-precise-3.8
# - ubuntu-toolchain-r-test
# - george-edison55-precise-backports
# packages:
# - clang-3.8
# - cmake
# - cmake-data
- env: C_COMPILER=clang-3.7
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
- george-edison55-precise-backports
packages:
- clang-3.7
- cmake
- cmake-data
# - env: C_COMPILER=clang-3.6
# addons:
# apt:
# sources:
# - llvm-toolchain-precise-3.6
# - ubuntu-toolchain-r-test
# - george-edison55-precise-backports
# packages:
# - clang-3.6
# - cmake
# - cmake-data
- env: C_COMPILER=clang-3.5
addons:
apt:
sources:
- llvm-toolchain-precise-3.5
- ubuntu-toolchain-r-test
- george-edison55-precise-backports
packages:
- clang-3.5
- cmake
- cmake-data
###
## PGI
###
- env: C_COMPILER=pgcc ENABLE_OPENMP=y
addons:
apt:
sources:
- george-edison55-precise-backports
packages:
- cmake
- cmake-data
###
## OS X
###
# - os: osx
before_install:
###
## If we use the matrix to set CC/CXX Travis, overwrites the values,
## so instead we use C/CXX_COMPILER, then copy the values to CC/CXX
## here (after Travis has set CC/CXX).
###
- if [ "${C_COMPILER}" = "pgcc" ]; then wget -q -O /dev/stdout 'https://raw.githubusercontent.com/nemequ/pgi-travis/master/install-pgi.sh' | /bin/sh; fi
- if [ -n "${C_COMPILER}" ]; then export CC="${C_COMPILER}"; fi
- mkdir tests/build
- cd tests/build
script:
- cmake --version
- cmake .. -DCMAKE_C_COMPILER="${C_COMPILER}" -DCMAKE_C_FLAGS="${CFLAGS}" -DENABLE_OPENMP="${ENABLE_OPENMP}" -DENABLE_AGGRESSIVE_WARNINGS=yes -DFATAL_WARNINGS=yes
- make VERBOSE=1
- ctest -V

124
thirdparty/portable-snippets/COPYING.md vendored Normal file
View file

@ -0,0 +1,124 @@
Each source file contains a preamble explaining the license situation
for that file, which takes priority over this file. With the
exception of some code pulled in from other repositories (such as
µnit, an MIT-licensed project which is used for testing), the code is
public domain, released using the CC0 1.0 Universal dedication, which
is reproduced below:
# CC0 1.0 Universal Public Domain Dedication
The laws of most jurisdictions throughout the world automatically
confer exclusive Copyright and Related Rights (defined below) upon the
creator and subsequent owner(s) (each and all, an "owner") of an
original work of authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work
for the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without
fear of later claims of infringement build upon, modify, incorporate
in other works, reuse and redistribute as freely as possible in any
form whatsoever and for any purposes, including without limitation
commercial purposes. These owners may contribute to the Commons to
promote the ideal of a free culture and the further production of
creative, cultural and scientific works, or to gain reputation or
greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or
she is an owner of Copyright and Related Rights in the Work,
voluntarily elects to apply CC0 to the Work and publicly distribute
the Work under its terms, with knowledge of his or her Copyright and
Related Rights in the Work and the meaning and intended legal effect
of CC0 on those rights.
1. **Copyright and Related Rights**. A Work made available under CC0
may be protected by copyright and related or neighboring rights
("Copyright and Related Rights"). Copyright and Related Rights
include, but are not limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or
performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a
Work, subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse
of data in a Work;
vi. database rights (such as those arising under Directive 96/9/EC
of the European Parliament and of the Council of 11 March 1996
on the legal protection of databases, and under any national
implementation thereof, including any amended or successor
version of such directive); and
vii. other similar, equivalent or corresponding rights throughout
the world based on applicable law or treaty, and any national
implementations thereof.
2. **Waiver**. To the greatest extent permitted by, but not in
contravention of, applicable law, Affirmer hereby overtly, fully,
permanently, irrevocably and unconditionally waives, abandons, and
surrenders all of Affirmer's Copyright and Related Rights and
associated claims and causes of action, whether now known or
unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including
future time extensions), (iii) in any current or future medium and
for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit
of each member of the public at large and to the detriment of
Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation,
termination, or any other legal or equitable action to disrupt the
quiet enjoyment of the Work by the public as contemplated by
Affirmer's express Statement of Purpose.
3. **Public License Fallback**. Should any part of the Waiver for any
reason be judged legally invalid or ineffective under applicable
law, then the Waiver shall be preserved to the maximum extent
permitted taking into account Affirmer's express Statement of
Purpose. In addition, to the extent the Waiver is so judged
Affirmer hereby grants to each affected person a royalty-free, non
transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related
Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including
future time extensions), (iii) in any current or future medium and
for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any
part of the License for any reason be judged legally invalid or
ineffective under applicable law, such partial invalidity or
ineffectiveness shall not invalidate the remainder of the License,
and in such case Affirmer hereby affirms that he or she will not
(i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes
of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. **Limitations and Disclaimers**.
a. No trademark or patent rights held by Affirmer are waived,
abandoned, surrendered, licensed or otherwise affected by this
document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties
of title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects,
accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under
applicable law.
c. Affirmer disclaims responsibility for clearing rights of other
persons that may apply to the Work or any use thereof, including
without limitation any person's Copyright and Related Rights in
the Work. Further, Affirmer disclaims responsibility for
obtaining any necessary consents, permissions or other rights
required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is
not a party to this document and has no duty or obligation with
respect to this CC0 or use of the Work.

83
thirdparty/portable-snippets/README.md vendored Normal file
View file

@ -0,0 +1,83 @@
# Portable Snippets
This is a collection of public domain (CC0) code snippets written in C
for performing various common tasks which are typically OS,
architecture, and/or compiler-dependent. Basically, our goal is to
move those annoying preprocessor conditionals from your code to ours.
Modules have no fixed target (such as C89) since that would preclude
some functionality; instead, we simply try to provide the widest
support we can for each module. If you have a platform which isn't
supported for a particular feature but could be, please let us know;
we'd be happy to try to work out a way to support it.
Everything is tested continuously with various versions of GCC, Clang,
and PGI ([on Travis
CI](https://travis-ci.org/nemequ/portable-snippets)), MSVC ([on
AppVeyor](https://ci.appveyor.com/project/quixdb/portable-snippets)),
and Emscripten (on
[Codefresh](https://g.codefresh.io/repositories/nemequ/portable-snippets/builds?filter=trigger:build;branch:master;service:591f783d728f4b0001051d3e~portable-snippets)):
[![Travis CI status](https://travis-ci.org/nemequ/portable-snippets.svg?branch=master)](https://travis-ci.org/nemequ/portable-snippets) [![AppVeyor status](https://ci.appveyor.com/api/projects/status/quoq2hwes530p29w/branch/master?svg=true)](https://ci.appveyor.com/project/quixdb/portable-snippets/branch/master) [![Codefresh status](https://g.codefresh.io/api/badges/build?repoOwner=nemequ&repoName=portable-snippets&branch=master&pipelineName=portable-snippets&accountName=nemequ&type=cf-1)](https://g.codefresh.io/repositories/nemequ/portable-snippets/builds?filter=trigger:build;branch:master;service:591f783d728f4b0001051d3e~portable-snippets)
Currently ready-to-use modules include:
* [builtin](https://github.com/nemequ/portable-snippets/tree/master/builtin) —
use compiler built-ins/intrinsics, or fall back on standard C
* [endian](https://github.com/nemequ/portable-snippets/tree/master/endian) —
endianness detection and swapping
* [atomic](https://github.com/nemequ/portable-snippets/tree/master/atomic) —
common atomic synchronization operations
* [safe-math](https://github.com/nemequ/portable-snippets/tree/master/safe-math) —
overflow-safe integer functions
* [exact-int](https://github.com/nemequ/portable-snippets/tree/master/exact-int) —
exact-width integer types (think `<stdint.h>`)
* [clock](https://github.com/nemequ/portable-snippets/tree/master/clock) —
cross-platform wall clock, CPU time, and monotonic time
There are also modules which may not yet be ready for widespread use, but
would benefit greatly from testing:
* [unaligned](https://github.com/nemequ/portable-snippets/tree/master/unaligned) —
fast unaligned loads & stores
* [once](https://github.com/nemequ/portable-snippets/tree/master/once) —
one-time initialization
* [random](https://github.com/nemequ/portable-snippets/tree/master/random) —
random number generation (3 flavors: cryptographic, reproducible, and fast)
* [debug-trap](https://github.com/nemequ/portable-snippets/tree/master/debug-trap) —
debugging traps and assertions
* [check](https://github.com/nemequ/portable-snippets/tree/master/check) —
assertion checking
Modules can be used in isolation, though some do work better together,
so if you can keep the whole repository together instead of just
copying a single file we recommend you do so.
Please don't be shy about filing issues about any of these; if you
have problems it's likely others will, as well, so we would like to
fix them.
If you have something you would like to contribute, please file an
issue or pull request. If you'd like to help out by writing something
new, take a look at the ["enhancement"
issues](https://github.com/nemequ/portable-snippets/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement)
in our issue tracker for ideas.
Some things don't really fit this repository, so here are a few
small-ish projects for doing things portably which you may be
interested in:
* [Hedley](https://nemequ.github.io/hedley/) — macros to enable
compiler-specific features which make your code easier to use,
harder to misuse, safer, faster, and more portable.
* [parg](https://github.com/jibsen/parg) —
Argument parsing similar to getopt/getopt_long. Public domain.
* [TinyCThread](https://tinycthread.github.io/) — Implements the C11
threads API on top of pthreads and the Windows API. zlib license.
* [win-iconv](https://github.com/win-iconv/win-iconv) — Windows
implementation of the iconv API (character set conversion).
* [mman-win32](https://github.com/witwall/mman-win32) — `mman.h`
(`mmap()`, *etc.*) implementation for Windows.
If there is a project you'd like to see added to the list, please file
an issue or pull request.

View file

@ -0,0 +1,60 @@
# Atomic Operations
This header provides atomic operations in a way which is portable to
most platforms. Current back-ends include:
* C11
* GCC-style __atomic_* builtins
* Old-style GCC sync_* builtins
* clang-style __c11_atomic_* builtins
* MSVC-style Interlocked* intrinsics
* OpenMP (using critical sections; there is no atomic CAS)
This is sufficient to support most modern, actively developed
compilers. [PGI C/C++ Compiler](http://www.pgroup.com/), which
[doesn't currently support
atomics](http://www.pgroup.com/userforum/viewtopic.php?t=5504) but
hopefully will soon, in the meantime you can use the OpenMP backend
(just pass `-mp` to the compiler).
Most things are implemented with the preprocessor, but if they were
functions the prototypes (the 64-bit versions, just s/64/32/ for the
32-bit versions) would loo like:
```c
psnip_int64_t psnip_atomic_int64_load(
psnip_atomic_int64* object);
void psnip_atomic_int64_store(
psnip_atomic_int64* object,
psnip_int64_t desired);
_Bool psnip_atomic_int64_compare_exchange(
psnip_atomic_int64* object,
psnip_int64_t* expected,
psnip_int64_t desired);
psnip_nonatomic_int64 psnip_atomic_int64_add(
psnip_atomic_int64* object,
psnip_int64_t operand);
psnip_nonatomic_int64 psnip_atomic_int64_sub(
psnip_atomic_int64* object,
psnip_int64_t operand);
```
If no atomics are supported, `PSNIP_ATOMIC_NOT_FOUND` will be defined;
you'll probably have to use locks (if you want a portable API for that
you may be interested in
[TinyCThread](https://github.com/tinycthread/tinycthread/)), or you
could try the [atomic_ops](https://github.com/ivmai/libatomic_ops/)
package.
## Dependencies
To maximize portability you should #include the exact-int module
before including atomic.h, but if you don't want to add the extra
file to your project you can omit it and this module will simply rely
on <stdint.h>. As an alternative you may define `psnip_int32_t`, and
`psnip_int64_t` to appropriate values yourself before including
atomic.h.

View file

@ -0,0 +1,419 @@
/* Atomic operations (v1)
* Portable Snippets - https://github.com/nemequ/portable-snippets
* Created by Evan Nemerson <evan@nemerson.com>
*
* To the extent possible under law, the authors have waived all
* copyright and related or neighboring rights to this code. For
* details, see the Creative Commons Zero 1.0 Universal license at
* https://creativecommons.org/publicdomain/zero/1.0/
*
* This is a small abstraction layer for some common atomic operations
* (load, store, add, subtract, and compare & swap) implemented using
* various compiler-specific builtins.
*
* There are four types, 32-bit and 64-bit integers which are both
* atomic and non-atomic. The atomic versions should be used for the
* atomic variable, the non-atomic variables should be used to store
* values read from or written to an atomic variable. For example, a
* basic CAS loop:
*
* void square_dest(psnip_atomic_int64* value) {
* psnip_int64_t expected;
* do {
* expected = psnip_atomic_int64_load(&value);
* } while (!psnip_atomic_int64_compare_exchange(&value, &expected, expected * expected));
* }
*
* Most things are implemented with the preprocessor, but if they were
* functions the prototypes (the 64-bit versions, just s/64/32/ for
* the 32-bit versions) would loo like:
*
* psnip_int64_t psnip_atomic_int64_load(
* psnip_atomic_int64* object);
* void psnip_atomic_int64_store(
* psnip_atomic_int64* object,
* psnip_int64_t desired);
* _Bool psnip_atomic_int64_compare_exchange(
* psnip_atomic_int64* object,
* psnip_int64_t* expected,
* psnip_int64_t desired);
* psnip_int64_t psnip_atomic_int64_add(
* psnip_atomic_int64* object,
* psnip_int64_t operand);
* psnip_int64_t psnip_atomic_int64_sub(
* psnip_atomic_int64* object,
* psnip_int64_t operand);
*/
#if !defined(PSNIP_ATOMIC_H)
#define PSNIP_ATOMIC_H
/* For maximum portability include the exact-int module from
portable snippets. */
#if \
!defined(psnip_int64_t) || \
!defined(psnip_int32_t)
# include <stdint.h>
# if !defined(psnip_int64_t)
# define psnip_int64_t int64_t
# endif
# if !defined(psnip_int32_t)
# define psnip_int32_t int32_t
# endif
#endif
#if !defined(PSNIP_ATOMIC_STATIC_INLINE)
# if defined(__GNUC__)
# define PSNIP_ATOMIC__COMPILER_ATTRIBUTES __attribute__((__unused__))
# else
# define PSNIP_ATOMIC__COMPILER_ATTRIBUTES
# endif
# if defined(HEDLEY_INLINE)
# define PSNIP_ATOMIC__INLINE HEDLEY_INLINE
# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
# define PSNIP_ATOMIC__INLINE inline
# elif defined(__GNUC_STDC_INLINE__)
# define PSNIP_ATOMIC__INLINE __inline__
# elif defined(_MSC_VER) && _MSC_VER >= 1200
# define PSNIP_ATOMIC__INLINE __inline
# else
# define PSNIP_ATOMIC__INLINE
# endif
# define PSNIP_ATOMIC__FUNCTION PSNIP_ATOMIC__COMPILER_ATTRIBUTES static PSNIP_ATOMIC__INLINE
#endif
#if defined(__has_feature)
# define PSNIP_ATOMIC_HAS_FEATURE(feature) __has_feature(feature)
#else
# define PSNIP_ATOMIC_HAS_FEATURE(feature) 0
#endif
#define PSNIP_ATOMIC_IMPL_NONE 0
#define PSNIP_ATOMIC_IMPL_GCC 1
#define PSNIP_ATOMIC_IMPL_GCC_SYNC 2
#define PSNIP_ATOMIC_IMPL_CLANG 3
#define PSNIP_ATOMIC_IMPL_MS 4
#define PSNIP_ATOMIC_IMPL_OPENMP 5
#define PSNIP_ATOMIC_IMPL_C11 11
#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
# define PSNIP_ATOMIC_IMPL PSNIP_ATOMIC_IMPL_GCC
#elif !defined(__INTEL_COMPILER) && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__)
/* GCC 4.7 and 4.8 sets __STDC_VERSION__ to C11 (if compiling in C11
* mode) and didn't have stdatomic.h, but failed to set
* __STDC_NO_ATOMICS__. Verions prior to 4.7 didn't set
* __STDC_VERSION__ to C11. */
# if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 9)
# define PSNIP_ATOMIC_IMPL PSNIP_ATOMIC_IMPL_GCC
# else
# define PSNIP_ATOMIC_IMPL PSNIP_ATOMIC_IMPL_C11
# endif
#elif defined(_MSC_VER)
# define PSNIP_ATOMIC_IMPL PSNIP_ATOMIC_IMPL_MS
#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
# define PSNIP_ATOMIC_IMPL PSNIP_ATOMIC_IMPL_GCC
#elif PSNIP_ATOMIC_HAS_FEATURE(c_atomic)
# define PSNIP_ATOMIC_IMPL PSNIP_ATOMIC_IMPL_CLANG
#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
# define PSNIP_ATOMIC_IMPL PSNIP_ATOMIC_IMPL_GCC_SYNC
#elif (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5140)) || (defined(__SUNPRO_CC) && (__SUNPRO_CC >= 0x5140))
# define PSNIP_ATOMIC_IMPL PSNIP_ATOMIC_IMPL_GCC
#elif defined(_OPENMP)
# define PSNIP_ATOMIC_IMPL PSNIP_ATOMIC_IMPL_OPENMP
#else
# define PSNIP_ATOMIC_NOT_FOUND
# define PSNIP_ATOMIC_IMPL PSNIP_ATOMIC_IMPL_NONE
# warning No atomic implementation found
#endif
#if !defined(PSNIP_ATOMIC_NOT_FOUND)
#if PSNIP_ATOMIC_IMPL == PSNIP_ATOMIC_IMPL_C11
#include <stdatomic.h>
typedef atomic_int_fast64_t psnip_atomic_int64;
typedef atomic_int_fast32_t psnip_atomic_int32;
#define PSNIP_ATOMIC_VAR_INIT(value) ATOMIC_VAR_INIT(value)
#define psnip_atomic_int64_load(object) \
atomic_load(object)
#define psnip_atomic_int64_store(object, desired) \
atomic_store(object, desired)
#define psnip_atomic_int64_compare_exchange(object, expected, desired) \
atomic_compare_exchange_strong(object, expected, desired)
#define psnip_atomic_int64_add(object, operand) \
atomic_fetch_add(object, operand)
#define psnip_atomic_int64_sub(object, operand) \
atomic_fetch_sub(object, operand)
#define psnip_atomic_fence() \
atomic_thread_fence(memory_order_seq_cst)
#define PSNIP_ATOMIC_IS_TG
#elif PSNIP_ATOMIC_IMPL == PSNIP_ATOMIC_IMPL_CLANG
#include <stdint.h>
typedef _Atomic psnip_int64_t psnip_atomic_int64;
typedef _Atomic psnip_int32_t psnip_atomic_int32;
#define psnip_atomic_int64_load(object) \
__c11_atomic_load(object, __ATOMIC_SEQ_CST)
#define psnip_atomic_int64_store(object, desired) \
__c11_atomic_store(object, desired, __ATOMIC_SEQ_CST)
#define psnip_atomic_int64_compare_exchange(object, expected, desired) \
__c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
#define psnip_atomic_int64_add(object, operand) \
__c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST)
#define psnip_atomic_int64_sub(object, operand) \
__c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST)
#define psnip_atomic_fence() \
__c11_atomic_thread_fence(__ATOMIC_SEQ_CST)
#define PSNIP_ATOMIC_IS_TG
#elif PSNIP_ATOMIC_IMPL == PSNIP_ATOMIC_IMPL_GCC
#include <stdint.h>
#if !defined(__INTEL_COMPILER) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && !defined(_OPENMP)
typedef _Atomic psnip_int64_t psnip_atomic_int64;
typedef _Atomic psnip_int32_t psnip_atomic_int32;
#else
typedef psnip_int64_t psnip_atomic_int64;
typedef psnip_int32_t psnip_atomic_int32;
#endif
#define psnip_atomic_int64_load(object) \
__atomic_load_n(object, __ATOMIC_SEQ_CST)
#define psnip_atomic_int64_store(object, desired) \
__atomic_store_n(object, desired, __ATOMIC_SEQ_CST)
#define psnip_atomic_int64_compare_exchange(object, expected, desired) \
__atomic_compare_exchange_n(object, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
#define psnip_atomic_int64_add(object, operand) \
__atomic_add_fetch(object, operand, __ATOMIC_SEQ_CST)
#define psnip_atomic_int64_sub(object, operand) \
__atomic_sub_fetch(object, operand, __ATOMIC_SEQ_CST)
#define psnip_atomic_fence() \
__atomic_thread_fence(__ATOMIC_SEQ_CST)
#define PSNIP_ATOMIC_IS_TG
#elif PSNIP_ATOMIC_IMPL == PSNIP_ATOMIC_IMPL_GCC_SYNC
#include <stdint.h>
typedef psnip_int64_t psnip_atomic_int64;
typedef psnip_int32_t psnip_atomic_int32;
PSNIP_ATOMIC__FUNCTION
psnip_int64_t
psnip_atomic_int64_load(psnip_atomic_int64* object) {
__sync_synchronize();
return (psnip_int64_t) *object;
}
PSNIP_ATOMIC__FUNCTION
void
psnip_atomic_int64_store(psnip_atomic_int64* object, psnip_int64_t desired) {
*object = desired;
__sync_synchronize();
}
#define psnip_atomic_int64_compare_exchange(object, expected, desired) \
__sync_bool_compare_and_swap(object, *(expected), desired)
#define psnip_atomic_int64_add(object, operand) \
__sync_fetch_and_add(object, operand)
#define psnip_atomic_int64_sub(object, operand) \
__sync_fetch_and_sub(object, operand)
PSNIP_ATOMIC__FUNCTION
psnip_int32_t
psnip_atomic_int32_load(psnip_atomic_int32* object) {
__sync_synchronize();
return (psnip_int32_t) *object;
}
PSNIP_ATOMIC__FUNCTION
void
psnip_atomic_int32_store(psnip_atomic_int32* object, psnip_int32_t desired) {
*object = desired;
__sync_synchronize();
}
#define psnip_atomic_int32_compare_exchange(object, expected, desired) \
__sync_bool_compare_and_swap(object, *(expected), desired)
#define psnip_atomic_int32_add(object, operand) \
__sync_fetch_and_add(object, operand)
#define psnip_atomic_int32_sub(object, operand) \
__sync_fetch_and_sub(object, operand)
#define psnip_atomic_fence() \
__sync_synchronize()
#elif PSNIP_ATOMIC_IMPL == PSNIP_ATOMIC_IMPL_MS
#include <Windows.h>
typedef long long volatile psnip_atomic_int64;
typedef long volatile psnip_atomic_int32;
#define psnip_atomic_int32_load(object) \
__pragma(warning(push)) \
__pragma(warning(disable:28112)) \
(*(object)) \
__pragma(warning(pop))
#define psnip_atomic_int32_store(object, desired) \
InterlockedExchange(object, desired)
#define psnip_atomic_int32_compare_exchange(object, expected, desired) \
InterlockedCompareExchange(object, desired, *(expected))
#define psnip_atomic_int32_add(object, operand) \
InterlockedExchangeAdd(object, operand)
#define psnip_atomic_int32_sub(object, operand) \
InterlockedExchangeAdd(object, -(operand))
#define psnip_atomic_int64_load(object) \
__pragma(warning(push)) \
__pragma(warning(disable:28112)) \
(*(object)) \
__pragma(warning(pop))
#define psnip_atomic_int64_store(object, desired) \
InterlockedExchange64(object, desired)
#define psnip_atomic_int64_compare_exchange(object, expected, desired) \
InterlockedCompareExchange64(object, desired, *(expected))
#define psnip_atomic_int64_add(object, operand) \
InterlockedExchangeAdd64(object, operand)
#define psnip_atomic_int64_sub(object, operand) \
InterlockedExchangeAdd64(object, -(operand))
#define psnip_atomic_fence() \
MemoryBarrier()
#elif PSNIP_ATOMIC_IMPL == PSNIP_ATOMIC_IMPL_OPENMP
#include <stdint.h>
typedef psnip_int64_t psnip_atomic_int64;
typedef psnip_int32_t psnip_atomic_int32;
PSNIP_ATOMIC__FUNCTION
psnip_int64_t
psnip_atomic_int64_load(psnip_atomic_int64* object) {
psnip_int64_t ret;
#pragma omp critical(psnip_atomic)
ret = *object;
return ret;
}
PSNIP_ATOMIC__FUNCTION
void
psnip_atomic_int64_store(psnip_atomic_int64* object, psnip_int64_t desired) {
#pragma omp critical(psnip_atomic)
*object = desired;
}
PSNIP_ATOMIC__FUNCTION
int
psnip_atomic_int64_compare_exchange_(psnip_atomic_int64* object, psnip_int64_t* expected, psnip_int64_t desired) {
int ret;
#pragma omp critical(psnip_atomic)
ret = (*object == *expected) ? ((*object = desired), 1) : 0;
return ret;
}
#define psnip_atomic_int64_compare_exchange(object, expected, desired) \
psnip_atomic_int64_compare_exchange_(object, expected, desired)
PSNIP_ATOMIC__FUNCTION
psnip_int64_t
psnip_atomic_int64_add(psnip_atomic_int64* object, psnip_int64_t operand) {
int ret;
#pragma omp critical(psnip_atomic)
*object = (ret = *object) + operand;
return ret;
}
PSNIP_ATOMIC__FUNCTION
psnip_int64_t
psnip_atomic_int64_sub(psnip_atomic_int64* object, psnip_int64_t operand) {
int ret;
#pragma omp critical(psnip_atomic)
*object = (ret = *object) - operand;
return ret;
}
PSNIP_ATOMIC__FUNCTION
psnip_int32_t
psnip_atomic_int32_load(psnip_atomic_int32* object) {
psnip_int32_t ret;
#pragma omp critical(psnip_atomic)
ret = *object;
return ret;
}
PSNIP_ATOMIC__FUNCTION
void
psnip_atomic_int32_store(psnip_atomic_int32* object, psnip_int32_t desired) {
#pragma omp critical(psnip_atomic)
*object = desired;
}
PSNIP_ATOMIC__FUNCTION
int
psnip_atomic_int32_compare_exchange_(psnip_atomic_int32* object, psnip_int32_t* expected, psnip_int32_t desired) {
int ret = 1;
#pragma omp critical(psnip_atomic)
ret = (*object == *expected) ? ((*object = desired), 1) : 0;
return ret;
}
#define psnip_atomic_int32_compare_exchange(object, expected, desired) \
psnip_atomic_int32_compare_exchange_(object, expected, desired)
PSNIP_ATOMIC__FUNCTION
psnip_int32_t
psnip_atomic_int32_add(psnip_atomic_int32* object, psnip_int32_t operand) {
int ret;
#pragma omp critical(psnip_atomic)
*object = (ret = *object) + operand;
return ret;
}
PSNIP_ATOMIC__FUNCTION
psnip_int32_t
psnip_atomic_int32_sub(psnip_atomic_int32* object, psnip_int32_t operand) {
int ret;
#pragma omp critical(psnip_atomic)
*object = (ret = *object) - operand;
return ret;
}
PSNIP_ATOMIC__FUNCTION
void
psnip_atomic_fence() {
#pragma omp critical(psnip_atomic)
{ }
}
#endif
#if !defined(PSNIP_ATOMIC_VAR_INIT)
# define PSNIP_ATOMIC_VAR_INIT(value) (value)
#endif
/* Most compilers have type-generic atomic implementations. */
#if defined(PSNIP_ATOMIC_IS_TG)
#define psnip_atomic_int32_load(object) \
psnip_atomic_int64_load(object)
#define psnip_atomic_int32_store(object, desired) \
psnip_atomic_int64_store(object, desired)
#define psnip_atomic_int32_compare_exchange(object, expected, desired) \
psnip_atomic_int64_compare_exchange(object, expected, desired)
#define psnip_atomic_int32_add(object, operand) \
psnip_atomic_int64_add(object, operand)
#define psnip_atomic_int32_sub(object, operand) \
psnip_atomic_int64_sub(object, operand)
#endif /* defined(PSNIP_ATOMIC_IS_TG) */
#endif /* !defined(PSNIP_ATOMIC_NOT_FOUND) */
#endif /* defined(PSNIP_ATOMIC_H) */

View file

@ -0,0 +1,158 @@
# Built-Ins
This module provides portable implementations of many compiler
builtins and intrinsics, allowing you to use builtins and intrinsics
on compilers which don't support them. This includes other compilers
(*e.g.*, GCC builtins on MSVC) and older versions of the same
compiler.
We also provide exact-width variants of many builtins; no more calling
different functions depending on the size of `int`, `long`, `long
long`, etc. These are typically just aliases for the appropriate
function, but if we can't find an appropriate type a portable
implementation will be used.
If you define `PSNIP_BUILTIN_EMULATE_NATIVE` *before* `builtin.h` is
included, this header will also define any missing native-style
built-ins, allowing you to use the native names without regard for
which compiler is actually in use (*i.e.*, you can use `__builtin_ffs`
directly in MSVC, or any other compiler, including GCC < 3.3).
If the compiler already has the builtin, the psnip function will
simply be defined to that builtin (*e.g.*,
`#define psnip_builtin_clz __builtin_clz`). If the compiler does not
have an implementation one will be provided using either a
built-in/intrinsic the compiler *does* support (*e.g.*, using an MSVC
intrinsic to implement a GCC built-in), inline assembly,
architecture-specific functions, or a fully-portable pure C
implementation.
For example, for GCC's `__builtin_ffs` builtin, we provide
implementations which work everywhere (including versions of GCC prior
to 3.3, when `__builtin_ffs` was introduced) of the following
functions:
```c
int psnip_builtin_ffs(int);
int psnip_builtin_ffsl(long);
int psnip_builtin_ffsll(long long);
int psnip_builtin_ffs32(psnip_int32_t);
int psnip_builtin_ffs64(psnip_int64_t);
```
Additionally, when when PSNIP_BUILTIN_EMULATE_NATIVE is defined (and
the compiler doesn't already provide them), we also provide
```c
int __builtin_ffs(int);
int __builtin_ffsl(long);
int __builtin_ffsll(long long);
```
Note that these are often provided as macros, the prototypes are for
documentation only.
## Dependencies
To maximize portability you should #include the exact-int module
before including builtin.h, but if you don't want to add the extra
file to your project you can omit it and this module will simply rely
on <stdint.h>. As an alternative you may define the following macros
to appropriate values yourself:
* `psnip_int8_t`
* `psnip_uint8_t`
* `psnip_int16_t`
* `psnip_uint16_t`
* `psnip_int32_t`
* `psnip_uint32_t`
* `psnip_int64_t`
* `psnip_uint64_t`
## Implementation Status
Virtually every generic builtin we can implement has been implemented.
This should work almost everywhere, but every commit is tested before
landing in the master branch on various versions of GCC, clang, MSVC,
and PGI (thanks to [Travis
CI](https://travis-ci.org/nemequ/portable-snippets) and
[AppVeyor](https://ci.appveyor.com/project/quixdb/portable-snippets)).
Sporadic testing is also done on ICC and Oracle Developer Studio.
GCC builtins:
- [x] ffs, ffsl, ffsll, ffs32, ffs64
- [x] clz, clzl, clzll, clz32, clz64
- [x] ctz, ctzl, ctzll, ctz32, ctz64
- [x] clrsb, clrsbl, clrsbll, clrsb32, clrsb64
- [x] popcount, popcountl, popcountll, popcount32, popcount64
- [x] parity, parityl, parityll, parity32, parity64
- [x] bswap16, bswap32, bswap64
Clang builtins:
- [x] bitreverse8, bitreverse16, bitreverse32, bitreverse64
- [x] addcb, addcs, addc, addcl, addcll, addc8, addc16, addc32, addc64
- [x] subcb, subcs, subc, subcl, subcll, subc8, subc16, subc32, subc64
MSVC intrinsics:
- [x] rotl8, rotl16, rotl, rotl64
- [x] rotr8, rotr16, rotr, rotr64
- [x] BitScanForward, BitScanForward64
- [x] BitScanReverse, BitScanReverse64
- [ ] mul128, umul128
- [x] shiftleft128, shiftright128
- [ ] mulh, umulh
- [x] byteswap_ushort, byteswap_ulong, byteswap_uint64
- [x] bittest, bittest64
- [x] bittestandcomplement, bittestandcomplement64
- [x] bittestandreset, bittestandreset64
- [x] bittestandset, bittestandset64
If we are missing a function you feel should be included, please [file
an issue](https://github.com/nemequ/portable-snippets/issues). Please
keep in mind that some things are simply impossible to implement
without compiler support.
## Alternatives & Supplements
For overflow-safe integer operations (i.e., `__builtin_*_overflow`),
use [safe-math.h](../safe-math).
For bswap/byteswap functions, you should really use
[endian.h](../endian), which depends on this module and handles
endianness detection as well as providing easier to use APIs which
integrate endianness detection logic.
For SIMD intrinsics (SSE, AVX, NEON, etc.), take a look at the
[SIMDe](https://github.com/nemequ/simde/) project.
For things which are effectively compiler hints (such as
`__builtin_expect`) as opposed to data manipulation functions, see
[Hedley](https://nemequ.github.io/hedley/).
## Areas for future work
### Optimization
Performance should be pretty good but we're always open to shaving off
a few operations, even if it means creating different variants for
different compilers or architectures.
Creating implementations of one compiler's builtins using builtins
from another is probably your best bet to improve performance.
Another useful possibility is using architecture-specific builtins, or
even embedded assembly, when they are available.
### Architecture-specific builtins
GCC and MSVC both have lots of architecture-specific builtins.
Especially GCC, which supports many architectures. If you come across
one which is useful and could be implemented with a portable fallback,
let us know.
### Builtins from other compilers
We've looked at GCC, MSVC, and Clang, but we're happy to support
builtins from other compilers, too.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,38 @@
# Assertion Checking
This module provide a variety of assert()-style macros. Unlike the
standard `assert()` macro from `<assert.h>`, most of these macros are
typed so the input values can be propogated to the string output on
failure.
For documentation, µnit offers very similar macros (this module was
originally based off of the macros from µnit), most of
[the documentation for them](https://nemequ.github.io/munit/#assertions)
applies to this module's macros, just substitute the `munit_` namespace
with `psnip_`.
Additionally, unless you define `PSNIP_CHECK_FAIL_DEFINED`, a failing
assertion should be considered undefined behavior when `NDEBUG` and/or
`PSNIP_NDEBUG` is defined. This allows the compiler to perform
optimizations which would not otherwise be possible.
## Dependencies
To maximize portability you should #include the exact-int module
before including check.h, but if you don't want to add the extra
file to your project you can omit it and this module will simply rely
on <stdint.h>. As an alternative you may define the following macros
to appropriate values yourself:
* `psnip_int8_t`
* `psnip_uint8_t`
* `psnip_int16_t`
* `psnip_uint16_t`
* `psnip_int32_t`
* `psnip_uint32_t`
* `psnip_int64_t`
* `psnip_uint64_t`
Including [Hedley](https://nemequ.github.io/hedley/) before check.h
will significantly improve compiler support and may improve
performance.

View file

@ -0,0 +1,376 @@
/* Check (assertions)
* Portable Snippets - https://github.com/nemequ/portable-snippets
* Created by Evan Nemerson <evan@nemerson.com>
*
* To the extent possible under law, the authors have waived all
* copyright and related or neighboring rights to this code. For
* details, see the Creative Commons Zero 1.0 Universal license at
* https://creativecommons.org/publicdomain/zero/1.0/
*/
#if !defined(PSNIP_CHECK_H)
#define PSNIP_CHECK_H
#if !defined(PSNIP_NDEBUG) && defined(NDEBUG) && !defined(PSNIP_DEBUG)
# define PSNIP_NDEBUG 1
#endif
#if !defined(PSNIP_CHECK_LIKELY)
# if defined(HEDLEY_LIKELY)
# define PSNIP_CHECK_LIKELY(expr) HEDLEY_LIKELY(expr)
# elif defined(__GNUC__)
# define PSNIP_CHECK_LIKELY(expr) (__builtin_expect(!!(expr), !0))
# else
# define PSNIP_CHECK_LIKELY(expr) (!!(expr))
# endif
#endif
#if !defined(PSNIP_CHECK_UNLIKELY)
# if defined(PSNIP_CHECK_UNLIKELY)
# define PSNIP_CHECK_UNLIKELY(expr) PSNIP_CHECK_UNLIKELY(expr)
# elif defined(__GNUC__)
# define PSNIP_CHECK_UNLIKELY(expr) (__builtin_expect(!!(expr), !!0))
# else
# define PSNIP_CHECK_UNLIKELY(expr) (!!(expr))
# endif
#endif
/* For maximum portability include the exact-int module from
portable snippets. */
#if \
!defined(psnip_uint64_t) || \
!defined(psnip_uint32_t) || \
!defined(psnip_uint16_t) || \
!defined(psnip_uint8_t) || \
!defined(psnip_int64_t) || \
!defined(psnip_int32_t) || \
!defined(psnip_int16_t) || \
!defined(psnip_int8_t)
# include <stdint.h>
# if !defined(psnip_uint64_t)
# define psnip_uint64_t uint64_t
# endif
# if !defined(psnip_uint32_t)
# define psnip_uint32_t uint32_t
# endif
# if !defined(psnip_uint16_t)
# define psnip_uint16_t uint16_t
# endif
# if !defined(psnip_uint8_t)
# define psnip_uint8_t uint8_t
# endif
# if !defined(psnip_int64_t)
# define psnip_int64_t int64_t
# endif
# if !defined(psnip_int32_t)
# define psnip_int32_t int32_t
# endif
# if !defined(psnip_int16_t)
# define psnip_int16_t int16_t
# endif
# if !defined(psnip_int8_t)
# define psnip_int8_t int8_t
# endif
#endif
#if \
!defined(PRIi8) || \
!defined(PRIi16) || \
!defined(PRIi32) || \
!defined(PRIi64) || \
!defined(PRId8) || \
!defined(PRId16) || \
!defined(PRId32) || \
!defined(PRId64) || \
!defined(PRIx8) || \
!defined(PRIx16) || \
!defined(PRIx32) || \
!defined(PRIx64) || \
!defined(PRIu8) || \
!defined(PRIu16) || \
!defined(PRIu32) || \
!defined(PRIu64)
# if defined(_MSC_VER) && (_MSC_VER < 1800)
# if !defined(PRIi8)
# define PRIi8 "i"
# endif
# if !defined(PRIi16)
# define PRIi16 "i"
# endif
# if !defined(PRIi32)
# define PRIi32 "i"
# endif
# if !defined(PRIi64)
# define PRIi64 "I64i"
# endif
# if !defined(PRId8)
# define PRId8 "d"
# endif
# if !defined(PRId16)
# define PRId16 "d"
# endif
# if !defined(PRId32)
# define PRId32 "d"
# endif
# if !defined(PRId64)
# define PRId64 "I64d"
# endif
# if !defined(PRIx8)
# define PRIx8 "x"
# endif
# if !defined(PRIx16)
# define PRIx16 "x"
# endif
# if !defined(PRIx32)
# define PRIx32 "x"
# endif
# if !defined(PRIx64)
# define PRIx64 "I64x"
# endif
# if !defined(PRIu8)
# define PRIu8 "u"
# endif
# if !defined(PRIu16)
# define PRIu16 "u"
# endif
# if !defined(PRIu32)
# define PRIu32 "u"
# endif
# if !defined(PRIu64)
# define PRIu64 "I64u"
# endif
# else
# include <inttypes.h>
# endif
#endif
#if !defined(_WIN32)
# define PSNIP_SIZE_MODIFIER "z"
# define PSNIP_CHAR_MODIFIER "hh"
# define PSNIP_SHORT_MODIFIER "h"
#else
# if defined(_M_X64) || defined(__amd64__)
# define PSNIP_SIZE_MODIFIER "I64"
# else
# define PSNIP_SIZE_MODIFIER ""
# endif
# define PSNIP_CHAR_MODIFIER ""
# define PSNIP_SHORT_MODIFIER ""
#endif
#if defined(_MSC_VER) && (_MSC_VER >= 1500)
# define PSNIP__PUSH_DISABLE_MSVC_C4127 __pragma(warning(push)) __pragma(warning(disable:4127))
# define PSNIP__POP_DISABLE_MSVC_C4127 __pragma(warning(pop))
#else
# define PSNIP__PUSH_DISABLE_MSVC_C4127
# define PSNIP__POP_DISABLE_MSVC_C4127
#endif
#if !defined(psnip_errorf)
# include <stdio.h>
# include <stdlib.h>
# define psnip_errorf(format, ...) (fprintf(stderr, format, __VA_ARGS__), abort())
#endif
#define psnip_error(msg) psnip_errorf("%s", msg)
#if defined(PSNIP_NDEBUG)
# if defined(PSNIP_CHECK_FAIL_DEFINED)
# define psnip_assert(expr)
# else
# if defined(HEDLEY_ASSUME)
# define psnip_assert(expr) HEDLEY_ASSUME(expr)
# elif defined(__GNUC__)
# define psnip_assert(expr) ((void) (!!(expr) ? 1 : (__builtin_unreachable(), 1)))
# elif defined(_MSC_VER)
# define psnip_assert(expr) __assume(expr)
# else
# define psnip_assert(expr)
# endif
# endif
# define psnip_assert_true(expr) psnip_assert(expr)
# define psnip_assert_false(expr) psnip_assert(!(expr))
# define psnip_assert_type_full(prefix, suffix, T, fmt, a, op, b) psnip_assert(((a) op (b)))
# define psnip_assert_double_equal(a, b, precision)
# define psnip_assert_string_equal(a, b)
# define psnip_assert_string_not_equal(a, b)
# define psnip_assert_memory_equal(size, a, b)
# define psnip_assert_memory_not_equal(size, a, b)
#else
# define psnip_assert(expr) \
do { \
if (!PSNIP_CHECK_LIKELY(expr)) { \
psnip_error("assertion failed: " #expr "\n"); \
} \
PSNIP__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
PSNIP__POP_DISABLE_MSVC_C4127
# define psnip_assert_true(expr) \
do { \
if (!PSNIP_CHECK_LIKELY(expr)) { \
psnip_error("assertion failed: " #expr " is not true\n"); \
} \
PSNIP__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
PSNIP__POP_DISABLE_MSVC_C4127
# define psnip_assert_false(expr) \
do { \
if (!PSNIP_CHECK_LIKELY(!(expr))) { \
psnip_error("assertion failed: " #expr " is not false\n"); \
} \
PSNIP__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
PSNIP__POP_DISABLE_MSVC_C4127
# define psnip_assert_type_full(prefix, suffix, T, fmt, a, op, b) \
do { \
T psnip_tmp_a_ = (a); \
T psnip_tmp_b_ = (b); \
if (!(psnip_tmp_a_ op psnip_tmp_b_)) { \
psnip_errorf("assertion failed: %s %s %s (" prefix "%" fmt suffix " %s " prefix "%" fmt suffix ")\n", \
#a, #op, #b, psnip_tmp_a_, #op, psnip_tmp_b_); \
} \
PSNIP__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
PSNIP__POP_DISABLE_MSVC_C4127
# define psnip_assert_double_equal(a, b, precision) \
do { \
const double psnip_tmp_a_ = (a); \
const double psnip_tmp_b_ = (b); \
const double psnip_tmp_diff_ = ((psnip_tmp_a_ - psnip_tmp_b_) < 0) ? \
-(psnip_tmp_a_ - psnip_tmp_b_) : \
(psnip_tmp_a_ - psnip_tmp_b_); \
if (PSNIP_CHECK_UNLIKELY(psnip_tmp_diff_ > 1e-##precision)) { \
psnip_errorf("assertion failed: %s == %s (%0." #precision "g == %0." #precision "g)\n", \
#a, #b, psnip_tmp_a_, psnip_tmp_b_); \
} \
PSNIP__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
PSNIP__POP_DISABLE_MSVC_C4127
# include <string.h>
# define psnip_assert_string_equal(a, b) \
do { \
const char* psnip_tmp_a_ = a; \
const char* psnip_tmp_b_ = b; \
if (PSNIP_CHECK_UNLIKELY(strcmp(psnip_tmp_a_, psnip_tmp_b_) != 0)) { \
psnip_errorf("assertion failed: string %s == %s (\"%s\" == \"%s\")\n", \
#a, #b, psnip_tmp_a_, psnip_tmp_b_); \
} \
PSNIP__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
PSNIP__POP_DISABLE_MSVC_C4127
# define psnip_assert_string_not_equal(a, b) \
do { \
const char* psnip_tmp_a_ = a; \
const char* psnip_tmp_b_ = b; \
if (PSNIP_CHECK_UNLIKELY(strcmp(psnip_tmp_a_, psnip_tmp_b_) == 0)) { \
psnip_errorf("assertion failed: string %s != %s (\"%s\" == \"%s\")\n", \
#a, #b, psnip_tmp_a_, psnip_tmp_b_); \
} \
PSNIP__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
PSNIP__POP_DISABLE_MSVC_C4127
# define psnip_assert_memory_equal(size, a, b) \
do { \
const unsigned char* psnip_tmp_a_ = (const unsigned char*) (a); \
const unsigned char* psnip_tmp_b_ = (const unsigned char*) (b); \
const size_t psnip_tmp_size_ = (size); \
if (PSNIP_CHECK_UNLIKELY(memcmp(psnip_tmp_a_, psnip_tmp_b_, psnip_tmp_size_)) != 0) { \
size_t psnip_tmp_pos_; \
for (psnip_tmp_pos_ = 0 ; psnip_tmp_pos_ < psnip_tmp_size_ ; psnip_tmp_pos_++) { \
if (psnip_tmp_a_[psnip_tmp_pos_] != psnip_tmp_b_[psnip_tmp_pos_]) { \
psnip_errorf("assertion failed: memory %s == %s, at offset %" PSNIP_SIZE_MODIFIER "u\n", \
#a, #b, psnip_tmp_pos_); \
break; \
} \
} \
} \
PSNIP__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
PSNIP__POP_DISABLE_MSVC_C4127
# define psnip_assert_memory_not_equal(size, a, b) \
do { \
const unsigned char* psnip_tmp_a_ = (const unsigned char*) (a); \
const unsigned char* psnip_tmp_b_ = (const unsigned char*) (b); \
const size_t psnip_tmp_size_ = (size); \
if (PSNIP_CHECK_UNLIKELY(memcmp(psnip_tmp_a_, psnip_tmp_b_, psnip_tmp_size_)) == 0) { \
psnip_errorf("assertion failed: memory %s != %s (%" PSNIP_SIZE_MODIFIER "u bytes)\n", \
#a, #b, psnip_tmp_size_); \
} \
PSNIP__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
PSNIP__POP_DISABLE_MSVC_C4127
#endif
#define psnip_assert_type(T, fmt, a, op, b) \
psnip_assert_type_full("", "", T, fmt, a, op, b)
#define psnip_assert_char(a, op, b) \
psnip_assert_type_full("'\\x", "'", char, "02" PSNIP_CHAR_MODIFIER "x", a, op, b)
#define psnip_assert_uchar(a, op, b) \
psnip_assert_type_full("'\\x", "'", unsigned char, "02" PSNIP_CHAR_MODIFIER "x", a, op, b)
#define psnip_assert_short(a, op, b) \
psnip_assert_type(short, PSNIP_SHORT_MODIFIER "d", a, op, b)
#define psnip_assert_ushort(a, op, b) \
psnip_assert_type(unsigned short, PSNIP_SHORT_MODIFIER "u", a, op, b)
#define psnip_assert_int(a, op, b) \
psnip_assert_type(int, "d", a, op, b)
#define psnip_assert_uint(a, op, b) \
psnip_assert_type(unsigned int, "u", a, op, b)
#define psnip_assert_long(a, op, b) \
psnip_assert_type(long int, "ld", a, op, b)
#define psnip_assert_ulong(a, op, b) \
psnip_assert_type(unsigned long int, "lu", a, op, b)
#define psnip_assert_llong(a, op, b) \
psnip_assert_type(long long int, "lld", a, op, b)
#define psnip_assert_ullong(a, op, b) \
psnip_assert_type(unsigned long long int, "llu", a, op, b)
#define psnip_assert_size(a, op, b) \
psnip_assert_type(size_t, PSNIP_SIZE_MODIFIER "u", a, op, b)
#define psnip_assert_float(a, op, b) \
psnip_assert_type(float, "f", a, op, b)
#define psnip_assert_double(a, op, b) \
psnip_assert_type(double, "g", a, op, b)
#define psnip_assert_ptr(a, op, b) \
psnip_assert_type(const void*, "p", a, op, b)
#define psnip_assert_int8(a, op, b) \
psnip_assert_type(psnip_int8_t, PRIi8, a, op, b)
#define psnip_assert_uint8(a, op, b) \
psnip_assert_type(psnip_uint8_t, PRIu8, a, op, b)
#define psnip_assert_int16(a, op, b) \
psnip_assert_type(psnip_int16_t, PRIi16, a, op, b)
#define psnip_assert_uint16(a, op, b) \
psnip_assert_type(psnip_uint16_t, PRIu16, a, op, b)
#define psnip_assert_int32(a, op, b) \
psnip_assert_type(psnip_int32_t, PRIi32, a, op, b)
#define psnip_assert_uint32(a, op, b) \
psnip_assert_type(psnip_uint32_t, PRIu32, a, op, b)
#define psnip_assert_int64(a, op, b) \
psnip_assert_type(psnip_int64_t, PRIi64, a, op, b)
#define psnip_assert_uint64(a, op, b) \
psnip_assert_type(psnip_uint64_t, PRIu64, a, op, b)
#define psnip_assert_ptr_equal(a, b) \
psnip_assert_ptr(a, ==, b)
#define psnip_assert_ptr_not_equal(a, b) \
psnip_assert_ptr(a, !=, b)
#define psnip_assert_null(ptr) \
psnip_assert_ptr(ptr, ==, NULL)
#define psnip_assert_not_null(ptr) \
psnip_assert_ptr(ptr, !=, NULL)
#define psnip_assert_ptr_null(ptr) \
psnip_assert_ptr(ptr, ==, NULL)
#define psnip_assert_ptr_not_null(ptr) \
psnip_assert_ptr(ptr, !=, NULL)
#endif /* !defined(PSNIP_CHECK_H) */

View file

@ -0,0 +1,44 @@
# Clock
This header provides a way to access time information. It's basically
a more portable version of `clock_gettime` with fewer supported
clocks. Currently supported clocks are:
* Wall clock
* `clock_gettime`
* `gettimeofday`
* `time`
* CPU clock
* `clock_gettime`
* `GetProcessTimes`
* `getrusage`
* Monotonic clock
* `clock_gettime`
* `mach_absolute_time`
* `QueryPerformanceCounter`
If you are using a platform where a clock isn't provided, please let
us know about it so we can try to figure out how to add support!
On some platforms, `clock_gettime` requires linking to librt. If you
prefer, you can define `PSNIP_CLOCK_NO_LIBRT` prior to including
`clock.h` and `clock_gettime` will only be used on platforms known to
support using `clock_gettime` *without* linking against librt. The
price will likely be lower-resolution CPU and wall clocks, and no
monotonic clock.
Also, if you're compiling in a strict standard mode instead of a mode
with GNU extensions (e.g., -std=c11 instead of -std=gnu11), POSIX
extensions will not be enabled by default so you won't get to use the
`clock_gettime` implementation; to avoid this, you can define
`_POSIX_C_SOURCE` to `199309L` or greater prior to including
`clock.h`, or just define `_GNU_SOURCE`.
## Dependencies
To maximize portability you should #include the exact-int module
before including clock.h, but if you don't want to add the extra
file to your project you can omit it and this module will simply rely
on <stdint.h>. As an alternative you may define `psnip_uint64_t`,
`psnip_uint32_t`, `psnip_int64_t`, `psnip_int32_t` to an appropriate
value yourself before including clock.h.

View file

@ -0,0 +1,464 @@
/* Clocks (v1)
* Portable Snippets - https://github.com/nemequ/portable-snippets
* Created by Evan Nemerson <evan@nemerson.com>
*
* To the extent possible under law, the authors have waived all
* copyright and related or neighboring rights to this code. For
* details, see the Creative Commons Zero 1.0 Universal license at
* https://creativecommons.org/publicdomain/zero/1.0/
*/
#if !defined(PSNIP_CLOCK_H)
#define PSNIP_CLOCK_H
/* For maximum portability include the exact-int module from
portable snippets. */
#if !defined(psnip_uint64_t) || !defined(psnip_int32_t) || \
!defined(psnip_uint32_t) || !defined(psnip_int32_t)
# include <stdint.h>
# if !defined(psnip_int64_t)
# define psnip_int64_t int64_t
# endif
# if !defined(psnip_uint64_t)
# define psnip_uint64_t uint64_t
# endif
# if !defined(psnip_int32_t)
# define psnip_int32_t int32_t
# endif
# if !defined(psnip_uint32_t)
# define psnip_uint32_t uint32_t
# endif
#endif
#if !defined(PSNIP_CLOCK_STATIC_INLINE)
# if defined(__GNUC__)
# define PSNIP_CLOCK__COMPILER_ATTRIBUTES __attribute__((__unused__))
# else
# define PSNIP_CLOCK__COMPILER_ATTRIBUTES
# endif
# define PSNIP_CLOCK__FUNCTION PSNIP_CLOCK__COMPILER_ATTRIBUTES static
#endif
enum PsnipClockType {
/* This clock provides the current time, in units since 1970-01-01
* 00:00:00 UTC not including leap seconds. In other words, UNIX
* time. Keep in mind that this clock doesn't account for leap
* seconds, and can go backwards (think NTP adjustments). */
PSNIP_CLOCK_TYPE_WALL = 1,
/* The CPU time is a clock which increases only when the current
* process is active (i.e., it doesn't increment while blocking on
* I/O). */
PSNIP_CLOCK_TYPE_CPU = 2,
/* Monotonic time is always running (unlike CPU time), but it only
ever moves forward unless you reboot the system. Things like NTP
adjustments have no effect on this clock. */
PSNIP_CLOCK_TYPE_MONOTONIC = 3
};
struct PsnipClockTimespec {
psnip_uint64_t seconds;
psnip_uint64_t nanoseconds;
};
/* Methods we support: */
#define PSNIP_CLOCK_METHOD_CLOCK_GETTIME 1
#define PSNIP_CLOCK_METHOD_TIME 2
#define PSNIP_CLOCK_METHOD_GETTIMEOFDAY 3
#define PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER 4
#define PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME 5
#define PSNIP_CLOCK_METHOD_CLOCK 6
#define PSNIP_CLOCK_METHOD_GETPROCESSTIMES 7
#define PSNIP_CLOCK_METHOD_GETRUSAGE 8
#define PSNIP_CLOCK_METHOD_GETSYSTEMTIMEPRECISEASFILETIME 9
#define PSNIP_CLOCK_METHOD_GETTICKCOUNT64 10
#include <assert.h>
#if defined(HEDLEY_UNREACHABLE)
# define PSNIP_CLOCK_UNREACHABLE() HEDLEY_UNREACHABLE()
#else
# define PSNIP_CLOCK_UNREACHABLE() assert(0)
#endif
/* Choose an implementation */
/* #undef PSNIP_CLOCK_WALL_METHOD */
/* #undef PSNIP_CLOCK_CPU_METHOD */
/* #undef PSNIP_CLOCK_MONOTONIC_METHOD */
/* We want to be able to detect the libc implementation, so we include
<limits.h> (<features.h> isn't available everywhere). */
#if defined(__unix__) || defined(__unix) || defined(__linux__)
# include <limits.h>
# include <unistd.h>
#endif
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
/* glibc 2.17+ and FreeBSD are known to work without librt. If you
* know of others please let us know so we can add them. */
# if \
(defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17))) || \
(defined(__FreeBSD__)) || \
!defined(PSNIP_CLOCK_NO_LIBRT)
/* Even though glibc unconditionally sets _POSIX_TIMERS, it doesn't
actually declare the relevant APIs unless _POSIX_C_SOURCE >=
199309L, and if you compile in standard C mode (e.g., c11 instead
of gnu11) _POSIX_C_SOURCE will be unset by default. */
# if _POSIX_C_SOURCE >= 199309L
# define PSNIP_CLOCK_HAVE_CLOCK_GETTIME
# endif
# endif
#endif
#if defined(_WIN32)
# if !defined(PSNIP_CLOCK_CPU_METHOD)
# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_GETPROCESSTIMES
# endif
# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER
# endif
#endif
#if defined(__MACH__) && !defined(__gnu_hurd__)
# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME
# endif
#endif
#if defined(PSNIP_CLOCK_HAVE_CLOCK_GETTIME)
# include <time.h>
# if !defined(PSNIP_CLOCK_WALL_METHOD)
# if defined(CLOCK_REALTIME_PRECISE)
# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
# define PSNIP_CLOCK_CLOCK_GETTIME_WALL CLOCK_REALTIME_PRECISE
# elif !defined(__sun)
# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
# define PSNIP_CLOCK_CLOCK_GETTIME_WALL CLOCK_REALTIME
# endif
# endif
# if !defined(PSNIP_CLOCK_CPU_METHOD)
# if defined(_POSIX_CPUTIME) || defined(CLOCK_PROCESS_CPUTIME_ID)
# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
# define PSNIP_CLOCK_CLOCK_GETTIME_CPU CLOCK_PROCESS_CPUTIME_ID
# elif defined(CLOCK_VIRTUAL)
# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
# define PSNIP_CLOCK_CLOCK_GETTIME_CPU CLOCK_VIRTUAL
# endif
# endif
# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
# if defined(_POSIX_MONOTONIC_CLOCK) || defined(CLOCK_MONOTONIC)
# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
# define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC
# endif
# endif
#endif
#if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200112L)
# if !defined(PSNIP_CLOCK_WALL_METHOD)
# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_GETTIMEOFDAY
# endif
#endif
#if !defined(PSNIP_CLOCK_WALL_METHOD)
# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_TIME
#endif
#if !defined(PSNIP_CLOCK_CPU_METHOD)
# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK
#endif
/* Primarily here for testing. */
#if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) && defined(PSNIP_CLOCK_REQUIRE_MONOTONIC)
# error No monotonic clock found.
#endif
/* Implementations */
#if \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) || \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_TIME)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_TIME))
# include <time.h>
#endif
#if \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY))
# include <sys/time.h>
#endif
#if \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64))
# include <windows.h>
#endif
#if \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE))
# include <sys/time.h>
# include <sys/resource.h>
#endif
#if \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME))
# include <CoreServices/CoreServices.h>
# include <mach/mach.h>
# include <mach/mach_time.h>
#endif
/*** Implementations ***/
#define PSNIP_CLOCK_NSEC_PER_SEC ((psnip_uint32_t) (1000000000ULL))
#if \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME))
PSNIP_CLOCK__FUNCTION psnip_uint32_t
psnip_clock__clock_getres (clockid_t clk_id) {
struct timespec res;
int r;
r = clock_getres(clk_id, &res);
if (r != 0)
return 0;
return (psnip_uint32_t) (PSNIP_CLOCK_NSEC_PER_SEC / res.tv_nsec);
}
PSNIP_CLOCK__FUNCTION int
psnip_clock__clock_gettime (clockid_t clk_id, struct PsnipClockTimespec* res) {
struct timespec ts;
if (clock_gettime(clk_id, &ts) != 0)
return -10;
res->seconds = (psnip_uint64_t) (ts.tv_sec);
res->nanoseconds = (psnip_uint64_t) (ts.tv_nsec);
return 0;
}
#endif
PSNIP_CLOCK__FUNCTION psnip_uint32_t
psnip_clock_wall_get_precision (void) {
#if !defined(PSNIP_CLOCK_WALL_METHOD)
return 0;
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_WALL);
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY
return 1000000;
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME
return 1;
#else
return 0;
#endif
}
PSNIP_CLOCK__FUNCTION int
psnip_clock_wall_get_time (struct PsnipClockTimespec* res) {
(void) res;
#if !defined(PSNIP_CLOCK_WALL_METHOD)
return -2;
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_WALL, res);
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME
res->seconds = time(NULL);
res->nanoseconds = 0;
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY
struct timeval tv;
if (gettimeofday(&tv, NULL) != 0)
return -6;
res->seconds = tv.tv_sec;
res->nanoseconds = tv.tv_usec * 1000;
#else
return -2;
#endif
return 0;
}
PSNIP_CLOCK__FUNCTION psnip_uint32_t
psnip_clock_cpu_get_precision (void) {
#if !defined(PSNIP_CLOCK_CPU_METHOD)
return 0;
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_CPU);
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK
return CLOCKS_PER_SEC;
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES
return PSNIP_CLOCK_NSEC_PER_SEC / 100;
#else
return 0;
#endif
}
PSNIP_CLOCK__FUNCTION int
psnip_clock_cpu_get_time (struct PsnipClockTimespec* res) {
#if !defined(PSNIP_CLOCK_CPU_METHOD)
(void) res;
return -2;
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_CPU, res);
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK
clock_t t = clock();
if (t == ((clock_t) -1))
return -5;
res->seconds = t / CLOCKS_PER_SEC;
res->nanoseconds = (t % CLOCKS_PER_SEC) * (PSNIP_CLOCK_NSEC_PER_SEC / CLOCKS_PER_SEC);
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES
FILETIME CreationTime, ExitTime, KernelTime, UserTime;
LARGE_INTEGER date, adjust;
if (!GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, &KernelTime, &UserTime))
return -7;
/* http://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ */
date.HighPart = UserTime.dwHighDateTime;
date.LowPart = UserTime.dwLowDateTime;
adjust.QuadPart = 11644473600000 * 10000;
date.QuadPart -= adjust.QuadPart;
res->seconds = date.QuadPart / 10000000;
res->nanoseconds = (date.QuadPart % 10000000) * (PSNIP_CLOCK_NSEC_PER_SEC / 100);
#elif PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE
struct rusage usage;
if (getrusage(RUSAGE_SELF, &usage) != 0)
return -8;
res->seconds = usage.ru_utime.tv_sec;
res->nanoseconds = tv.tv_usec * 1000;
#else
(void) res;
return -2;
#endif
return 0;
}
PSNIP_CLOCK__FUNCTION psnip_uint32_t
psnip_clock_monotonic_get_precision (void) {
#if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
return 0;
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC);
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME
static mach_timebase_info_data_t tbi = { 0, };
if (tbi.denom == 0)
mach_timebase_info(&tbi);
return (psnip_uint32_t) (tbi.numer / tbi.denom);
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64
return 1000;
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER
LARGE_INTEGER Frequency;
QueryPerformanceFrequency(&Frequency);
return (psnip_uint32_t) ((Frequency.QuadPart > PSNIP_CLOCK_NSEC_PER_SEC) ? PSNIP_CLOCK_NSEC_PER_SEC : Frequency.QuadPart);
#else
return 0;
#endif
}
PSNIP_CLOCK__FUNCTION int
psnip_clock_monotonic_get_time (struct PsnipClockTimespec* res) {
#if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
(void) res;
return -2;
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC, res);
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME
psnip_uint64_t nsec = mach_absolute_time();
static mach_timebase_info_data_t tbi = { 0, };
if (tbi.denom == 0)
mach_timebase_info(&tbi);
nsec *= ((psnip_uint64_t) tbi.numer) / ((psnip_uint64_t) tbi.denom);
res->seconds = nsec / PSNIP_CLOCK_NSEC_PER_SEC;
res->nanoseconds = nsec % PSNIP_CLOCK_NSEC_PER_SEC;
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER
LARGE_INTEGER t, f;
if (QueryPerformanceCounter(&t) == 0)
return -12;
QueryPerformanceFrequency(&f);
res->seconds = t.QuadPart / f.QuadPart;
res->nanoseconds = t.QuadPart % f.QuadPart;
if (f.QuadPart > PSNIP_CLOCK_NSEC_PER_SEC)
res->nanoseconds /= f.QuadPart / PSNIP_CLOCK_NSEC_PER_SEC;
else
res->nanoseconds *= PSNIP_CLOCK_NSEC_PER_SEC / f.QuadPart;
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64
const ULONGLONG msec = GetTickCount64();
res->seconds = msec / 1000;
res->nanoseconds = sec % 1000;
#else
return -2;
#endif
return 0;
}
/* Returns the number of ticks per second for the specified clock.
* For example, a clock with millisecond precision would return 1000,
* and a clock with 1 second (such as the time() function) would
* return 1.
*
* If the requested clock isn't available, it will return 0.
* Hopefully this will be rare, but if it happens to you please let us
* know so we can work on finding a way to support your system.
*
* Note that different clocks on the same system often have a
* different precisions.
*/
PSNIP_CLOCK__FUNCTION psnip_uint32_t
psnip_clock_get_precision (enum PsnipClockType clock_type) {
switch (clock_type) {
case PSNIP_CLOCK_TYPE_MONOTONIC:
return psnip_clock_monotonic_get_precision ();
case PSNIP_CLOCK_TYPE_CPU:
return psnip_clock_cpu_get_precision ();
case PSNIP_CLOCK_TYPE_WALL:
return psnip_clock_wall_get_precision ();
}
PSNIP_CLOCK_UNREACHABLE();
return 0;
}
/* Set the provided timespec to the requested time. Returns 0 on
* success, or a negative value on failure. */
PSNIP_CLOCK__FUNCTION int
psnip_clock_get_time (enum PsnipClockType clock_type, struct PsnipClockTimespec* res) {
assert(res != NULL);
switch (clock_type) {
case PSNIP_CLOCK_TYPE_MONOTONIC:
return psnip_clock_monotonic_get_time (res);
case PSNIP_CLOCK_TYPE_CPU:
return psnip_clock_cpu_get_time (res);
case PSNIP_CLOCK_TYPE_WALL:
return psnip_clock_wall_get_time (res);
}
return -1;
}
#endif /* !defined(PSNIP_CLOCK_H) */

View file

@ -0,0 +1,16 @@
# CPU Information
This module provides an API for querying some CPU features, such as
ISA extension support, that works across multiple architectures and
platforms.
## Dependencies
This module requires the once portable-snippet module. If you do not
include once.h before cpu.h, cpu.h will automatically include
"../once/once.h". If you include once.h manually you are free to use
whatever directory structure you like.
## Limitations
This code currently only supports x86/x86-64 and ARM.

167
thirdparty/portable-snippets/cpu/cpu.c vendored Normal file
View file

@ -0,0 +1,167 @@
/* CPU Information (v1)
* Portable Snippets - https://github.com/nemequ/portable-snippets
* Created by Evan Nemerson <evan@nemerson.com>
*
* To the extent possible under law, the authors have waived all
* copyright and related or neighboring rights to this code. For
* details, see the Creative Commons Zero 1.0 Universal license at
* https://creativecommons.org/publicdomain/zero/1.0/
*/
#include "cpu.h"
#if !defined(PSNIP_ONCE__H)
# include "../once/once.h"
#endif
#include <assert.h>
#if defined(_WIN32)
# include <Windows.h>
# define PSNIP_CPU__IMPL_WIN32
#elif defined(unix) || defined(__unix__) || defined(__unix)
# include <unistd.h>
# if defined(_SC_NPROCESSORS_ONLN) || defined(_SC_NPROC_ONLN)
# define PSNIP_CPU__IMPL_SYSCONF
# else
# include <sys/sysctl.h>
# endif
#endif
#if defined(PSNIP_CPU_ARCH_X86) || defined(PSNIP_CPU_ARCH_X86_64)
# if defined(_MSC_VER)
static void psnip_cpu_getid(int func, int* data) {
__cpuid(data, func);
}
# else
static void psnip_cpu_getid(int func, int* data) {
__asm__ ("cpuid"
: "=a" (data[0]), "=b" (data[1]), "=c" (data[2]), "=d" (data[3])
: "0" (func), "2" (0));
}
# endif
#elif defined(PSNIP_CPU_ARCH_ARM) || defined(PSNIP_CPU_ARCH_ARM64)
# if (defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 16)))
# define PSNIP_CPU__IMPL_GETAUXVAL
# include <sys/auxv.h>
# endif
#endif
static psnip_once psnip_cpu_once = PSNIP_ONCE_INIT;
#if defined(PSNIP_CPU_ARCH_X86) || defined(PSNIP_CPU_ARCH_X86_64)
static unsigned int psnip_cpuinfo[8 * 4] = { 0, };
#elif defined(PSNIP_CPU_ARCH_ARM) || defined(PSNIP_CPU_ARCH_ARM_64)
static unsigned long psnip_cpuinfo[2] = { 0, };
#endif
static void psnip_cpu_init(void) {
#if defined(PSNIP_CPU_ARCH_X86) || defined(PSNIP_CPU_ARCH_X86_64)
int i;
for (i = 0 ; i < 8 ; i++) {
psnip_cpu_getid(i, (int*) &(psnip_cpuinfo[i * 4]));
}
#elif defined(PSNIP_CPU_ARCH_ARM) || defined(PSNIP_CPU_ARCH_ARM_64)
psnip_cpuinfo[0] = getauxval (AT_HWCAP);
psnip_cpuinfo[1] = getauxval (AT_HWCAP2);
#endif
}
int
psnip_cpu_feature_check (enum PSnipCPUFeature feature) {
#if defined(PSNIP_CPU_ARCH_X86) || defined(PSNIP_CPU_ARCH_X86_64)
unsigned int i, r, b;
#elif defined(PSNIP_CPU_ARCH_ARM) || defined(PSNIP_CPU_ARCH_ARM_64)
unsigned long b, i;
#endif
#if defined(PSNIP_CPU_ARCH_X86) || defined(PSNIP_CPU_ARCH_X86_64)
if ((feature & PSNIP_CPU_FEATURE_CPU_MASK) != PSNIP_CPU_FEATURE_X86)
return 0;
#elif defined(PSNIP_CPU_ARCH_ARM) || defined(PSNIP_CPU_ARCH_ARM_64)
if ((feature & PSNIP_CPU_FEATURE_CPU_MASK) != PSNIP_CPU_FEATURE_ARM)
return 0;
#else
return 0;
#endif
feature &= (enum PSnipCPUFeature) ~PSNIP_CPU_FEATURE_CPU_MASK;
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4152)
#endif
psnip_once_call (&psnip_cpu_once, psnip_cpu_init);
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#if defined(PSNIP_CPU_ARCH_X86) || defined(PSNIP_CPU_ARCH_X86_64)
i = (feature >> 16) & 0xff;
r = (feature >> 8) & 0xff;
b = (feature ) & 0xff;
if (i > 7 || r > 3 || b > 31)
return 0;
return (psnip_cpuinfo[(i * 4) + r] >> b) & 1;
#elif defined(PSNIP_CPU_ARCH_ARM) || defined(PSNIP_CPU_ARCH_ARM_64)
b = 1 << ((feature & 0xff) - 1);
i = psnip_cpuinfo[(feature >> 0x08) & 0xff];
return (psnip_cpuinfo[(feature >> 0x08) & 0xff] & b) == b;
#endif
}
int
psnip_cpu_feature_check_many (enum PSnipCPUFeature* feature) {
int n;
for (n = 0 ; feature[n] != PSNIP_CPU_FEATURE_NONE ; n++)
if (!psnip_cpu_feature_check(feature[n]))
return 0;
return 1;
}
int
psnip_cpu_count (void) {
static int count = 0;
int c;
#if defined(_WIN32)
DWORD_PTR lpProcessAffinityMask;
DWORD_PTR lpSystemAffinityMask;
int i;
#elif defined(PSNIP_CPU__IMPL_SYSCONF) && defined(HW_NCPU)
int mib[2];
size_t len;
#endif
if (count != 0)
return count;
#if defined(_WIN32)
if (!GetProcessAffinityMask(GetCurrentProcess(), &lpProcessAffinityMask, &lpSystemAffinityMask)) {
c = -1;
} else {
c = 0;
for (i = 0 ; lpProcessAffinityMask != 0 ; lpProcessAffinityMask >>= 1)
c += lpProcessAffinityMask & 1;
}
#elif defined(_SC_NPROCESSORS_ONLN)
c = sysconf (_SC_NPROCESSORS_ONLN);
#elif defined(_SC_NPROC_ONLN)
c = sysconf (_SC_NPROC_ONLN);
#elif defined(_hpux)
c = mpctl(MPC_GETNUMSPUS, NULL, NULL);
#elif defined(HW_NCPU)
c = 0;
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
len = sizeof(c);
sysctl (mib, 2, &c, &len, NULL, 0);
#endif
count = (c > 0) ? c : -1;
return count;
}

190
thirdparty/portable-snippets/cpu/cpu.h vendored Normal file
View file

@ -0,0 +1,190 @@
/* CPU Information (v1)
* Portable Snippets - https://github.com/nemequ/portable-snippets
* Created by Evan Nemerson <evan@nemerson.com>
*
* To the extent possible under law, the authors have waived all
* copyright and related or neighboring rights to this code. For
* details, see the Creative Commons Zero 1.0 Universal license at
* https://creativecommons.org/publicdomain/zero/1.0/
*/
#if !defined(PSNIP_CPU__H)
#define PSNIP_CPU__H
#if defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
# define PSNIP_CPU_ARCH_X86_64
#elif defined(__i686__) || defined(__i586__) || defined(__i486__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_X86_) || defined(__THW_INTEL__)
# define PSNIP_CPU_ARCH_X86
#elif defined(__arm__) || defined(_M_ARM)
# define PSNIP_CPU_ARCH_ARM
#elif defined(__aarch64__)
# define PSNIP_CPU_ARCH_ARM64
#endif
#if defined(__cplusplus)
extern "C" {
#endif
enum PSnipCPUFeature {
PSNIP_CPU_FEATURE_NONE = 0,
PSNIP_CPU_FEATURE_CPU_MASK = 0x1f000000,
PSNIP_CPU_FEATURE_X86 = 0x01000000,
PSNIP_CPU_FEATURE_ARM = 0x04000000,
/* x86 CPU features are constructed as:
*
* (PSNIP_CPU_FEATURE_X86 | (eax << 16) | (ret_reg << 8) | (bit_position)
*
* For example, SSE3 is determined by the fist bit in the ECX
* register for a CPUID call with EAX=1, so we get:
*
* PSNIP_CPU_FEATURE_X86 | (1 << 16) | (2 << 8) | (0) = 0x01010200
*
* We should have information for inputs of EAX=0-7 w/ ECX=0.
*/
PSNIP_CPU_FEATURE_X86_FPU = 0x01010300,
PSNIP_CPU_FEATURE_X86_VME = 0x01010301,
PSNIP_CPU_FEATURE_X86_DE = 0x01010302,
PSNIP_CPU_FEATURE_X86_PSE = 0x01010303,
PSNIP_CPU_FEATURE_X86_TSC = 0x01010304,
PSNIP_CPU_FEATURE_X86_MSR = 0x01010305,
PSNIP_CPU_FEATURE_X86_PAE = 0x01010306,
PSNIP_CPU_FEATURE_X86_MCE = 0x01010307,
PSNIP_CPU_FEATURE_X86_CX8 = 0x01010308,
PSNIP_CPU_FEATURE_X86_APIC = 0x01010309,
PSNIP_CPU_FEATURE_X86_SEP = 0x0101030b,
PSNIP_CPU_FEATURE_X86_MTRR = 0x0101030c,
PSNIP_CPU_FEATURE_X86_PGE = 0x0101030d,
PSNIP_CPU_FEATURE_X86_MCA = 0x0101030e,
PSNIP_CPU_FEATURE_X86_CMOV = 0x0101030f,
PSNIP_CPU_FEATURE_X86_PAT = 0x01010310,
PSNIP_CPU_FEATURE_X86_PSE_36 = 0x01010311,
PSNIP_CPU_FEATURE_X86_PSN = 0x01010312,
PSNIP_CPU_FEATURE_X86_CLFSH = 0x01010313,
PSNIP_CPU_FEATURE_X86_DS = 0x01010314,
PSNIP_CPU_FEATURE_X86_ACPI = 0x01010316,
PSNIP_CPU_FEATURE_X86_MMX = 0x01010317,
PSNIP_CPU_FEATURE_X86_FXSR = 0x01010318,
PSNIP_CPU_FEATURE_X86_SSE = 0x01010319,
PSNIP_CPU_FEATURE_X86_SSE2 = 0x0101031a,
PSNIP_CPU_FEATURE_X86_SS = 0x0101031b,
PSNIP_CPU_FEATURE_X86_HTT = 0x0101031c,
PSNIP_CPU_FEATURE_X86_TM = 0x0101031d,
PSNIP_CPU_FEATURE_X86_IA64 = 0x0101031e,
PSNIP_CPU_FEATURE_X86_PBE = 0x0101031f,
PSNIP_CPU_FEATURE_X86_SSE3 = 0x01010200,
PSNIP_CPU_FEATURE_X86_PCLMULQDQ = 0x01010201,
PSNIP_CPU_FEATURE_X86_DTES64 = 0x01010202,
PSNIP_CPU_FEATURE_X86_MONITOR = 0x01010203,
PSNIP_CPU_FEATURE_X86_DS_CPL = 0x01010204,
PSNIP_CPU_FEATURE_X86_VMX = 0x01010205,
PSNIP_CPU_FEATURE_X86_SMX = 0x01010206,
PSNIP_CPU_FEATURE_X86_EST = 0x01010207,
PSNIP_CPU_FEATURE_X86_TM2 = 0x01010208,
PSNIP_CPU_FEATURE_X86_SSSE3 = 0x01010209,
PSNIP_CPU_FEATURE_X86_CNXT_ID = 0x0101020a,
PSNIP_CPU_FEATURE_X86_SDBG = 0x0101020b,
PSNIP_CPU_FEATURE_X86_FMA = 0x0101020c,
PSNIP_CPU_FEATURE_X86_CX16 = 0x0101020d,
PSNIP_CPU_FEATURE_X86_XTPR = 0x0101020e,
PSNIP_CPU_FEATURE_X86_PDCM = 0x0101020f,
PSNIP_CPU_FEATURE_X86_PCID = 0x01010211,
PSNIP_CPU_FEATURE_X86_DCA = 0x01010212,
PSNIP_CPU_FEATURE_X86_SSE4_1 = 0x01010213,
PSNIP_CPU_FEATURE_X86_SSE4_2 = 0x01010214,
PSNIP_CPU_FEATURE_X86_X2APIC = 0x01010215,
PSNIP_CPU_FEATURE_X86_MOVBE = 0x01010216,
PSNIP_CPU_FEATURE_X86_POPCNT = 0x01010217,
PSNIP_CPU_FEATURE_X86_TSC_DEADLINE = 0x01010218,
PSNIP_CPU_FEATURE_X86_AES = 0x01010219,
PSNIP_CPU_FEATURE_X86_XSAVE = 0x0101021a,
PSNIP_CPU_FEATURE_X86_OSXSAVE = 0x0101021b,
PSNIP_CPU_FEATURE_X86_AVX = 0x0101021c,
PSNIP_CPU_FEATURE_X86_F16C = 0x0101021d,
PSNIP_CPU_FEATURE_X86_RDRND = 0x0101021e,
PSNIP_CPU_FEATURE_X86_HYPERVISOR = 0x0101021f,
PSNIP_CPU_FEATURE_X86_FSGSBASE = 0x01070100,
PSNIP_CPU_FEATURE_X86_TSC_ADJ = 0x01070101,
PSNIP_CPU_FEATURE_X86_SGX = 0x01070102,
PSNIP_CPU_FEATURE_X86_BMI1 = 0x01070103,
PSNIP_CPU_FEATURE_X86_HLE = 0x01070104,
PSNIP_CPU_FEATURE_X86_AVX2 = 0x01070105,
PSNIP_CPU_FEATURE_X86_SMEP = 0x01070107,
PSNIP_CPU_FEATURE_X86_BMI2 = 0x01070108,
PSNIP_CPU_FEATURE_X86_ERMS = 0x01070109,
PSNIP_CPU_FEATURE_X86_INVPCID = 0x0107010a,
PSNIP_CPU_FEATURE_X86_RTM = 0x0107010b,
PSNIP_CPU_FEATURE_X86_PQM = 0x0107010c,
PSNIP_CPU_FEATURE_X86_MPX = 0x0107010e,
PSNIP_CPU_FEATURE_X86_PQE = 0x0107010f,
PSNIP_CPU_FEATURE_X86_AVX512F = 0x01070110,
PSNIP_CPU_FEATURE_X86_AVX512DQ = 0x01070111,
PSNIP_CPU_FEATURE_X86_RDSEED = 0x01070112,
PSNIP_CPU_FEATURE_X86_ADX = 0x01070113,
PSNIP_CPU_FEATURE_X86_SMAP = 0x01070114,
PSNIP_CPU_FEATURE_X86_AVX512IFMA = 0x01070115,
PSNIP_CPU_FEATURE_X86_PCOMMIT = 0x01070116,
PSNIP_CPU_FEATURE_X86_CLFLUSHOPT = 0x01070117,
PSNIP_CPU_FEATURE_X86_CLWB = 0x01070118,
PSNIP_CPU_FEATURE_X86_INTEL_PT = 0x01070119,
PSNIP_CPU_FEATURE_X86_AVX512PF = 0x0107011a,
PSNIP_CPU_FEATURE_X86_AVX512ER = 0x0107011b,
PSNIP_CPU_FEATURE_X86_AVX512CD = 0x0107011c,
PSNIP_CPU_FEATURE_X86_SHA = 0x0107011d,
PSNIP_CPU_FEATURE_X86_AVX512BW = 0x0107011e,
PSNIP_CPU_FEATURE_X86_AVX512VL = 0x0107011f,
PSNIP_CPU_FEATURE_X86_PREFETCHWT1 = 0x01070200,
PSNIP_CPU_FEATURE_X86_AVX512VBMI = 0x01070201,
PSNIP_CPU_FEATURE_X86_UMIP = 0x01070202,
PSNIP_CPU_FEATURE_X86_PKU = 0x01070203,
PSNIP_CPU_FEATURE_X86_OSPKE = 0x01070204,
PSNIP_CPU_FEATURE_X86_AVX512VPOPCNTDQ = 0x0107020e,
PSNIP_CPU_FEATURE_X86_RDPID = 0x01070215,
PSNIP_CPU_FEATURE_X86_SGX_LC = 0x0107021e,
PSNIP_CPU_FEATURE_X86_AVX512_4VNNIW = 0x01070302,
PSNIP_CPU_FEATURE_X86_AVX512_4FMAPS = 0x01070303,
PSNIP_CPU_FEATURE_ARM_SWP = PSNIP_CPU_FEATURE_ARM | 1,
PSNIP_CPU_FEATURE_ARM_HALF = PSNIP_CPU_FEATURE_ARM | 2,
PSNIP_CPU_FEATURE_ARM_THUMB = PSNIP_CPU_FEATURE_ARM | 3,
PSNIP_CPU_FEATURE_ARM_26BIT = PSNIP_CPU_FEATURE_ARM | 4,
PSNIP_CPU_FEATURE_ARM_FAST_MULT = PSNIP_CPU_FEATURE_ARM | 5,
PSNIP_CPU_FEATURE_ARM_FPA = PSNIP_CPU_FEATURE_ARM | 6,
PSNIP_CPU_FEATURE_ARM_VFP = PSNIP_CPU_FEATURE_ARM | 7,
PSNIP_CPU_FEATURE_ARM_EDSP = PSNIP_CPU_FEATURE_ARM | 8,
PSNIP_CPU_FEATURE_ARM_JAVA = PSNIP_CPU_FEATURE_ARM | 9,
PSNIP_CPU_FEATURE_ARM_IWMMXT = PSNIP_CPU_FEATURE_ARM | 10,
PSNIP_CPU_FEATURE_ARM_CRUNCH = PSNIP_CPU_FEATURE_ARM | 11,
PSNIP_CPU_FEATURE_ARM_THUMBEE = PSNIP_CPU_FEATURE_ARM | 12,
PSNIP_CPU_FEATURE_ARM_NEON = PSNIP_CPU_FEATURE_ARM | 13,
PSNIP_CPU_FEATURE_ARM_VFPV3 = PSNIP_CPU_FEATURE_ARM | 14,
PSNIP_CPU_FEATURE_ARM_VFPV3D16 = PSNIP_CPU_FEATURE_ARM | 15,
PSNIP_CPU_FEATURE_ARM_TLS = PSNIP_CPU_FEATURE_ARM | 16,
PSNIP_CPU_FEATURE_ARM_VFPV4 = PSNIP_CPU_FEATURE_ARM | 17,
PSNIP_CPU_FEATURE_ARM_IDIVA = PSNIP_CPU_FEATURE_ARM | 18,
PSNIP_CPU_FEATURE_ARM_IDIVT = PSNIP_CPU_FEATURE_ARM | 19,
PSNIP_CPU_FEATURE_ARM_VFPD32 = PSNIP_CPU_FEATURE_ARM | 20,
PSNIP_CPU_FEATURE_ARM_LPAE = PSNIP_CPU_FEATURE_ARM | 21,
PSNIP_CPU_FEATURE_ARM_EVTSTRM = PSNIP_CPU_FEATURE_ARM | 22,
PSNIP_CPU_FEATURE_ARM_AES = PSNIP_CPU_FEATURE_ARM | 0x0100 | 1,
PSNIP_CPU_FEATURE_ARM_PMULL = PSNIP_CPU_FEATURE_ARM | 0x0100 | 2,
PSNIP_CPU_FEATURE_ARM_SHA1 = PSNIP_CPU_FEATURE_ARM | 0x0100 | 3,
PSNIP_CPU_FEATURE_ARM_SHA2 = PSNIP_CPU_FEATURE_ARM | 0x0100 | 4,
PSNIP_CPU_FEATURE_ARM_CRC32 = PSNIP_CPU_FEATURE_ARM | 0x0100 | 5
};
int psnip_cpu_count (void);
int psnip_cpu_feature_check (enum PSnipCPUFeature feature);
int psnip_cpu_feature_check_many (enum PSnipCPUFeature* feature);
#if defined(__cplusplus)
}
#endif
#endif /* PSNIP_CPU__H */

View file

@ -0,0 +1,24 @@
# Debugging assertions and traps
This is an attempt to provide a fairly portable way to generate traps
in code. `__builtin_trap` is `_Noreturn`, so the compiler may optimize
away code found after it, which means you can't really drop into a
debugger and step through the code after the trap has been hit.
If `PSNIP_NDEBUG` is defined, or `NDEBUG` is defined and `PSNIP_DEBUG`
is not, `psnip_dbg_assert(expr)` will be preprocessed to nothing
(i.e., `expr` will not be evaluated). Otherwise it will call
`psnip_trap` if `expr` evaluates to false.
Knowledge about how to do this portably basically comes from:
* [scottt/debugbreak](https://github.com/scottt/debugbreak/).
* GLib's [G_BREAKPOINT](https://developer.gnome.org/glib/stable/glib-Warnings-and-Assertions.html#G-BREAKPOINT:CAPS) macro.
* [TI's Wiki](http://processors.wiki.ti.com/index.php/Software_Breakpoints_in_the_IDE)
* Assorted compiler documentation.
On non-hosted platforms we *may* have to fall back on
`__builtin_trap`. On non-hosted non-GNU-compatible compilers on
relatively exotic architectures you may end up with an error about
stdlib.h being missing... if you have a good way to resolve that on
your platform please contact us.

View file

@ -0,0 +1,83 @@
/* Debugging assertions and traps
* Portable Snippets - https://github.com/nemequ/portable-snippets
* Created by Evan Nemerson <evan@nemerson.com>
*
* To the extent possible under law, the authors have waived all
* copyright and related or neighboring rights to this code. For
* details, see the Creative Commons Zero 1.0 Universal license at
* https://creativecommons.org/publicdomain/zero/1.0/
*/
#if !defined(PSNIP_DEBUG_TRAP_H)
#define PSNIP_DEBUG_TRAP_H
#if !defined(PSNIP_NDEBUG) && defined(NDEBUG) && !defined(PSNIP_DEBUG)
# define PSNIP_NDEBUG 1
#endif
#if defined(__has_builtin) && !defined(__ibmxl__)
# if __has_builtin(__builtin_debugtrap)
# define psnip_trap() __builtin_debugtrap()
# elif __has_builtin(__debugbreak)
# define psnip_trap() __debugbreak()
# endif
#endif
#if !defined(psnip_trap)
# if defined(_MSC_VER) || defined(__INTEL_COMPILER)
# define psnip_trap() __debugbreak()
# elif defined(__ARMCC_VERSION)
# define psnip_trap() __breakpoint(42)
# elif defined(__ibmxl__) || defined(__xlC__)
# include <builtins.h>
# define psnip_trap() __trap(42)
# elif defined(__DMC__) && defined(_M_IX86)
static inline void psnip_trap(void) { __asm int 3h; }
# elif defined(__i386__) || defined(__x86_64__)
static inline void psnip_trap(void) { __asm__ __volatile__("int3"); }
# elif defined(__thumb__)
static inline void psnip_trap(void) { __asm__ __volatile__(".inst 0xde01"); }
# elif defined(__aarch64__)
static inline void psnip_trap(void) { __asm__ __volatile__(".inst 0xd4200000"); }
# elif defined(__arm__)
static inline void psnip_trap(void) { __asm__ __volatile__(".inst 0xe7f001f0"); }
# elif defined (__alpha__) && !defined(__osf__)
static inline void psnip_trap(void) { __asm__ __volatile__("bpt"); }
# elif defined(_54_)
static inline void psnip_trap(void) { __asm__ __volatile__("ESTOP"); }
# elif defined(_55_)
static inline void psnip_trap(void) { __asm__ __volatile__(";\n .if (.MNEMONIC)\n ESTOP_1\n .else\n ESTOP_1()\n .endif\n NOP"); }
# elif defined(_64P_)
static inline void psnip_trap(void) { __asm__ __volatile__("SWBP 0"); }
# elif defined(_6x_)
static inline void psnip_trap(void) { __asm__ __volatile__("NOP\n .word 0x10000000"); }
# elif defined(__STDC_HOSTED__) && (__STDC_HOSTED__ == 0) && defined(__GNUC__)
# define psnip_trap() __builtin_trap()
# else
# include <signal.h>
# if defined(SIGTRAP)
# define psnip_trap() raise(SIGTRAP)
# else
# define psnip_trap() raise(SIGABRT)
# endif
# endif
#endif
#if defined(HEDLEY_LIKELY)
# define PSNIP_DBG_LIKELY(expr) HEDLEY_LIKELY(expr)
#elif defined(__GNUC__) && (__GNUC__ >= 3)
# define PSNIP_DBG_LIKELY(expr) __builtin_expect(!!(expr), 1)
#else
# define PSNIP_DBG_LIKELY(expr) (!!(expr))
#endif
#if !defined(PSNIP_NDEBUG) || (PSNIP_NDEBUG == 0)
# define psnip_dbg_assert(expr) do { \
if (!PSNIP_DBG_LIKELY(expr)) { \
psnip_trap(); \
} \
} while (0)
#else
# define psnip_dbg_assert(expr)
#endif
#endif /* !defined(PSNIP_DEBUG_TRAP_H) */

View file

@ -0,0 +1,53 @@
# Endianness Detection and Swapping
This header provides a convenient way to detect endianness, and
perform swapping. It provides 6 important functions:
```c
psnip_uint16_t psnip_endian_le16(psnip_uint16_t v);
psnip_uint32_t psnip_endian_le32(psnip_uint32_t v);
psnip_uint64_t psnip_endian_le64(psnip_uint64_t v);
psnip_uint16_t psnip_endian_be16(psnip_uint16_t v);
psnip_uint32_t psnip_endian_be32(psnip_uint32_t v);
psnip_uint64_t psnip_endian_be64(psnip_uint64_t v);
```
These are usually implemented as macros, the prototypes above are
purely for documentation.
These functions will swap byte ordering to or from the provided type
**if necessary**. For example, `psnip_endian_le32` is used to convert
a 32-bit unsigned integer to/from little-endian. If the machine is
little-endian nothing will be done, but if it is big-endian then a
swap will be performed. It's a bit like `hton`/`ntoh`, except instead
of host to/from network order, it's host to/from whatever order you
want.
If you wish to ignore the result of compile-time detection attempts,
you may define `PSNIP_ENDIAN_FORCE_RT` prior to including this header
to force run-time detection.
If you're only interested in detection you can just ignore the
swapping functions mentioned above. If endianness could be determined
at compile-time (i.e., through preprocessor macros),
`PSNIP_ENDIAN_ORDER` will be defined to either `PSNIP_ENDIAN_LITTLE`
or `PSNIP_ENDIAN_BIG`.
If you need (or prefer) to fall back on run-time detection,
`PSNIP_ENDIAN_ORDER_RT` will evaluate to the same values
(`PSNIP_ENDIAN_LITTLE` or `PSNIP_ENDIAN_BIG`). Note that the
"run-time" detection will likely be optimized away by the compiler.
## Dependencies
To maximize portability you should #include the exact-int module
before including endian.h, but if you don't want to add the extra
file to your project you can omit it and this module will simply rely
on <stdint.h>. As an alternative you may define `psnip_uint16_t`,
`psnip_uint32_t`, and `psnip_uint64_t` to appropriate values yourself
before including endian.h.
This module requires the builtin portable-snippet module. If you do
not include builtin.h before endian.h, endian.h will automatically
include "../builtin/builtin.h". If you include builtin.h manually you
are free to use whatever directory structure you like.

View file

@ -0,0 +1,200 @@
/* Endianness detection and swapping (v3)
* Portable Snippets - https://github.com/nemequ/portable-snippets
* Created by Evan Nemerson <evan@nemerson.com>
*
* To the extent possible under law, the authors have waived all
* copyright and related or neighboring rights to this code. For
* details, see the Creative Commons Zero 1.0 Universal license at
* https://creativecommons.org/publicdomain/zero/1.0/
*/
#if !defined(PSNIP_ENDIAN_H)
#define PSNIP_ENDIAN_H
/* For maximum portability include the exact-int module from
portable snippets. */
#if \
!defined(psnip_uint64_t) || \
!defined(psnip_uint32_t) || \
!defined(psnip_uint16_t)
# include <stdint.h>
# if !defined(psnip_uint64_t)
# define psnip_uint64_t uint64_t
# endif
# if !defined(psnip_uint32_t)
# define psnip_uint32_t uint32_t
# endif
# if !defined(psnip_uint16_t)
# define psnip_uint16_t uint16_t
# endif
#endif
#if !defined(PSNIP_BUILTIN_H)
# include "../builtin/builtin.h"
#endif
#if !defined(PSNIP_ENDIAN_STATIC_INLINE)
# if defined(__GNUC__)
# define PSNIP_ENDIAN__COMPILER_ATTRIBUTES __attribute__((__unused__))
# else
# define PSNIP_ENDIAN__COMPILER_ATTRIBUTES
# endif
# if defined(HEDLEY_INLINE)
# define PSNIP_ENDIAN__INLINE HEDLEY_INLINE
# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
# define PSNIP_ENDIAN__INLINE inline
# elif defined(__GNUC_STDC_INLINE__)
# define PSNIP_ENDIAN__INLINE __inline__
# elif defined(_MSC_VER) && _MSC_VER >= 1200
# define PSNIP_ENDIAN__INLINE __inline
# else
# define PSNIP_ENDIAN__INLINE
# endif
# define PSNIP_ENDIAN__FUNCTION PSNIP_ENDIAN__COMPILER_ATTRIBUTES static PSNIP_ENDIAN__INLINE
#endif
#if !defined(PSNIP_ENDIAN_LITTLE)
# define PSNIP_ENDIAN_LITTLE 1234
#endif
#if !defined(PSNIP_ENDIAN_BIG)
# define PSNIP_ENDIAN_BIG 4321
#endif
#if !defined(PSNIP_ENDIAN_PDP)
# define PSNIP_ENDIAN_PDP 3412
#endif
/* Detection
*
* Detecting endianness can be a bit tricky. There isn't really a
* good standard way of determining endianness, and it's actually
* possible to mix endianness within a single program. This is
* currently pretty rare, though.
*
* We try to define PSNIP_ENDIAN_ORDER to PSNIP_ENDIAN_LITTLE,
* PSNIP_ENDIAN_BIG, or PSNIP_ENDIAN_PDP. Additionally, you can use
* the PSNIP_RT_BYTE_ORDER to check the runtime byte order, which is a
* bit more reliable (though it may introduce some runtime overhead).
*
* In the event we are unable to determine endianness at compile-time,
* PSNIP_ENDIAN_ORDER is left undefined and you will be forced to rely
* on PSNIP_RT_BYTE_ORDER. */
#if !defined(PSNIP_ENDIAN_FORCE_RT)
#if !defined(PSNIP_ENDIAN_ORDER)
/* GCC (and compilers masquerading as GCC) define __BYTE_ORDER__. */
# if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_LITTLE
# elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_BIG
# elif defined(__BYTE_ORDER__) && defined(__ORDER_PDP_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_PDP_ENDIAN__)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_PDP
/* TI defines _BIG_ENDIAN or _LITTLE_ENDIAN */
# elif defined(_BIG_ENDIAN)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_BIG
# elif defined(_LITTLE_ENDIAN)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_LITTLE
/* We know the endianness of some common architectures. Common
* architectures not listed (ARM, POWER, MIPS, etc.) here are
* bi-endian. */
# elif defined(__amd64) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_LITTLE
# elif defined(__s390x__) || defined(__zarch__)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_BIG
/* Looks like we'll have to rely on the platform. If we're missing a
* platform, please let us know. */
# elif defined(_WIN32)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_LITTLE
# elif defined(sun) || defined(__sun) /* Solaris */
# include <sys/byteorder.h>
# if defined(_LITTLE_ENDIAN)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_LITTLE
# elif defined(_BIG_ENDIAN)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_BIG
# endif
# elif defined(__APPLE__)
# include <libkern/OSByteOrder.h>
# if defined(__LITTLE_ENDIAN__)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_LITTLE
# elif defined(__BIG_ENDIAN__)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_BIG
# endif
# elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(BSD)
# include <machine/endian.h>
# if defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_LITTLE
# elif defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_BIG
# elif defined(__BYTE_ORDER) && (__BYTE_ORDER == __PDP_ENDIAN)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_PDP
# endif
# elif defined(__linux__) || defined(__linux) || defined(__gnu_linux__)
# include <endian.h>
# if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_LITTLE
# elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_BIG
# elif defined(__BYTE_ORDER) && defined(__PDP_ENDIAN) && (__BYTE_ORDER == __PDP_ENDIAN)
# define PSNIP_ENDIAN_ORDER PSNIP_ENDIAN_PDP
# endif
# endif
#endif
/* PDP endian not yet supported. Patches welcome. */
#if defined(PSNIP_ENDIAN_ORDER) && (PSNIP_ENDIAN_ORDER == PSNIP_ENDIAN_PDP)
# error PDP endian is not supported.
#endif
#endif /* !defined(PSNIP_ENDIAN_FORCE_RT) */
static const union {
unsigned long long value;
unsigned char bytes[4];
} psnip_endian_rt_data = {
1
};
#define PSNIP_ENDIAN_ORDER_RT_IS_LE (psnip_endian_rt_data.bytes[0] == 1)
#define PSNIP_ENDIAN_ORDER_RT_IS_BE (psnip_endian_rt_data.bytes[sizeof(unsigned long long) - 1] == 1)
#define PSNIP_ENDIAN_ORDER_RT (PSNIP_ENDIAN_ORDER_RT_IS_LE ? PSNIP_ENDIAN_LITTLE : PSNIP_ENDIAN_BIG)
#if defined(PSNIP_ENDIAN_FORCE_RT) || !defined(PSNIP_ENDIAN_ORDER)
#define PSNIP_ENDIAN__DEFINE_LE_FUNC(siz) \
PSNIP_ENDIAN__FUNCTION \
psnip_uint##siz##_t psnip_endian_le##siz(psnip_uint##siz##_t v) { \
return PSNIP_ENDIAN_ORDER_RT_IS_LE ? v : psnip_builtin_bswap##siz(v); \
}
#define PSNIP_ENDIAN__DEFINE_BE_FUNC(siz) \
PSNIP_ENDIAN__FUNCTION \
psnip_uint##siz##_t psnip_endian_be##siz(psnip_uint##siz##_t v) { \
return PSNIP_ENDIAN_ORDER_RT_IS_BE ? v : psnip_builtin_bswap##siz(v); \
}
PSNIP_ENDIAN__DEFINE_LE_FUNC(16)
PSNIP_ENDIAN__DEFINE_LE_FUNC(32)
PSNIP_ENDIAN__DEFINE_LE_FUNC(64)
PSNIP_ENDIAN__DEFINE_BE_FUNC(16)
PSNIP_ENDIAN__DEFINE_BE_FUNC(32)
PSNIP_ENDIAN__DEFINE_BE_FUNC(64)
#elif PSNIP_ENDIAN_ORDER == PSNIP_ENDIAN_LITTLE
# define psnip_endian_le16(v) ((psnip_uint16_t) (v))
# define psnip_endian_le32(v) ((psnip_uint32_t) (v))
# define psnip_endian_le64(v) ((psnip_uint64_t) (v))
# define psnip_endian_be16(v) psnip_builtin_bswap16((psnip_uint16_t) (v))
# define psnip_endian_be32(v) psnip_builtin_bswap32((psnip_uint32_t) (v))
# define psnip_endian_be64(v) psnip_builtin_bswap64((psnip_uint64_t) (v))
#elif PSNIP_ENDIAN_ORDER == PSNIP_ENDIAN_BIG
# define psnip_endian_le16(v) psnip_builtin_bswap16((psnip_uint16_t) (v))
# define psnip_endian_le32(v) psnip_builtin_bswap32((psnip_uint32_t) (v))
# define psnip_endian_le64(v) psnip_builtin_bswap64((psnip_uint64_t) (v))
# define psnip_endian_be16(v) ((psnip_uint16_t) (v))
# define psnip_endian_be32(v) ((psnip_uint32_t) (v))
# define psnip_endian_be64(v) ((psnip_uint64_t) (v))
#else
# error Unknown endianness.
#endif
#endif /* !defined(PSNIP_ENDIAN_H) */

View file

@ -0,0 +1,30 @@
# Exact-Width Integer Types
Lots of stuff in psnip (as well as outside of psnip) requires
exact-width integer types. C99 provides them in `<stdint.h>`, but
sometimes you can't rely on C99 being available.
This header will define macros for `psnip_(u)int(8,16,32,64)_t`, using
methods a bit more portable than just blindly including `<stdint.h>`:
* If `__(U)INTN_TYPE__` is defined, use those types.
* On platforms where we know `<stdint.h>` is available (such as if
we're compiling in C99 mode), we include `<stdint.h>`.
* Otherwise, if we're using Visual Studio, use types we know exist.
* If not, use `<limits.h>` to try to find some correctly-size types.
Headers in portable-snippets which use these types will only try to
include `exact-int.h` if they are missing a type they actually use,
which means you're free to create your own definitions for these
types. This should help ensure that, if you already have exact-size
types, portable-snippets will be compatible with them.
If are looking for a more complete portable implementation of
`<stdint.h>` (for example, if you need the `UINT*_C` macros), there
are several projects which aim to provide a more complete
implementation, including:
* [pstdint.h](http://www.azillionmonkeys.com/qed/pstdint.h) (BSD-3)
* [msinttypes](https://code.google.com/archive/p/msinttypes/) (BSD-3)
Feel free to file a PR if I'm missing anything.

View file

@ -0,0 +1,251 @@
/* Exact-width integer types
* Portable Snippets - https://github.com/nemequ/portable-snippets
* Created by Evan Nemerson <evan@nemerson.com>
*
* To the extent possible under law, the authors have waived all
* copyright and related or neighboring rights to this code. For
* details, see the Creative Commons Zero 1.0 Universal license at
* https://creativecommons.org/publicdomain/zero/1.0/
*
* This header tries to define psnip_(u)int(8|16|32|64)_t to
* appropriate types given your system. For most systems this means
* including <stdint.h> and adding a few preprocessor definitions, but
* when that isn't an option things get a bit more complicated.
*/
#if !defined(PSNIP_EXACT_INT_H)
# define PSNIP_EXACT_INT_H
# if defined(psnip_int8_t)
# undef psnip_int8_t
# endif
# if defined(psnip_uint8_t)
# undef psnip_uint8_t
# endif
# if defined(psnip_int16_t)
# undef psnip_int16_t
# endif
# if defined(psnip_uint16_t)
# undef psnip_uint16_t
# endif
# if defined(psnip_int32_t)
# undef psnip_int32_t
# endif
# if defined(psnip_uint32_t)
# undef psnip_uint32_t
# endif
# if defined(psnip_int64_t)
# undef psnip_int64_t
# endif
# if defined(psnip_uint64_t)
# undef psnip_uint64_t
# endif
# if !defined(PSNIP_EXACT_INT_HAVE_STDINT)
# if defined(_STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
# define PSNIP_EXACT_INT_HAVE_STDINT
# elif defined(__has_include)
# if __has_include(<stdint.h>)
# define PSNIP_EXACT_INT_HAVE_STDINT
# endif
# elif \
defined(HAVE_STDINT_H) || \
defined(_STDINT_H_INCLUDED) || \
defined(_STDINT_H) || \
defined(_STDINT_H_)
# define PSNIP_EXACT_INT_HAVE_STDINT
# elif \
(defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))) || \
(defined(_MSC_VER) && (_MSC_VER >= 1600)) || \
(defined(__SUNPRO_C) && (__SUNPRO_C >= 0x570)) || \
(defined(__WATCOMC__) && (__WATCOMC__ >= 1250))
# define PSNIP_EXACT_INT_HAVE_STDINT
# endif
# endif
# if \
defined(__INT8_TYPE__) && defined(__INT16_TYPE__) && defined(__INT32_TYPE__) && defined(__INT64_TYPE__) && \
defined(__UINT8_TYPE__) && defined(__UINT16_TYPE__) && defined(__UINT32_TYPE__) && defined(__UINT64_TYPE__)
# define psnip_int8_t __INT8_TYPE__
# define psnip_int16_t __INT16_TYPE__
# define psnip_int32_t __INT32_TYPE__
# define psnip_int64_t __INT64_TYPE__
# define psnip_uint8_t __UINT8_TYPE__
# define psnip_uint16_t __UINT16_TYPE__
# define psnip_uint32_t __UINT32_TYPE__
# define psnip_uint64_t __UINT64_TYPE__
# elif defined(PSNIP_EXACT_INT_HAVE_STDINT)
# include <stdint.h>
# if !defined(psnip_int8_t)
# define psnip_int8_t int8_t
# endif
# if !defined(psnip_uint8_t)
# define psnip_uint8_t uint8_t
# endif
# if !defined(psnip_int16_t)
# define psnip_int16_t int16_t
# endif
# if !defined(psnip_uint16_t)
# define psnip_uint16_t uint16_t
# endif
# if !defined(psnip_int32_t)
# define psnip_int32_t int32_t
# endif
# if !defined(psnip_uint32_t)
# define psnip_uint32_t uint32_t
# endif
# if !defined(psnip_int64_t)
# define psnip_int64_t int64_t
# endif
# if !defined(psnip_uint64_t)
# define psnip_uint64_t uint64_t
# endif
# elif defined(_MSC_VER)
# if !defined(psnip_int8_t)
# define psnip_int8_t __int8
# endif
# if !defined(psnip_uint8_t)
# define psnip_uint8_t unsigned __int8
# endif
# if !defined(psnip_int16_t)
# define psnip_int16_t __int16
# endif
# if !defined(psnip_uint16_t)
# define psnip_uint16_t unsigned __int16
# endif
# if !defined(psnip_int32_t)
# define psnip_int32_t __int32
# endif
# if !defined(psnip_uint32_t)
# define psnip_uint32_t unsigned __int32
# endif
# if !defined(psnip_int64_t)
# define psnip_int64_t __int64
# endif
# if !defined(psnip_uint64_t)
# define psnip_uint64_t unsigned __int64
# endif
# else
# include <limits.h>
# if !defined(psnip_int8_t)
# if defined(CHAR_MIN) && defined(CHAR_MAX) && (CHAR_MIN == (-127-1)) && (CHAR_MAX == 127)
# define psnip_int8_t char
# elif defined(SHRT_MIN) && defined(SHRT_MAX) && (SHRT_MIN == (-127-1)) && (SHRT_MAX == 127)
# define psnip_int8_t short
# elif defined(INT_MIN) && defined(INT_MAX) && (INT_MIN == (-127-1)) && (INT_MAX == 127)
# define psnip_int8_t int
# elif defined(LONG_MIN) && defined(LONG_MAX) && (LONG_MIN == (-127-1)) && (LONG_MAX == 127)
# define psnip_int8_t long
# elif defined(LLONG_MIN) && defined(LLONG_MAX) && (LLONG_MIN == (-127-1)) && (LLONG_MAX == 127)
# define psnip_int8_t long long
# else
# error Unable to locate 8-bit signed integer type.
# endif
# endif
# if !defined(psnip_uint8_t)
# if defined(UCHAR_MAX) && (UCHAR_MAX == 255)
# define psnip_uint8_t unsigned char
# elif defined(USHRT_MAX) && (USHRT_MAX == 255)
# define psnip_uint8_t unsigned short
# elif defined(UINT_MAX) && (UINT_MAX == 255)
# define psnip_uint8_t unsigned int
# elif defined(ULONG_MAX) && (ULONG_MAX == 255)
# define psnip_uint8_t unsigned long
# elif defined(ULLONG_MAX) && (ULLONG_MAX == 255)
# define psnip_uint8_t unsigned long long
# else
# error Unable to locate 8-bit unsigned integer type.
# endif
# endif
# if !defined(psnip_int16_t)
# if defined(CHAR_MIN) && defined(CHAR_MAX) && (CHAR_MIN == (-32767-1)) && (CHAR_MAX == 32767)
# define psnip_int16_t char
# elif defined(SHRT_MIN) && defined(SHRT_MAX) && (SHRT_MIN == (-32767-1)) && (SHRT_MAX == 32767)
# define psnip_int16_t short
# elif defined(INT_MIN) && defined(INT_MAX) && (INT_MIN == (-32767-1)) && (INT_MAX == 32767)
# define psnip_int16_t int
# elif defined(LONG_MIN) && defined(LONG_MAX) && (LONG_MIN == (-32767-1)) && (LONG_MAX == 32767)
# define psnip_int16_t long
# elif defined(LLONG_MIN) && defined(LLONG_MAX) && (LLONG_MIN == (-32767-1)) && (LLONG_MAX == 32767)
# define psnip_int16_t long long
# else
# error Unable to locate 16-bit signed integer type.
# endif
# endif
# if !defined(psnip_uint16_t)
# if defined(UCHAR_MAX) && (UCHAR_MAX == 65535)
# define psnip_uint16_t unsigned char
# elif defined(USHRT_MAX) && (USHRT_MAX == 65535)
# define psnip_uint16_t unsigned short
# elif defined(UINT_MAX) && (UINT_MAX == 65535)
# define psnip_uint16_t unsigned int
# elif defined(ULONG_MAX) && (ULONG_MAX == 65535)
# define psnip_uint16_t unsigned long
# elif defined(ULLONG_MAX) && (ULLONG_MAX == 65535)
# define psnip_uint16_t unsigned long long
# else
# error Unable to locate 16-bit unsigned integer type.
# endif
# endif
# if !defined(psnip_int32_t)
# if defined(CHAR_MIN) && defined(CHAR_MAX) && (CHAR_MIN == (-2147483647-1)) && (CHAR_MAX == 2147483647)
# define psnip_int32_t char
# elif defined(SHRT_MIN) && defined(SHRT_MAX) && (SHRT_MIN == (-2147483647-1)) && (SHRT_MAX == 2147483647)
# define psnip_int32_t short
# elif defined(INT_MIN) && defined(INT_MAX) && (INT_MIN == (-2147483647-1)) && (INT_MAX == 2147483647)
# define psnip_int32_t int
# elif defined(LONG_MIN) && defined(LONG_MAX) && (LONG_MIN == (-2147483647-1)) && (LONG_MAX == 2147483647)
# define psnip_int32_t long
# elif defined(LLONG_MIN) && defined(LLONG_MAX) && (LLONG_MIN == (-2147483647-1)) && (LLONG_MAX == 2147483647)
# define psnip_int32_t long long
# else
# error Unable to locate 32-bit signed integer type.
# endif
# endif
# if !defined(psnip_uint32_t)
# if defined(UCHAR_MAX) && (UCHAR_MAX == 4294967295)
# define psnip_uint32_t unsigned char
# elif defined(USHRT_MAX) && (USHRT_MAX == 4294967295)
# define psnip_uint32_t unsigned short
# elif defined(UINT_MAX) && (UINT_MAX == 4294967295)
# define psnip_uint32_t unsigned int
# elif defined(ULONG_MAX) && (ULONG_MAX == 4294967295)
# define psnip_uint32_t unsigned long
# elif defined(ULLONG_MAX) && (ULLONG_MAX == 4294967295)
# define psnip_uint32_t unsigned long long
# else
# error Unable to locate 32-bit unsigned integer type.
# endif
# endif
# if !defined(psnip_int64_t)
# if defined(CHAR_MIN) && defined(CHAR_MAX) && (CHAR_MIN == (-9223372036854775807LL-1)) && (CHAR_MAX == 9223372036854775807LL)
# define psnip_int64_t char
# elif defined(SHRT_MIN) && defined(SHRT_MAX) && (SHRT_MIN == (-9223372036854775807LL-1)) && (SHRT_MAX == 9223372036854775807LL)
# define psnip_int64_t short
# elif defined(INT_MIN) && defined(INT_MAX) && (INT_MIN == (-9223372036854775807LL-1)) && (INT_MAX == 9223372036854775807LL)
# define psnip_int64_t int
# elif defined(LONG_MIN) && defined(LONG_MAX) && (LONG_MIN == (-9223372036854775807LL-1)) && (LONG_MAX == 9223372036854775807LL)
# define psnip_int64_t long
# elif defined(LLONG_MIN) && defined(LLONG_MAX) && (LLONG_MIN == (-9223372036854775807LL-1)) && (LLONG_MAX == 9223372036854775807LL)
# define psnip_int64_t long long
# else
# error Unable to locate 64-bit signed integer type.
# endif
# endif
# if !defined(psnip_uint64_t)
# if defined(UCHAR_MAX) && (UCHAR_MAX == 18446744073709551615ULL)
# define psnip_uint64_t unsigned char
# elif defined(USHRT_MAX) && (USHRT_MAX == 18446744073709551615ULL)
# define psnip_uint64_t unsigned short
# elif defined(UINT_MAX) && (UINT_MAX == 18446744073709551615ULL)
# define psnip_uint64_t unsigned int
# elif defined(ULONG_MAX) && (ULONG_MAX == 18446744073709551615ULL)
# define psnip_uint64_t unsigned long
# elif defined(ULLONG_MAX) && (ULLONG_MAX == 18446744073709551615ULL)
# define psnip_uint64_t unsigned long long
# else
# error Unable to locate 64-bit unsigned integer type.
# endif
# endif
# endif
#endif

View file

@ -0,0 +1,11 @@
# Once
This is a simple abstraction for a once which will choose from a few
different back-ends:
* If C11 threads are available, use `call_once()`.
* On Windows, use
[InitOnceExecuteOnce()](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683493(v=vs.85).aspx)
* If `PTHREAD_ONCE_INIT` is defined (*i.e.*, if `<pthread.h>` has
been included prior to including `once.h`), use `pthread_once()`.
* Use `[atomic.h](../atomic)`.

129
thirdparty/portable-snippets/once/once.h vendored Normal file
View file

@ -0,0 +1,129 @@
/* Once (v1)
* Portable Snippets - https://github.com/nemequ/portable-snippets
* Created by Evan Nemerson <evan@nemerson.com>
*
* To the extent possible under law, the authors have waived all
* copyright and related or neighboring rights to this code. For
* details, see the Creative Commons Zero 1.0 Universal license at
* https://creativecommons.org/publicdomain/zero/1.0/
*/
#if !defined(PSNIP_ONCE__H)
#define PSNIP_ONCE__H
#define PSNIP_ONCE__BACKEND_ATOMIC 1
#define PSNIP_ONCE__BACKEND_PTHREAD 2
#define PSNIP_ONCE__BACKEND_NONE 3
#define PSNIP_ONCE__BACKEND_C11 11
#define PSNIP_ONCE__BACKEND_WIN32 32
#include <limits.h>
#if !defined(PSNIP_ONCE_BACKEND)
# if defined(__STDC_NO_THREADS__) && __STDC_NO_THREADS__
# elif defined(__EMSCRIPTEN__)
# elif defined(__has_include)
# if __has_include(<threads.h>)
# if !defined(__GLIBC__) || (defined(__GLIBC__) && defined(PSNIP_ENABLE_PTHREADS))
# include <threads.h>
# define PSNIP_ONCE_BACKEND PSNIP_ONCE__BACKEND_C11
# endif
# endif
# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L) && !defined(__STDC_NO_THREADS__)
# if (defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 16)))
/* stdc-predef.h didn't include __STDC_NO_THREADS__ until 2.16. */
# else
# include <threads.h>
# define PSNIP_ONCE_BACKEND PSNIP_ONCE__BACKEND_C11
# endif
# endif
#endif
#if !defined(PSNIP_ONCE_BACKEND) && defined(_WIN32) && (!defined(WINVER) || (defined(WINVER) && (WINVER >= 0x0600)))
# include <Windows.h>
# define PSNIP_ONCE_BACKEND PSNIP_ONCE__BACKEND_WIN32
#endif
#if !defined(PSNIP_ONCE_BACKEND) && defined(PTHREAD_ONCE_INIT)
# define PSNIP_ONCE_BACKEND PSNIP_ONCE__BACKEND_PTHREAD
#endif
#if !defined(PSNIP_ONCE_BACKEND)
# include "../atomic/atomic.h"
# if !defined(PSNIP_ATOMIC_NOT_FOUND)
# define PSNIP_ONCE_BACKEND PSNIP_ONCE__BACKEND_ATOMIC
# endif
#endif
#if !defined(PSNIP_ONCE_BACKEND)
# error No once backend found.
#endif
#if defined(__GNUC__) && (__GNUC__ >= 3)
# define PSNIP_ONCE__UNLIKELY(expr) __builtin_expect(!!(expr), !!0)
#else
# define PSNIP_ONCE__UNLIKELY(expr) (!!(expr))
#endif
#if PSNIP_ONCE_BACKEND == PSNIP_ONCE__BACKEND_C11
# define PSNIP_ONCE_INIT ONCE_FLAG_INIT
typedef once_flag psnip_once;
# define psnip_once_call(flag, func) call_once(flag, func)
#elif PSNIP_ONCE_BACKEND == PSNIP_ONCE__BACKEND_PTHREAD
# define PSNIP_ONCE_INIT PTHREAD_ONCE_INIT
typedef pthread_once_t psnip_once;
# define psnip_once_call(flag, func) pthread_once(flag, func)
#elif PSNIP_ONCE_BACKEND == PSNIP_ONCE__BACKEND_WIN32
# define PSNIP_ONCE_INIT INIT_ONCE_STATIC_INIT
typedef INIT_ONCE psnip_once;
static BOOL CALLBACK psnip_once__callback_wrap(INIT_ONCE* InitOnce, void* Parameter, void** Context) {
(void) Context;
(void) InitOnce;
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable:4055)
#endif
((void (*)(void)) Parameter)();
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
return !0;
}
# if defined(_MSC_VER) && (_MSC_VER >= 1500)
# define psnip_once_call(flag, func) \
__pragma(warning(push)) \
__pragma(warning(disable:4152)) \
InitOnceExecuteOnce(flag, &psnip_once__callback_wrap, func, NULL) \
__pragma(warning(pop))
# else
# define psnip_once_call(flag, func) InitOnceExecuteOnce(flag, &psnip_once__callback_wrap, func, NULL)
# endif
#elif PSNIP_ONCE_BACKEND == PSNIP_ONCE__BACKEND_ATOMIC
# define PSNIP_ONCE_INIT PSNIP_ATOMIC_VAR_INIT(0)
typedef psnip_atomic_int32 psnip_once;
static void psnip_once_call(psnip_once* flag, void (*func)(void)) {
psnip_int32_t state = psnip_atomic_int32_load(flag);
if (PSNIP_ONCE__UNLIKELY(state == 0)) {
if (psnip_atomic_int32_compare_exchange(flag, &state, 1)) {
func();
psnip_atomic_int32_store(flag, 2);
} else {
do {
/* Spin; another thread is calling the initialization
function. */
} while (psnip_atomic_int32_load(flag) == 1);
}
}
}
#elif PSNIP_ONCE_BACKEND == PSNIP_ONCE__BACKEND_NONE
# define PSNIP_ONCE_INIT 0
typedef int psnip_once;
static void psnip_once_call(psnip_once* flag, void (*func)(void)) {
if (*flag == 0) {
func();
*flag = 1;
}
}
#endif
#endif /* !defined(PSNIP_ONCE__H) */

View file

@ -0,0 +1,84 @@
# Random Numbers
This provides methods for obtaining random, or pseudo-random, numbers.
There is generally only on function to worry about:
```c
int
psnip_random_bytes(enum PSnipRandomSource source,
size_t length,
psnip_uint8_t data[length]);
```
This will fill `data` with `length` bytes of randomness from `source`.
It returns 0 on success or, -1 if the source is not available (only
possible with the secure source), -2 if you supplied an invalid source
argument, or another negative number for other unexpected errors.
## Secure
`PSNIP_RANDOM_SOURCE_SECURE` tries to obtain cryptographically secure
random numbers. This may or may not be available, depending on the
platform; if no source can be found `psnip_random_get_bytes` will
return -1 (you can pass 0 for the length if you just want to query for
support without actually generating anything).
This will try various methods. Currently, this means:
* [`RtlGenRandom()`](http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694%28v=vs.85%29.aspx) on Windows
* `getrandom()` on Solaris >= 11.3 (**TODO**), Linux >= 3.17
* `arc4random()` on some BSDs (**TODO**)
* [AES-NI](https://software.intel.com/en-us/articles/intel-advanced-encryption-standard-aes-instructions-set/) on CPUs which support it
* Reading from `/dev/urandom` or `/dev/random` (if they exist)
If your platform isn't supported, please get in touch to discuss
adding a back-end.
## Reproducible
`PSNIP_RANDOM_SOURCE_REPRODUCIBLE` generates a *reproducible* stream
of pseudo-random numbers. Currently we use a 32-bit variant of PCG;
this was chosen because it provides pretty good quality random
numbers, and the state is small enough that we can use atomic
operations instead of a mutex.
To deal with seeding, there are two additional functions:
```c
psnip_uint32_t psnip_random_get_seed (void);
void psnip_random_set_seed (const psnip_uint32_t seed);
```
You can use the `psnip_random_set_seed` function to seed this
generator. If you do not provide a seed we'll try to generate a
decent seed for you, but we make no promises about the quality.
Potential sources for the seed include libc's `rand()`, system time,
`lrand48()`, etc.
Even with a high quality seed, **this is not cryptographically secure**.
## Fast
`PSNIP_RANDOM_SOURCE_FAST` just tries to provide a random number
quickly. It probably isn't cryptographically secure, but may be; for
example, if you have a hardware-based RNG which we believe would be
faster than the reproducible PRNG, we'll use it.
Note that, even if the fast source is implemented using the same
algorithm as the reproducible source (i.e., PGC with a 32-bit state),
the fast source will *not* alter the state of the reproducible PRNG.
## Dependencies
This module requires the following portable-snippet modules:
* exact-int
* atomic — for thread-safety
* clock — for seeding
* once — for thread-safety
* cpu — to detect CPU-based PRNGs (*i.e.*, RdRand on Intel)
The code currently assumes the same directory structure as is used in
the portable-snippets repository. Patches to allow other structures
will be seriously considered.

View file

@ -0,0 +1,400 @@
#define _GNU_SOURCE
#include "random.h"
#if !defined(psnip_uint64_t)
# include "../exact-int/exact-int.h"
#endif
#include "../atomic/atomic.h"
#include "../clock/clock.h"
#include "../once/once.h"
#include "../cpu/cpu.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>
#if !defined(_WIN32)
# include <sys/types.h>
# include <unistd.h>
#endif
#if defined(PSNIP_CPU_ARCH_X86_64) || defined(PSNIP_CPU_ARCH_X86)
# if defined(__has_builtin)
# if defined(__clang__) && (__clang_major__ == 3 && __clang_minor__ == 5)
# elif __has_builtin(__builtin_ia32_rdrand64_step) || __has_builtin(__builtin_ia32_rdrand32_step)
# define PSNIP_RANDOM__SECURE_ALLOW_RDRAND
# endif
# elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
# define PSNIP_RANDOM__SECURE_ALLOW_RDRAND
# endif
#endif
static int (* psnip_random_secure_generate)(size_t length, psnip_uint8_t data[PSNIP_RANDOM_ARRAY_PARAM(length)]) = NULL;
static psnip_once psnip_random_secure_once = PSNIP_ONCE_INIT;
#if defined(__linux)
# include <unistd.h>
# include <sys/syscall.h>
# if defined(SYS_getrandom)
# include <linux/version.h>
# include <sys/utsname.h>
static int
psnip_random__have_getrandom(void) {
struct utsname buf;
int major, minor, revision, r;
uname(&buf);
r = sscanf(buf.release, "%d.%d.%d", &major, &minor, &revision);
if (r != 3)
return 0;
return KERNEL_VERSION(major, minor, revision) >= KERNEL_VERSION(3, 17, 0);
}
# if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 26))
# include <sys/random.h>
# define psnip_random__getrandom(buf, buflen, flags) getrandom(buf, buflen, flags)
# else
static int
psnip_random__getrandom(void* buf, size_t buflen, unsigned int flags) {
return (int) syscall(SYS_getrandom, buf, buflen, flags);
}
# endif
static int
psnip_random_secure_generate_getrandom(size_t length, psnip_uint8_t data[PSNIP_RANDOM_ARRAY_PARAM(length)]) {
size_t bytes_read = 0;
int r;
while (bytes_read < length) {
r = psnip_random__getrandom(&(data[bytes_read]), length - bytes_read, 0);
if (r == -1)
return -4;
bytes_read += r;
}
return 0;
}
# endif
#endif
#if defined(PSNIP_RANDOM__SECURE_ALLOW_RDRAND)
# if defined(__GNUC__)
# include <x86intrin.h>
# else
# include <immintrin.h>
# endif
#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
__attribute__((__target__("rdrnd")))
#endif
static int
psnip_random__rdrand (size_t length, psnip_uint8_t data[PSNIP_RANDOM_ARRAY_PARAM(length)]) {
size_t remaining = length;
unsigned int r;
#if defined(PSNIP_CPU_ARCH_X86_64)
unsigned long long int v;
#else
unsigned int v;
#endif
while (remaining > 0) {
do {
#if defined(PSNIP_CPU_ARCH_X86_64)
# if defined(__GNUC__)
r = __builtin_ia32_rdrand64_step(&v);
# else
r = _rdrand64_step(&v);
# endif
#else
# if defined(__GNUC__)
r = __builtin_ia32_rdrand32_step(&v);
# else
r = _rdrand32_step(&v);
# endif
#endif
} while (r == 0);
if (remaining >= sizeof(v)) {
memcpy(&(data[length - remaining]), &v, sizeof(v));
remaining -= sizeof(v);
} else {
memcpy(&(data[length - remaining]), &v, remaining);
remaining = 0;
}
}
return 0;
}
#endif
#if defined(_WIN32)
static HMODULE psnip_rand_secure__advapi32_dll = NULL;
static BOOLEAN (APIENTRY *psnip_rand_secure__RtlGenRandom)(void*, ULONG);
static int psnip_random_secure_generate_RtlGenRandom(size_t length, psnip_uint8_t data[PSNIP_RANDOM_ARRAY_PARAM(length)]) {
assert(psnip_rand_secure__RtlGenRandom != NULL);
return psnip_rand_secure__RtlGenRandom(data, (ULONG) length) ? 0 : -3;
}
static void
psnip_random_secure_init(void) {
psnip_rand_secure__advapi32_dll = LoadLibrary("ADVAPI32.DLL");
if (psnip_rand_secure__advapi32_dll == NULL)
return;
psnip_rand_secure__RtlGenRandom = (BOOLEAN (APIENTRY *)(void*,ULONG))
GetProcAddress(psnip_rand_secure__advapi32_dll, "SystemFunction036");
if (psnip_rand_secure__RtlGenRandom == NULL)
return;
psnip_random_secure_generate = &psnip_random_secure_generate_RtlGenRandom;
}
# define PSNIP_RANDOM_SECURE_FOUND
#endif /* defined(_WIN32) */
#if !defined(PSNIP_RANDOM_SECURE_FOUND)
static int
psnip_random_secure_generate_dev_random(size_t length, psnip_uint8_t data[PSNIP_RANDOM_ARRAY_PARAM(length)]) {
static FILE* dev_random = NULL;
size_t bytes_read = 0;
if (dev_random == NULL) {
dev_random = fopen("/dev/random", "rb");
if (dev_random == NULL)
return -1;
}
if (length > 0) {
bytes_read = fread(data, 1, length, dev_random);
if (bytes_read != length)
return -5;
}
return 0;
}
static int
psnip_random_secure_generate_dev_urandom(size_t length, psnip_uint8_t data[PSNIP_RANDOM_ARRAY_PARAM(length)]) {
static FILE* dev_urandom = NULL;
size_t bytes_read = 0;
if (dev_urandom == NULL) {
dev_urandom = fopen("/dev/random", "rb");
if (dev_urandom == NULL)
return -1;
}
if (length > 0) {
bytes_read = fread(data, 1, length, dev_urandom);
if (bytes_read != length)
return -5;
}
return 0;
}
static void
psnip_random_secure_init(void) {
#if defined(__linux) && defined(SYS_getrandom)
if (psnip_random__have_getrandom()) {
psnip_random_secure_generate = &psnip_random_secure_generate_getrandom;
return;
}
#endif
if (psnip_random_secure_generate_dev_urandom(0, NULL) == 0) {
psnip_random_secure_generate = &psnip_random_secure_generate_dev_urandom;
return;
}
if (psnip_random_secure_generate_dev_random(0, NULL) == 0) {
psnip_random_secure_generate = &psnip_random_secure_generate_dev_random;
return;
}
#if defined(PSNIP_RANDOM__SECURE_ALLOW_RDRAND)
if (psnip_cpu_feature_check(PSNIP_CPU_FEATURE_X86_RDRND)) {
psnip_random_secure_generate = &psnip_random__rdrand;
return;
}
#endif
}
#endif
/* http://burtleburtle.net/bob/hash/integer.html */
static psnip_uint32_t psnip_random__seed_hash(psnip_uint32_t a) {
a = (a ^ 61) ^ (a >> 16);
a += (a << 3);
a ^= (a >> 4);
a *= 0x27d4eb2dU;
a ^= (a >> 15);
return a;
}
static psnip_uint32_t
psnip_random__pcg_gen_seed(void) {
psnip_uint32_t res = 0;
struct PsnipClockTimespec cur_time = { 0, };
int precision;
precision = psnip_clock_get_precision(PSNIP_CLOCK_TYPE_WALL);
if (precision != 0) {
if (psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &cur_time) == 0) {
goto complete;
}
}
precision = psnip_clock_get_precision(PSNIP_CLOCK_TYPE_MONOTONIC);
if (precision != 0) {
if (psnip_clock_get_time(PSNIP_CLOCK_TYPE_MONOTONIC, &cur_time) == 0) {
goto complete;
}
}
precision = psnip_clock_get_precision(PSNIP_CLOCK_TYPE_CPU);
if (precision != 0) {
if (psnip_clock_get_time(PSNIP_CLOCK_TYPE_CPU, &cur_time) == 0) {
goto complete;
}
}
complete:
res ^= psnip_random__seed_hash((psnip_uint32_t) cur_time.nanoseconds);
res ^= psnip_random__seed_hash((psnip_uint32_t) cur_time.seconds);
res ^= psnip_random__seed_hash((psnip_uint32_t) rand());
#if !defined(_WIN32)
res ^= psnip_random__seed_hash((psnip_uint32_t) getpid());
res ^= psnip_random__seed_hash((psnip_uint32_t) getppid());
#endif
return res;
}
/* PCG */
#define PSNIP_RANDOM__PCG_MULTIPLIER (747796405U)
#define PSNIP_RANDOM__PCG_INCREMENT (1729U)
static psnip_uint32_t
psnip_random__pcg_next_state(psnip_uint32_t state) {
return state * PSNIP_RANDOM__PCG_MULTIPLIER + PSNIP_RANDOM__PCG_INCREMENT;
}
static psnip_uint32_t
psnip_random__pcg_from_state(psnip_uint32_t state) {
psnip_uint32_t res = ((state >> ((state >> 28) + 4)) ^ state) * (277803737U);
res ^= res >> 22;
return res;
}
static int
psnip_random__pgc_generate(psnip_atomic_int32* state, size_t length, psnip_uint8_t data[PSNIP_RANDOM_ARRAY_PARAM(length)]) {
psnip_int32_t old_state;
psnip_uint32_t new_state, v;
size_t remaining;
do {
old_state = psnip_atomic_int32_load(state);
new_state = (psnip_uint32_t) old_state;
remaining = length;
while (remaining > 0) {
v = psnip_random__pcg_from_state(new_state);
new_state = psnip_random__pcg_next_state(new_state);
if (remaining >= sizeof(psnip_uint32_t)) {
memcpy(&(data[length - remaining]), &v, sizeof(psnip_uint32_t));
remaining -= sizeof(psnip_uint32_t);
} else {
memcpy(&(data[length - remaining]), &v, remaining);
remaining = 0;
}
}
} while (!psnip_atomic_int32_compare_exchange(state, &old_state, (psnip_int32_t) new_state));
return 0;
}
/* Reproducible */
static psnip_atomic_int32 psnip_random__reproducible_seed = 0;
static psnip_atomic_int32 psnip_random__reproducible_state = 0;
static psnip_once psnip_random_reproducible_once = PSNIP_ONCE_INIT;
static void
psnip_random_reproducible_init(void) {
psnip_int32_t seed = (psnip_uint32_t) psnip_random__pcg_gen_seed();
psnip_atomic_int32_store(&psnip_random__reproducible_seed, seed);
psnip_atomic_int32_store(&psnip_random__reproducible_state, seed);
}
void
psnip_random_set_seed (psnip_uint32_t seed) {
const psnip_int32_t sseed = (psnip_int32_t) seed;
psnip_once_call(&psnip_random_reproducible_once, &psnip_random_reproducible_init);
psnip_atomic_int32_store(&psnip_random__reproducible_seed, sseed);
psnip_atomic_int32_store(&psnip_random__reproducible_state, sseed);
}
psnip_uint32_t
psnip_random_get_seed (void) {
psnip_once_call(&psnip_random_reproducible_once, &psnip_random_reproducible_init);
return (psnip_uint32_t) psnip_atomic_int32_load(&psnip_random__reproducible_seed);
}
/* Fast */
static psnip_atomic_int32 psnip_random__fast_state = 0;
static psnip_once psnip_random_fast_once = PSNIP_ONCE_INIT;
static void
psnip_random_fast_init(void) {
psnip_int32_t seed = (psnip_int32_t) psnip_random__pcg_gen_seed();
psnip_atomic_int32_store((psnip_atomic_int32*) &psnip_random__fast_state, seed);
}
int
psnip_random_bytes(enum PSnipRandomSource source,
size_t length,
psnip_uint8_t data[PSNIP_RANDOM_ARRAY_PARAM(length)]) {
switch (source) {
case PSNIP_RANDOM_SOURCE_SECURE:
#if !defined(PSNIP_RANDOM_SECURE_NO_INIT)
psnip_once_call(&psnip_random_secure_once, &psnip_random_secure_init);
if (psnip_random_secure_generate == NULL)
return -1;
#endif
return psnip_random_secure_generate(length, data);
case PSNIP_RANDOM_SOURCE_REPRODUCIBLE:
#if !defined(PSNIP_RANDOM_REPRODUCIBLE_NO_INIT)
psnip_once_call(&psnip_random_reproducible_once, &psnip_random_reproducible_init);
#endif
return psnip_random__pgc_generate(&psnip_random__reproducible_state, length, data);
case PSNIP_RANDOM_SOURCE_FAST:
#if !defined(PSNIP_RANDOM_FAST_NO_INIT)
psnip_once_call(&psnip_random_fast_once, &psnip_random_fast_init);
#endif
return psnip_random__pgc_generate(&psnip_random__fast_state, length, data);
}
return -2;
}

View file

@ -0,0 +1,38 @@
#if !defined(PSNIP_RANDOM__H)
#define PSNIP_RANDOM__H
#include <stdlib.h>
#if !defined(psnip_uint8_t)
# include "../exact-int/exact-int.h"
#endif
#if defined(HEDLEY_ARRAY_PARAM)
# define PSNIP_RANDOM_ARRAY_PARAM(expr) HEDLEY_ARRAY_PARAM(expr)
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) && !defined(__PGI)
# define PSNIP_RANDOM_ARRAY_PARAM(expr) (expr)
#else
# define PSNIP_RANDOM_ARRAY_PARAM(expr)
#endif
#if defined(__cplusplus)
extern "C" {
#endif
enum PSnipRandomSource {
PSNIP_RANDOM_SOURCE_SECURE,
PSNIP_RANDOM_SOURCE_REPRODUCIBLE,
PSNIP_RANDOM_SOURCE_FAST,
};
int psnip_random_bytes (enum PSnipRandomSource source,
size_t length,
psnip_uint8_t data[PSNIP_RANDOM_ARRAY_PARAM(length)]);
psnip_uint32_t psnip_random_get_seed (void);
void psnip_random_set_seed (psnip_uint32_t seed);
#if defined(__cplusplus)
}
#endif
#endif /* defined(PSNIP_RANDOM__H) */

View file

@ -0,0 +1,184 @@
# Overflow-safe math functions
The safe-math.h header defines numerous functions for verifying that
integer operations do not overflow. Available implementations, in
order of priority:
* Compiler builtins (i.e., `__builtin_*_overflow`).
* On Windows, use `<intsafe.h>` for the types it supports.
* If a larger type is available, promote the inputs and verify the
result falls within the range of the result type before casting to
it.
* Check that the operation would not result in an overflow before
performing it. See [INT32-C in CERT's C Coding
Standard](https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow)
for details.
# APIs
## Preferred API
Regardless of which implementation is chosen, the preferred API is the
same. For each type and operation, we define:
```c
psnip_safe_bool psnip_safe_{type_identifier}_{operation} ({T}* result, {T} a, {T} b);
```
which returns true if the operation succeeded, or false if it resulted
in an overflow (which is the opposite of how e.g.
`__builtin_*_overflow` builtins work).
For example, for addition on signed integers, there is
```c
psnip_safe_bool psnip_safe_int_add (int* res, int a, int b);
```
Values for type_identifier and T are:
| Identifier | Type |
| ---------- | -------------------- |
| `char` | `char` |
| `uchar` | `unsigned char` |
| `short` | `short` |
| `ushort` | `unsigned short` |
| `int` | `int` |
| `uint` | `unsigned int` |
| `long` | `long` |
| `ulong` | `unsigned long` |
| `llong` | `long long` |
| `ullong` | `unsigned long long` |
| `size` | `size_t` |
| `int8` | `int8_t` |
| `uint8` | `uint8_t` |
| `int16` | `int16_t` |
| `uint16` | `uint16_t` |
| `int32` | `int32_t` |
| `uint32` | `uint32_t` |
| `int64` | `int64_t` |
| `uint64` | `uint64_t` |
Operations are:
* add (addition)
* sub (subtraction)
* mul (multiplication)
* div (division)
* mod (modulus)
* neg (negation, for signed types only)
Negation only has one input argument, all the others have two.
`psnip_safe_bool` is defined to _Bool (for C99) or int.
## Emulation of native APIs
If you prefer, you can `#define` either `PSNIP_SAFE_EMULATE_NATIVE` or
`PSNIP_BUILTIN_EMULATE_NATIVE` and we will also provide an API
compatible with [GCC's overflow
builtins](https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html)
unless the compiler we're using already provides it. There are two
things to watch out for if you choose this:
* The type-generic functions (`__builtin_add_overflow`,
`__builtin_sub_overflow`, and `__builtin_mul_overflow`) will only
be available in C11 mode.
* The argument order in GCC's API is slightly different, with the
result coming last instead of first. We prefer the result to come
first so the call looks a bit more like an assignment operation,
but GCC made a different choice.
In other words, `__builtin_*_overflow(a, b, res)` are macros
defined to `(!psnip_safe_*(res, a, b))` so existing code needn't
be altered.
## The `safe_larger_*` API
In order to implement the versions of functions which promote the
arguments then check the result before casting back to original type,
we had to create an API. It's really intended as an internal API, and
is a bit of a pain, but if you'd rather just have a larger result
instead of having to check for the overflow case it can be useful.
For types where we know of a larger type we define the macro
`PSNIP_SAFE_HAVE_TYPE_LARGER`, as well as a typedef to the larger type
called `psnip_safe_type_larger`. For example, we know that there is a type
larger than `int16_t` (`int32_t`), so there is:
```C
#define PSNIP_SAFE_HAVE_INT16_LARGER
typedef int32_t psnip_safe_int16_larger;
```
This gets slightly more complicated (but more useful) when dealing
with the non-fixed-length types. For example, short may or may not be
larger than char (it's not shorter, but they may be equal). So,
assuming char is less than 64-bits (or the compiler supports 128-bit
numbers), we will define `PSNIP_SAFE_HAVE_CHAR_LARGER` and
`psnip_safe_char_larger` will be a typedef to the first type which is larger
than char (the order we try is `char`, `short`, `int`, `long`, `long
long`, `int8_t`, `int16_t`, `int32_t`, `int64_t`, then the 128-bit
integer type if available). So, `psnip_safe_char_larger` is a typedef to
`short` if `short` is larger than `char`, otherwise `int` if `int` is
larger than `char`, otherwise `long`, etc.
In addition to the typedefs, if there is a larger known type we
also generate a set of functions in the form of
```C
psnip_safe_type_larger psnip_safe_larger_type_operation(type, type)
```
This is done for every type and every operation; for example, if
`PSNIP_SAFE_HAVE_CHAR_LARGER` is defined, then so too will be
* `psnip_safe_char_larger psnip_safe_larger_char_add(char, char)`
* `psnip_safe_char_larger psnip_safe_larger_char_sub(char, char)`
* `psnip_safe_char_larger psnip_safe_larger_char_mul(char, char)`
* `psnip_safe_char_larger psnip_safe_larger_char_div(char, char)`
* `psnip_safe_char_larger psnip_safe_larger_char_mod(char, char)`
* `psnip_safe_char_larger psnip_safe_larger_char_neg(char)`
# Caveats
The type-generic functions are only guaranteed to be available in C11
mode since there was no standard way to implement them until C11.
Even if you request emulation of the GCC builtins, we cannot provide
the `__builtin_*_overflow_p` functions.
## Dependencies
To maximize portability you should #include the exact-int module
before including safe-math.h, but if you don't want to add the extra
file to your project you can omit it and this module will simply rely
on <stdint.h>. As an alternative you may define the following macros
to appropriate values yourself:
* `psnip_int8_t`
* `psnip_uint8_t`
* `psnip_int16_t`
* `psnip_uint16_t`
* `psnip_int32_t`
* `psnip_uint32_t`
* `psnip_int64_t`
* `psnip_uint64_t`
# Alternatives
## C
* [GCC Integer Overflow
Builtins](https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html)
(GCC 5+)
* [Windows'
<intsafe.h>](https://msdn.microsoft.com/en-us/library/windows/desktop/ff521693(v=vs.85).aspx)
(Windows only, unsigned only)
This module will use the above APIs if available.
## C++
* [SafeInt](https://safeint.codeplex.com/)
* [Boost Safe Numerics](http://blincubator.com/bi_library/safe-numerics/?gform_post_id=426)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,198 @@
cmake_minimum_required(VERSION 3.0)
project(portable-snippet-tests)
enable_testing()
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/munit/munit.c")
find_program(GIT git)
if(GIT)
execute_process(COMMAND ${GIT} submodule update --init --recursive)
else()
message (FATAL_ERROR "It looks like you don't have submodules checked out. Please run `git submodule update --init --recursive'")
endif()
endif()
if(ENABLE_OPENMP)
find_package(OpenMP REQUIRED)
endif()
include(CheckFunctionExists)
check_function_exists(clock_gettime CLOCK_GETTIME_RES)
if(CLOCK_GETTIME_RES)
set(CLOCK_GETTIME_EXISTS yes)
else()
set(orig_req_libs "${CMAKE_REQUIRED_LIBRARIES}")
set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};rt")
check_function_exists(clock_gettime CLOCK_GETTIME_LIBRT_RES)
if(CLOCK_GETTIME_LIBRT_RES)
set(CLOCK_GETTIME_EXISTS yes)
set(CLOCK_GETTIME_LIBRARY "rt")
endif()
set(CMAKE_REQUIRED_LIBRARIES "${orig_req_libs}")
unset(orig_req_libs)
endif()
include (AddCompilerFlags)
set(PSNIP_C_FLAGS)
if(FATAL_WARNINGS)
set_compiler_specific_flags(VARIABLE FATAL_WARNING_FLAGS
GCCISH -Werror
MSVC /WX)
list(APPEND PSNIP_C_FLAGS ${FATAL_WARNING_FLAGS})
endif()
if(ENABLE_AGGRESSIVE_WARNINGS)
set_compiler_specific_flags(VARIABLE EXTRA_WARNING_FLAGS
GCCISH
-Wall
-Waggregate-return
-Wcast-align
-Wclobbered
-Wempty-body
-Werror=format=2
-Werror=format-security
-Werror=implicit-function-declaration
-Werror=init-self
-Werror=missing-include-dirs
-Werror=missing-prototypes
-Werror=pointer-arith
-Wextra
-Wformat-nonliteral
-Wformat-security
-Wignored-qualifiers
-Winit-self
-Winvalid-pch
-Wlogical-op
-Wmissing-declarations
-Wmissing-format-attribute
-Wmissing-include-dirs
-Wmissing-noreturn
-Wmissing-parameter-type
-Wmissing-prototypes
-Wnested-externs
-Wno-missing-field-initializers
-Wno-strict-aliasing
-Wno-uninitialized
-Wno-unused-parameter
-Wold-style-definition
-Woverride-init
-Wpacked
-Wpointer-arith
-Wredundant-decls
-Wreturn-type
-Wshadow
-Wsign-compare
-Wstrict-prototypes
-Wswitch-enum
-Wsync-nand
-Wtype-limits
-Wundef
-Wuninitialized
-WUnsafe-loop-optimizations
-Wwrite-strings
-Wsuggest-attribute=format
PGI
-Minform=inform
MSVC
/W4
/analyze)
list(APPEND PSNIP_C_FLAGS ${EXTRA_WARNING_FLAGS})
endif()
if(NOT ENABLE_SANITIZER STREQUAL "")
if(ENABLE_SANITIZER STREQUAL "undefined")
set_compiler_specific_flags(VARIABLE UBSAN_FLAGS
GCCISH -fsanitize=undefined
GCC -fno-sanitize-recover=undefined,float-cast-overflow,float-divide-by-zero
CLANG -fno-sanitize-recover=undefined,integer)
list(APPEND PSNIP_C_FLAGS ${UBSAN_FLAGS})
endif()
endif()
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_C_FLAGS_DEBUG)
set(CMAKE_C_FLAGS_RELEASE)
set_compiler_specific_flags(
VARIABLE PSNIP_RELEASE_FLAGS
GCCISH -O3 -DNDEBUG)
foreach(flag ${PSNIP_RELEASE_FLAGS})
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${flag}")
endforeach()
set_compiler_specific_flags(
VARIABLE PSNIP_DEBUG_FLAGS
GCCISH -O3 -g)
foreach(flag ${PSNIP_DEBUG_FLAGS})
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${flag}")
endforeach()
add_library(munit munit/munit.c)
set_property(TARGET munit PROPERTY C_STANDARD "99")
if("${CLOCK_GETTIME_EXISTS}")
target_compile_definitions(munit PRIVATE "MUNIT_ALLOW_CLOCK_GETTIME")
target_link_libraries(munit "${CLOCK_GETTIME_LIBRARY}")
endif()
function(psnip_add_tests)
set(options)
set(oneValueArgs TARGET)
set(multiValueArgs SOURCES TESTS)
cmake_parse_arguments(PSNIP_TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
add_executable("${PSNIP_TEST_TARGET}" ${PSNIP_TEST_SOURCES})
target_link_libraries("${PSNIP_TEST_TARGET}" munit)
target_add_compiler_flags("${PSNIP_TEST_TARGET}" ${PSNIP_C_FLAGS})
if(PSNIP_TEST_TESTS)
foreach(TEST ${PSNIP_TEST_TESTS})
add_test(NAME "${TEST}"
COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:${PSNIP_TEST_TARGET}> "${TEST}")
endforeach(TEST)
else()
add_test(NAME "/${PSNIP_TEST_TARGET}"
COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:${PSNIP_TEST_TARGET}>)
endif()
endfunction(psnip_add_tests)
psnip_add_tests(TARGET endian SOURCES endian.c)
psnip_add_tests(TARGET atomic SOURCES atomic.c)
psnip_add_tests(TARGET builtin SOURCES builtin.c
TESTS "/builtin" "/intrin" "/wrapper")
psnip_add_tests(TARGET safe-math SOURCES safe-math.c)
psnip_add_tests(TARGET unaligned SOURCES unaligned.c)
psnip_add_tests(TARGET clock SOURCES clock.c)
psnip_add_tests(TARGET once SOURCES once.c)
psnip_add_tests(TARGET cpu SOURCES cpu.c ../cpu/cpu.c)
psnip_add_tests(TARGET random SOURCES random.c ../random/random.c ../cpu/cpu.c)
if(ENABLE_PTHREADS)
find_package (Threads REQUIRED)
foreach(tgt once cpu random)
target_link_libraries(${tgt} ${CMAKE_THREAD_LIBS_INIT})
target_compile_definitions(${tgt} PRIVATE PSNIP_ENABLE_PTHREADS)
endforeach()
endif()
if(ENABLE_OPENMP)
foreach(tgt atomic once cpu random)
target_compile_options(${tgt} PRIVATE ${OpenMP_C_FLAGS})
endforeach()
endif()
if("${CLOCK_GETTIME_EXISTS}")
target_link_libraries(clock "${CLOCK_GETTIME_LIBRARY}")
else()
target_compile_definitions(clock PRIVATE "PSNIP_CLOCK_NO_LIBRT")
endif()

View file

@ -0,0 +1,101 @@
#include <stdlib.h>
#include "../exact-int/exact-int.h"
#include "../atomic/atomic.h"
#include "munit/munit.h"
#if !defined(PSNIP_ATOMIC_NOT_FOUND)
static psnip_atomic_int64 value64 = PSNIP_ATOMIC_VAR_INIT(9);
static psnip_atomic_int32 value32 = PSNIP_ATOMIC_VAR_INIT(9);
#endif
static MunitResult
test_atomic_int64(const MunitParameter params[], void* data) {
#if !defined(PSNIP_ATOMIC_NOT_FOUND)
psnip_int64_t v, expected;
#endif
(void) params;
(void) data;
#if !defined(PSNIP_ATOMIC_NOT_FOUND)
v = psnip_atomic_int64_load(&value64);
munit_assert_int64(v, ==, 9);
v = v * v * v;
psnip_atomic_int64_store(&value64, v);
v = psnip_atomic_int64_load(&value64);
munit_assert_int64(v, ==, 729);
psnip_atomic_int64_add(&value64, 1000);
v = psnip_atomic_int64_load(&value64);
munit_assert_int64(v, ==, 1729);
psnip_atomic_int64_sub(&value64, 729);
v = psnip_atomic_int64_load(&value64);
munit_assert_int64(v, ==, 1000);
do {
expected = psnip_atomic_int64_load(&value64);
v = expected * expected;
} while (!psnip_atomic_int64_compare_exchange(&value64, &expected, v));
v = psnip_atomic_int64_load(&value64);
munit_assert_int64(v, ==, 1000 * 1000);
return MUNIT_OK;
#else
return MUNIT_SKIP;
#endif
}
static MunitResult
test_atomic_int32(const MunitParameter params[], void* data) {
#if !defined(PSNIP_ATOMIC_NOT_FOUND)
psnip_int32_t v, expected;
#endif
(void) params;
(void) data;
#if !defined(PSNIP_ATOMIC_NOT_FOUND)
v = psnip_atomic_int32_load(&value32);
munit_assert_int32(v, ==, 9);
v = v * v * v;
psnip_atomic_int32_store(&value32, v);
v = psnip_atomic_int32_load(&value32);
munit_assert_int32(v, ==, 729);
psnip_atomic_int32_add(&value32, 1000);
v = psnip_atomic_int32_load(&value32);
munit_assert_int32(v, ==, 1729);
psnip_atomic_int32_sub(&value32, 729);
v = psnip_atomic_int32_load(&value32);
munit_assert_int32(v, ==, 1000);
do {
expected = psnip_atomic_int32_load(&value32);
v = expected * expected;
} while (!psnip_atomic_int32_compare_exchange(&value32, &expected, v));
v = psnip_atomic_int32_load(&value32);
munit_assert_int32(v, ==, 1000 * 1000);
return MUNIT_OK;
#else
return MUNIT_SKIP;
#endif
}
static MunitTest test_suite_tests[] = {
{ (char*) "/atomic/int64", test_atomic_int64, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ (char*) "/atomic/int32", test_atomic_int32, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
};
static const MunitSuite test_suite = {
(char*) "", test_suite_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE
};
int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) {
return munit_suite_main(&test_suite, NULL, argc, argv);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,175 @@
#define _POSIX_C_SOURCE 199309L
#include "../exact-int/exact-int.h"
#include "../clock/clock.h"
#include "munit/munit.h"
/* These tests can yield false positives in some situations, but I'm
* having trouble thinking of better ways to test. Ideas welcome. */
#if !defined(_WIN32)
# include <unistd.h>
# define sleep_seconds(n) sleep(n)
#else
# include <Windows.h>
# define sleep_seconds(n) Sleep((n) * 1000)
#endif
static MunitResult
test_clock_wall_time(const MunitParameter params[], void* data) {
#if defined(PSNIP_CLOCK_WALL_METHOD)
struct PsnipClockTimespec res;
psnip_uint32_t precision = psnip_clock_get_precision(PSNIP_CLOCK_TYPE_WALL);
time_t t;
int r;
(void) params;
(void) data;
munit_logf(MUNIT_LOG_DEBUG, "Wall clock method: %d", PSNIP_CLOCK_WALL_METHOD);
munit_assert_uint32(precision, !=, 0);
t = time(NULL);
/* This test may fail if more than 1 second passes here, but this
* thread could conceivably be preempted for longer. */
r = psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &res);
munit_assert_int(r, ==, 0);
munit_assert_uint64(t, <=, res.seconds);
munit_assert_uint64(t, >=, res.seconds - 1);
return MUNIT_OK;
#else
(void) params;
(void) data;
return MUNIT_SKIP;
#endif
}
static int ts_difference(struct PsnipClockTimespec* earlier, struct PsnipClockTimespec* later) {
return
(int) ((later->seconds - earlier->seconds) * 1000) +
(int) ((((psnip_int64_t) later->nanoseconds) - ((psnip_int64_t) earlier->nanoseconds)) / 1000000);
}
static MunitResult
test_clock_wall_veracity(const MunitParameter params[], void* data) {
#if defined(PSNIP_CLOCK_WALL_METHOD)
struct PsnipClockTimespec res1, res2;
int elapsed_ms;
int r;
r = psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &res1);
munit_assert_int(r, ==, 0);
/* Assuming we aren't interrupted by a signal, aren't suspended for
* much more than 1 seconds, etc. */
sleep_seconds(1);
r = psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &res2);
munit_assert_int(r, ==, 0);
elapsed_ms = ts_difference(&res1, &res2);
munit_assert_int(elapsed_ms, >, 900);
munit_assert_int(elapsed_ms, <, 1100);
(void) params;
(void) data;
return MUNIT_OK;
#else
(void) params;
(void) data;
return MUNIT_SKIP;
#endif
}
static MunitResult
test_clock_cpu(const MunitParameter params[], void* data) {
#if defined(PSNIP_CLOCK_CPU_METHOD)
struct PsnipClockTimespec res1, res2;
psnip_uint32_t precision = psnip_clock_get_precision(PSNIP_CLOCK_TYPE_WALL);
int r;
int elapsed_ms;
munit_logf(MUNIT_LOG_DEBUG, "CPU clock method: %d", PSNIP_CLOCK_CPU_METHOD);
munit_assert_uint32(precision, !=, 0);
r = psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &res1);
munit_assert_int(r, ==, 0);
sleep_seconds(1);
r = psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &res2);
munit_assert_int(r, ==, 0);
elapsed_ms = ts_difference(&res1, &res2);
munit_assert_int(elapsed_ms, >=, 1000);
if (precision >= 1000)
munit_assert_int(elapsed_ms, <=, 1100);
(void) params;
(void) data;
return MUNIT_OK;
#else
(void) params;
(void) data;
return MUNIT_SKIP;
#endif
}
static MunitResult
test_clock_monotonic(const MunitParameter params[], void* data) {
#if defined(PSNIP_CLOCK_MONOTONIC_METHOD)
struct PsnipClockTimespec res1, res2;
int r;
int elapsed_ms;
r = psnip_clock_get_time(PSNIP_CLOCK_TYPE_MONOTONIC, &res1);
munit_assert_int(r, ==, 0);
/* Assuming we aren't interrupted by a signal, aren't suspended for
* much more than 2 seconds, etc. */
sleep_seconds(1);
r = psnip_clock_get_time(PSNIP_CLOCK_TYPE_MONOTONIC, &res2);
munit_assert_int(r, ==, 0);
elapsed_ms = ts_difference(&res1, &res2);
munit_assert_int(elapsed_ms, >, 900);
munit_assert_int(elapsed_ms, <, 1100);
(void) params;
(void) data;
return MUNIT_OK;
#else
return MUNIT_SKIP;
#endif
}
static MunitTest test_suite_tests[] = {
{ (char*) "/clock/wall/time", test_clock_wall_time, NULL, NULL, MUNIT_TEST_OPTION_SINGLE_ITERATION, NULL },
{ (char*) "/clock/wall/veracity", test_clock_wall_veracity, NULL, NULL, MUNIT_TEST_OPTION_SINGLE_ITERATION, NULL },
{ (char*) "/clock/cpu", test_clock_cpu, NULL, NULL, MUNIT_TEST_OPTION_SINGLE_ITERATION, NULL },
{ (char*) "/clock/monotonic", test_clock_monotonic, NULL, NULL, MUNIT_TEST_OPTION_SINGLE_ITERATION, NULL },
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
};
static const MunitSuite test_suite = {
(char*) "", test_suite_tests, NULL, 16384, MUNIT_SUITE_OPTION_NONE
};
int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) {
return munit_suite_main(&test_suite, NULL, argc, argv);
}

View file

@ -0,0 +1,171 @@
# This module provides a convenient way to add C/C++ compiler flags if
# the compiler supports them.
include (CheckCCompilerFlag)
include (CheckCXXCompilerFlag)
cmake_policy(SET CMP0054 NEW)
# Depending on the settings, some compilers will accept unknown flags.
# We try to disable this behavior by also passing these flags when we
# check if a flag is supported.
set (ADD_COMPILER_FLAGS_PREPEND "")
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
set (ADD_COMPILER_FLAGS_PREPEND "-Wall -Wextra -Werror")
elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
set (ADD_COMPILER_FLAGS_PREPEND "-Werror=unknown-warning-option")
endif ()
##
# Set a variable to different flags, depending on which compiler is in
# use.
#
# Example:
# set_compiler_flags(VARIABLE varname MSVC /wd666 INTEL /wd1729)
#
# This will set varname to /wd666 if the compiler is MSVC, and /wd1729
# if it is Intel.
#
# Possible compilers:
# - GCC: GNU C Compiler
# - GCCISH: A compiler that (tries to) be GCC-compatible on the CLI
# (i.e., anything but MSVC).
# - CLANG: clang
# - MSVC: Microsoft Visual C++ compiler
# - INTEL: Intel C Compiler
# - PGI: PGI C Compiler
#
# Note: the compiler is determined based on the value of the
# CMAKE_C_COMPILER_ID variable, not CMAKE_CXX_COMPILER_ID.
##
function (set_compiler_specific_flags)
set (oneValueArgs VARIABLE)
set (multiValueArgs GCC GCCISH INTEL CLANG MSVC PGI)
cmake_parse_arguments(COMPILER_SPECIFIC_FLAGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
unset (options)
unset (oneValueArgs)
unset (multiValueArgs)
set (compiler_flags)
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
list (APPEND compiler_flags ${COMPILER_SPECIFIC_FLAGS_GCC})
elseif(CMAKE_C_COMPILER_ID STREQUAL "Clang")
list (APPEND compiler_flags ${COMPILER_SPECIFIC_FLAGS_CLANG})
elseif(CMAKE_C_COMPILER_ID STREQUAL "Intel")
list (APPEND compiler_flags ${COMPILER_SPECIFIC_FLAGS_INTEL})
elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
list (APPEND compiler_flags ${COMPILER_SPECIFIC_FLAGS_MSVC})
elseif(CMAKE_C_COMPILER_ID STREQUAL "PGI")
list (APPEND compiler_flags ${COMPILER_SPECIFIC_FLAGS_PGI})
endif()
set(GCCISH_COMPILERS GNU Clang Intel)
list(FIND GCCISH_COMPILERS "${CMAKE_C_COMPILER_ID}" IS_GCCISH)
if (IS_GCCISH GREATER -1)
list (APPEND compiler_flags ${COMPILER_SPECIFIC_FLAGS_GCCISH})
endif ()
set (${COMPILER_SPECIFIC_FLAGS_VARIABLE} "${compiler_flags}" PARENT_SCOPE)
endfunction ()
function (source_file_add_compiler_flags_unchecked file)
set (flags ${ARGV})
list (REMOVE_AT flags 0)
get_source_file_property (sources ${file} SOURCES)
foreach (flag ${flags})
get_source_file_property (existing ${file} COMPILE_FLAGS)
if ("${existing}" STREQUAL "NOTFOUND")
set_source_files_properties (${file}
PROPERTIES COMPILE_FLAGS "${flag}")
else ()
set_source_files_properties (${file}
PROPERTIES COMPILE_FLAGS "${existing} ${flag}")
endif ()
endforeach (flag)
endfunction ()
function (source_file_add_compiler_flags file)
set (flags ${ARGV})
list (REMOVE_AT flags 0)
get_source_file_property (sources ${file} SOURCES)
foreach (flag ${flags})
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
# Because https://gcc.gnu.org/wiki/FAQ#wnowarning
string (REGEX REPLACE "\\-Wno\\-(.+)" "-W\\1" flag_to_test "${flag}")
else ()
set (flag_to_test ${flag})
endif ()
if (file MATCHES "\\.c$")
string (REGEX REPLACE "[^a-zA-Z0-9]+" "_" test_name "CFLAG_${flag_to_test}")
CHECK_C_COMPILER_FLAG ("${ADD_COMPILER_FLAGS_PREPEND} ${flag_to_test}" ${test_name})
elseif (file MATCHES "\\.(cpp|cc|cxx)$")
string (REGEX REPLACE "[^a-zA-Z0-9]+" "_" test_name "CXXFLAG_${flag_to_test}")
CHECK_CXX_COMPILER_FLAG ("${ADD_COMPILER_FLAGS_PREPEND} ${flag_to_test}" ${test_name})
endif ()
if (${test_name})
source_file_add_compiler_flags_unchecked (${file} ${flag})
endif ()
unset (test_name)
unset (flag_to_test)
endforeach (flag)
unset (flags)
endfunction ()
function (target_add_compiler_flags target)
set (flags ${ARGV})
list (REMOVE_AT flags 0)
get_target_property (sources ${target} SOURCES)
foreach (source ${sources})
source_file_add_compiler_flags (${source} ${flags})
endforeach (source)
unset (flags)
unset (sources)
endfunction (target_add_compiler_flags)
# global_add_compiler_flags (flag1 [flag2 [flag3 ...]]):
#
# This just adds the requested compiler flags to
# CMAKE_C/CXX_FLAGS variable if they work with the compiler.
function (global_add_compiler_flags)
set (flags ${ARGV})
foreach (flag ${flags})
if ("GNU" STREQUAL "${CMAKE_C_COMPILER_ID}")
# Because https://gcc.gnu.org/wiki/FAQ#wnowarning
string (REGEX REPLACE "\\-Wno\\-(.+)" "-W\\1" flag_to_test "${flag}")
else ()
set (flag_to_test "${flag}")
endif ()
string (REGEX REPLACE "[^a-zA-Z0-9]+" "_" c_test_name "CFLAG_${flag_to_test}")
CHECK_C_COMPILER_FLAG ("${ADD_COMPILER_FLAGS_PREPEND} ${flag_to_test}" ${c_test_name})
if (${c_test_name})
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}")
endif ()
unset (c_test_name)
string (REGEX REPLACE "[^a-zA-Z0-9]+" "_" cxx_test_name "CFLAG_${flag_to_test}")
CHECK_CXX_COMPILER_FLAG ("${ADD_COMPILER_FLAGS_PREPEND} ${flag_to_test}" ${cxx_test_name})
if (${cxx_test_name})
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}")
endif ()
unset (cxx_test_name)
unset (flag_to_test)
endforeach (flag)
unset (flags)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" PARENT_SCOPE)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE)
endfunction (global_add_compiler_flags)

View file

@ -0,0 +1,40 @@
include (CheckFunctionExists)
set(ClockGettime_LIBRARIES "")
set(ClockGettime_FOUND 0)
mark_as_advanced(ClockGettime_LIBRARIES CLOCK_GETTIME_FOUND)
set(CMAKE_REQUIRED_LIBRARIES_orig "${CMAKE_REQUIRED_LIBRARIES}")
set(CMAKE_REQUIRED_LIBRARIES "")
check_function_exists(clock_gettime ClockGettime_LIBC)
if(ClockGettime_LIBC)
set(ClockGettime_LIBRARIES "")
set(ClockGettime_FOUND 1)
else()
set(CMAKE_REQUIRED_LIBRARIES rt)
check_function_exists(clock_gettime ClockGettime_LIBRT)
if(ClockGettime_LIBRT)
set(ClockGettime_LIBRARIES rt)
set(ClockGettime_FOUND 1)
else()
# mingw puts clock_gettime in pthreads
set(CMAKE_REQUIRED_LIBRARIES pthread)
check_function_exists(clock_gettime ClockGettime_LIBPTHREAD)
if(ClockGettime_LIBPTHREAD)
set(ClockGettime_LIBRARIES pthread)
set(ClockGettime_FOUND 1)
endif()
unset(ClockGettime_LIBPTHREAD)
endif()
unset(ClockGettime_LIBRT)
endif()
unset(ClockGettime_LIBC)
set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_orig}")
unset(CMAKE_REQUIRED_LIBRARIES_orig)

View file

@ -0,0 +1,57 @@
#include "../exact-int/exact-int.h"
#include "../cpu/cpu.h"
#include "munit/munit.h"
static MunitResult
test_cpu_info(const MunitParameter params[], void* data) {
(void) params;
(void) data;
#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ > 7))
# if defined(PSNIP_CPU_ARCH_X86_64) || defined(PSNIP_CPU_ARCH_X86)
__builtin_cpu_init();
munit_assert_int(__builtin_cpu_supports("cmov") != 0, ==, psnip_cpu_feature_check(PSNIP_CPU_FEATURE_X86_CMOV));
munit_assert_int(__builtin_cpu_supports("mmx") != 0, ==, psnip_cpu_feature_check(PSNIP_CPU_FEATURE_X86_MMX));
munit_assert_int(__builtin_cpu_supports("popcnt") != 0, ==, psnip_cpu_feature_check(PSNIP_CPU_FEATURE_X86_POPCNT));
munit_assert_int(__builtin_cpu_supports("sse") != 0, ==, psnip_cpu_feature_check(PSNIP_CPU_FEATURE_X86_SSE));
munit_assert_int(__builtin_cpu_supports("sse2") != 0, ==, psnip_cpu_feature_check(PSNIP_CPU_FEATURE_X86_SSE2));
munit_assert_int(__builtin_cpu_supports("sse3") != 0, ==, psnip_cpu_feature_check(PSNIP_CPU_FEATURE_X86_SSE3));
munit_assert_int(__builtin_cpu_supports("sse4.1") != 0, ==, psnip_cpu_feature_check(PSNIP_CPU_FEATURE_X86_SSE4_1));
munit_assert_int(__builtin_cpu_supports("sse4.2") != 0, ==, psnip_cpu_feature_check(PSNIP_CPU_FEATURE_X86_SSE4_2));
munit_assert_int(__builtin_cpu_supports("avx") != 0, ==, psnip_cpu_feature_check(PSNIP_CPU_FEATURE_X86_AVX));
munit_assert_int(__builtin_cpu_supports("avx2") != 0, ==, psnip_cpu_feature_check(PSNIP_CPU_FEATURE_X86_AVX2));
#if __GNUC__ >= 5
munit_assert_int(__builtin_cpu_supports("avx512f") != 0, ==, psnip_cpu_feature_check(PSNIP_CPU_FEATURE_X86_AVX512F));
#endif
return MUNIT_OK;
# endif
#endif
return MUNIT_SKIP;
}
static MunitResult
test_cpu_count(const MunitParameter params[], void* data) {
(void) params;
(void) data;
munit_assert_int(psnip_cpu_count(), >, 0);
return MUNIT_OK;
}
static MunitTest test_suite_tests[] = {
{ (char*) "/cpu/info", test_cpu_info, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ (char*) "/cpu/count", test_cpu_count, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
};
static const MunitSuite test_suite = {
(char*) "", test_suite_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE
};
int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) {
return munit_suite_main(&test_suite, NULL, argc, argv);
}

View file

@ -0,0 +1,139 @@
#include <stdlib.h>
#include "../exact-int/exact-int.h"
#include "../endian/endian.h"
#include "munit/munit.h"
const union {
unsigned char bytes[2];
psnip_uint16_t value;
} test_data_16 = {
{ 1, 2 }
};
const union {
unsigned char bytes[4];
psnip_uint32_t value;
} test_data_32 = {
{ 1, 2, 3, 4 }
};
const union {
unsigned char bytes[8];
psnip_uint64_t value;
} test_data_64 = {
{ 1, 2, 3, 4, 5, 6, 7, 8 }
};
#if !defined(UINT8_C)
# define UINT8_C(c) ((psnip_uint8_t) (c ## U))
#endif
#if !defined(UINT16_C)
# define UINT16_C(c) ((psnip_uint16_t) (c ## U))
#endif
#if !defined(UINT32_C)
# define UINT32_C(c) c ## U
#endif
#if !defined(UINT64_C)
# define UINT64_C(c) c ## ULL
#endif
static MunitResult
test_endian_swap_known(const MunitParameter params[], void* data) {
(void) params;
(void) data;
munit_assert_uint16(psnip_builtin_bswap16(UINT16_C(0xefbe)), ==, UINT16_C(0xbeef));
munit_assert_uint32(psnip_builtin_bswap32(UINT32_C(0xefbeadde)), ==, UINT32_C(0xdeadbeef));
munit_assert_uint64(psnip_builtin_bswap64(UINT64_C(0x0df0dde0fe0fdcba)), ==, UINT64_C(0xbadc0ffee0ddf00d));
return MUNIT_OK;
}
static MunitResult
test_endian_swap_random(const MunitParameter params[], void* data) {
(void) params;
(void) data;
munit_assert_uint16(psnip_builtin_bswap16(UINT16_C(0xefbe)), ==, UINT16_C(0xbeef));
{
const psnip_uint16_t input = (psnip_uint16_t) munit_rand_uint32();
const psnip_uint16_t swapped = psnip_builtin_bswap16(input);
const psnip_uint16_t double_swapped = psnip_builtin_bswap16(swapped);
munit_assert_uint16(input, ==, double_swapped);
}
munit_assert_uint32(psnip_builtin_bswap32(UINT32_C(0xefbeadde)), ==, UINT32_C(0xdeadbeef));
{
const psnip_uint32_t input = munit_rand_uint32();
const psnip_uint32_t swapped = psnip_builtin_bswap32(input);
const psnip_uint32_t double_swapped = psnip_builtin_bswap32(swapped);
munit_assert_uint32(input, ==, double_swapped);
}
munit_assert_uint64(psnip_builtin_bswap64(UINT64_C(0xdf0dde0fe0fdcba)), ==, UINT64_C(0xbadc0ffee0ddf00d));
{
const psnip_uint64_t input = (((psnip_uint64_t) munit_rand_uint32()) << 32) | munit_rand_uint32();
const psnip_uint64_t swapped = psnip_builtin_bswap64(input);
const psnip_uint64_t double_swapped = psnip_builtin_bswap64(swapped);
munit_assert_uint64(input, ==, double_swapped);
}
return MUNIT_OK;
}
static MunitResult
test_endian_from_be(const MunitParameter params[], void* data) {
(void) params;
(void) data;
munit_assert_uint16(psnip_endian_be16(test_data_16.value), ==, UINT16_C(0x0102));
munit_assert_uint32(psnip_endian_be32(test_data_32.value), ==, UINT32_C(0x01020304));
munit_assert_uint64(psnip_endian_be64(test_data_64.value), ==, UINT64_C(0x0102030405060708));
return MUNIT_OK;
}
static MunitResult
test_endian_from_le(const MunitParameter params[], void* data) {
(void) params;
(void) data;
munit_assert_uint16(psnip_endian_le16(test_data_16.value), ==, UINT16_C(0x0201));
munit_assert_uint32(psnip_endian_le32(test_data_32.value), ==, UINT32_C(0x04030201));
munit_assert_uint64(psnip_endian_le64(test_data_64.value), ==, UINT64_C(0x0807060504030201));
return MUNIT_OK;
}
static MunitResult
test_endian_match_rt(const MunitParameter params[], void* data) {
(void) params;
(void) data;
#if defined(PSNIP_ENDIAN_ORDER)
munit_assert_uint32(PSNIP_ENDIAN_ORDER, ==, PSNIP_ENDIAN_ORDER_RT);
#endif
return MUNIT_OK;
}
static MunitTest test_suite_tests[] = {
{ (char*) "/endian/swap/known", test_endian_swap_known, NULL, NULL, MUNIT_TEST_OPTION_SINGLE_ITERATION, NULL },
{ (char*) "/endian/swap/random", test_endian_swap_random, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ (char*) "/endian/from-be", test_endian_from_be, NULL, NULL, MUNIT_TEST_OPTION_SINGLE_ITERATION, NULL },
{ (char*) "/endian/from-le", test_endian_from_le, NULL, NULL, MUNIT_TEST_OPTION_SINGLE_ITERATION, NULL },
{ (char*) "/endian/match-rt", test_endian_match_rt, NULL, NULL, MUNIT_TEST_OPTION_SINGLE_ITERATION, NULL },
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
};
static const MunitSuite test_suite = {
(char*) "", test_suite_tests, NULL, 16384, MUNIT_SUITE_OPTION_NONE
};
int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) {
return munit_suite_main(&test_suite, NULL, argc, argv);
}

View file

@ -0,0 +1,34 @@
version: "{build}"
environment:
matrix:
- ARCHITECTURE: x64
MSVC_VER: 14
- ARCHITECTURE: x86
MSVC_VER: 14
- ARCHITECTURE: x64
MSVC_VER: 12
- ARCHITECTURE: x86
MSVC_VER: 12
- ARCHITECTURE: x86
MSVC_VER: 11
- ARCHITECTURE: x86
MSVC_VER: 10
- ARCHITECTURE: x86
MSVC_VER: 9
branches:
except:
- master
- /^(wip\/)?(travis|osx|mingw|ipp)(\-.+)?$/
configuration: Debug
install:
before_build:
- call "C:\Program Files (x86)\Microsoft Visual Studio %MSVC_VER%.0\VC\vcvarsall.bat" %ARCHITECTURE%
build_script: cl.exe /W4 /WX /Feexample munit.c example.c
test_script: example.exe --color always

View file

@ -0,0 +1,2 @@
((nil . ((indent-tabs-mode . nil)
(c-basic-offset . 2))))

View file

@ -0,0 +1,6 @@
*~
.#*
/*.o
/example
/*.exe
/*.dll

View file

@ -0,0 +1,142 @@
language: c
sudo: false
dist: trusty
branches:
except:
- /^(wip\/)?(appveyor|msvc|mingw|windows)(\-.+)?$/
- /^master$/
matrix:
include:
###
## Linux builds using various versions of GCC.
###
- env: C_COMPILER=gcc-6
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-6
- g++-6
- env: C_COMPILER=gcc-5
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-5
- g++-5
# - env: C_COMPILER=gcc-4.9
# addons:
# apt:
# sources:
# - ubuntu-toolchain-r-test
# packages:
# - gcc-4.9
# - g++-4.9
- env: C_COMPILER=gcc-4.8
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-4.8
- g++-4.8
# - env: C_COMPILER=gcc-4.7
# addons:
# apt:
# sources:
# - ubuntu-toolchain-r-test
# packages:
# - gcc-4.7
# - g++-4.7
- env: C_COMPILER=gcc-4.6
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-4.6
- g++-4.6
# - os: linux
# env: C_COMPILER=gcc-4.5
# addons:
# apt:
# sources:
# - ubuntu-toolchain-r-test
# packages:
# - gcc-4.5
# - g++-4.5
- env: C_COMPILER=gcc-4.4
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-4.4
- g++-4.4
###
## clang on Linux
###
- env: C_COMPILER=clang-3.9
addons:
apt:
sources:
- llvm-toolchain-precise-3.9
- ubuntu-toolchain-r-test
packages:
- clang-3.9
# - env: C_COMPILER=clang-3.8
# addons:
# apt:
# sources:
# - llvm-toolchain-precise-3.8
# - ubuntu-toolchain-r-test
# packages:
# - clang-3.8
- env: C_COMPILER=clang-3.7
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- clang-3.7
# - env: C_COMPILER=clang-3.6
# addons:
# apt:
# sources:
# - llvm-toolchain-precise-3.6
# - ubuntu-toolchain-r-test
# packages:
# - clang-3.6
- env: C_COMPILER=clang-3.5
addons:
apt:
sources:
- llvm-toolchain-precise-3.5
- ubuntu-toolchain-r-test
packages:
- clang-3.5
###
## PGI
###
- env: C_COMPILER=pgcc OPENMP=y
###
## OS X
###
- os: osx
before_install:
- if [ -n "${C_COMPILER}" ]; then export CC="${C_COMPILER}"; fi
- if [ "${C_COMPILER}" = "pgcc" ]; then wget -q -O /dev/stdout 'https://raw.githubusercontent.com/nemequ/pgi-travis/master/install-pgi.sh' | /bin/sh; fi
script:
- make CC="${CC}" AGGRESSIVE_WARNINGS=y EXTENSION="${EXTENSION}" OPENMP="${OPENMP}" ASAN="${ASAN}" UBSAN="${UBSAN}"
- make test
notifications:
email: false

View file

@ -0,0 +1,21 @@
µnit Testing Framework
Copyright (c) 2013-2016 Evan Nemerson <evan@nemerson.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,55 @@
# Using µnit is very simple; just include the header and add the C
# file to your sources. That said, here is a simple Makefile to build
# the example.
CSTD:=99
OPENMP:=n
ASAN:=n
UBSAN:=n
EXTENSION:=
TEST_ENV:=
CFLAGS:=
AGGRESSIVE_WARNINGS=n
ifeq ($(CC),pgcc)
CFLAGS+=-c$(CSTD)
else
CFLAGS+=-std=c$(CSTD)
endif
ifeq ($(OPENMP),y)
ifeq ($(CC),pgcc)
CFLAGS+=-mp
else
CFLAGS+=-fopenmp
endif
endif
ifneq ($(SANITIZER),)
CFLAGS+=-fsanitize=$(SANITIZER)
endif
ifneq ($(CC),pgcc)
ifeq ($(EXTRA_WARNINGS),y)
CFLAGS+=-Wall -Wextra -Werror
endif
ifeq ($(ASAN),y)
CFLAGS+=-fsanitize=address
endif
ifeq ($(UBSAN),y)
CFLAGS+=-fsanitize=undefined
endif
endif
example$(EXTENSION): munit.h munit.c example.c
$(CC) $(CFLAGS) -o $@ munit.c example.c
test:
$(TEST_ENV) ./example$(EXTENSION)
clean:
rm -f example$(EXTENSION)
all: example$(EXTENSION)

View file

@ -0,0 +1,40 @@
# µnit
µnit is a small but full-featured unit testing framework for C. It has
no dependencies (beyond libc), is permissively licensed (MIT), and is
easy to include into any project.
For more information, see
[the µnit web site](https://nemequ.github.io/munit).
[![Build status](https://travis-ci.org/nemequ/munit.svg?branch=master)](https://travis-ci.org/nemequ/munit)
[![Windows build status](https://ci.appveyor.com/api/projects/status/db515g5ifcwjohq7/branch/master?svg=true)](https://ci.appveyor.com/project/quixdb/munit/branch/master)
## Features
Features µnit currently includes include:
* Handy assertion macros which make for nice error messages.
* Reproducible cross-platform random number generation, including
support for supplying a seed via CLI.
* Timing of both wall-clock and CPU time.
* Parameterized tests.
* Nested test suites.
* Flexible CLI.
* Forking
([except on Windows](https://github.com/nemequ/munit/issues/2)).
* Hiding output of successful tests.
Features µnit does not currently include, but some day may include
(a.k.a., if you file a PR…), include:
* [TAP](http://testanything.org/) support; feel free to discuss in
[issue #1](https://github.com/nemequ/munit/issues/1)
## Documentation
See [the µnit web site](https://nemequ.github.io/munit).
Additionally, there is a heavily-commented
[example.c](https://github.com/nemequ/munit/blob/master/example.c) in
the repository.

View file

@ -0,0 +1,351 @@
/* Example file for using µnit.
*
* µnit is MIT-licensed, but for this file and this file alone:
*
* To the extent possible under law, the author(s) of this file have
* waived all copyright and related or neighboring rights to this
* work. See <https://creativecommons.org/publicdomain/zero/1.0/> for
* details.
*********************************************************************/
#include "munit.h"
/* This is just to disable an MSVC warning about conditional
* expressions being constant, which you shouldn't have to do for your
* code. It's only here because we want to be able to do silly things
* like assert that 0 != 1 for our demo. */
#if defined(_MSC_VER)
#pragma warning(disable: 4127)
#endif
/* Tests are functions that return void, and take a single void*
* parameter. We'll get to what that parameter is later. */
static MunitResult
test_compare(const MunitParameter params[], void* data) {
/* We'll use these later */
const unsigned char val_uchar = 'b';
const short val_short = 1729;
double pi = 3.141592654;
char* stewardesses = "stewardesses";
char* most_fun_word_to_type;
/* These are just to silence compiler warnings about the parameters
* being unused. */
(void) params;
(void) data;
/* Let's start with the basics. */
munit_assert(0 != 1);
/* There is also the more verbose, though slightly more descriptive
munit_assert_true/false: */
munit_assert_false(0);
/* You can also call munit_error and munit_errorf yourself. We
* won't do it is used to indicate a failure, but here is what it
* would look like: */
/* munit_error("FAIL"); */
/* munit_errorf("Goodbye, cruel %s", "world"); */
/* There are macros for comparing lots of types. */
munit_assert_char('a', ==, 'a');
/* Sure, you could just assert('a' == 'a'), but if you did that, a
* failed assertion would just say something like "assertion failed:
* val_uchar == 'b'". µnit will tell you the actual values, so a
* failure here would result in something like "assertion failed:
* val_uchar == 'b' ('X' == 'b')." */
munit_assert_uchar(val_uchar, ==, 'b');
/* Obviously we can handle values larger than 'char' and 'uchar'.
* There are versions for char, short, int, long, long long,
* int8/16/32/64_t, as well as the unsigned versions of them all. */
munit_assert_short(42, <, val_short);
/* There is also support for size_t.
*
* The longest word in English without repeating any letters is
* "uncopyrightables", which has uncopyrightable (and
* dermatoglyphics, which is the study of fingerprints) beat by a
* character */
munit_assert_size(strlen("uncopyrightables"), >, strlen("dermatoglyphics"));
/* Of course there is also support for doubles and floats. */
munit_assert_double(pi, ==, 3.141592654);
/* If you want to compare two doubles for equality, you might want
* to consider using munit_assert_double_equal. It compares two
* doubles for equality within a precison of 1.0 x 10^-(precision).
* Note that precision (the third argument to the macro) needs to be
* fully evaluated to an integer by the preprocessor so µnit doesn't
* have to depend pow, which is often in libm not libc. */
munit_assert_double_equal(3.141592654, 3.141592653589793, 9);
/* And if you want to check strings for equality (or inequality),
* there is munit_assert_string_equal/not_equal.
*
* "stewardesses" is the longest word you can type on a QWERTY
* keyboard with only one hand, which makes it loads of fun to type.
* If I'm going to have to type a string repeatedly, let's make it a
* good one! */
munit_assert_string_equal(stewardesses, "stewardesses");
/* A personal favorite macro which is fantastic if you're working
* with binary data, is the one which naïvely checks two blobs of
* memory for equality. If this fails it will tell you the offset
* of the first differing byte. */
munit_assert_memory_equal(7, stewardesses, "steward");
/* You can also make sure that two blobs differ *somewhere*: */
munit_assert_memory_not_equal(8, stewardesses, "steward");
/* There are equal/not_equal macros for pointers, too: */
most_fun_word_to_type = stewardesses;
munit_assert_ptr_equal(most_fun_word_to_type, stewardesses);
/* And null/not_null */
munit_assert_null(NULL);
munit_assert_not_null(most_fun_word_to_type);
/* Lets verify that the data parameter is what we expected. We'll
* see where this comes from in a bit.
*
* Note that the casting isn't usually required; if you give this
* function a real pointer (instead of a number like 0xdeadbeef) it
* would work as expected. */
munit_assert_ptr_equal(data, (void*)(uintptr_t)0xdeadbeef);
return MUNIT_OK;
}
static MunitResult
test_rand(const MunitParameter params[], void* user_data) {
int random_int;
double random_dbl;
munit_uint8_t data[5];
(void) params;
(void) user_data;
/* One thing missing from a lot of unit testing frameworks is a
* random number generator. You can't just use srand/rand because
* the implementation varies across different platforms, and it's
* important to be able to look at the seed used in a failing test
* to see if you can reproduce it. Some randomness is a fantastic
* thing to have in your tests, I don't know why more people don't
* do it...
*
* µnit's PRNG is re-seeded with the same value for each iteration
* of each test. The seed is retrieved from the MUNIT_SEED
* envirnment variable or, if none is provided, one will be
* (pseudo-)randomly generated. */
/* If you need an integer in a given range */
random_int = munit_rand_int_range(128, 4096);
munit_assert_int(random_int, >=, 128);
munit_assert_int(random_int, <=, 4096);
/* Or maybe you want a double, between 0 and 1: */
random_dbl = munit_rand_double();
munit_assert_double(random_dbl, >=, 0.0);
munit_assert_double(random_dbl, <=, 1.0);
/* Of course, you want to be able to reproduce bugs discovered
* during testing, so every time the tests are run they print the
* random seed used. When you want to reproduce a result, just put
* that random seed in the MUNIT_SEED environment variable; it even
* works on different platforms.
*
* If you want this to pass, use 0xdeadbeef as the random seed and
* uncomment the next line of code. Note that the PRNG is not
* re-seeded between iterations of the same test, so this will only
* work on the first iteration. */
/* munit_assert_uint32(munit_rand_uint32(), ==, 1306447409); */
/* You can also get blobs of random memory: */
munit_rand_memory(sizeof(data), data);
return MUNIT_OK;
}
/* This test case shows how to accept parameters. We'll see how to
* specify them soon.
*
* By default, every possible variation of a parameterized test is
* run, but you can specify parameters manually if you want to only
* run specific test(s), or you can pass the --single argument to the
* CLI to have the harness simply choose one variation at random
* instead of running them all. */
static MunitResult
test_parameters(const MunitParameter params[], void* user_data) {
const char* foo;
const char* bar;
(void) user_data;
/* The "foo" parameter is specified as one of the following values:
* "one", "two", or "three". */
foo = munit_parameters_get(params, "foo");
/* Similarly, "bar" is one of "four", "five", or "six". */
bar = munit_parameters_get(params, "bar");
/* "baz" is a bit more complicated. We don't actually specify a
* list of valid values, so by default NULL is passed. However, the
* CLI will accept any value. This is a good way to have a value
* that is usually selected randomly by the test, but can be
* overridden on the command line if desired. */
/* const char* baz = munit_parameters_get(params, "baz"); */
/* Notice that we're returning MUNIT_FAIL instead of writing an
* error message. Error messages are generally preferable, since
* they make it easier to diagnose the issue, but this is an
* option.
*
* Possible values are:
* - MUNIT_OK: Sucess
* - MUNIT_FAIL: Failure
* - MUNIT_SKIP: The test was skipped; usually this happens when a
* particular feature isn't in use. For example, if you're
* writing a test which uses a Wayland-only feature, but your
* application is running on X11.
* - MUNIT_ERROR: The test failed, but not because of anything you
* wanted to test. For example, maybe your test downloads a
* remote resource and tries to parse it, but the network was
* down.
*/
if (strcmp(foo, "one") != 0 &&
strcmp(foo, "two") != 0 &&
strcmp(foo, "three") != 0)
return MUNIT_FAIL;
if (strcmp(bar, "red") != 0 &&
strcmp(bar, "green") != 0 &&
strcmp(bar, "blue") != 0)
return MUNIT_FAIL;
return MUNIT_OK;
}
/* The setup function, if you provide one, for a test will be run
* before the test, and the return value will be passed as the sole
* parameter to the test function. */
static void*
test_compare_setup(const MunitParameter params[], void* user_data) {
(void) params;
munit_assert_string_equal(user_data, "µnit");
return (void*) (uintptr_t) 0xdeadbeef;
}
/* To clean up after a test, you can use a tear down function. The
* fixture argument is the value returned by the setup function
* above. */
static void
test_compare_tear_down(void* fixture) {
munit_assert_ptr_equal(fixture, (void*)(uintptr_t)0xdeadbeef);
}
static char* foo_params[] = {
(char*) "one", (char*) "two", (char*) "three", NULL
};
static char* bar_params[] = {
(char*) "red", (char*) "green", (char*) "blue", NULL
};
static MunitParameterEnum test_params[] = {
{ (char*) "foo", foo_params },
{ (char*) "bar", bar_params },
{ (char*) "baz", NULL },
{ NULL, NULL },
};
/* Creating a test suite is pretty simple. First, you'll need an
* array of tests: */
static MunitTest test_suite_tests[] = {
{
/* The name is just a unique human-readable way to identify the
* test. You can use it to run a specific test if you want, but
* usually it's mostly decorative. */
(char*) "/example/compare",
/* You probably won't be surprised to learn that the tests are
* functions. */
test_compare,
/* If you want, you can supply a function to set up a fixture. If
* you supply NULL, the user_data parameter from munit_suite_main
* will be used directly. If, however, you provide a callback
* here the user_data parameter will be passed to this callback,
* and the return value from this callback will be passed to the
* test function.
*
* For our example we don't really need a fixture, but lets
* provide one anyways. */
test_compare_setup,
/* If you passed a callback for the fixture setup function, you
* may want to pass a corresponding callback here to reverse the
* operation. */
test_compare_tear_down,
/* Finally, there is a bitmask for options you can pass here. You
* can provide either MUNIT_TEST_OPTION_NONE or 0 here to use the
* defaults. */
MUNIT_TEST_OPTION_NONE,
NULL
},
/* Usually this is written in a much more compact format; all these
* comments kind of ruin that, though. Here is how you'll usually
* see entries written: */
{ (char*) "/example/rand", test_rand, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
/* To tell the test runner when the array is over, just add a NULL
* entry at the end. */
{ (char*) "/example/parameters", test_parameters, NULL, NULL, MUNIT_TEST_OPTION_NONE, test_params },
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
};
/* If you wanted to have your test suite run other test suites you
* could declare an array of them. Of course each sub-suite can
* contain more suites, etc. */
/* static const MunitSuite other_suites[] = { */
/* { "/second", test_suite_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE }, */
/* { NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE } */
/* }; */
/* Now we'll actually declare the test suite. You could do this in
* the main function, or on the heap, or whatever you want. */
static const MunitSuite test_suite = {
/* This string will be prepended to all test names in this suite;
* for example, "/example/rand" will become "/µnit/example/rand".
* Note that, while it doesn't really matter for the top-level
* suite, NULL signal the end of an array of tests; you should use
* an empty string ("") instead. */
(char*) "",
/* The first parameter is the array of test suites. */
test_suite_tests,
/* In addition to containing test cases, suites can contain other
* test suites. This isn't necessary in this example, but it can be
* a great help to projects with lots of tests by making it easier
* to spread the tests across many files. This is where you would
* put "other_suites" (which is commented out above). */
NULL,
/* An interesting feature of µnit is that it supports automatically
* running multiple iterations of the tests. This is usually only
* interesting if you make use of the PRNG to randomize your tests
* cases a bit, or if you are doing performance testing and want to
* average multiple runs. 0 is an alias for 1. */
1,
/* Just like MUNIT_TEST_OPTION_NONE, you can provide
* MUNIT_SUITE_OPTION_NONE or 0 to use the default settings. */
MUNIT_SUITE_OPTION_NONE
};
/* This is only necessary for EXIT_SUCCESS and EXIT_FAILURE, which you
* *should* be using but probably aren't (no, zero and non-zero don't
* always mean success and failure). I guess my point is that nothing
* about µnit requires it. */
#include <stdlib.h>
int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) {
/* Finally, we'll actually run our test suite! That second argument
* is the user_data parameter which will be passed either to the
* test or (if provided) the fixture setup function. */
return munit_suite_main(&test_suite, (void*) "µnit", argc, argv);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,533 @@
/* µnit Testing Framework
* Copyright (c) 2013-2017 Evan Nemerson <evan@nemerson.com>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#if !defined(MUNIT_H)
#define MUNIT_H
#include <stdarg.h>
#include <stdlib.h>
#define MUNIT_VERSION(major, minor, revision) \
(((major) << 16) | ((minor) << 8) | (revision))
#define MUNIT_CURRENT_VERSION MUNIT_VERSION(0, 4, 1)
#if defined(_MSC_VER) && (_MSC_VER < 1600)
# define munit_int8_t __int8
# define munit_uint8_t unsigned __int8
# define munit_int16_t __int16
# define munit_uint16_t unsigned __int16
# define munit_int32_t __int32
# define munit_uint32_t unsigned __int32
# define munit_int64_t __int64
# define munit_uint64_t unsigned __int64
#else
# include <stdint.h>
# define munit_int8_t int8_t
# define munit_uint8_t uint8_t
# define munit_int16_t int16_t
# define munit_uint16_t uint16_t
# define munit_int32_t int32_t
# define munit_uint32_t uint32_t
# define munit_int64_t int64_t
# define munit_uint64_t uint64_t
#endif
#if defined(_MSC_VER) && (_MSC_VER < 1800)
# if !defined(PRIi8)
# define PRIi8 "i"
# endif
# if !defined(PRIi16)
# define PRIi16 "i"
# endif
# if !defined(PRIi32)
# define PRIi32 "i"
# endif
# if !defined(PRIi64)
# define PRIi64 "I64i"
# endif
# if !defined(PRId8)
# define PRId8 "d"
# endif
# if !defined(PRId16)
# define PRId16 "d"
# endif
# if !defined(PRId32)
# define PRId32 "d"
# endif
# if !defined(PRId64)
# define PRId64 "I64d"
# endif
# if !defined(PRIx8)
# define PRIx8 "x"
# endif
# if !defined(PRIx16)
# define PRIx16 "x"
# endif
# if !defined(PRIx32)
# define PRIx32 "x"
# endif
# if !defined(PRIx64)
# define PRIx64 "I64x"
# endif
# if !defined(PRIu8)
# define PRIu8 "u"
# endif
# if !defined(PRIu16)
# define PRIu16 "u"
# endif
# if !defined(PRIu32)
# define PRIu32 "u"
# endif
# if !defined(PRIu64)
# define PRIu64 "I64u"
# endif
# if !defined(bool)
# define bool int
# endif
# if !defined(true)
# define true (!0)
# endif
# if !defined(false)
# define false (!!0)
# endif
#else
# include <inttypes.h>
# include <stdbool.h>
#endif
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(__GNUC__)
# define MUNIT_LIKELY(expr) (__builtin_expect ((expr), 1))
# define MUNIT_UNLIKELY(expr) (__builtin_expect ((expr), 0))
# define MUNIT_UNUSED __attribute__((__unused__))
#else
# define MUNIT_LIKELY(expr) (expr)
# define MUNIT_UNLIKELY(expr) (expr)
# define MUNIT_UNUSED
#endif
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__PGI)
# define MUNIT_ARRAY_PARAM(name) name
#else
# define MUNIT_ARRAY_PARAM(name)
#endif
#if !defined(_WIN32)
# define MUNIT_SIZE_MODIFIER "z"
# define MUNIT_CHAR_MODIFIER "hh"
# define MUNIT_SHORT_MODIFIER "h"
#else
# if defined(_M_X64) || defined(__amd64__)
# define MUNIT_SIZE_MODIFIER "I64"
# else
# define MUNIT_SIZE_MODIFIER ""
# endif
# define MUNIT_CHAR_MODIFIER ""
# define MUNIT_SHORT_MODIFIER ""
#endif
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
# define MUNIT_NO_RETURN _Noreturn
#elif defined(__GNUC__)
# define MUNIT_NO_RETURN __attribute__((__noreturn__))
#elif defined(_MSC_VER)
# define MUNIT_NO_RETURN __declspec(noreturn)
#else
# define MUNIT_NO_RETURN
#endif
#if defined(_MSC_VER) && (_MSC_VER >= 1500)
# define MUNIT__PUSH_DISABLE_MSVC_C4127 __pragma(warning(push)) __pragma(warning(disable:4127))
# define MUNIT__POP_DISABLE_MSVC_C4127 __pragma(warning(pop))
#else
# define MUNIT__PUSH_DISABLE_MSVC_C4127
# define MUNIT__POP_DISABLE_MSVC_C4127
#endif
typedef enum {
MUNIT_LOG_DEBUG,
MUNIT_LOG_INFO,
MUNIT_LOG_WARNING,
MUNIT_LOG_ERROR
} MunitLogLevel;
#if defined(__GNUC__) && !defined(__MINGW32__)
# define MUNIT_PRINTF(string_index, first_to_check) __attribute__((format (printf, string_index, first_to_check)))
#else
# define MUNIT_PRINTF(string_index, first_to_check)
#endif
MUNIT_PRINTF(4, 5)
void munit_logf_ex(MunitLogLevel level, const char* filename, int line, const char* format, ...);
#define munit_logf(level, format, ...) \
munit_logf_ex(level, __FILE__, __LINE__, format, __VA_ARGS__)
#define munit_log(level, msg) \
munit_logf(level, "%s", msg)
MUNIT_NO_RETURN
MUNIT_PRINTF(3, 4)
void munit_errorf_ex(const char* filename, int line, const char* format, ...);
#define munit_errorf(format, ...) \
munit_errorf_ex(__FILE__, __LINE__, format, __VA_ARGS__)
#define munit_error(msg) \
munit_errorf("%s", msg)
#define munit_assert(expr) \
do { \
if (!MUNIT_LIKELY(expr)) { \
munit_error("assertion failed: " #expr); \
} \
MUNIT__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
MUNIT__POP_DISABLE_MSVC_C4127
#define munit_assert_true(expr) \
do { \
if (!MUNIT_LIKELY(expr)) { \
munit_error("assertion failed: " #expr " is not true"); \
} \
MUNIT__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
MUNIT__POP_DISABLE_MSVC_C4127
#define munit_assert_false(expr) \
do { \
if (!MUNIT_LIKELY(!(expr))) { \
munit_error("assertion failed: " #expr " is not false"); \
} \
MUNIT__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
MUNIT__POP_DISABLE_MSVC_C4127
#define munit_assert_type_full(prefix, suffix, T, fmt, a, op, b) \
do { \
T munit_tmp_a_ = (a); \
T munit_tmp_b_ = (b); \
if (!(munit_tmp_a_ op munit_tmp_b_)) { \
munit_errorf("assertion failed: " #a " " #op " " #b " (" prefix "%" fmt suffix " " #op " " prefix "%" fmt suffix ")", \
munit_tmp_a_, munit_tmp_b_); \
} \
MUNIT__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
MUNIT__POP_DISABLE_MSVC_C4127
#define munit_assert_type(T, fmt, a, op, b) \
munit_assert_type_full("", "", T, fmt, a, op, b)
#define munit_assert_char(a, op, b) \
munit_assert_type_full("'\\x", "'", char, "02" MUNIT_CHAR_MODIFIER "x", a, op, b)
#define munit_assert_uchar(a, op, b) \
munit_assert_type_full("'\\x", "'", unsigned char, "02" MUNIT_CHAR_MODIFIER "x", a, op, b)
#define munit_assert_short(a, op, b) \
munit_assert_type(short, MUNIT_SHORT_MODIFIER "d", a, op, b)
#define munit_assert_ushort(a, op, b) \
munit_assert_type(unsigned short, MUNIT_SHORT_MODIFIER "u", a, op, b)
#define munit_assert_int(a, op, b) \
munit_assert_type(int, "d", a, op, b)
#define munit_assert_uint(a, op, b) \
munit_assert_type(unsigned int, "u", a, op, b)
#define munit_assert_long(a, op, b) \
munit_assert_type(long int, "ld", a, op, b)
#define munit_assert_ulong(a, op, b) \
munit_assert_type(unsigned long int, "lu", a, op, b)
#define munit_assert_llong(a, op, b) \
munit_assert_type(long long int, "lld", a, op, b)
#define munit_assert_ullong(a, op, b) \
munit_assert_type(unsigned long long int, "llu", a, op, b)
#define munit_assert_size(a, op, b) \
munit_assert_type(size_t, MUNIT_SIZE_MODIFIER "u", a, op, b)
#define munit_assert_float(a, op, b) \
munit_assert_type(float, "f", a, op, b)
#define munit_assert_double(a, op, b) \
munit_assert_type(double, "g", a, op, b)
#define munit_assert_ptr(a, op, b) \
munit_assert_type(const void*, "p", a, op, b)
#define munit_assert_int8(a, op, b) \
munit_assert_type(munit_int8_t, PRIi8, a, op, b)
#define munit_assert_uint8(a, op, b) \
munit_assert_type(munit_uint8_t, PRIu8, a, op, b)
#define munit_assert_int16(a, op, b) \
munit_assert_type(munit_int16_t, PRIi16, a, op, b)
#define munit_assert_uint16(a, op, b) \
munit_assert_type(munit_uint16_t, PRIu16, a, op, b)
#define munit_assert_int32(a, op, b) \
munit_assert_type(munit_int32_t, PRIi32, a, op, b)
#define munit_assert_uint32(a, op, b) \
munit_assert_type(munit_uint32_t, PRIu32, a, op, b)
#define munit_assert_int64(a, op, b) \
munit_assert_type(munit_int64_t, PRIi64, a, op, b)
#define munit_assert_uint64(a, op, b) \
munit_assert_type(munit_uint64_t, PRIu64, a, op, b)
#define munit_assert_double_equal(a, b, precision) \
do { \
const double munit_tmp_a_ = (a); \
const double munit_tmp_b_ = (b); \
const double munit_tmp_diff_ = ((munit_tmp_a_ - munit_tmp_b_) < 0) ? \
-(munit_tmp_a_ - munit_tmp_b_) : \
(munit_tmp_a_ - munit_tmp_b_); \
if (MUNIT_UNLIKELY(munit_tmp_diff_ > 1e-##precision)) { \
munit_errorf("assertion failed: " #a " == " #b " (%0." #precision "g == %0." #precision "g)", \
munit_tmp_a_, munit_tmp_b_); \
} \
MUNIT__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
MUNIT__POP_DISABLE_MSVC_C4127
#include <string.h>
#define munit_assert_string_equal(a, b) \
do { \
const char* munit_tmp_a_ = a; \
const char* munit_tmp_b_ = b; \
if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) != 0)) { \
munit_errorf("assertion failed: string " #a " == " #b " (\"%s\" == \"%s\")", \
munit_tmp_a_, munit_tmp_b_); \
} \
MUNIT__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
MUNIT__POP_DISABLE_MSVC_C4127
#define munit_assert_string_not_equal(a, b) \
do { \
const char* munit_tmp_a_ = a; \
const char* munit_tmp_b_ = b; \
if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) == 0)) { \
munit_errorf("assertion failed: string " #a " != " #b " (\"%s\" == \"%s\")", \
munit_tmp_a_, munit_tmp_b_); \
} \
MUNIT__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
MUNIT__POP_DISABLE_MSVC_C4127
#define munit_assert_memory_equal(size, a, b) \
do { \
const unsigned char* munit_tmp_a_ = (const unsigned char*) (a); \
const unsigned char* munit_tmp_b_ = (const unsigned char*) (b); \
const size_t munit_tmp_size_ = (size); \
if (MUNIT_UNLIKELY(memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) != 0) { \
size_t munit_tmp_pos_; \
for (munit_tmp_pos_ = 0 ; munit_tmp_pos_ < munit_tmp_size_ ; munit_tmp_pos_++) { \
if (munit_tmp_a_[munit_tmp_pos_] != munit_tmp_b_[munit_tmp_pos_]) { \
munit_errorf("assertion failed: memory " #a " == " #b ", at offset %" MUNIT_SIZE_MODIFIER "u", munit_tmp_pos_); \
break; \
} \
} \
} \
MUNIT__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
MUNIT__POP_DISABLE_MSVC_C4127
#define munit_assert_memory_not_equal(size, a, b) \
do { \
const unsigned char* munit_tmp_a_ = (const unsigned char*) (a); \
const unsigned char* munit_tmp_b_ = (const unsigned char*) (b); \
const size_t munit_tmp_size_ = (size); \
if (MUNIT_UNLIKELY(memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) == 0) { \
munit_errorf("assertion failed: memory" #a " != " #b " (%zu bytes)", munit_tmp_size_); \
} \
MUNIT__PUSH_DISABLE_MSVC_C4127 \
} while (0) \
MUNIT__POP_DISABLE_MSVC_C4127
#define munit_assert_ptr_equal(a, b) \
munit_assert_ptr(a, ==, b)
#define munit_assert_ptr_not_equal(a, b) \
munit_assert_ptr(a, !=, b)
#define munit_assert_null(ptr) \
munit_assert_ptr(ptr, ==, NULL)
#define munit_assert_not_null(ptr) \
munit_assert_ptr(ptr, !=, NULL)
#define munit_assert_ptr_null(ptr) \
munit_assert_ptr(ptr, ==, NULL)
#define munit_assert_ptr_not_null(ptr) \
munit_assert_ptr(ptr, !=, NULL)
/*** Memory allocation ***/
void* munit_malloc_ex(const char* filename, int line, size_t size);
#define munit_malloc(size) \
munit_malloc_ex(__FILE__, __LINE__, (size))
#define munit_new(type) \
((type*) munit_malloc(sizeof(type)))
#define munit_calloc(nmemb, size) \
munit_malloc((nmemb) * (size))
#define munit_newa(type, nmemb) \
((type*) munit_calloc((nmemb), sizeof(type)))
/*** Random number generation ***/
void munit_rand_seed(munit_uint32_t seed);
munit_uint32_t munit_rand_uint32(void);
int munit_rand_int_range(int min, int max);
double munit_rand_double(void);
void munit_rand_memory(size_t size, munit_uint8_t buffer[MUNIT_ARRAY_PARAM(size)]);
/*** Tests and Suites ***/
typedef enum {
/* Test successful */
MUNIT_OK,
/* Test failed */
MUNIT_FAIL,
/* Test was skipped */
MUNIT_SKIP,
/* Test failed due to circumstances not intended to be tested
* (things like network errors, invalid parameter value, failure to
* allocate memory in the test harness, etc.). */
MUNIT_ERROR
} MunitResult;
typedef struct {
char* name;
char** values;
} MunitParameterEnum;
typedef struct {
char* name;
char* value;
} MunitParameter;
const char* munit_parameters_get(const MunitParameter params[], const char* key);
typedef enum {
MUNIT_TEST_OPTION_NONE = 0,
MUNIT_TEST_OPTION_SINGLE_ITERATION = 1 << 0,
MUNIT_TEST_OPTION_TODO = 1 << 1
} MunitTestOptions;
typedef MunitResult (* MunitTestFunc)(const MunitParameter params[], void* user_data_or_fixture);
typedef void* (* MunitTestSetup)(const MunitParameter params[], void* user_data);
typedef void (* MunitTestTearDown)(void* fixture);
typedef struct {
char* name;
MunitTestFunc test;
MunitTestSetup setup;
MunitTestTearDown tear_down;
MunitTestOptions options;
MunitParameterEnum* parameters;
} MunitTest;
typedef enum {
MUNIT_SUITE_OPTION_NONE = 0
} MunitSuiteOptions;
typedef struct MunitSuite_ MunitSuite;
struct MunitSuite_ {
char* prefix;
MunitTest* tests;
MunitSuite* suites;
unsigned int iterations;
MunitSuiteOptions options;
};
int munit_suite_main(const MunitSuite* suite, void* user_data, int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)]);
/* Note: I'm not very happy with this API; it's likely to change if I
* figure out something better. Suggestions welcome. */
typedef struct MunitArgument_ MunitArgument;
struct MunitArgument_ {
char* name;
bool (* parse_argument)(const MunitSuite* suite, void* user_data, int* arg, int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)]);
void (* write_help)(const MunitArgument* argument, void* user_data);
};
int munit_suite_main_custom(const MunitSuite* suite,
void* user_data,
int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)],
const MunitArgument arguments[]);
#if defined(MUNIT_ENABLE_ASSERT_ALIASES)
#define assert_true(expr) munit_assert_true(expr)
#define assert_false(expr) munit_assert_false(expr)
#define assert_char(a, op, b) munit_assert_char(a, op, b)
#define assert_uchar(a, op, b) munit_assert_uchar(a, op, b)
#define assert_short(a, op, b) munit_assert_short(a, op, b)
#define assert_ushort(a, op, b) munit_assert_ushort(a, op, b)
#define assert_int(a, op, b) munit_assert_int(a, op, b)
#define assert_uint(a, op, b) munit_assert_uint(a, op, b)
#define assert_long(a, op, b) munit_assert_long(a, op, b)
#define assert_ulong(a, op, b) munit_assert_ulong(a, op, b)
#define assert_llong(a, op, b) munit_assert_llong(a, op, b)
#define assert_ullong(a, op, b) munit_assert_ullong(a, op, b)
#define assert_size(a, op, b) munit_assert_size(a, op, b)
#define assert_float(a, op, b) munit_assert_float(a, op, b)
#define assert_double(a, op, b) munit_assert_double(a, op, b)
#define assert_ptr(a, op, b) munit_assert_ptr(a, op, b)
#define assert_int8(a, op, b) munit_assert_int8(a, op, b)
#define assert_uint8(a, op, b) munit_assert_uint8(a, op, b)
#define assert_int16(a, op, b) munit_assert_int16(a, op, b)
#define assert_uint16(a, op, b) munit_assert_uint16(a, op, b)
#define assert_int32(a, op, b) munit_assert_int32(a, op, b)
#define assert_uint32(a, op, b) munit_assert_uint32(a, op, b)
#define assert_int64(a, op, b) munit_assert_int64(a, op, b)
#define assert_uint64(a, op, b) munit_assert_uint64(a, op, b)
#define assert_double_equal(a, b, precision) munit_assert_double_equal(a, b, precision)
#define assert_string_equal(a, b) munit_assert_string_equal(a, b)
#define assert_string_not_equal(a, b) munit_assert_string_not_equal(a, b)
#define assert_memory_equal(size, a, b) munit_assert_memory_equal(size, a, b)
#define assert_memory_not_equal(size, a, b) munit_assert_memory_not_equal(size, a, b)
#define assert_ptr_equal(a, b) munit_assert_ptr_equal(a, b)
#define assert_ptr_not_equal(a, b) munit_assert_ptr_not_equal(a, b)
#define assert_ptr_null(ptr) munit_assert_null_equal(ptr)
#define assert_ptr_not_null(ptr) munit_assert_not_null(ptr)
#define assert_null(ptr) munit_assert_null(ptr)
#define assert_not_null(ptr) munit_assert_not_null(ptr)
#endif /* defined(MUNIT_ENABLE_ASSERT_ALIASES) */
#if defined(__cplusplus)
}
#endif
#endif /* !defined(MUNIT_H) */
#if defined(MUNIT_ENABLE_ASSERT_ALIASES)
# if defined(assert)
# undef assert
# endif
# define assert(expr) munit_assert(expr)
#endif

View file

@ -0,0 +1,45 @@
#if defined(PSNIP_ENABLE_PTHREADS)
# include <pthread.h>
#endif
#include "../exact-int/exact-int.h"
#include "../once/once.h"
#include "munit/munit.h"
static psnip_once test_once_basic_once = PSNIP_ONCE_INIT;
static int test_once_basic_times_called = 0;
static void test_once_basic_init(void) {
munit_assert_int(test_once_basic_times_called, ==, 0);
test_once_basic_times_called++;
}
static MunitResult
test_once_basic(const MunitParameter params[], void* data) {
(void) params;
(void) data;
munit_assert_int(test_once_basic_times_called, ==, 0);
psnip_once_call(&test_once_basic_once, &test_once_basic_init);
munit_assert_int(test_once_basic_times_called, ==, 1);
psnip_once_call(&test_once_basic_once, &test_once_basic_init);
munit_assert_int(test_once_basic_times_called, ==, 1);
psnip_once_call(&test_once_basic_once, &test_once_basic_init);
munit_assert_int(test_once_basic_times_called, ==, 1);
return MUNIT_OK;
}
/* TODO: thread safety test. */
static MunitTest test_suite_tests[] = {
{ (char*) "/once/basic", test_once_basic, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
};
static const MunitSuite test_suite = {
(char*) "", test_suite_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE
};
int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) {
return munit_suite_main(&test_suite, NULL, argc, argv);
}

View file

@ -0,0 +1,93 @@
#include "../exact-int/exact-int.h"
#include "../random/random.h"
#include "munit/munit.h"
static MunitResult
test_random_secure(const MunitParameter params[], void* data) {
psnip_uint8_t buf[4096] = { 0, };
int r;
size_t p;
(void) params;
(void) data;
r = psnip_random_bytes(PSNIP_RANDOM_SOURCE_SECURE, sizeof(buf), buf);
munit_assert_int(r, ==, 0);
/* Make sure we actually read some data. */
for (p = 0 ; p < sizeof(buf) ; p++)
if (buf[p] != 0)
break;
munit_assert_size(p, <, sizeof(buf));
return MUNIT_OK;
}
static MunitResult
test_random_reproducible(const MunitParameter params[], void* data) {
const psnip_uint32_t test_data[] = {
0x8a4b308cU, 0x15534978U, 0xfec18d9aU, 0x7f345f7dU,
0x297766eeU, 0x771fb9f4U, 0x31e5a255U, 0xd0c9819dU,
0xef73a350U, 0xd9d26480U, 0xb5367e1aU, 0xc1a02725U,
0x8b2a1228U, 0x735c43f6U, 0x63ca3280U, 0x9bcd8362U,
0xac305d31U, 0x45f16be6U, 0x53247d92U, 0x363d54fbU,
0xaccbf201U, 0xc5963be4U, 0x646402c1U, 0xcbbf2841U,
0x16c42c02U, 0xf1b19a74U, 0xe2c78da3U, 0x352ac7a4U,
0x0e208ef3U, 0x94fec876U, 0x9fd96b4bU, 0x3ed00c53U
};
psnip_uint32_t buf[sizeof(test_data) / sizeof(test_data[0])] = { 0, };
size_t i;
int r;
(void) params;
(void) data;
psnip_random_set_seed(1729);
r = psnip_random_bytes(PSNIP_RANDOM_SOURCE_REPRODUCIBLE, sizeof(buf), (psnip_uint8_t*) buf);
munit_assert_int(r, ==, 0);
for (i = 0 ; i < sizeof(buf) / sizeof(buf[0]) ; i++) {
munit_assert_uint32(buf[i], ==, test_data[i]);
}
return MUNIT_OK;
}
static MunitResult
test_random_fast(const MunitParameter params[], void* data) {
psnip_uint8_t buf[4096] = { 0, };
int r;
size_t p;
(void) params;
(void) data;
r = psnip_random_bytes(PSNIP_RANDOM_SOURCE_FAST, sizeof(buf), buf);
munit_assert_int(r, ==, 0);
/* Make sure we actually read some data. */
for (p = 0 ; p < sizeof(buf) ; p++)
if (buf[p] != 0)
break;
munit_assert_size(p, <, sizeof(buf));
return MUNIT_OK;
}
static MunitTest test_suite_tests[] = {
{ (char*) "/random/secure", test_random_secure, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ (char*) "/random/reproducible", test_random_reproducible, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ (char*) "/random/fast", test_random_fast, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
};
static const MunitSuite test_suite = {
(char*) "", test_suite_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE
};
int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) {
return munit_suite_main(&test_suite, NULL, argc, argv);
}

View file

@ -0,0 +1,211 @@
#include "../exact-int/exact-int.h"
#define PSNIP_BUILTIN_EMULATE_NATIVE
#include "../safe-math/safe-math.h"
#include "munit/munit.h"
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
static MunitResult
test_safe_generic(const MunitParameter params[], void* user_data) {
unsigned long long a = 1, b = 1, res;
(void) params;
(void) user_data;
do {
if (!psnip_safe_add(&res, a, b)) {
munit_logf(MUNIT_LOG_DEBUG, "%llu + %llu overflows", a, b);
break;
}
munit_logf(MUNIT_LOG_DEBUG, "%llu + %llu = %llu", a, b, res);
a = b;
b = res;
} while (1);
return MUNIT_OK;
}
#endif
#define DEFINE_PSNIP_SAFE_TESTS(T, name, min, max) \
static MunitResult \
test_safe_##name##_add(const MunitParameter params[], void* user_data) { \
T result; \
(void) params; \
(void) user_data; \
munit_assert_true(psnip_safe_##name##_add(&result, 0, 1)); \
munit_assert_##name(result, ==, 1); \
munit_assert_true(psnip_safe_##name##_add(&result, 1, 1)); \
munit_assert_##name(result, ==, 2); \
munit_assert_true(psnip_safe_##name##_add(&result, 1, max - 1)); \
munit_assert_##name(result, ==, max); \
munit_assert_false(psnip_safe_##name##_add(&result, max, 1)); \
return MUNIT_OK; \
} \
\
static MunitResult \
test_safe_##name##_sub(const MunitParameter params[], void* user_data) { \
T result; \
(void) params; \
(void) user_data; \
munit_assert_true(psnip_safe_##name##_sub(&result, 1, 1)); \
munit_assert_##name(result, ==, 0); \
munit_assert_false(psnip_safe_##name##_sub(&result, min, 1)); \
munit_assert_true(psnip_safe_##name##_sub(&result, max, 1)); \
munit_assert_##name(result, ==, max - 1); \
return MUNIT_OK; \
} \
\
static MunitResult \
test_safe_##name##_mul(const MunitParameter params[], void* user_data) { \
T result; \
(void) params; \
(void) user_data; \
munit_assert_true(psnip_safe_##name##_mul(&result, 2, 2)); \
munit_assert_##name(result, ==, 4); \
munit_assert_true(psnip_safe_##name##_mul(&result, 0, max)); \
munit_assert_##name(result, ==, 0); \
munit_assert_true(psnip_safe_##name##_mul(&result, max, 0)); \
munit_assert_##name(result, ==, 0); \
munit_assert_true(psnip_safe_##name##_mul(&result, min, 0)); \
munit_assert_##name(result, ==, 0); \
return MUNIT_OK; \
} \
\
static MunitResult \
test_safe_##name##_div(const MunitParameter params[], void* user_data) { \
T result; \
(void) params; \
(void) user_data; \
munit_assert_true(psnip_safe_##name##_div(&result, 2, 2)); \
munit_assert_##name(result, ==, 1); \
munit_assert_false(psnip_safe_##name##_div(&result, 1, 0)); \
munit_assert_##name(result, ==, 0); \
return MUNIT_OK; \
} \
\
static MunitResult \
test_safe_##name##_mod(const MunitParameter params[], void* user_data) { \
T result; \
(void) params; \
(void) user_data; \
munit_assert_true(psnip_safe_##name##_mod(&result, 10, 4)); \
munit_assert_##name(result, ==, 2); \
munit_assert_false(psnip_safe_##name##_mod(&result, 1, 0)); \
munit_assert_##name(result, ==, 0); \
return MUNIT_OK; \
}
#define DEFINE_PSNIP_SAFE_TESTS_S(T, name, min, max) \
DEFINE_PSNIP_SAFE_TESTS(T, name, min, max) \
static MunitResult \
test_safe_##name##_div_signed(const MunitParameter params[], void* user_data) { \
T result; \
(void) params; \
(void) user_data; \
munit_assert_false(psnip_safe_##name##_div(&result, min, -1)); \
munit_assert_##name(result, ==, min); \
return MUNIT_OK; \
} \
\
static MunitResult \
test_safe_##name##_neg_signed(const MunitParameter params[], void* user_data) { \
T result; \
(void) params; \
(void) user_data; \
munit_assert_true(psnip_safe_##name##_neg(&result, max)); \
munit_assert_##name(result, ==, -max); \
munit_assert_false(psnip_safe_##name##_neg(&result, min)); \
munit_assert_##name(result, ==, max); \
return MUNIT_OK; \
}
#define DEFINE_PSNIP_SAFE_TEST_ENTRY(name, op) \
{ (char*) "/" #name "/" #op, test_safe_##name##_##op, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
#define DEFINE_PSNIP_SAFE_TEST_ENTRY_S(name, op) \
{ (char*) "/" #name "/" #op "/signed", test_safe_##name##_##op##_signed, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
#define DEFINE_PSNIP_SAFE_TEST_ENTRIES(name) \
DEFINE_PSNIP_SAFE_TEST_ENTRY(name, add), \
DEFINE_PSNIP_SAFE_TEST_ENTRY(name, sub), \
DEFINE_PSNIP_SAFE_TEST_ENTRY(name, mul), \
DEFINE_PSNIP_SAFE_TEST_ENTRY(name, div), \
DEFINE_PSNIP_SAFE_TEST_ENTRY(name, mod)
#define DEFINE_PSNIP_SAFE_TEST_ENTRIES_S(name) \
DEFINE_PSNIP_SAFE_TEST_ENTRIES(name), \
DEFINE_PSNIP_SAFE_TEST_ENTRY_S(name, div), \
DEFINE_PSNIP_SAFE_TEST_ENTRY_S(name, neg)
#if CHAR_MIN < 0
DEFINE_PSNIP_SAFE_TESTS_S(char, char, CHAR_MIN, CHAR_MAX)
#else
DEFINE_PSNIP_SAFE_TESTS (char, char, CHAR_MIN, CHAR_MAX)
#endif
DEFINE_PSNIP_SAFE_TESTS (unsigned char, uchar, 0, UCHAR_MAX)
DEFINE_PSNIP_SAFE_TESTS_S(short, short, SHRT_MIN, SHRT_MAX)
DEFINE_PSNIP_SAFE_TESTS (unsigned short, ushort, 0, USHRT_MAX)
DEFINE_PSNIP_SAFE_TESTS_S(int, int, INT_MIN, INT_MAX)
DEFINE_PSNIP_SAFE_TESTS (unsigned int, uint, 0, UINT_MAX)
DEFINE_PSNIP_SAFE_TESTS_S(long, long, LONG_MIN, LONG_MAX)
DEFINE_PSNIP_SAFE_TESTS (unsigned long, ulong, 0, ULONG_MAX)
DEFINE_PSNIP_SAFE_TESTS_S(long long, llong, LLONG_MIN, LLONG_MAX)
DEFINE_PSNIP_SAFE_TESTS (unsigned long long, ullong, 0, ULLONG_MAX)
#if defined(SIZE_MAX)
DEFINE_PSNIP_SAFE_TESTS (size_t, size, 0, SIZE_MAX)
#endif
#if !defined(PSNIP_SAFE_NO_FIXED)
DEFINE_PSNIP_SAFE_TESTS_S(psnip_int8_t, int8, (-0x7fLL-1), 0x7f)
DEFINE_PSNIP_SAFE_TESTS (psnip_uint8_t, uint8, 0, 0xffU)
DEFINE_PSNIP_SAFE_TESTS_S(psnip_int16_t, int16, (-0x7fffLL-1), 0x7fff)
DEFINE_PSNIP_SAFE_TESTS (psnip_uint16_t, uint16, 0, 0xffffU)
DEFINE_PSNIP_SAFE_TESTS_S(psnip_int32_t, int32, (-0x7fffffffLL-1), 0x7fffffffL)
DEFINE_PSNIP_SAFE_TESTS (psnip_uint32_t, uint32, 0, 0xffffffffUL)
DEFINE_PSNIP_SAFE_TESTS_S(psnip_int64_t, int64, (-0x7fffffffffffffffLL-1), 0x7fffffffffffffffLL)
DEFINE_PSNIP_SAFE_TESTS (psnip_uint64_t, uint64, 0, 0xffffffffffffffffULL)
#endif /* !defined(PSNIP_SAFE_NO_FIXED) */
static MunitTest psnip_safe_test_suite_tests[] = {
#if CHAR_MIN < 0
DEFINE_PSNIP_SAFE_TEST_ENTRIES_S(char),
#else
DEFINE_PSNIP_SAFE_TEST_ENTRIES(char),
#endif
DEFINE_PSNIP_SAFE_TEST_ENTRIES(uchar),
DEFINE_PSNIP_SAFE_TEST_ENTRIES_S(short),
DEFINE_PSNIP_SAFE_TEST_ENTRIES(ushort),
DEFINE_PSNIP_SAFE_TEST_ENTRIES_S(int),
DEFINE_PSNIP_SAFE_TEST_ENTRIES(uint),
DEFINE_PSNIP_SAFE_TEST_ENTRIES_S(long),
DEFINE_PSNIP_SAFE_TEST_ENTRIES(ulong),
DEFINE_PSNIP_SAFE_TEST_ENTRIES_S(llong),
DEFINE_PSNIP_SAFE_TEST_ENTRIES(ullong),
DEFINE_PSNIP_SAFE_TEST_ENTRIES(size),
#if !defined(PSNIP_SAFE_NO_FIXED)
DEFINE_PSNIP_SAFE_TEST_ENTRIES_S(int8),
DEFINE_PSNIP_SAFE_TEST_ENTRIES(uint8),
DEFINE_PSNIP_SAFE_TEST_ENTRIES_S(int16),
DEFINE_PSNIP_SAFE_TEST_ENTRIES(uint16),
DEFINE_PSNIP_SAFE_TEST_ENTRIES_S(int32),
DEFINE_PSNIP_SAFE_TEST_ENTRIES(uint32),
DEFINE_PSNIP_SAFE_TEST_ENTRIES_S(int64),
DEFINE_PSNIP_SAFE_TEST_ENTRIES(uint64),
#endif /* !defined(PSNIP_SAFE_NO_FIXED) */
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
{ (char*) "/generic", test_safe_generic, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
#endif
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
};
static const MunitSuite test_suite = {
(char*) "/safe-math",
psnip_safe_test_suite_tests,
NULL,
1,
MUNIT_SUITE_OPTION_NONE
};
int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) {
return munit_suite_main(&test_suite, NULL, argc, argv);
}

View file

@ -0,0 +1,146 @@
#define PSNIP_UNALIGNED_ALLOW_UNDEFINED
/* #define PSNIP_UNALIGNED_ALLOW_UBSAN */
/* #define PSNIP_UNALIGNED_IMPL 2 */
/* #define PSNIP_UNALIGNED_IMPL 3 */
#include "../exact-int/exact-int.h"
#include "../unaligned/unaligned.h"
#include "munit/munit.h"
#include <stdio.h>
static psnip_uint8_t buffer[1024 * 1024];
static MunitResult
test_unaligned_uint64(const MunitParameter params[], void* data) {
psnip_uint64_t v;
psnip_uint8_t* c = buffer;
psnip_uint8_t* e = &(buffer[sizeof(buffer)]) - sizeof(v);
(void) params;
(void) data;
while (c <= e) {
munit_rand_memory(sizeof(v), (psnip_uint8_t*) &v);
v ^= psnip_unaligned_load_uint64(c);
psnip_unaligned_store_uint64(c, v);
c++;
}
return MUNIT_OK;
}
static MunitResult
test_unaligned_uint32(const MunitParameter params[], void* data) {
psnip_uint32_t v;
psnip_uint8_t* c = buffer;
psnip_uint8_t* e = &(buffer[sizeof(buffer)]) - sizeof(v);
(void) params;
(void) data;
while (c <= e) {
munit_rand_memory(sizeof(v), (psnip_uint8_t*) &v);
v ^= psnip_unaligned_load_uint32(c);
psnip_unaligned_store_uint32(c, v);
c++;
}
return MUNIT_OK;
}
static MunitResult
test_unaligned_uint16(const MunitParameter params[], void* data) {
psnip_uint16_t v;
psnip_uint8_t* c = buffer;
psnip_uint8_t* e = &(buffer[sizeof(buffer)]) - sizeof(v);
(void) params;
(void) data;
while (c <= e) {
munit_rand_memory(sizeof(v), (psnip_uint8_t*) &v);
v ^= psnip_unaligned_load_uint16(c);
psnip_unaligned_store_uint16(c, v);
c++;
}
return MUNIT_OK;
}
/* Try to get the compiler to vectorize this; SIMD instructions are
more likely to have problems with unaligned accesses. */
#if defined(__GNUC__)
# if !defined(__clang__)
__attribute__((__optimize__(3),__noinline__))
# else
__attribute__((__noinline__))
# endif
#endif
static void
dangerous_copy(size_t count, psnip_uint64_t* dest, const psnip_uint64_t* src) {
size_t i;
for (i = 0 ; i < count ; i++) {
psnip_unaligned_store_uint64(&(dest[i]), psnip_unaligned_load_uint64(&(src[i])));
}
}
#if defined(__GNUC__)
# if defined(__has_attribute) && !defined(__ibmxl__)
# if __has_attribute(optnone)
__attribute__((__optnone__))
# endif
# elif !defined(__clang__)
__attribute__((__optimize__(0)))
# endif
__attribute__((__noinline__))
#endif
static MunitResult
test_unaligned_uint64_tempt(const MunitParameter params[], void* data) {
static psnip_uint8_t buffer2[sizeof(buffer)];
psnip_uint8_t buffer_x = 0;
psnip_uint8_t buffer_y = 0;
size_t i;
(void) params;
(void) data;
munit_rand_memory(sizeof(buffer), buffer);
dangerous_copy((sizeof(buffer) / sizeof(psnip_uint64_t)) - 1,
(void*) (buffer2 + 1), (void*) (buffer + 1));
/* XOR all the data together, just to try to convince the compiler
* not to optimize anything away. */
for (i = 1 ; i < (sizeof(buffer) - (sizeof(psnip_uint64_t) - 1)) ; i++) {
buffer_x ^= buffer[i];
buffer_y ^= buffer[i];
}
munit_assert_uint8(buffer_x, ==, buffer_y);
return MUNIT_OK;
}
static MunitTest test_suite_tests[] = {
{ (char*) "/unaligned/uint64", test_unaligned_uint64, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ (char*) "/unaligned/uint32", test_unaligned_uint32, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ (char*) "/unaligned/uint16", test_unaligned_uint16, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ (char*) "/unaligned/uint64/tempt", test_unaligned_uint64_tempt, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
};
static const MunitSuite test_suite = {
(char*) "", test_suite_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE
};
int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) {
munit_rand_memory(sizeof(buffer), buffer);
return munit_suite_main(&test_suite, NULL, argc, argv);
}

View file

@ -0,0 +1,107 @@
# Unaligned Loads and Stores
**WARNING**: This module is work-in-progress, and not yet ready for
widespread adoption. Testing, however, would be greatly appreciated.
This header provides fast load/store operations.
## Rationale
Yann Collet wrote a [great blog
post](https://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html)
about accessing unaligned memory a while back which is well worth a
read. Basically, there are a few different methods to access
unaligned memory, with different performance implications. `memcpy`
is safe, but slow on some compilers. Other methods rely on undefined
behavior which may or may not be safe depending on the compiler and
platform, and/or compiler-specific constructs.
It's important to note that, if you rely on undefined behavior,
compilers which currently work may stop working in the future when
optimizations are added. For example, unaligned accesses are usually
allowed on x86, but not for some SIMD instructions. GCC 4.9 added an
optimization which automatically vectorized some code in LZ4, and
since LZ4 (at the time) relied on unaligned accesses that change broke
LZ4.
The biggest value of this module is the logic to determine which
method to use on different combinations of compilers, compiler
versions, and architectures.
## Usage
`unaligned.h` defines macros which can be used to generate inline
functions for whatever types you want. For example, to generate
functions for `int`:
```c
PSNIP_UNALIGNED_LOAD_DEFINE(foo_load, int)
PSNIP_UNALIGNED_STORE_DEFINE(foo_store, int)
```
Would yield functions which look something like:
```c
int foo_load(const void* src);
void foo_store(void* dest, int src);
```
By default, we will use `memcpy` as it's the only completely safe
option. However, if you define `PSNIP_UNALIGNED_ALLOW_UNDEFINED`
prior to including `unaligned.h` it will check for platforms where
unaligned accesses are safe and faster than `memcpy()`. On such
platforms, access may be done through either a cast & dereference or
through a packed union.
If you include `exact-int.h` before including `unaligned.h` (or define
the exact-width types yourself), we will also define functions to
load/store to/from those types:
```c
psnip_int16_t psnip_unaligned_load_int16 (const void* src);
psnip_int32_t psnip_unaligned_load_int32 (const void* src);
psnip_int64_t psnip_unaligned_load_int64 (const void* src);
psnip_uint16_t psnip_unaligned_load_uint16 (const void* src);
psnip_uint32_t psnip_unaligned_load_uint32 (const void* src);
psnip_uint64_t psnip_unaligned_load_uint64 (const void* src);
void psnip_unaligned_store_int16 (void* dest, int16_t src);
void psnip_unaligned_store_int32 (void* dest, int32_t src);
void psnip_unaligned_store_int64 (void* dest, int64_t src);
void psnip_unaligned_store_uint16(void* dest, uint16_t src);
void psnip_unaligned_store_uint32(void* dest, uint32_t src);
void psnip_unaligned_store_uint64(void* dest, uint64_t src);
```
If you also include `endian.h` before including `unaligned.h`, we will
also define macros to load/store different-endian values to/from
the exact-width types:
```c
psnip_int16_t psnip_unaligned_load_int16le (const void* src);
psnip_int32_t psnip_unaligned_load_int32le (const void* src);
psnip_int64_t psnip_unaligned_load_int64le (const void* src);
psnip_int16_t psnip_unaligned_load_int16be (const void* src);
psnip_int32_t psnip_unaligned_load_int32be (const void* src);
psnip_int64_t psnip_unaligned_load_int64be (const void* src);
psnip_uint16_t psnip_unaligned_load_uint16le (const void* src);
psnip_uint32_t psnip_unaligned_load_uint32le (const void* src);
psnip_uint64_t psnip_unaligned_load_uint64le (const void* src);
psnip_uint16_t psnip_unaligned_load_uint16be (const void* src);
psnip_uint32_t psnip_unaligned_load_uint32be (const void* src);
psnip_uint64_t psnip_unaligned_load_uint64be (const void* src);
void psnip_unaligned_store_int16le (void* dest, psnip_int16_t src);
void psnip_unaligned_store_int32le (void* dest, psnip_int32_t src);
void psnip_unaligned_store_int64le (void* dest, psnip_int64_t src);
void psnip_unaligned_store_int16be (void* dest, psnip_int16_t src);
void psnip_unaligned_store_int32be (void* dest, psnip_int32_t src);
void psnip_unaligned_store_int64be (void* dest, psnip_int64_t src);
void psnip_unaligned_store_uint16le(void* dest, psnip_int16_t src);
void psnip_unaligned_store_uint32le(void* dest, psnip_int32_t src);
void psnip_unaligned_store_uint64le(void* dest, psnip_int64_t src);
void psnip_unaligned_store_uint16be(void* dest, psnip_int16_t src);
void psnip_unaligned_store_uint32be(void* dest, psnip_int32_t src);
void psnip_unaligned_store_uint64be(void* dest, psnip_int64_t src);
```
These are implemented as macros, the prototypes above are purely for
documentation.

View file

@ -0,0 +1,230 @@
/* Unaligned operations (v1)
* Portable Snippets - https://github.com/nemequ/portable-snippets
* Created by Evan Nemerson <evan@nemerson.com>
*
* To the extent possible under law, the authors have waived all
* copyright and related or neighboring rights to this code. For
* details, see the Creative Commons Zero 1.0 Universal license at
* https://creativecommons.org/publicdomain/zero/1.0/
*
* Most architectures allow unaligned access to some degree, but
* according to the C specification unaligned accesses are undefined
* behavior. The portable thing to do is use memcpy(), but depending
* on the architecture and compiler that may be slower than either
* dereferencing a pointer or using a union.
*
* If you define PSNIP_UNALIGNED_ALLOW_UNDEFINED prior to including
* this header, it will try to implement the fastest method which is
* known to work given the architecture and compiler.
*
* Some of the tests are taken from zstd; Yann Collet has done some
* great work benchmarking different methods on different
* architectures.
*/
#if !defined(PSNIP_UNALIGNED_H)
#define PSNIP_UNALIGNED_H
#define PSNIP_UNALIGNED_IMPL_MEMCPY 1
#define PSNIP_UNALIGNED_IMPL_DEREF 2
#define PSNIP_UNALIGNED_IMPL_UNION 3
#if defined(PSNIP_UNALIGNED_IMPL)
# if (PSNIP_UNALIGNED_IMPL < 1) || (PSNIP_UNALIGNED_IMPL > 3)
# error Unsupported unaligned access method requested.
# endif
#elif !defined(PSNIP_UNALIGNED_ALLOW_UNDEFINED)
# define PSNIP_UNALIGNED_IMPL PSNIP_UNALIGNED_IMPL_MEMCPY
#elif defined(__INTEL_COMPILER)
# define PSNIP_UNALIGNED_IMPL PSNIP_UNALIGNED_IMPL_UNION
#elif defined(__GNUC__)
# if (__GNUC__ >= 6)
# define PSNIP_UNALIGNED_IMPL PSNIP_UNALIGNED_IMPL_MEMCPY
# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__)
# define PSNIP_UNALIGNED_IMPL PSNIP_UNALIGNED_IMPL_UNION
# elif (defined(__amd64) || defined(__i386))
# if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
# define PSNIP_UNALIGNED_IMPL PSNIP_UNALIGNED_IMPL_MEMCPY
# else
# define PSNIP_UNALIGNED_IMPL PSNIP_UNALIGNED_IMPL_DEREF
# endif
# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
# define PSNIP_UNALIGNED_IMPL PSNIP_UNALIGNED_IMPL_DEREF
# else
# define PSNIP_UNALIGNED_IMPL PSNIP_UNALIGNED_IMPL_MEMCPY
# endif
#endif
#if !defined(PSNIP_UNALIGNED_IMPL)
# define PSNIP_UNALIGNED_IMPL PSNIP_UNALIGNED_IMPL_MEMCPY
#endif
#if !defined(PSNIP_UNALIGNED_STATIC_INLINE)
# if defined(__GNUC__)
# define PSNIP_UNALIGNED__COMPILER_ATTRIBUTES __attribute__((__unused__))
# else
# define PSNIP_UNALIGNED__COMPILER_ATTRIBUTES
# endif
# if defined(HEDLEY_ALWAYS_INLINE)
# define PSNIP_UNALIGNED__INLINE HEDLEY_ALWAYS_INLINE
# elif defined(__GNUC__) && (__GNUC__ >= 4)
# define PSNIP_UNALIGNED__INLINE __attribute__((__always_inline__,__gnu_inline__)) inline
# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
# define PSNIP_UNALIGNED__INLINE inline
# elif defined(__GNUC_STDC_INLINE__)
# define PSNIP_UNALIGNED__INLINE __inline__
# elif defined(_MSC_VER) && _MSC_VER >= 1200
# define PSNIP_UNALIGNED__INLINE __inline
# else
# define PSNIP_UNALIGNED__INLINE
# endif
# define PSNIP_UNALIGNED__FUNCTION PSNIP_UNALIGNED__COMPILER_ATTRIBUTES static PSNIP_UNALIGNED__INLINE
#endif
#if !defined(PSNIP_UNALIGNED_ALLOW_UBSAN)
# if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))
# define PSNIP_UNALIGNED__NO_UBSAN __attribute__((__no_sanitize_undefined__))
# elif defined(__clang__) && defined(__has_attribute)
# if __has_attribute(no_sanitize)
# define PSNIP_UNALIGNED__NO_UBSAN __attribute__((no_sanitize("undefined")))
# endif
# endif
#endif
#if !defined(PSNIP_UNALIGNED__NO_UBSAN)
# define PSNIP_UNALIGNED__NO_UBSAN
#endif
/* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/4972.html */
#if defined(__CC_ARM)
# define PSNIP_UNALIGNED__PACKED __packed
#else
# define PSNIP_UNALIGNED__PACKED
#endif
#if PSNIP_UNALIGNED_IMPL == PSNIP_UNALIGNED_IMPL_MEMCPY
# include <string.h>
# define PSNIP_UNALIGNED_LOAD_DEFINE(name, T) \
PSNIP_UNALIGNED__FUNCTION \
T name(const void* src) { \
T r; \
memcpy(&r, (PSNIP_UNALIGNED__PACKED const void*) src, sizeof(T)); \
return r; \
}
# define PSNIP_UNALIGNED_STORE_DEFINE(name, T) \
PSNIP_UNALIGNED__FUNCTION \
void name(void* dest, T src) { \
memcpy((PSNIP_UNALIGNED__PACKED void*) &dest, &src, sizeof(T)); \
}
#elif PSNIP_UNALIGNED_IMPL == PSNIP_UNALIGNED_IMPL_DEREF
# if defined(__cplusplus)
# define PSNIP_UNALIGNED_LOAD_DEFINE(name, T) \
PSNIP_UNALIGNED__FUNCTION \
PSNIP_UNALIGNED__NO_UBSAN \
T name(const void* src) { \
return *static_cast<PSNIP_UNALIGNED__PACKED const T*>(src); \
}
# define PSNIP_UNALIGNED_STORE_DEFINE(name, T) \
PSNIP_UNALIGNED__FUNCTION \
PSNIP_UNALIGNED__NO_UBSAN \
void name(void* dest, T src) { \
*(static_cast<PSNIP_UNALIGNED__PACKED T*>(dest)) = src; \
}
# else
# define PSNIP_UNALIGNED_LOAD_DEFINE(name, T) \
PSNIP_UNALIGNED__FUNCTION \
PSNIP_UNALIGNED__NO_UBSAN \
T name(const void* src) { \
return *((PSNIP_UNALIGNED__PACKED T*) src); \
}
# define PSNIP_UNALIGNED_STORE_DEFINE(name, T) \
PSNIP_UNALIGNED__FUNCTION \
PSNIP_UNALIGNED__NO_UBSAN \
void name(void* dest, T src) { \
*((PSNIP_UNALIGNED__PACKED T*) dest) = src; \
}
# endif
#elif PSNIP_UNALIGNED_IMPL == PSNIP_UNALIGNED_IMPL_UNION
# if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))
# define PSNIP_UNALIGNED__UNION_T(T) \
__pragma(pack(push, 1)) \
union { psnip_int64_t v; char a[sizeof(psnip_int64_t)]; } \
__pragma(pack(pop))
# else
# define PSNIP_UNALIGNED__UNION_T(T) \
union { psnip_int64_t v; char a[sizeof(psnip_int64_t)]; } \
__attribute__((packed))
# endif
# define PSNIP_UNALIGNED_LOAD_DEFINE(name, T) \
PSNIP_UNALIGNED__FUNCTION \
T name(const void* src) { \
return ((PSNIP_UNALIGNED__UNION_T(T) *) src)->v; \
}
# define PSNIP_UNALIGNED_STORE_DEFINE(name, T) \
PSNIP_UNALIGNED__FUNCTION \
void name(void* dest, T src) { \
((PSNIP_UNALIGNED__UNION_T(T) *) dest)->v = src; \
}
#endif
/* If we've already included exact-int.h (or defined the relevant
types), we'll set up functions for those types */
#if defined(psnip_int16_t)
PSNIP_UNALIGNED_LOAD_DEFINE(psnip_unaligned_load_int16, psnip_int16_t)
PSNIP_UNALIGNED_STORE_DEFINE(psnip_unaligned_store_int16, psnip_int16_t)
#endif
#if defined(psnip_uint16_t)
PSNIP_UNALIGNED_LOAD_DEFINE(psnip_unaligned_load_uint16, psnip_uint16_t)
PSNIP_UNALIGNED_STORE_DEFINE(psnip_unaligned_store_uint16, psnip_uint16_t)
#endif
#if defined(psnip_int32_t)
PSNIP_UNALIGNED_LOAD_DEFINE(psnip_unaligned_load_int32, psnip_int32_t)
PSNIP_UNALIGNED_STORE_DEFINE(psnip_unaligned_store_int32, psnip_int32_t)
#endif
#if defined(psnip_uint32_t)
PSNIP_UNALIGNED_LOAD_DEFINE(psnip_unaligned_load_uint32, psnip_uint32_t)
PSNIP_UNALIGNED_STORE_DEFINE(psnip_unaligned_store_uint32, psnip_uint32_t)
#endif
#if defined(psnip_int64_t)
PSNIP_UNALIGNED_LOAD_DEFINE(psnip_unaligned_load_int64, psnip_int64_t)
PSNIP_UNALIGNED_STORE_DEFINE(psnip_unaligned_store_int64, psnip_int64_t)
#endif
#if defined(psnip_uint64_t)
PSNIP_UNALIGNED_LOAD_DEFINE(psnip_unaligned_load_uint64, psnip_uint64_t)
PSNIP_UNALIGNED_STORE_DEFINE(psnip_unaligned_store_uint64, psnip_uint64_t)
#endif
/* And, if endian.h has been included, we can also define functions to
load different-endian data from unaligned addresses… */
#if defined(PSNIP_ENDIAN_H)
# psnip_unaligned_load_int16le(src) psnip_endian_le16(psnip_unaligned_load_int16(src))
# psnip_unaligned_load_int32le(src) psnip_endian_le32(psnip_unaligned_load_int32(src))
# psnip_unaligned_load_int64le(src) psnip_endian_le64(psnip_unaligned_load_int64(src))
# psnip_unaligned_load_int16be(src) psnip_endian_be16(psnip_unaligned_load_int16(src))
# psnip_unaligned_load_int32be(src) psnip_endian_be32(psnip_unaligned_load_int32(src))
# psnip_unaligned_load_int64be(src) psnip_endian_be64(psnip_unaligned_load_int64(src))
# psnip_unaligned_load_uint16le(src) psnip_endian_le16(psnip_unaligned_load_uint16(src))
# psnip_unaligned_load_uint32le(src) psnip_endian_le32(psnip_unaligned_load_uint32(src))
# psnip_unaligned_load_uint64le(src) psnip_endian_le64(psnip_unaligned_load_uint64(src))
# psnip_unaligned_load_uint16be(src) psnip_endian_be16(psnip_unaligned_load_uint16(src))
# psnip_unaligned_load_uint32be(src) psnip_endian_be32(psnip_unaligned_load_uint32(src))
# psnip_unaligned_load_uint64be(src) psnip_endian_be64(psnip_unaligned_load_uint64(src))
# psnip_unaligned_store_int16le(dest, src) psnip_unaligned_store_int16(dest, (psnip_int16_t) psnip_endian_le16(src))
# psnip_unaligned_store_int32le(dest, src) psnip_unaligned_store_int32(dest, (psnip_int32_t) psnip_endian_le32(src))
# psnip_unaligned_store_int64le(dest, src) psnip_unaligned_store_int64(dest, (psnip_int64_t) psnip_endian_le64(src))
# psnip_unaligned_store_int16be(dest, src) psnip_unaligned_store_int16(dest, (psnip_int16_t) psnip_endian_be16(src))
# psnip_unaligned_store_int32be(dest, src) psnip_unaligned_store_int32(dest, (psnip_int32_t) psnip_endian_be32(src))
# psnip_unaligned_store_int64be(dest, src) psnip_unaligned_store_int64(dest, (psnip_int64_t) psnip_endian_be64(src))
# psnip_unaligned_store_uint16le(dest, src) psnip_unaligned_store_uint16(dest, (psnip_uint16_t) psnip_endian_le16(src))
# psnip_unaligned_store_uint32le(dest, src) psnip_unaligned_store_uint32(dest, (psnip_uint32_t) psnip_endian_le32(src))
# psnip_unaligned_store_uint64le(dest, src) psnip_unaligned_store_uint64(dest, (psnip_uint64_t) psnip_endian_le64(src))
# psnip_unaligned_store_uint16be(dest, src) psnip_unaligned_store_uint16(dest, (psnip_uint16_t) psnip_endian_be16(src))
# psnip_unaligned_store_uint32be(dest, src) psnip_unaligned_store_uint32(dest, (psnip_uint32_t) psnip_endian_be32(src))
# psnip_unaligned_store_uint64be(dest, src) psnip_unaligned_store_uint64(dest, (psnip_uint64_t) psnip_endian_be64(src))
#endif
#endif /* PSNIP_UNALIGNED_H */