nostrdb: pull latest, adding flatcc and lmdb

This commit is contained in:
William Casarin
2023-08-25 12:32:30 -07:00
parent f30f93f65c
commit 1f5f1e28a4
104 changed files with 36269 additions and 28 deletions

View File

@@ -0,0 +1,14 @@
Copyright (c) 2016 Mikkel F. Jørgensen, dvide.com
Some files also Copyright author of MathGeoLib (https://github.com/juj)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. http://www.apache.org/licenses/LICENSE-2.0

View File

@@ -0,0 +1,57 @@
A small library for adding C11 compatibility to older C compilers, but
only a small highly useful subset such as static assertions, inline
functions and alignment.
C++ is not a primary target, but the library has been updated to be more
C++ friendly based on user feedback.
Many compilers already have the required functionality but with slightly
different names and arguments.
In addition, compatibility with the Linux `<endian.h>` system file is
provided, and "punaligned.h" is provided for unaligned memory reads
which in part depends on endian support.
The library also provides fast integer printing and floating point
printing and parsing optionally using the grisu3 algorithm, but can fall
back to strtod and related. The `pgrisu3` folder is header only and
excludes test cases found in the main grisu3 project the files were
extracted from. Base64 conversion is also provided.
Integer conversion is not just an optimization. It is more difficult
than it would appear to portably parse an integer of known size such as
`uint64_t` up to at most n bytes which is needed for safe parsing. At
the same time, the sometimes significant performance gains warrants
custom implementations that might as well be done once and for all.
Files can be included individually, or portable.h may be included to get
all functionality. If the compiler is C11 compliant, portable.h will not
include anything, except: it will provide a patch for static assertions
which clang does not fully support in all versions even with C11 flagged.
The grisu3 header files are the runtime files for the Grisu3 floating
point conversion to/from text C port. Test coverage is provided separately.
This library can be used indirectly via pparsefp.h and pprintfp.h.
The `pstatic_assert.h` file is often needed on C11 systems because the
compiler and standard library may support `_Static_assert` without
`static_assert`. For compilers without `_Static_assert`, a unique
identifier is needed for each assertion. This is done non-standard with
the `__COUNTER__` macro, but has a fallback to `pstatic_assert_scope.h`
for systems witout the `__COUNTER__` macro. Because of this fallback,
`pstatic_assert.h` needs to be included in every file using
`static_assert` in order to increment a scope counter, otherwise there
is a risk of assert identifier conflicts when `static_assert` happen on
the same line in different files.
The `paligned_alloc.h` file implements the non-standard `aligned_free`
to match the C11 standard `aligned_alloc` call. `aligned_free` is
normally equivalent to `free`, but not on systems where `aligned_free`
cannot be implemented using a system provived `free` call. Use of
`aligned_free` is thus optional on some systems, but using it increases
general portablity at the cost of pure C11 compatibility.
IMPORTANT NOTE: this library has been used on various platforms and
updated with user feedback but it is impossibly to systematically test
all platforms so please test for specific uses cases and report
any issues upstream.

View File

@@ -0,0 +1,329 @@
/*
* Copyright (c) 2016 Mikkel F. Jørgensen, dvide.com
* Copyright author of MathGeoLib (https://github.com/juj)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License. http://www.apache.org/licenses/LICENSE-2.0
*/
/* 2016-02-02: Updated by mikkelfj
*
* Extracted from MatGeoLib grisu3.c, Apache 2.0 license, and extended.
*
* This file is usually include via grisu3_print.h or grisu3_parse.h.
*
* The original MatGeoLib dtoa_grisu3 implementation is largely
* unchanged except for the uint64 to double cast. The remaining changes
* are file structure, name changes, and new additions for parsing:
*
* - Split into header files only:
* grisu3_math.h, grisu3_print.h, (added grisu3_parse.h)
*
* - names prefixed with grisu3_, grisu3_diy_fp_, GRISU3_.
* - added static to all functions.
* - disabled clang unused function warnings.
* - guarded <stdint.h> to allow for alternative impl.
* - added extra numeric constants needed for parsing.
* - added dec_pow, cast_double_from_diy_fp.
* - changed some function names for consistency.
* - moved printing specific grisu3 functions to grisu3_print.h.
* - changed double to uint64 cast to avoid aliasing.
* - added new grisu3_parse.h for parsing doubles.
* - grisu3_print_double (dtoa_grisu3) format .1 as 0.1 needed for valid JSON output
* and grisu3_parse_double wouldn't consume it.
* - grsu3_print_double changed formatting to prefer 0.012 over 1.2e-2.
*
* These changes make it possible to include the files as headers only
* in other software libraries without risking name conflicts, and to
* extend the implementation with a port of Googles Double Conversion
* strtod functionality for parsing doubles.
*
* Extracted from: rev. 915501a / Dec 22, 2015
* <https://github.com/juj/MathGeoLib/blob/master/src/Math/grisu3.c>
* MathGeoLib License: http://www.apache.org/licenses/LICENSE-2.0.html
*/
#ifndef GRISU3_MATH_H
#define GRISU3_MATH_H
#ifdef __cplusplus
extern "C" {
#endif
/* Guarded to allow inclusion of pstdint.h first, if stdint.h is not supported. */
#ifndef UINT8_MAX
#include <stdint.h> /* uint64_t etc. */
#endif
#ifdef GRISU3_NO_ASSERT
#undef GRISU3_ASSERT
#define GRISU3_ASSERT(x) ((void)0)
#endif
#ifndef GRISU3_ASSERT
#include <assert.h> /* assert */
#define GRISU3_ASSERT(x) assert(x)
#endif
#ifdef _MSC_VER
#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer */
#endif
#define GRISU3_D64_SIGN 0x8000000000000000ULL
#define GRISU3_D64_EXP_MASK 0x7FF0000000000000ULL
#define GRISU3_D64_FRACT_MASK 0x000FFFFFFFFFFFFFULL
#define GRISU3_D64_IMPLICIT_ONE 0x0010000000000000ULL
#define GRISU3_D64_EXP_POS 52
#define GRISU3_D64_EXP_BIAS 1075
#define GRISU3_D64_DENORM_EXP (-GRISU3_D64_EXP_BIAS + 1)
#define GRISU3_DIY_FP_FRACT_SIZE 64
#define GRISU3_D_1_LOG2_10 0.30102999566398114 /* 1 / lg(10) */
#define GRISU3_MIN_TARGET_EXP -60
#define GRISU3_MASK32 0xFFFFFFFFULL
#define GRISU3_MIN_CACHED_EXP -348
#define GRISU3_MAX_CACHED_EXP 340
#define GRISU3_CACHED_EXP_STEP 8
#define GRISU3_D64_MAX_DEC_EXP 309
#define GRISU3_D64_MIN_DEC_EXP -324
#define GRISU3_D64_INF GRISU3_D64_EXP_MASK
#define GRISU3_MIN(x,y) ((x) <= (y) ? (x) : (y))
#define GRISU3_MAX(x,y) ((x) >= (y) ? (x) : (y))
typedef struct grisu3_diy_fp
{
uint64_t f;
int e;
} grisu3_diy_fp_t;
typedef struct grisu3_diy_fp_power
{
uint64_t fract;
int16_t b_exp, d_exp;
} grisu3_diy_fp_power_t;
typedef union {
uint64_t u64;
double d64;
} grisu3_cast_double_t;
static uint64_t grisu3_cast_uint64_from_double(double d)
{
grisu3_cast_double_t cd;
cd.d64 = d;
return cd.u64;
}
static double grisu3_cast_double_from_uint64(uint64_t u)
{
grisu3_cast_double_t cd;
cd.u64 = u;
return cd.d64;
}
#define grisu3_double_infinity grisu3_cast_double_from_uint64(GRISU3_D64_INF)
#define grisu3_double_nan grisu3_cast_double_from_uint64(GRISU3_D64_INF + 1)
static const grisu3_diy_fp_power_t grisu3_diy_fp_pow_cache[] =
{
{ 0xfa8fd5a0081c0288ULL, -1220, -348 },
{ 0xbaaee17fa23ebf76ULL, -1193, -340 },
{ 0x8b16fb203055ac76ULL, -1166, -332 },
{ 0xcf42894a5dce35eaULL, -1140, -324 },
{ 0x9a6bb0aa55653b2dULL, -1113, -316 },
{ 0xe61acf033d1a45dfULL, -1087, -308 },
{ 0xab70fe17c79ac6caULL, -1060, -300 },
{ 0xff77b1fcbebcdc4fULL, -1034, -292 },
{ 0xbe5691ef416bd60cULL, -1007, -284 },
{ 0x8dd01fad907ffc3cULL, -980, -276 },
{ 0xd3515c2831559a83ULL, -954, -268 },
{ 0x9d71ac8fada6c9b5ULL, -927, -260 },
{ 0xea9c227723ee8bcbULL, -901, -252 },
{ 0xaecc49914078536dULL, -874, -244 },
{ 0x823c12795db6ce57ULL, -847, -236 },
{ 0xc21094364dfb5637ULL, -821, -228 },
{ 0x9096ea6f3848984fULL, -794, -220 },
{ 0xd77485cb25823ac7ULL, -768, -212 },
{ 0xa086cfcd97bf97f4ULL, -741, -204 },
{ 0xef340a98172aace5ULL, -715, -196 },
{ 0xb23867fb2a35b28eULL, -688, -188 },
{ 0x84c8d4dfd2c63f3bULL, -661, -180 },
{ 0xc5dd44271ad3cdbaULL, -635, -172 },
{ 0x936b9fcebb25c996ULL, -608, -164 },
{ 0xdbac6c247d62a584ULL, -582, -156 },
{ 0xa3ab66580d5fdaf6ULL, -555, -148 },
{ 0xf3e2f893dec3f126ULL, -529, -140 },
{ 0xb5b5ada8aaff80b8ULL, -502, -132 },
{ 0x87625f056c7c4a8bULL, -475, -124 },
{ 0xc9bcff6034c13053ULL, -449, -116 },
{ 0x964e858c91ba2655ULL, -422, -108 },
{ 0xdff9772470297ebdULL, -396, -100 },
{ 0xa6dfbd9fb8e5b88fULL, -369, -92 },
{ 0xf8a95fcf88747d94ULL, -343, -84 },
{ 0xb94470938fa89bcfULL, -316, -76 },
{ 0x8a08f0f8bf0f156bULL, -289, -68 },
{ 0xcdb02555653131b6ULL, -263, -60 },
{ 0x993fe2c6d07b7facULL, -236, -52 },
{ 0xe45c10c42a2b3b06ULL, -210, -44 },
{ 0xaa242499697392d3ULL, -183, -36 },
{ 0xfd87b5f28300ca0eULL, -157, -28 },
{ 0xbce5086492111aebULL, -130, -20 },
{ 0x8cbccc096f5088ccULL, -103, -12 },
{ 0xd1b71758e219652cULL, -77, -4 },
{ 0x9c40000000000000ULL, -50, 4 },
{ 0xe8d4a51000000000ULL, -24, 12 },
{ 0xad78ebc5ac620000ULL, 3, 20 },
{ 0x813f3978f8940984ULL, 30, 28 },
{ 0xc097ce7bc90715b3ULL, 56, 36 },
{ 0x8f7e32ce7bea5c70ULL, 83, 44 },
{ 0xd5d238a4abe98068ULL, 109, 52 },
{ 0x9f4f2726179a2245ULL, 136, 60 },
{ 0xed63a231d4c4fb27ULL, 162, 68 },
{ 0xb0de65388cc8ada8ULL, 189, 76 },
{ 0x83c7088e1aab65dbULL, 216, 84 },
{ 0xc45d1df942711d9aULL, 242, 92 },
{ 0x924d692ca61be758ULL, 269, 100 },
{ 0xda01ee641a708deaULL, 295, 108 },
{ 0xa26da3999aef774aULL, 322, 116 },
{ 0xf209787bb47d6b85ULL, 348, 124 },
{ 0xb454e4a179dd1877ULL, 375, 132 },
{ 0x865b86925b9bc5c2ULL, 402, 140 },
{ 0xc83553c5c8965d3dULL, 428, 148 },
{ 0x952ab45cfa97a0b3ULL, 455, 156 },
{ 0xde469fbd99a05fe3ULL, 481, 164 },
{ 0xa59bc234db398c25ULL, 508, 172 },
{ 0xf6c69a72a3989f5cULL, 534, 180 },
{ 0xb7dcbf5354e9beceULL, 561, 188 },
{ 0x88fcf317f22241e2ULL, 588, 196 },
{ 0xcc20ce9bd35c78a5ULL, 614, 204 },
{ 0x98165af37b2153dfULL, 641, 212 },
{ 0xe2a0b5dc971f303aULL, 667, 220 },
{ 0xa8d9d1535ce3b396ULL, 694, 228 },
{ 0xfb9b7cd9a4a7443cULL, 720, 236 },
{ 0xbb764c4ca7a44410ULL, 747, 244 },
{ 0x8bab8eefb6409c1aULL, 774, 252 },
{ 0xd01fef10a657842cULL, 800, 260 },
{ 0x9b10a4e5e9913129ULL, 827, 268 },
{ 0xe7109bfba19c0c9dULL, 853, 276 },
{ 0xac2820d9623bf429ULL, 880, 284 },
{ 0x80444b5e7aa7cf85ULL, 907, 292 },
{ 0xbf21e44003acdd2dULL, 933, 300 },
{ 0x8e679c2f5e44ff8fULL, 960, 308 },
{ 0xd433179d9c8cb841ULL, 986, 316 },
{ 0x9e19db92b4e31ba9ULL, 1013, 324 },
{ 0xeb96bf6ebadf77d9ULL, 1039, 332 },
{ 0xaf87023b9bf0ee6bULL, 1066, 340 }
};
/* Avoid dependence on lib math to get (int)ceil(v) */
static int grisu3_iceil(double v)
{
int k = (int)v;
if (v < 0) return k;
return v - k == 0 ? k : k + 1;
}
static int grisu3_diy_fp_cached_pow(int exp, grisu3_diy_fp_t *p)
{
int k = grisu3_iceil((exp+GRISU3_DIY_FP_FRACT_SIZE-1) * GRISU3_D_1_LOG2_10);
int i = (k-GRISU3_MIN_CACHED_EXP-1) / GRISU3_CACHED_EXP_STEP + 1;
p->f = grisu3_diy_fp_pow_cache[i].fract;
p->e = grisu3_diy_fp_pow_cache[i].b_exp;
return grisu3_diy_fp_pow_cache[i].d_exp;
}
static grisu3_diy_fp_t grisu3_diy_fp_minus(grisu3_diy_fp_t x, grisu3_diy_fp_t y)
{
grisu3_diy_fp_t d; d.f = x.f - y.f; d.e = x.e;
GRISU3_ASSERT(x.e == y.e && x.f >= y.f);
return d;
}
static grisu3_diy_fp_t grisu3_diy_fp_multiply(grisu3_diy_fp_t x, grisu3_diy_fp_t y)
{
uint64_t a, b, c, d, ac, bc, ad, bd, tmp;
grisu3_diy_fp_t r;
a = x.f >> 32; b = x.f & GRISU3_MASK32;
c = y.f >> 32; d = y.f & GRISU3_MASK32;
ac = a*c; bc = b*c;
ad = a*d; bd = b*d;
tmp = (bd >> 32) + (ad & GRISU3_MASK32) + (bc & GRISU3_MASK32);
tmp += 1U << 31; /* round */
r.f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);
r.e = x.e + y.e + 64;
return r;
}
static grisu3_diy_fp_t grisu3_diy_fp_normalize(grisu3_diy_fp_t n)
{
GRISU3_ASSERT(n.f != 0);
while(!(n.f & 0xFFC0000000000000ULL)) { n.f <<= 10; n.e -= 10; }
while(!(n.f & GRISU3_D64_SIGN)) { n.f <<= 1; --n.e; }
return n;
}
static grisu3_diy_fp_t grisu3_cast_diy_fp_from_double(double d)
{
grisu3_diy_fp_t fp;
uint64_t u64 = grisu3_cast_uint64_from_double(d);
if (!(u64 & GRISU3_D64_EXP_MASK)) { fp.f = u64 & GRISU3_D64_FRACT_MASK; fp.e = 1 - GRISU3_D64_EXP_BIAS; }
else { fp.f = (u64 & GRISU3_D64_FRACT_MASK) + GRISU3_D64_IMPLICIT_ONE; fp.e = (int)((u64 & GRISU3_D64_EXP_MASK) >> GRISU3_D64_EXP_POS) - GRISU3_D64_EXP_BIAS; }
return fp;
}
static double grisu3_cast_double_from_diy_fp(grisu3_diy_fp_t n)
{
const uint64_t hidden_bit = GRISU3_D64_IMPLICIT_ONE;
const uint64_t frac_mask = GRISU3_D64_FRACT_MASK;
const int denorm_exp = GRISU3_D64_DENORM_EXP;
const int exp_bias = GRISU3_D64_EXP_BIAS;
const int exp_pos = GRISU3_D64_EXP_POS;
grisu3_diy_fp_t v = n;
uint64_t e_biased;
while (v.f > hidden_bit + frac_mask) {
v.f >>= 1;
++v.e;
}
if (v.e < denorm_exp) {
return 0.0;
}
while (v.e > denorm_exp && (v.f & hidden_bit) == 0) {
v.f <<= 1;
--v.e;
}
if (v.e == denorm_exp && (v.f & hidden_bit) == 0) {
e_biased = 0;
} else {
e_biased = (uint64_t)(v.e + exp_bias);
}
return grisu3_cast_double_from_uint64((v.f & frac_mask) | (e_biased << exp_pos));
}
/* pow10_cache[i] = 10^(i-1) */
static const unsigned int grisu3_pow10_cache[] = { 0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
static int grisu3_largest_pow10(uint32_t n, int n_bits, uint32_t *power)
{
int guess = ((n_bits + 1) * 1233 >> 12) + 1/*skip first entry*/;
if (n < grisu3_pow10_cache[guess]) --guess; /* We don't have any guarantees that 2^n_bits <= n. */
*power = grisu3_pow10_cache[guess];
return guess;
}
#ifdef __cplusplus
}
#endif
#endif /* GRISU3_MATH_H */

View File

@@ -0,0 +1,582 @@
/*
* Copyright (c) 2016 Mikkel F. Jørgensen, dvide.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License. http://www.apache.org/licenses/LICENSE-2.0
*/
/*
* Port of parts of Google Double Conversion strtod functionality
* but with fallback to strtod instead of a bignum implementation.
*
* Based on grisu3 math from MathGeoLib.
*
* See also grisu3_math.h comments.
*/
#ifndef GRISU3_PARSE_H
#define GRISU3_PARSE_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef UINT8_MAX
#include <stdint.h>
#endif
#include <stdlib.h>
#include <limits.h>
#include "grisu3_math.h"
/*
* The maximum number characters a valid number may contain. The parse
* fails if the input length is longer but the character after max len
* was part of the number.
*
* The length should not be set too high because it protects against
* overflow in the exponent part derived from the input length.
*/
#define GRISU3_NUM_MAX_LEN 1000
/*
* The lightweight "portable" C library recognizes grisu3 support if
* included first.
*/
#define grisu3_parse_double_is_defined 1
/*
* Disable to compare performance and to test diy_fp algorithm in
* broader range.
*/
#define GRISU3_PARSE_FAST_CASE
/* May result in a one off error, otherwise when uncertain, fall back to strtod. */
//#define GRISU3_PARSE_ALLOW_ERROR
/*
* The dec output exponent jumps in 8, so the result is offset at most
* by 7 when the input is within range.
*/
static int grisu3_diy_fp_cached_dec_pow(int d_exp, grisu3_diy_fp_t *p)
{
const int cached_offset = -GRISU3_MIN_CACHED_EXP;
const int d_exp_dist = GRISU3_CACHED_EXP_STEP;
int i, a_exp;
GRISU3_ASSERT(GRISU3_MIN_CACHED_EXP <= d_exp);
GRISU3_ASSERT(d_exp < GRISU3_MAX_CACHED_EXP + d_exp_dist);
i = (d_exp + cached_offset) / d_exp_dist;
a_exp = grisu3_diy_fp_pow_cache[i].d_exp;
p->f = grisu3_diy_fp_pow_cache[i].fract;
p->e = grisu3_diy_fp_pow_cache[i].b_exp;
GRISU3_ASSERT(a_exp <= d_exp);
GRISU3_ASSERT(d_exp < a_exp + d_exp_dist);
return a_exp;
}
/*
* Ported from google double conversion strtod using
* MathGeoLibs diy_fp functions for grisu3 in C.
*
* ulp_half_error is set if needed to trunacted non-zero trialing
* characters.
*
* The actual value we need to encode is:
*
* (sign ? -1 : 1) * fraction * 2 ^ (exponent - fraction_exp)
* where exponent is the base 10 exponent assuming the decimal point is
* after the first digit. fraction_exp is the base 10 magnitude of the
* fraction or number of significant digits - 1.
*
* If the exponent is between 0 and 22 and the fraction is encoded in
* the lower 53 bits (the largest bit is implicit in a double, but not
* in this fraction), then the value can be trivially converted to
* double without loss of precision. If the fraction was in fact
* multiplied by trailing zeroes that we didn't convert to exponent,
* we there are larger values the 53 bits that can also be encoded
* trivially - but then it is better to handle this during parsing
* if it is worthwhile. We do not optimize for this here, because it
* can be done in a simple check before calling, and because it might
* not be worthwile to do at all since it cery likely will fail for
* numbers printed to be convertible back to double without loss.
*
* Returns 0 if conversion was not exact. In that case the vale is
* either one smaller than the correct one, or the correct one.
*
* Exponents must be range protected before calling otherwise cached
* powers will blow up.
*
* Google Double Conversion seems to prefer the following notion:
*
* x >= 10^309 => +Inf
* x <= 10^-324 => 0,
*
* max double: HUGE_VAL = 1.7976931348623157 * 10^308
* min double: 4.9406564584124654 * 10^-324
*
* Values just below or above min/max representable number
* may round towards large/small non-Inf/non-neg values.
*
* but `strtod` seems to return +/-HUGE_VAL on overflow?
*/
static int grisu3_diy_fp_encode_double(uint64_t fraction, int exponent, int fraction_exp, int ulp_half_error, double *result)
{
/*
* Error is measures in fractions of integers, so we scale up to get
* some resolution to represent error expressions.
*/
const int log2_error_one = 3;
const int error_one = 1 << log2_error_one;
const int denorm_exp = GRISU3_D64_DENORM_EXP;
const uint64_t hidden_bit = GRISU3_D64_IMPLICIT_ONE;
const int diy_size = GRISU3_DIY_FP_FRACT_SIZE;
const int max_digits = 19;
int error = ulp_half_error ? error_one / 2 : 0;
int d_exp = (exponent - fraction_exp);
int a_exp;
int o_exp;
grisu3_diy_fp_t v = { fraction, 0 };
grisu3_diy_fp_t cp;
grisu3_diy_fp_t rounded;
int mag;
int prec;
int prec_bits;
int half_way;
/* When fractions in a double aren't stored with implicit msb fraction bit. */
/* Shift fraction to msb. */
v = grisu3_diy_fp_normalize(v);
/* The half point error moves up while the exponent moves down. */
error <<= -v.e;
a_exp = grisu3_diy_fp_cached_dec_pow(d_exp, &cp);
/* Interpolate between cached powers at distance 8. */
if (a_exp != d_exp) {
int adj_exp = d_exp - a_exp - 1;
static grisu3_diy_fp_t cp_10_lut[] = {
{ 0xa000000000000000ULL, -60 },
{ 0xc800000000000000ULL, -57 },
{ 0xfa00000000000000ULL, -54 },
{ 0x9c40000000000000ULL, -50 },
{ 0xc350000000000000ULL, -47 },
{ 0xf424000000000000ULL, -44 },
{ 0x9896800000000000ULL, -40 },
};
GRISU3_ASSERT(adj_exp >= 0 && adj_exp < 7);
v = grisu3_diy_fp_multiply(v, cp_10_lut[adj_exp]);
/* 20 decimal digits won't always fit in 64 bit.
* (`fraction_exp` is one less than significant decimal
* digits in fraction, e.g. 1 * 10e0).
* If we cannot fit, introduce 1/2 ulp error
* (says double conversion reference impl.) */
if (1 + fraction_exp + adj_exp > max_digits) {
error += error_one / 2;
}
}
v = grisu3_diy_fp_multiply(v, cp);
/*
* Google double conversion claims that:
*
* The error introduced by a multiplication of a*b equals
* error_a + error_b + error_a*error_b/2^64 + 0.5
* Substituting a with 'input' and b with 'cached_power' we have
* error_b = 0.5 (all cached powers have an error of less than 0.5 ulp),
* error_ab = 0 or 1 / error_oner > error_a*error_b/ 2^64
*
* which in our encoding becomes:
* error_a = error_one/2
* error_ab = 1 / error_one (rounds up to 1 if error != 0, or 0 * otherwise)
* fixed_error = error_one/2
*
* error += error_a + fixed_error + (error ? 1 : 0)
*
* (this isn't entirely clear, but that is as close as we get).
*/
error += error_one + (error ? 1 : 0);
o_exp = v.e;
v = grisu3_diy_fp_normalize(v);
/* Again, if we shift the significant bits, the error moves along. */
error <<= o_exp - v.e;
/*
* The value `v` is bounded by 2^mag which is 64 + v.e. because we
* just normalized it by shifting towards msb.
*/
mag = diy_size + v.e;
/* The effective magnitude of the IEEE double representation. */
mag = mag >= diy_size + denorm_exp ? diy_size : mag <= denorm_exp ? 0 : mag - denorm_exp;
prec = diy_size - mag;
if (prec + log2_error_one >= diy_size) {
int e_scale = prec + log2_error_one - diy_size - 1;
v.f >>= e_scale;
v.e += e_scale;
error = (error >> e_scale) + 1 + error_one;
prec -= e_scale;
}
rounded.f = v.f >> prec;
rounded.e = v.e + prec;
prec_bits = (int)(v.f & ((uint64_t)1 << (prec - 1))) * error_one;
half_way = (int)((uint64_t)1 << (prec - 1)) * error_one;
if (prec >= half_way + error) {
rounded.f++;
/* Prevent overflow. */
if (rounded.f & (hidden_bit << 1)) {
rounded.f >>= 1;
rounded.e += 1;
}
}
*result = grisu3_cast_double_from_diy_fp(rounded);
return half_way - error >= prec_bits || prec_bits >= half_way + error;
}
/*
* `end` is unchanged if number is handled natively, or it is the result
* of strtod parsing in case of fallback.
*/
static const char *grisu3_encode_double(const char *buf, const char *end, int sign, uint64_t fraction, int exponent, int fraction_exp, int ulp_half_error, double *result)
{
const int max_d_exp = GRISU3_D64_MAX_DEC_EXP;
const int min_d_exp = GRISU3_D64_MIN_DEC_EXP;
char *v_end;
/* Both for user experience, and to protect internal power table lookups. */
if (fraction == 0 || exponent < min_d_exp) {
*result = 0.0;
goto done;
}
if (exponent - 1 > max_d_exp) {
*result = grisu3_double_infinity;
goto done;
}
/*
* `exponent` is the normalized value, fraction_exp is the size of
* the representation in the `fraction value`, or one less than
* number of significant digits.
*
* If the final value can be kept in 53 bits and we can avoid
* division, then we can convert to double quite fast.
*
* ulf_half_error only happens when fraction is maxed out, so
* fraction_exp > 22 by definition.
*
* fraction_exp >= 0 always.
*
* http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
*/
#ifdef GRISU3_PARSE_FAST_CASE
if (fraction < (1ULL << 53) && exponent >= 0 && exponent <= 22) {
double v = (double)fraction;
/* Multiplying by 1e-k instead of dividing by 1ek results in rounding error. */
switch (exponent - fraction_exp) {
case -22: v /= 1e22; break;
case -21: v /= 1e21; break;
case -20: v /= 1e20; break;
case -19: v /= 1e19; break;
case -18: v /= 1e18; break;
case -17: v /= 1e17; break;
case -16: v /= 1e16; break;
case -15: v /= 1e15; break;
case -14: v /= 1e14; break;
case -13: v /= 1e13; break;
case -12: v /= 1e12; break;
case -11: v /= 1e11; break;
case -10: v /= 1e10; break;
case -9: v /= 1e9; break;
case -8: v /= 1e8; break;
case -7: v /= 1e7; break;
case -6: v /= 1e6; break;
case -5: v /= 1e5; break;
case -4: v /= 1e4; break;
case -3: v /= 1e3; break;
case -2: v /= 1e2; break;
case -1: v /= 1e1; break;
case 0: break;
case 1: v *= 1e1; break;
case 2: v *= 1e2; break;
case 3: v *= 1e3; break;
case 4: v *= 1e4; break;
case 5: v *= 1e5; break;
case 6: v *= 1e6; break;
case 7: v *= 1e7; break;
case 8: v *= 1e8; break;
case 9: v *= 1e9; break;
case 10: v *= 1e10; break;
case 11: v *= 1e11; break;
case 12: v *= 1e12; break;
case 13: v *= 1e13; break;
case 14: v *= 1e14; break;
case 15: v *= 1e15; break;
case 16: v *= 1e16; break;
case 17: v *= 1e17; break;
case 18: v *= 1e18; break;
case 19: v *= 1e19; break;
case 20: v *= 1e20; break;
case 21: v *= 1e21; break;
case 22: v *= 1e22; break;
}
*result = v;
goto done;
}
#endif
if (grisu3_diy_fp_encode_double(fraction, exponent, fraction_exp, ulp_half_error, result)) {
goto done;
}
#ifdef GRISU3_PARSE_ALLOW_ERROR
goto done;
#endif
*result = strtod(buf, &v_end);
if (v_end < end) {
return v_end;
}
return end;
done:
if (sign) {
*result = -*result;
}
return end;
}
/*
* Returns buf if number wasn't matched, or null if number starts ok
* but contains invalid content.
*/
static const char *grisu3_parse_hex_fp(const char *buf, const char *end, int sign, double *result)
{
(void)buf;
(void)end;
(void)sign;
*result = 0.0;
/* Not currently supported. */
return buf;
}
/*
* Returns end pointer on success, or null, or buf if start is not a number.
* Sets result to 0.0 on error.
* Reads up to len + 1 bytes from buffer where len + 1 must not be a
* valid part of a number, but all of buf, buf + len need not be a
* number. Leading whitespace is NOT valid.
* Very small numbers are truncated to +/-0.0 and numerically very large
* numbers are returns as +/-infinity.
*
* A value must not end or begin with '.' (like JSON), but can have
* leading zeroes (unlike JSON). A single leading zero followed by
* an encoding symbol may or may not be interpreted as a non-decimal
* encoding prefix, e.g. 0x, but a leading zero followed by a digit is
* NOT interpreted as octal.
* A single leading negative sign may appear before digits, but positive
* sign is not allowed and space after the sign is not allowed.
* At most the first 1000 characters of the input is considered.
*/
static const char *grisu3_parse_double(const char *buf, size_t len, double *result)
{
const char *mark, *k, *end;
int sign = 0, esign = 0;
uint64_t fraction = 0;
int exponent = 0;
int ee = 0;
int fraction_exp = 0;
int ulp_half_error = 0;
*result = 0.0;
end = buf + len + 1;
/* Failsafe for exponent overflow. */
if (len > GRISU3_NUM_MAX_LEN) {
end = buf + GRISU3_NUM_MAX_LEN + 1;
}
if (buf == end) {
return buf;
}
mark = buf;
if (*buf == '-') {
++buf;
sign = 1;
if (buf == end) {
return 0;
}
}
if (*buf == '0') {
++buf;
/* | 0x20 is lower case ASCII. */
if (buf != end && (*buf | 0x20) == 'x') {
k = grisu3_parse_hex_fp(buf, end, sign, result);
if (k == buf) {
return mark;
}
return k;
}
/* Not worthwhile, except for getting the scale of integer part. */
while (buf != end && *buf == '0') {
++buf;
}
} else {
if (*buf < '1' || *buf > '9') {
/*
* If we didn't see a sign, just don't recognize it as
* number, otherwise make it an error.
*/
return sign ? 0 : mark;
}
fraction = (uint64_t)(*buf++ - '0');
}
k = buf;
/*
* We do not catch trailing zeroes when there is no decimal point.
* This misses an opportunity for moving the exponent down into the
* fast case. But it is unlikely to be worthwhile as it complicates
* parsing.
*/
while (buf != end && *buf >= '0' && *buf <= '9') {
if (fraction >= UINT64_MAX / 10) {
fraction += *buf >= '5';
ulp_half_error = 1;
break;
}
fraction = fraction * 10 + (uint64_t)(*buf++ - '0');
}
fraction_exp = (int)(buf - k);
/* Skip surplus digits. Trailing zero does not introduce error. */
while (buf != end && *buf == '0') {
++exponent;
++buf;
}
if (buf != end && *buf >= '1' && *buf <= '9') {
ulp_half_error = 1;
++exponent;
++buf;
while (buf != end && *buf >= '0' && *buf <= '9') {
++exponent;
++buf;
}
}
if (buf != end && *buf == '.') {
++buf;
k = buf;
if (*buf < '0' || *buf > '9') {
/* We don't accept numbers without leading or trailing digit. */
return 0;
}
while (buf != end && *buf >= '0' && *buf <= '9') {
if (fraction >= UINT64_MAX / 10) {
if (!ulp_half_error) {
fraction += *buf >= '5';
ulp_half_error = 1;
}
break;
}
fraction = fraction * 10 + (uint64_t)(*buf++ - '0');
--exponent;
}
fraction_exp += (int)(buf - k);
while (buf != end && *buf == '0') {
++exponent;
++buf;
}
if (buf != end && *buf >= '1' && *buf <= '9') {
ulp_half_error = 1;
++buf;
while (buf != end && *buf >= '0' && *buf <= '9') {
++buf;
}
}
}
/*
* Normalized exponent e.g: 1.23434e3 with fraction = 123434,
* fraction_exp = 5, exponent = 3.
* So value = fraction * 10^(exponent - fraction_exp)
*/
exponent += fraction_exp;
if (buf != end && (*buf | 0x20) == 'e') {
if (end - buf < 2) {
return 0;
}
++buf;
if (*buf == '+') {
++buf;
if (buf == end) {
return 0;
}
} else if (*buf == '-') {
esign = 1;
++buf;
if (buf == end) {
return 0;
}
}
if (*buf < '0' || *buf > '9') {
return 0;
}
ee = *buf++ - '0';
while (buf != end && *buf >= '0' && *buf <= '9') {
/*
* This test impacts performance and we do not need an
* exact value just one large enough to dominate the fraction_exp.
* Subsequent handling maps large absolute ee to 0 or infinity.
*/
if (ee <= 0x7fff) {
ee = ee * 10 + *buf - '0';
}
++buf;
}
}
exponent = exponent + (esign ? -ee : ee);
/*
* Exponent is now a base 10 normalized exponent so the absolute value
* is less the 10^(exponent + 1) for positive exponents. For
* denormalized doubles (using 11 bit exponent 0 with a fraction
* shiftet down, extra small numbers can be achieved.
*
* https://en.wikipedia.org/wiki/Double-precision_floating-point_format
*
* 10^-324 holds the smallest normalized exponent (but not value) and
* 10^308 holds the largest exponent. Internally our lookup table is
* only safe to use within a range slightly larger than this.
* Externally, a slightly larger/smaller value represents NaNs which
* are technically also possible to store as a number.
*
*/
/* This also protects strod fallback parsing. */
if (buf == end) {
return 0;
}
return grisu3_encode_double(mark, buf, sign, fraction, exponent, fraction_exp, ulp_half_error, result);
}
#ifdef __cplusplus
}
#endif
#endif /* GRISU3_PARSE_H */

View File

@@ -0,0 +1,265 @@
/*
* Copyright (c) 2016 Mikkel F. Jørgensen, dvide.com
* Copyright author of MathGeoLib (https://github.com/juj)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License. http://www.apache.org/licenses/LICENSE-2.0
*/
/*
* Extracted from MathGeoLib.
*
* mikkelfj:
* - Fixed final output when printing single digit negative exponent to
* have leading zero (important for JSON).
* - Changed formatting to prefer 0.012 over 1.2-e-2.
*
* Large portions of the original grisu3.c file has been moved to
* grisu3_math.h, the rest is placed here.
*
* See also comments in grisu3_math.h.
*
* MatGeoLib grisu3.c comment:
*
* This file is part of an implementation of the "grisu3" double to string
* conversion algorithm described in the research paper
*
* "Printing Floating-Point Numbers Quickly And Accurately with Integers"
* by Florian Loitsch, available at
* http://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf
*/
#ifndef GRISU3_PRINT_H
#define GRISU3_PRINT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h> /* sprintf, only needed for fallback printing */
#include <assert.h> /* assert */
#include "grisu3_math.h"
/*
* The lightweight "portable" C library recognizes grisu3 support if
* included first.
*/
#define grisu3_print_double_is_defined 1
/*
* Not sure we have an exact definition, but we get up to 23
* emperically. There is some math ensuring it does not go awol though,
* like 18 digits + exponent or so.
* This max should be safe size buffer for printing, including zero term.
*/
#define GRISU3_PRINT_MAX 30
static int grisu3_round_weed(char *buffer, int len, uint64_t wp_W, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t ulp)
{
uint64_t wp_Wup = wp_W - ulp;
uint64_t wp_Wdown = wp_W + ulp;
while(rest < wp_Wup && delta - rest >= ten_kappa
&& (rest + ten_kappa < wp_Wup || wp_Wup - rest >= rest + ten_kappa - wp_Wup))
{
--buffer[len-1];
rest += ten_kappa;
}
if (rest < wp_Wdown && delta - rest >= ten_kappa
&& (rest + ten_kappa < wp_Wdown || wp_Wdown - rest > rest + ten_kappa - wp_Wdown))
return 0;
return 2*ulp <= rest && rest <= delta - 4*ulp;
}
static int grisu3_digit_gen(grisu3_diy_fp_t low, grisu3_diy_fp_t w, grisu3_diy_fp_t high, char *buffer, int *length, int *kappa)
{
uint64_t unit = 1;
grisu3_diy_fp_t too_low = { low.f - unit, low.e };
grisu3_diy_fp_t too_high = { high.f + unit, high.e };
grisu3_diy_fp_t unsafe_interval = grisu3_diy_fp_minus(too_high, too_low);
grisu3_diy_fp_t one = { 1ULL << -w.e, w.e };
uint32_t p1 = (uint32_t)(too_high.f >> -one.e);
uint64_t p2 = too_high.f & (one.f - 1);
uint32_t div;
*kappa = grisu3_largest_pow10(p1, GRISU3_DIY_FP_FRACT_SIZE + one.e, &div);
*length = 0;
while(*kappa > 0)
{
uint64_t rest;
char digit = (char)(p1 / div);
buffer[*length] = '0' + digit;
++*length;
p1 %= div;
--*kappa;
rest = ((uint64_t)p1 << -one.e) + p2;
if (rest < unsafe_interval.f) return grisu3_round_weed(buffer, *length, grisu3_diy_fp_minus(too_high, w).f, unsafe_interval.f, rest, (uint64_t)div << -one.e, unit);
div /= 10;
}
for(;;)
{
char digit;
p2 *= 10;
unit *= 10;
unsafe_interval.f *= 10;
/* Integer division by one. */
digit = (char)(p2 >> -one.e);
buffer[*length] = '0' + digit;
++*length;
p2 &= one.f - 1; /* Modulo by one. */
--*kappa;
if (p2 < unsafe_interval.f) return grisu3_round_weed(buffer, *length, grisu3_diy_fp_minus(too_high, w).f * unit, unsafe_interval.f, p2, one.f, unit);
}
}
static int grisu3(double v, char *buffer, int *length, int *d_exp)
{
int mk, kappa, success;
grisu3_diy_fp_t dfp = grisu3_cast_diy_fp_from_double(v);
grisu3_diy_fp_t w = grisu3_diy_fp_normalize(dfp);
/* normalize boundaries */
grisu3_diy_fp_t t = { (dfp.f << 1) + 1, dfp.e - 1 };
grisu3_diy_fp_t b_plus = grisu3_diy_fp_normalize(t);
grisu3_diy_fp_t b_minus;
grisu3_diy_fp_t c_mk; /* Cached power of ten: 10^-k */
uint64_t u64 = grisu3_cast_uint64_from_double(v);
assert(v > 0 && v <= 1.7976931348623157e308); /* Grisu only handles strictly positive finite numbers. */
if (!(u64 & GRISU3_D64_FRACT_MASK) && (u64 & GRISU3_D64_EXP_MASK) != 0) { b_minus.f = (dfp.f << 2) - 1; b_minus.e = dfp.e - 2;} /* lower boundary is closer? */
else { b_minus.f = (dfp.f << 1) - 1; b_minus.e = dfp.e - 1; }
b_minus.f = b_minus.f << (b_minus.e - b_plus.e);
b_minus.e = b_plus.e;
mk = grisu3_diy_fp_cached_pow(GRISU3_MIN_TARGET_EXP - GRISU3_DIY_FP_FRACT_SIZE - w.e, &c_mk);
w = grisu3_diy_fp_multiply(w, c_mk);
b_minus = grisu3_diy_fp_multiply(b_minus, c_mk);
b_plus = grisu3_diy_fp_multiply(b_plus, c_mk);
success = grisu3_digit_gen(b_minus, w, b_plus, buffer, length, &kappa);
*d_exp = kappa - mk;
return success;
}
static int grisu3_i_to_str(int val, char *str)
{
int len, i;
char *s;
char *begin = str;
if (val < 0) { *str++ = '-'; val = -val; }
s = str;
for(;;)
{
int ni = val / 10;
int digit = val - ni*10;
*s++ = (char)('0' + digit);
if (ni == 0)
break;
val = ni;
}
*s = '\0';
len = (int)(s - str);
for(i = 0; i < len/2; ++i)
{
char ch = str[i];
str[i] = str[len-1-i];
str[len-1-i] = ch;
}
return (int)(s - begin);
}
static int grisu3_print_nan(uint64_t v, char *dst)
{
static char hexdigits[16] = "0123456789ABCDEF";
int i = 0;
dst[0] = 'N';
dst[1] = 'a';
dst[2] = 'N';
dst[3] = '(';
dst[20] = ')';
dst[21] = '\0';
dst += 4;
for (i = 15; i >= 0; --i) {
dst[i] = hexdigits[v & 0x0F];
v >>= 4;
}
return 21;
}
static int grisu3_print_double(double v, char *dst)
{
int d_exp, len, success, decimals, i;
uint64_t u64 = grisu3_cast_uint64_from_double(v);
char *s2 = dst;
assert(dst);
/* Prehandle NaNs */
if ((u64 << 1) > 0xFFE0000000000000ULL) return grisu3_print_nan(u64, dst);
/* Prehandle negative values. */
if ((u64 & GRISU3_D64_SIGN) != 0) { *s2++ = '-'; v = -v; u64 ^= GRISU3_D64_SIGN; }
/* Prehandle zero. */
if (!u64) { *s2++ = '0'; *s2 = '\0'; return (int)(s2 - dst); }
/* Prehandle infinity. */
if (u64 == GRISU3_D64_EXP_MASK) { *s2++ = 'i'; *s2++ = 'n'; *s2++ = 'f'; *s2 = '\0'; return (int)(s2 - dst); }
success = grisu3(v, s2, &len, &d_exp);
/* If grisu3 was not able to convert the number to a string, then use old sprintf (suboptimal). */
if (!success) return sprintf(s2, "%.17g", v) + (int)(s2 - dst);
/* We now have an integer string of form "151324135" and a base-10 exponent for that number. */
/* Next, decide the best presentation for that string by whether to use a decimal point, or the scientific exponent notation 'e'. */
/* We don't pick the absolute shortest representation, but pick a balance between readability and shortness, e.g. */
/* 1.545056189557677e-308 could be represented in a shorter form */
/* 1545056189557677e-323 but that would be somewhat unreadable. */
decimals = GRISU3_MIN(-d_exp, GRISU3_MAX(1, len-1));
/* mikkelfj:
* fix zero prefix .1 => 0.1, important for JSON export.
* prefer unscientific notation at same length:
* -1.2345e-4 over -1.00012345,
* -1.0012345 over -1.2345e-3
*/
if (d_exp < 0 && (len + d_exp) > -3 && len <= -d_exp)
{
/* mikkelfj: fix zero prefix .1 => 0.1, and short exponents 1.3e-2 => 0.013. */
memmove(s2 + 2 - d_exp - len, s2, (size_t)len);
s2[0] = '0';
s2[1] = '.';
for (i = 2; i < 2-d_exp-len; ++i) s2[i] = '0';
len += i;
}
else if (d_exp < 0 && len > 1) /* Add decimal point? */
{
for(i = 0; i < decimals; ++i) s2[len-i] = s2[len-i-1];
s2[len++ - decimals] = '.';
d_exp += decimals;
/* Need scientific notation as well? */
if (d_exp != 0) { s2[len++] = 'e'; len += grisu3_i_to_str(d_exp, s2+len); }
}
/* Add scientific notation? */
else if (d_exp < 0 || d_exp > 2) { s2[len++] = 'e'; len += grisu3_i_to_str(d_exp, s2+len); }
/* Add zeroes instead of scientific notation? */
else if (d_exp > 0) { while(d_exp-- > 0) s2[len++] = '0'; }
s2[len] = '\0'; /* grisu3 doesn't null terminate, so ensure termination. */
return (int)(s2+len-dst);
}
#ifdef __cplusplus
}
#endif
#endif /* GRISU3_PRINT_H */

View File

@@ -0,0 +1,4 @@
This directory holds subdirectories it can be added to the include path
such that standard and OS specific header includes like <stdint.h>,
<bool.h> and <endian.h> can succeed without explicitly including
special headers explicitly.

View File

@@ -0,0 +1 @@
#include "portable/pendian.h"

View File

@@ -0,0 +1 @@
#include "portable/inttypes.h"

View File

@@ -0,0 +1 @@
#include "portable/pstdalign.h"

View File

@@ -0,0 +1 @@
#include "portable/pstdbool.h"

View File

@@ -0,0 +1 @@
#include "portable/pstdint.h"

View File

@@ -0,0 +1,210 @@
#ifndef PALIGNED_ALLOC_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* NOTE: MSVC in general has no aligned alloc function that is
* compatible with free and it is not trivial to implement a version
* which is. Therefore, to remain portable, end user code needs to
* use `aligned_free` which is not part of C11 but defined in this header.
*
* glibc only provides aligned_alloc when _ISOC11_SOURCE is defined, but
* MingW does not support aligned_alloc despite of this, it uses the
* the _aligned_malloc as MSVC.
*
* The same issue is present on some Unix systems not providing
* posix_memalign.
*
* Note that clang and gcc with -std=c11 or -std=c99 will not define
* _POSIX_C_SOURCE and thus posix_memalign cannot be detected but
* aligned_alloc is not necessarily available either. We assume
* that clang always has posix_memalign although it is not strictly
* correct. For gcc, use -std=gnu99 or -std=gnu11 or don't use -std in
* order to enable posix_memalign, or live with the fallback until using
* a system where glibc has a version that supports aligned_alloc.
*
* For C11 compliant compilers and compilers with posix_memalign,
* it is valid to use free instead of aligned_free with the above
* caveats.
*/
#include <stdlib.h>
/*
* Define this to see which version is used so the fallback is not
* enganged unnecessarily:
*
* #define PORTABLE_DEBUG_ALIGNED_ALLOC
*/
#if 0
#define PORTABLE_DEBUG_ALIGNED_ALLOC
#endif
#if !defined(PORTABLE_C11_ALIGNED_ALLOC)
/*
* PORTABLE_C11_ALIGNED_ALLOC = 1
* indicates that the system has builtin aligned_alloc
* If it doesn't, the section after detection provides an implemention.
*/
#if defined (__MINGW32__)
/* MingW does not provide aligned_alloc despite defining _ISOC11_SOURCE */
#define PORTABLE_C11_ALIGNED_ALLOC 0
#elif defined (_ISOC11_SOURCE)
/* glibc aligned_alloc detection, but MingW is not truthful */
#define PORTABLE_C11_ALIGNED_ALLOC 1
#elif defined (__GLIBC__)
/* aligned_alloc is not available in glibc just because __STDC_VERSION__ >= 201112L. */
#define PORTABLE_C11_ALIGNED_ALLOC 0
#elif defined (__clang__)
#define PORTABLE_C11_ALIGNED_ALLOC 0
#elif defined(__IBMC__)
#define PORTABLE_C11_ALIGNED_ALLOC 0
#elif (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
#define PORTABLE_C11_ALIGNED_ALLOC 1
#else
#define PORTABLE_C11_ALIGNED_ALLOC 0
#endif
#endif /* PORTABLE_C11_ALIGNED_ALLOC */
/* https://linux.die.net/man/3/posix_memalign */
#if !defined(PORTABLE_POSIX_MEMALIGN) && defined(_GNU_SOURCE)
#define PORTABLE_POSIX_MEMALIGN 1
#endif
/* https://forum.kde.org/viewtopic.php?p=66274 */
#if !defined(PORTABLE_POSIX_MEMALIGN) && defined(_XOPEN_SOURCE)
#if _XOPEN_SOURCE >= 600
#define PORTABLE_POSIX_MEMALIGN 1
#endif
#endif
#if !defined(PORTABLE_POSIX_MEMALIGN) && defined(_POSIX_C_SOURCE)
#if _POSIX_C_SOURCE >= 200112L
#define PORTABLE_POSIX_MEMALIGN 1
#endif
#endif
#if !defined(PORTABLE_POSIX_MEMALIGN) && defined(__clang__)
#define PORTABLE_POSIX_MEMALIGN 1
#endif
#if !defined(PORTABLE_POSIX_MEMALIGN)
#define PORTABLE_POSIX_MEMALIGN 0
#endif
/* https://forum.kde.org/viewtopic.php?p=66274 */
#if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
/* C11 or newer */
#include <stdalign.h>
#endif
/* C11 or newer */
#if !defined(aligned_alloc) && !defined(__aligned_alloc_is_defined)
#if PORTABLE_C11_ALIGNED_ALLOC
#ifdef PORTABLE_DEBUG_ALIGNED_ALLOC
#error "DEBUG: C11_ALIGNED_ALLOC configured"
#endif
#elif defined(_MSC_VER) || defined(__MINGW32__)
#ifdef PORTABLE_DEBUG_ALIGNED_ALLOC
#error "DEBUG: Windows _aligned_malloc configured"
#endif
/* Aligned _aligned_malloc is not compatible with free. */
#define aligned_alloc(alignment, size) _aligned_malloc(size, alignment)
#define aligned_free(p) _aligned_free(p)
#define __aligned_alloc_is_defined 1
#define __aligned_free_is_defined 1
#elif PORTABLE_POSIX_MEMALIGN
#if defined(__GNUC__)
#if !defined(__GNUCC__)
extern int posix_memalign (void **, size_t, size_t);
#elif __GNUCC__ < 5
extern int posix_memalign (void **, size_t, size_t);
#endif
#endif
static inline void *__portable_aligned_alloc(size_t alignment, size_t size)
{
int err;
void *p = 0;
if (alignment < sizeof(void *)) {
alignment = sizeof(void *);
}
err = posix_memalign(&p, alignment, size);
if (err && p) {
free(p);
p = 0;
}
return p;
}
#ifdef PORTABLE_DEBUG_ALIGNED_ALLOC
#error "DEBUG: POSIX_MEMALIGN configured"
#endif
#define aligned_alloc(alignment, size) __portable_aligned_alloc(alignment, size)
#define aligned_free(p) free(p)
#define __aligned_alloc_is_defined 1
#define __aligned_free_is_defined 1
#else
static inline void *__portable_aligned_alloc(size_t alignment, size_t size)
{
char *raw;
void *buf;
size_t total_size = (size + alignment - 1 + sizeof(void *));
if (alignment < sizeof(void *)) {
alignment = sizeof(void *);
}
raw = (char *)(size_t)malloc(total_size);
buf = raw + alignment - 1 + sizeof(void *);
buf = (void *)(((size_t)buf) & ~(alignment - 1));
((void **)buf)[-1] = raw;
return buf;
}
static inline void __portable_aligned_free(void *p)
{
char *raw;
if (p) {
raw = (char*)((void **)p)[-1];
free(raw);
}
}
#define aligned_alloc(alignment, size) __portable_aligned_alloc(alignment, size)
#define aligned_free(p) __portable_aligned_free(p)
#define __aligned_alloc_is_defined 1
#define __aligned_free_is_defined 1
#ifdef PORTABLE_DEBUG_ALIGNED_ALLOC
#error "DEBUG: aligned_alloc malloc fallback configured"
#endif
#endif
#endif /* aligned_alloc */
#if !defined(aligned_free) && !defined(__aligned_free_is_defined)
#define aligned_free(p) free(p)
#define __aligned_free_is_defined 1
#endif
#ifdef __cplusplus
}
#endif
#endif /* PALIGNED_ALLOC_H */

View File

@@ -0,0 +1,84 @@
/*
* C23 introduces an attribute syntax `[[<attribute>]]`. Prior to that
* other non-standard syntaxes such as `__attribute__((<attribute>))`
* and `__declspec(<attribute>)` have been supported by some compiler
* versions.
*
* See also:
* https://en.cppreference.com/w/c/language/attributes
*
* There is no portable way to use C23 attributes in older C standards
* so in order to use these portably, some macro name needs to be
* defined for each attribute that either maps to the older supported
* syntax, or ignores the attribute as appropriate.
*
* The Linux kernel defines certain attributes as macros, such as
* `fallthrough`. When adding attributes it seems reasonable to follow
* the Linux conventions in lack of any official standard. However, it
* is not the intention that this file should mirror the Linux
* attributes 1 to 1.
*
* See also:
* https://github.com/torvalds/linux/blob/master/include/linux/compiler_attributes.h
*
* There is a risk that exposed attribute names may lead to name
* conflicts. A conflicting name can be undefined and if necessary used
* using `pattribute(<attribute>)`. All attributes can be hidden by
* defining `PORTABLE_EXPOSE_ATTRIBUTES=0` in which case
* `pattribute(<attribute>)` can still be used and then if a specific
* attribute name still needs to be exposed, it can be defined manually
* like `#define fallthrough pattribute(fallthrough)`.
*/
#ifndef PATTRIBUTES_H
#define PATTRIBUTES_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef PORTABLE_EXPOSE_ATTRIBUTES
#define PORTABLE_EXPOSE_ATTRIBUTES 1
#endif
#ifdef __has_c_attribute
# define PORTABLE_HAS_C_ATTRIBUTE(x) __has_c_attribute(x)
#else
# define PORTABLE_HAS_C_ATTRIBUTE(x) 0
#endif
#ifdef __has_attribute
# define PORTABLE_HAS_ATTRIBUTE(x) __has_attribute(x)
#else
# define PORTABLE_HAS_ATTRIBUTE(x) 0
#endif
/* https://en.cppreference.com/w/c/language/attributes/fallthrough */
#if PORTABLE_HAS_C_ATTRIBUTE(__fallthrough__)
# define pattribute_fallthrough [[__fallthrough__]]
#elif PORTABLE_HAS_ATTRIBUTE(__fallthrough__)
# define pattribute_fallthrough __attribute__((__fallthrough__))
#else
# define pattribute_fallthrough ((void)0)
#endif
#define pattribute(x) pattribute_##x
#if PORTABLE_EXPOSE_ATTRIBUTES
#ifndef fallthrough
# define fallthrough pattribute(fallthrough)
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif /* PATTRIBUTES_H */

View File

@@ -0,0 +1,448 @@
#ifndef PBASE64_H
#define PBASE64_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
/* Guarded to allow inclusion of pstdint.h first, if stdint.h is not supported. */
#ifndef UINT8_MAX
#include <stdint.h>
#endif
#define BASE64_EOK 0
/* 0 or mure full blocks decoded, remaining content may be parsed with fresh buffer. */
#define BASE64_EMORE 1
/* The `src_len` argument is required when encoding. */
#define BASE64_EARGS 2
/* Unsupported mode, or modifier not supported by mode when encoding. */
#define BASE64_EMODE 3
/* Decoding ends at invalid tail length - either by source length or by non-alphabet symbol. */
#define BASE64_ETAIL 4
/* Decoding ends at valid tail length but last byte has non-zero bits where it shouldn't have. */
#define BASE64_EDIRTY 5
static inline const char *base64_strerror(int err);
/* All codecs are URL safe. Only Crockford allow for non-canocical decoding. */
enum {
/* Most common base64 codec, but not url friendly. */
base64_mode_rfc4648 = 0,
/* URL safe version, '+' -> '-', '/' -> '_'. */
base64_mode_url = 1,
/*
* Skip ' ', '\r', and '\n' - we do not allow tab because common
* uses of base64 such as PEM do not allow tab.
*/
base64_dec_modifier_skipspace = 32,
/* Padding is excluded by default. Not allowed for zbase64. */
base64_enc_modifier_padding = 128,
/* For internal use or to decide codec of mode. */
base64_modifier_mask = 32 + 64 + 128,
};
/* Encoded size with or without padding. */
static inline size_t base64_encoded_size(size_t len, int mode);
/*
* Decoded size assuming no padding.
* If `len` does include padding, the actual size may be less
* when decoding, but never more.
*/
static inline size_t base64_decoded_size(size_t len);
/*
* `dst` must hold ceil(len * 4 / 3) bytes.
* `src_len` points to length of source and is updated with length of
* parse on both success and failure. If `dst_len` is not null
* it is used to store resulting output lengt withh length of decoded
* output on both success and failure.
* If `hyphen` is non-zero a hyphen is encoded every `hyphen` output bytes.
* `mode` selects encoding alphabet defaulting to Crockfords base64.
* Returns 0 on success.
*
* A terminal space can be added with `dst[dst_len++] = ' '` after the
* encode call. All non-alphabet can be used as terminators except the
* padding character '='. The following characters will work as
* terminator for all modes: { '\0', '\n', ' ', '\t' }. A terminator is
* optional when the source length is given to the decoder. Note that
* crockford also reserves a few extra characters for checksum but the
* checksum must be separate from the main buffer and is not supported
* by this library.
*/
static inline int base64_encode(uint8_t *dst, const uint8_t *src, size_t *dst_len, size_t *src_len, int mode);
/*
* Decodes according to mode while ignoring encoding modifiers.
* `src_len` and `dst_len` are optional pointers. If `src_len` is set it
* must contain the length of the input, otherwise the input must be
* terminated with a non-alphabet character or valid padding (a single
* padding character is accepted) - if the src_len output is needed but
* not the input due to guaranteed termination, then set it to
* (size_t)-1. `dst_len` must contain length of output buffer if present
* and parse will fail with BASE64_EMORE after decoding a block multiple
* if dst_len is exhausted - the parse can thus be resumed after
* draining destination. `src_len` and `dst_len` are updated with parsed
* and decoded length, when present, on both success and failure.
* Returns 0 on success. Invalid characters are not considered errors -
* they simply terminate the parse, however, if the termination is not
* at a block multiple or a valid partial block length then BASE64_ETAIL
* without output holding the last full block, if any. BASE64_ETAIL is also
* returned if the a valid length holds non-zero unused tail bits.
*/
static inline int base64_decode(uint8_t *dst, const uint8_t *src, size_t *dst_len, size_t *src_len, int mode);
static inline const char *base64_strerror(int err)
{
switch (err) {
case BASE64_EOK: return "ok";
case BASE64_EARGS: return "invalid argument";
case BASE64_EMODE: return "invalid mode";
case BASE64_EMORE: return "destination full";
case BASE64_ETAIL: return "invalid tail length";
case BASE64_EDIRTY: return "invalid tail content";
default: return "unknown error";
}
}
static inline size_t base64_encoded_size(size_t len, int mode)
{
size_t k = len % 3;
size_t n = (len * 4 / 3 + 3) & ~(size_t)3;
int pad = mode & base64_enc_modifier_padding;
if (!pad) {
switch (k) {
case 2:
n -= 1;
break;
case 1:
n -= 2;
break;
default:
break;
}
}
return n;
}
static inline size_t base64_decoded_size(size_t len)
{
size_t k = len % 4;
size_t n = len / 4 * 3;
switch (k) {
case 3:
return n + 2;
case 2:
return n + 1;
case 1: /* Not valid without padding. */
case 0:
default:
return n;
}
}
static inline int base64_encode(uint8_t *dst, const uint8_t *src, size_t *dst_len, size_t *src_len, int mode)
{
const uint8_t *rfc4648_alphabet = (const uint8_t *)
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const uint8_t *url_alphabet = (const uint8_t *)
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
const uint8_t *T;
uint8_t *dst_base = dst;
int pad = mode & base64_enc_modifier_padding;
size_t len = 0;
int ret = BASE64_EMODE;
if (!src_len) {
ret = BASE64_EARGS;
goto done;
}
len = *src_len;
mode = mode & ~base64_modifier_mask;
switch (mode) {
case base64_mode_rfc4648:
T = rfc4648_alphabet;
break;
case base64_mode_url:
T = url_alphabet;
break;
default:
/* Invalid mode. */
goto done;
}
ret = BASE64_EOK;
/* Encodes 4 destination bytes from 3 source bytes. */
while (len >= 3) {
dst[0] = T[((src[0] >> 2))];
dst[1] = T[((src[0] << 4) & 0x30) | (src[1] >> 4)];
dst[2] = T[((src[1] << 2) & 0x3c) | (src[2] >> 6)];
dst[3] = T[((src[2] & 0x3f))];
len -= 3;
dst += 4;
src += 3;
}
/* Encodes 8 destination bytes from 1 to 4 source bytes, if any. */
switch(len) {
case 2:
dst[0] = T[((src[0] >> 2))];
dst[1] = T[((src[0] << 4) & 0x30) | (src[1] >> 4)];
dst[2] = T[((src[1] << 2) & 0x3c)];
dst += 3;
if (pad) {
*dst++ = '=';
}
break;
case 1:
dst[0] = T[((src[0] >> 2))];
dst[1] = T[((src[0] << 4) & 0x30)];
dst += 2;
if (pad) {
*dst++ = '=';
*dst++ = '=';
}
break;
default:
pad = 0;
break;
}
len = 0;
done:
if (dst_len) {
*dst_len = (size_t)(dst - dst_base);
}
if (src_len) {
*src_len -= len;
}
return ret;
}
static inline int base64_decode(uint8_t *dst, const uint8_t *src, size_t *dst_len, size_t *src_len, int mode)
{
static const uint8_t cinvalid = 64;
static const uint8_t cignore = 65;
static const uint8_t cpadding = 66;
/*
* 0..63: 6-bit encoded value.
* 64: flags non-alphabet symbols.
* 65: codes for ignored symbols.
* 66: codes for pad symbol '='.
* All codecs consider padding an optional terminator and if present
* consumes as many pad bytes as possible up to block termination,
* but does not fail if a block is not full.
*
* We do not currently have any ignored characters but we might
* add spaces as per MIME spec, but assuming spaces only happen
* at block boundaries this is probalby better handled by repeated
* parsing.
*/
static const uint8_t base64rfc4648_decode[256] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 66, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};
static const uint8_t base64url_decode[256] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 66, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 63,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};
static const uint8_t base64rfc4648_decode_skipspace[256] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 64, 64, 65, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
65, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 66, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};
static const uint8_t base64url_decode_skipspace[256] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 64, 64, 65, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
65, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 66, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 63,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};
int ret = BASE64_EOK;
size_t i, k;
uint8_t hold[4];
uint8_t *dst_base = dst;
size_t limit = (size_t)-1;
size_t len = (size_t)-1, mark;
const uint8_t *T = base64rfc4648_decode;
int skipspace = mode & base64_dec_modifier_skipspace;
if (src_len) {
len = *src_len;
}
mark = len;
mode = mode & ~base64_modifier_mask;
switch (mode) {
case base64_mode_rfc4648:
T = skipspace ? base64rfc4648_decode_skipspace : base64rfc4648_decode;
break;
case base64_mode_url:
T = skipspace ? base64url_decode_skipspace : base64url_decode;
break;
default:
ret = BASE64_EMODE;
goto done;
}
if (dst_len && *dst_len > 0) {
limit = *dst_len;
}
while(limit > 0) {
for (i = 0; i < 4; ++i) {
if (len == i) {
k = i;
len -= i;
goto tail;
}
if ((hold[i] = T[src[i]]) >= cinvalid) {
if (hold[i] == cignore) {
++src;
--len;
--i;
continue;
}
k = i;
/* Strip padding and ignore hyphen in padding, if present. */
if (hold[i] == cpadding) {
++i;
while (i < len && i < 8) {
if (T[src[i]] != cpadding && T[src[i]] != cignore) {
break;
}
++i;
}
}
len -= i;
goto tail;
}
}
if (limit < 3) {
goto more;
}
dst[0] = (uint8_t)((hold[0] << 2) | (hold[1] >> 4));
dst[1] = (uint8_t)((hold[1] << 4) | (hold[2] >> 2));
dst[2] = (uint8_t)((hold[2] << 6) | (hold[3]));
dst += 3;
src += 4;
limit -= 3;
len -= 4;
mark = len;
}
done:
if (dst_len) {
*dst_len = (size_t)(dst - dst_base);
}
if (src_len) {
*src_len -= mark;
}
return ret;
tail:
switch (k) {
case 0:
break;
case 2:
if ((hold[1] << 4) & 0xff) {
goto dirty;
}
if (limit < 1) {
goto more;
}
dst[0] = (uint8_t)((hold[0] << 2) | (hold[1] >> 4));
dst += 1;
break;
case 3:
if ((hold[2] << 6) & 0xff) {
goto dirty;
}
if (limit < 2) {
goto more;
}
dst[0] = (uint8_t)((hold[0] << 2) | (hold[1] >> 4));
dst[1] = (uint8_t)((hold[1] << 4) | (hold[2] >> 2));
dst += 2;
break;
default:
ret = BASE64_ETAIL;
goto done;
}
mark = len;
goto done;
dirty:
ret = BASE64_EDIRTY;
goto done;
more:
ret = BASE64_EMORE;
goto done;
}
#ifdef __cplusplus
}
#endif
#endif /* PBASE64_H */

View File

@@ -0,0 +1,48 @@
#ifndef PCRT_H
#define PCRT_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* Assertions and pointer violations in debug mode may trigger a dialog
* on Windows. When running headless this is not helpful, but
* unfortunately it cannot be disabled with a compiler option so code
* must be injected into the runtime early in the main function.
* A call to the provided `init_headless_crt()` macro does this in
* a portable manner.
*
* See also:
* https://stackoverflow.com/questions/13943665/how-can-i-disable-the-debug-assertion-dialog-on-windows
*/
#if defined(_WIN32)
#include <crtdbg.h>
#include <stdio.h>
#include <stdlib.h>
static int _portable_msvc_headless_report_hook(int reportType, char *message, int *returnValue)
{
fprintf(stderr, "CRT[%d]: %s\n", reportType, message);
*returnValue = 1;
exit(1);
return 1;
}
#define init_headless_crt() _CrtSetReportHook(_portable_msvc_headless_report_hook)
#else
#define init_headless_crt() ((void)0)
#endif
#ifdef __cplusplus
}
#endif
#endif /* PCRT_H */

View File

@@ -0,0 +1,85 @@
/* There is intentionally no include guard in this file. */
/*
* Usage: optionally disable any of these before including.
*
* #define PDIAGNOSTIC_IGNORE_UNUSED_FUNCTION
* #define PDIAGNOSTIC_IGNORE_UNUSED_VARIABLE
* #define PDIAGNOSTIC_IGNORE_UNUSED_PARAMETER
* #define PDIAGNOSTIC_IGNORE_UNUSED // all of the above
*
* #include "pdiagnostic.h"
*
* Alternatively use #include "pdiagnostic_push/pop.h"
*/
#ifdef _MSC_VER
#pragma warning(disable: 4668) /* preprocessor name not defined */
#endif
#if !defined(PDIAGNOSTIC_AWARE_MSVC) && defined(_MSC_VER)
#define PDIAGNOSTIC_AWARE_MSVC 1
#elif !defined(PDIAGNOSTIC_AWARE_MSVC)
#define PDIAGNOSTIC_AWARE_MSVC 0
#endif
#if !defined(PDIAGNOSTIC_AWARE_CLANG) && defined(__clang__)
#define PDIAGNOSTIC_AWARE_CLANG 1
#elif !defined(PDIAGNOSTIC_AWARE_CLANG)
#define PDIAGNOSTIC_AWARE_CLANG 0
#endif
#if !defined(PDIAGNOSTIC_AWARE_GCC) && defined(__GNUC__) && !defined(__clang__)
/* Can disable some warnings even if push is not available (gcc-4.2 vs gcc-4.7) */
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)
#define PDIAGNOSTIC_AWARE_GCC 1
#endif
#endif
#if !defined(PDIAGNOSTIC_AWARE_GCC)
#define PDIAGNOSTIC_AWARE_GCC 0
#endif
#if defined(PDIAGNOSTIC_IGNORE_UNUSED_FUNCTION) || defined(PDIAGNOSTIC_IGNORE_UNUSED)
#if PDIAGNOSTIC_AWARE_CLANG
#pragma clang diagnostic ignored "-Wunused-function"
#elif PDIAGNOSTIC_AWARE_GCC
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#endif
#undef PDIAGNOSTIC_IGNORE_UNUSED_FUNCTION
#if defined(PDIAGNOSTIC_IGNORE_UNUSED_VARIABLE) || defined(PDIAGNOSTIC_IGNORE_UNUSED)
#if PDIAGNOSTIC_AWARE_MSVC
#pragma warning(disable: 4101) /* unused local variable */
#elif PDIAGNOSTIC_AWARE_CLANG
#pragma clang diagnostic ignored "-Wunused-variable"
#elif PDIAGNOSTIC_AWARE_GCC
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
#endif
#undef PDIAGNOSTIC_IGNORE_UNUSED_VARIABLE
#if defined(PDIAGNOSTIC_IGNORE_UNUSED_PARAMETER) || defined(PDIAGNOSTIC_IGNORE_UNUSED)
#if PDIAGNOSTIC_AWARE_CLANG
#pragma clang diagnostic ignored "-Wunused-parameter"
#elif PDIAGNOSTIC_AWARE_GCC
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#endif
#undef PDIAGNOSTIC_IGNORE_UNUSED_PARAMETER
#undef PDIAGNOSTIC_IGNORE_UNUSED
#if defined (__cplusplus) && __cplusplus < 201103L
#if PDIAGNOSTIC_AWARE_CLANG
/* Needed for < C++11 clang C++ static_assert */
#pragma clang diagnostic ignored "-Wc11-extensions"
/* Needed for empty macro arguments. */
#pragma clang diagnostic ignored "-Wc99-extensions"
/* Needed for trailing commas. */
#pragma clang diagnostic ignored "-Wc++11-extensions"
#endif
#endif

View File

@@ -0,0 +1,20 @@
#if defined(PDIAGNOSTIC_PUSHED_MSVC)
#if PDIAGNOSTIC_PUSHED_MSVC
#pragma warning( pop )
#endif // PDIAGNOSTIC_PUSHED_MSVC
#undef PDIAGNOSTIC_PUSHED_MSVC
#endif // defined(PDIAGNOSTIC_PUSHED_MSVC)
#if defined(PDIAGNOSTIC_PUSHED_CLANG)
#if PDIAGNOSTIC_PUSHED_CLANG
#pragma clang diagnostic pop
#endif // PDIAGNOSTIC_PUSHED_CLANG
#undef PDIAGNOSTIC_PUSHED_CLANG
#endif // defined(PDIAGNOSTIC_PUSHED_CLANG)
#if defined(PDIAGNOSTIC_PUSHED_GCC)
#if PDIAGNOSTIC_PUSHED_GCC
#pragma GCC diagnostic pop
#endif // PDIAGNOSTIC_PUSHED_GCC
#undef PDIAGNOSTIC_PUSHED_GCC
#endif // defined(PDIAGNOSTIC_PUSHED_GCC)

View File

@@ -0,0 +1,51 @@
/*
* See also comment in "pdiagnostic.h"
*
* e.g.
* #define PDIAGNOSTIC_IGNORE_USED_FUNCTION
* #define PDIAGNOSTIC_IGNORE_USED_VARIABLE
* #include "pdiagnostic_push"
* ...
* #include "pdiagnostic_pop.h"
* <eof>
*
* or if push pop isn't desired:
* #define PDIAGNOSTIC_IGNORE_USED_FUNCTION
* #define PDIAGNOSTIC_IGNORE_USED_VARIABLE
* #include "pdiagnostic.h"
* ...
* <eof>
*
*
* Some if these warnings cannot be ignored
* at the #pragma level, but might in the future.
* Use compiler switches like -Wno-unused-function
* to work around this.
*/
#if defined(_MSC_VER)
#pragma warning( push )
#define PDIAGNOSTIC_PUSHED_MSVC 1
#else
#define PDIAGNOSTIC_PUSHED_MSVC 0
#endif
#if defined(__clang__)
#pragma clang diagnostic push
#define PDIAGNOSTIC_PUSHED_CLANG 1
#else
#define PDIAGNOSTIC_PUSHED_CLANG 0
#endif
#if defined(__GNUC__) && !defined(__clang__)
#if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
#pragma GCC diagnostic push
#define PDIAGNOSTIC_PUSHED_GCC 1
#else
#define PDIAGNOSTIC_PUSHED_GCC 0
#endif // GNUC >= 4.6
#else
#define PDIAGNOSTIC_PUSHED_GCC 0
#endif // defined(__GNUC__) && !defined(__clang__)
#include "pdiagnostic.h"

View File

@@ -0,0 +1,206 @@
#ifndef PENDIAN_H
#define PENDIAN_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* Defines platform optimized (as per linux <endian.h>
*
* le16toh, le32to, le64toh, be16toh, be32toh, be64toh
* htole16, htole32, htole64, htobe16, htobe32, htobe64
*
* Falls back to auto-detect endian conversion which is also fast
* if fast byteswap operation was detected.
*
* Also defines platform optimized:
*
* bswap16, bswap32, bswap64,
*
* with fall-back to shift-or implementation.
*
* For convenience also defines:
*
* le8to, be8toh, htole8, htobe8
* bswap8
*
* The convience functions makes is simpler to define conversion macros
* based on type size.
*
* NOTE: this implementation expects arguments with no side-effects and
* with appropriately sized unsigned arguments. These are expected to be
* used with typesafe wrappers.
*/
#ifndef UINT8_MAX
#include "pstdint.h"
#endif
#if defined(__linux__)
#include <endian.h>
#elif defined(__OpenBSD__) || defined(__FreeBSD__)
#include <sys/endian.h>
#endif
#include "pendian_detect.h"
#if defined(_MSC_VER)
#if _MSC_VER >= 1300
#include <stdlib.h>
#define bswap16 _byteswap_ushort
#define bswap32 _byteswap_ulong
#define bswap64 _byteswap_uint64
#endif
#elif defined(__clang__)
#if __has_builtin(__builtin_bswap16)
#ifndef bswap16
#define bswap16 __builtin_bswap16
#endif
#endif
#if __has_builtin(__builtin_bswap32)
#ifndef bswap32
#define bswap32 __builtin_bswap32
#endif
#endif
#if __has_builtin(__builtin_bswap64)
#ifndef bswap64
#define bswap64 __builtin_bswap64
#endif
#endif
#elif defined(__OpenBSD__) || defined(__FreeBSD__)
#ifndef bswap16
#define bswap16 swap16
#endif
#ifndef bswap32
#define bswap32 swap32
#endif
#ifndef bswap64
#define bswap64 swap64
#endif
#elif defined(__GNUC__) /* Supported since at least GCC 4.4 */
#ifndef bswap32
#define bswap32 __builtin_bswap32
#endif
#ifndef bswap64
#define bswap64 __builtin_bswap64
#endif
#endif
#ifndef bswap16
#define bswap16(v) \
(((uint16_t)(v) << 8) | ((uint16_t)(v) >> 8))
#endif
#ifndef bswap32
#define bswap32(v) \
((((uint32_t)(v) << 24)) \
| (((uint32_t)(v) << 8) & UINT32_C(0x00FF0000)) \
| (((uint32_t)(v) >> 8) & UINT32_C(0x0000FF00)) \
| (((uint32_t)(v) >> 24)))
#endif
#ifndef bswap64
#define bswap64(v) \
((((uint64_t)(v) << 56)) \
| (((uint64_t)(v) << 40) & UINT64_C(0x00FF000000000000)) \
| (((uint64_t)(v) << 24) & UINT64_C(0x0000FF0000000000)) \
| (((uint64_t)(v) << 8) & UINT64_C(0x000000FF00000000)) \
| (((uint64_t)(v) >> 8) & UINT64_C(0x00000000FF000000)) \
| (((uint64_t)(v) >> 24) & UINT64_C(0x0000000000FF0000)) \
| (((uint64_t)(v) >> 40) & UINT64_C(0x000000000000FF00)) \
| (((uint64_t)(v) >> 56)))
#endif
#ifndef bswap8
#define bswap8(v) ((uint8_t)(v))
#endif
#if !defined(le16toh) && defined(letoh16)
#define le16toh letoh16
#define le32toh letoh32
#define le64toh letoh64
#endif
#if !defined(be16toh) && defined(betoh16)
#define be16toh betoh16
#define be32toh betoh32
#define be64toh betoh64
#endif
/* Assume it goes for all. */
#if !defined(le16toh)
#if defined(__LITTLE_ENDIAN__)
#define le16toh(v) (v)
#define le32toh(v) (v)
#define le64toh(v) (v)
#define htole16(v) (v)
#define htole32(v) (v)
#define htole64(v) (v)
#define be16toh(v) bswap16(v)
#define be32toh(v) bswap32(v)
#define be64toh(v) bswap64(v)
#define htobe16(v) bswap16(v)
#define htobe32(v) bswap32(v)
#define htobe64(v) bswap64(v)
#elif defined(__BIG_ENDIAN__)
#define le16toh(v) bswap16(v)
#define le32toh(v) bswap32(v)
#define le64toh(v) bswap64(v)
#define htole16(v) bswap16(v)
#define htole32(v) bswap32(v)
#define htole64(v) bswap64(v)
#define be16toh(v) (v)
#define be32toh(v) (v)
#define be64toh(v) (v)
#define htobe16(v) (v)
#define htobe32(v) (v)
#define htobe64(v) (v)
#else
static const int __pendian_test = 1;
#define le16toh(v) (*(char *)&__pendian_test ? (v) : bswap16(v))
#define le32toh(v) (*(char *)&__pendian_test ? (v) : bswap32(v))
#define le64toh(v) (*(char *)&__pendian_test ? (v) : bswap64(v))
#define htole16(v) (*(char *)&__pendian_test ? (v) : bswap16(v))
#define htole32(v) (*(char *)&__pendian_test ? (v) : bswap32(v))
#define htole64(v) (*(char *)&__pendian_test ? (v) : bswap64(v))
#define be16toh(v) (*(char *)&__pendian_test ? bswap16(v) : (v))
#define be32toh(v) (*(char *)&__pendian_test ? bswap32(v) : (v))
#define be64toh(v) (*(char *)&__pendian_test ? bswap64(v) : (v))
#define htobe16(v) (*(char *)&__pendian_test ? bswap16(v) : (v))
#define htobe32(v) (*(char *)&__pendian_test ? bswap32(v) : (v))
#define htobe64(v) (*(char *)&__pendian_test ? bswap64(v) : (v))
#endif
#endif /* le16toh */
/* Helpers not part of Linux <endian.h> */
#if !defined(le8toh)
#define le8toh(n) (n)
#define htole8(n) (n)
#define be8toh(n) (n)
#define htobe8(n) (n)
#endif
#ifdef __cplusplus
}
#endif
#endif /* PENDIAN_H */

View File

@@ -0,0 +1,118 @@
/*
* Uses various known flags to decide endianness and defines:
*
* __LITTLE_ENDIAN__ or __BIG_ENDIAN__ if not already defined
*
* and also defines
*
* __BYTE_ORDER__ to either __ORDER_LITTLE_ENDIAN__ or
* __ORDER_BIG_ENDIAN__ if not already defined
*
* If none of these could be set, __UNKNOWN_ENDIAN__ is defined,
* which is not a known flag. If __BYTE_ORDER__ is defined but
* not big or little endian, __UNKNOWN_ENDIAN__ is also defined.
*
* Note: Some systems define __BYTE_ORDER without __ at the end
* - this will be mapped to to __BYTE_ORDER__.
*/
#ifndef PENDIAN_DETECT
#define PENDIAN_DETECT
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __ORDER_LITTLE_ENDIAN__
#define __ORDER_LITTLE_ENDIAN__ 1234
#endif
#ifndef __ORDER_BIG_ENDIAN__
#define __ORDER_BIG_ENDIAN__ 4321
#endif
#ifdef __BYTE_ORDER__
#if defined(__LITTLE_ENDIAN__) && __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
#error __LITTLE_ENDIAN__ inconsistent with __BYTE_ORDER__
#endif
#if defined(__BIG_ENDIAN__) && __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__
#error __BIG_ENDIAN__ inconsistent with __BYTE_ORDER__
#endif
#else /* __BYTE_ORDER__ */
#if \
defined(__LITTLE_ENDIAN__) || \
(defined(__BYTE_ORDER) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \
defined(__ARMEL__) || defined(__THUMBEL__) || \
defined(__AARCH64EL__) || \
(defined(_MSC_VER) && defined(_M_ARM)) || \
defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
defined(_M_X64) || defined(_M_IX86) || defined(_M_I86) || \
defined(__i386__) || defined(__alpha__) || \
defined(__ia64) || defined(__ia64__) || \
defined(_M_IA64) || defined(_M_ALPHA) || \
defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || \
defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
defined(__bfin__)
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#endif
#if \
defined (__BIG_ENDIAN__) || \
(defined(__BYTE_ORDER) && __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \
defined(__ARMEB__) || defined(THUMBEB__) || defined (__AARCH64EB__) || \
defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || \
defined(__sparc) || defined(__sparc__) || \
defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || \
defined(__hpux) || defined(__hppa) || defined(__s390__)
#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
#endif
#endif /* __BYTE_ORDER__ */
#ifdef __BYTE_ORDER__
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#ifndef __LITTLE_ENDIAN__
#define __LITTLE_ENDIAN__ 1
#endif
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#ifndef __BIG_ENDIAN__
#define __BIG_ENDIAN__ 1
#endif
#else
/*
* Custom extension - we only define __BYTE_ORDER__ if known big or little.
* User code that understands __BYTE_ORDER__ may also assume unkown if
* it is not defined by now - this will allow other endian formats than
* big or little when supported by compiler.
*/
#ifndef __UNKNOWN_ENDIAN__
#define __UNKNOWN_ENDIAN__ 1
#endif
#endif
#endif /* __BYTE_ORDER__ */
#if defined(__LITTLE_ENDIAN__) && defined(__BIG_ENDIAN__)
#error conflicting definitions of __LITTLE_ENDIAN__ and __BIG_ENDIAN__
#endif
#ifdef __cplusplus
}
#endif
#endif /* PENDIAN_DETECT */

View File

@@ -0,0 +1,19 @@
#ifndef PINLINE_H
#define PINLINE_H
#ifndef __cplusplus
#if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
/* C99 or newer */
#elif _MSC_VER >= 1500 /* MSVC 9 or newer */
#undef inline
#define inline __inline
#elif __GNUC__ >= 3 /* GCC 3 or newer */
#define inline __inline
#else /* Unknown or ancient */
#define inline
#endif
#endif /* __cplusplus */
#endif /* PINLINE_H */

View File

@@ -0,0 +1,52 @@
#ifndef PINTTYPES_H
#define PINTTYPES_H
#ifndef PRId16
#if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
/* C99 or newer */
#include <inttypes.h>
#else
/*
* This is not a complete implementation of <inttypes.h>, just the most
* useful printf modifiers.
*/
#include "pstdint.h"
#ifndef PRINTF_INT64_MODIFIER
#error "please define PRINTF_INT64_MODIFIER"
#endif
#ifndef PRId64
#define PRId64 PRINTF_INT64_MODIFIER "d"
#define PRIu64 PRINTF_INT64_MODIFIER "u"
#define PRIx64 PRINTF_INT64_MODIFIER "x"
#endif
#ifndef PRINTF_INT32_MODIFIER
#define PRINTF_INT32_MODIFIER "l"
#endif
#ifndef PRId32
#define PRId32 PRINTF_INT32_MODIFIER "d"
#define PRIu32 PRINTF_INT32_MODIFIER "u"
#define PRIx32 PRINTF_INT32_MODIFIER "x"
#endif
#ifndef PRINTF_INT16_MODIFIER
#define PRINTF_INT16_MODIFIER "h"
#endif
#ifndef PRId16
#define PRId16 PRINTF_INT16_MODIFIER "d"
#define PRIu16 PRINTF_INT16_MODIFIER "u"
#define PRIx16 PRINTF_INT16_MODIFIER "x"
#endif
# endif /* __STDC__ */
#endif /* PRId16 */
#endif /* PINTTYPES */

View File

@@ -0,0 +1,2 @@
/* portable.h is widely used, so we redirect to a less conflicting name. */
#include "portable_basic.h"

View File

@@ -0,0 +1,25 @@
#ifndef PORTABLE_BASIC_H
#define PORTABLE_BASIC_H
/*
* Basic features need to make compilers support the most common moden C
* features, and endian / unligned read support as well.
*
* It is not assumed that this file is always included.
* Other include files are independent or include what they need.
*/
#include "pversion.h"
#include "pwarnings.h"
/* Featutures that ought to be supported by C11, but some aren't. */
#include "pinttypes.h"
#include "pstdalign.h"
#include "pinline.h"
#include "pstatic_assert.h"
/* These are not supported by C11 and are general platform abstractions. */
#include "pendian.h"
#include "punaligned.h"
#endif /* PORTABLE_BASIC_H */

View File

@@ -0,0 +1,140 @@
#ifndef PPARSEFP_H
#define PPARSEFP_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* Parses a float or double number and returns the length parsed if
* successful. The length argument is of limited value due to dependency
* on `strtod` - buf[len] must be accessible and must not be part of
* a valid number, including hex float numbers..
*
* Unlike strtod, whitespace is not parsed.
*
* May return:
* - null on error,
* - buffer start if first character does not start a number,
* - or end of parse on success.
*
*/
#define PDIAGNOSTIC_IGNORE_UNUSED_FUNCTION
#include "pdiagnostic_push.h"
/*
* isinf is needed in order to stay compatible with strtod's
* over/underflow handling but isinf has some portability issues.
*
* Use the parse_double/float_is_range_error instead of isinf directly.
* This ensures optimizations can be added when not using strtod.
*
* On gcc, clang and msvc we can use isinf or equivalent directly.
* Other compilers such as xlc may require linking with -lm which may not
* be convienent so a default isinf is provided. If isinf is available
* and there is a noticable performance issue, define
* `PORTABLE_USE_ISINF`.
*/
#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) || defined(PORTABLE_USE_ISINF)
#include <math.h>
#if defined(_MSC_VER) && !defined(isinf)
#include <float.h>
#define isnan _isnan
#define isinf(x) (!_finite(x))
#endif
/*
* clang-5 through clang-8 but not clang-9 issues incorrect precision
* loss warning with -Wconversion flag when cast is absent.
*/
#if defined(__clang__)
#if __clang_major__ >= 5 && __clang_major__ <= 8
#define parse_double_isinf(x) isinf((float)x)
#endif
#endif
#if !defined(parse_double_isinf)
#define parse_double_isinf isinf
#endif
#define parse_float_isinf isinf
#else
#ifndef UINT8_MAX
#include <stdint.h>
#endif
/* Avoid linking with libmath but depends on float/double being IEEE754 */
static inline int parse_double_isinf(double x)
{
union { uint64_t u64; double f64; } v;
v.f64 = x;
return (v.u64 & 0x7fffffff00000000ULL) == 0x7ff0000000000000ULL;
}
static inline int parse_float_isinf(float x)
{
union { uint32_t u32; float f32; } v;
v.f32 = x;
return (v.u32 & 0x7fffffff) == 0x7f800000;
}
#endif
/* Returns 0 when in range, 1 on overflow, and -1 on underflow. */
static inline int parse_double_is_range_error(double x)
{
return parse_double_isinf(x) ? (x < 0.0 ? -1 : 1) : 0;
}
static inline int parse_float_is_range_error(float x)
{
return parse_float_isinf(x) ? (x < 0.0f ? -1 : 1) : 0;
}
#ifndef PORTABLE_USE_GRISU3
#define PORTABLE_USE_GRISU3 1
#endif
#if PORTABLE_USE_GRISU3
#include "grisu3_parse.h"
#endif
#ifdef grisu3_parse_double_is_defined
static inline const char *parse_double(const char *buf, size_t len, double *result)
{
return grisu3_parse_double(buf, len, result);
}
#else
#include <stdio.h>
static inline const char *parse_double(const char *buf, size_t len, double *result)
{
char *end;
(void)len;
*result = strtod(buf, &end);
return end;
}
#endif
static inline const char *parse_float(const char *buf, size_t len, float *result)
{
const char *end;
double v;
union { uint32_t u32; float f32; } inf;
inf.u32 = 0x7f800000;
end = parse_double(buf, len, &v);
*result = (float)v;
if (parse_float_isinf(*result)) {
*result = v < 0 ? -inf.f32 : inf.f32;
return buf;
}
return end;
}
#include "pdiagnostic_pop.h"
#ifdef __cplusplus
}
#endif
#endif /* PPARSEFP_H */

View File

@@ -0,0 +1,374 @@
#ifndef PPARSEINT_H
#define PPARSEINT_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* Type specific integer parsers:
*
* const char *
* parse_<type-name>(const char *buf, size_t len, <type> *value, int *status);
*
* parse_uint64, parse_int64
* parse_uint32, parse_int32
* parse_uint16, parse_int16
* parse_uint8, parse_int8
* parse_ushort, parse_short
* parse_uint, parse_int
* parse_ulong, parse_long
*
* Leading space must be stripped in advance. Status argument can be
* null.
*
* Returns pointer to end of match and a non-negative status code
* on succcess (0 for unsigned, 1 for signed):
*
* PARSE_INTEGER_UNSIGNED
* PARSE_INTEGER_SIGNED
*
* Returns null with a negative status code and unmodified value on
* invalid integer formats:
*
* PARSE_INTEGER_OVERFLOW
* PARSE_INTEGER_UNDERFLOW
* PARSE_INTEGER_INVALID
*
* Returns input buffer with negative status code and unmodified value
* if first character does not start an integer (not a sign or a digit).
*
* PARSE_INTEGER_UNMATCHED
* PARSE_INTEGER_END
*
* The signed parsers only works with two's complement architectures.
*
* Note: the corresponding parse_float and parse_double parsers do not
* have a status argument because +/-Inf and NaN are conventionally used
* for this.
*/
#include "limits.h"
#ifndef UINT8_MAX
#include <stdint.h>
#endif
#define PARSE_INTEGER_UNSIGNED 0
#define PARSE_INTEGER_SIGNED 1
#define PARSE_INTEGER_OVERFLOW -1
#define PARSE_INTEGER_UNDERFLOW -2
#define PARSE_INTEGER_INVALID -3
#define PARSE_INTEGER_UNMATCHED -4
#define PARSE_INTEGER_END -5
/*
* Generic integer parser that holds 64-bit unsigned values and stores
* sign separately. Leading space is not valid.
*
* Note: this function differs from the type specific parsers like
* parse_int64 by not negating the value when there is a sign. It
* differs from parse_uint64 by being able to return a negative
* UINT64_MAX successfully.
*
* This parser is used by all type specific integer parsers.
*
* Status argument can be null.
*/
static const char *parse_integer(const char *buf, size_t len, uint64_t *value, int *status)
{
uint64_t x0, x = 0;
const char *k, *end = buf + len;
int sign, status_;
if (!status) {
status = &status_;
}
if (buf == end) {
*status = PARSE_INTEGER_END;
return buf;
}
k = buf;
sign = *buf == '-';
buf += sign;
while (buf != end && *buf >= '0' && *buf <= '9') {
x0 = x;
x = x * 10 + (uint64_t)(*buf - '0');
if (x0 > x) {
*status = sign ? PARSE_INTEGER_UNDERFLOW : PARSE_INTEGER_OVERFLOW;
return 0;
}
++buf;
}
if (buf == k) {
/* No number was matched, but it isn't an invalid number either. */
*status = PARSE_INTEGER_UNMATCHED;
return buf;
}
if (buf == k + sign) {
*status = PARSE_INTEGER_INVALID;
return 0;
}
if (buf != end)
switch (*buf) {
case 'e': case 'E': case '.': case 'p': case 'P':
*status = PARSE_INTEGER_INVALID;
return 0;
}
*value = x;
*status = sign;
return buf;
}
/*
* Parse hex values like 0xff, -0xff, 0XdeAdBeaf42, cannot be trailed by '.', 'p', or 'P'.
* Overflows if string is more than 16 valid hex digits. Otherwise similar to parse_integer.
*/
static const char *parse_hex_integer(const char *buf, size_t len, uint64_t *value, int *status)
{
uint64_t x = 0;
const char *k, *k2, *end = buf + len;
int sign, status_;
unsigned char c;
if (!status) {
status = &status_;
}
if (buf == end) {
*status = PARSE_INTEGER_END;
return buf;
}
sign = *buf == '-';
buf += sign;
if (end - buf < 2 || buf[0] != '0' || (buf[1] | 0x20) != 'x') {
*status = PARSE_INTEGER_UNMATCHED;
return buf - sign;
}
buf += 2;
k = buf;
k2 = end;
if (end - buf > 16) {
k2 = buf + 16;
}
while (buf != k2) {
c = (unsigned char)*buf;
if (c >= '0' && c <= '9') {
x = x * 16 + c - '0';
} else {
/* Lower case. */
c |= 0x20;
if (c >= 'a' && c <= 'f') {
x = x * 16 + c - 'a' + 10;
} else {
break;
}
}
++buf;
}
if (buf == k) {
if (sign) {
*status = PARSE_INTEGER_INVALID;
return 0;
} else {
/* No number was matched, but it isn't an invalid number either. */
*status = PARSE_INTEGER_UNMATCHED;
return buf;
}
}
if (buf == end) {
goto done;
}
c = (unsigned char)*buf;
if (buf == k2) {
if (c >= '0' && c <= '9') {
*status = sign ? PARSE_INTEGER_UNDERFLOW : PARSE_INTEGER_OVERFLOW;
return 0;
}
c |= 0x20;
if (c >= 'a' && c <= 'f') {
*status = sign ? PARSE_INTEGER_UNDERFLOW : PARSE_INTEGER_OVERFLOW;
return 0;
}
}
switch (c) {
case '.': case 'p': case 'P':
*status = PARSE_INTEGER_INVALID;
return 0;
}
done:
*value = x;
*status = sign;
return buf;
}
#define __portable_define_parse_unsigned(NAME, TYPE, LIMIT) \
static inline const char *parse_ ## NAME \
(const char *buf, size_t len, TYPE *value, int *status) \
{ \
int status_ = 0; \
uint64_t x; \
\
if (!status) { \
status = &status_; \
} \
buf = parse_integer(buf, len, &x, status); \
switch (*status) { \
case PARSE_INTEGER_UNSIGNED: \
if (x <= LIMIT) { \
*value = (TYPE)x; \
return buf; \
} \
*status = PARSE_INTEGER_OVERFLOW; \
return 0; \
case PARSE_INTEGER_SIGNED: \
*status = PARSE_INTEGER_UNDERFLOW; \
return 0; \
default: \
return buf; \
} \
}
#define __portable_define_parse_hex_unsigned(NAME, TYPE, LIMIT) \
static inline const char *parse_hex_ ## NAME \
(const char *buf, size_t len, TYPE *value, int *status) \
{ \
int status_ = 0; \
uint64_t x; \
\
if (!status) { \
status = &status_; \
} \
buf = parse_hex_integer(buf, len, &x, status); \
switch (*status) { \
case PARSE_INTEGER_UNSIGNED: \
if (x <= LIMIT) { \
*value = (TYPE)x; \
return buf; \
} \
*status = PARSE_INTEGER_OVERFLOW; \
return 0; \
case PARSE_INTEGER_SIGNED: \
*status = PARSE_INTEGER_UNDERFLOW; \
return 0; \
default: \
return buf; \
} \
}
/* This assumes two's complement. */
#define __portable_define_parse_signed(NAME, TYPE, LIMIT) \
static inline const char *parse_ ## NAME \
(const char *buf, size_t len, TYPE *value, int *status) \
{ \
int status_ = 0; \
uint64_t x; \
\
if (!status) { \
status = &status_; \
} \
buf = parse_integer(buf, len, &x, status); \
switch (*status) { \
case PARSE_INTEGER_UNSIGNED: \
if (x <= LIMIT) { \
*value = (TYPE)x; \
return buf; \
} \
*status = PARSE_INTEGER_OVERFLOW; \
return 0; \
case PARSE_INTEGER_SIGNED: \
if (x <= (uint64_t)(LIMIT) + 1) { \
*value = (TYPE)-(int64_t)x; \
return buf; \
} \
*status = PARSE_INTEGER_UNDERFLOW; \
return 0; \
default: \
return buf; \
} \
}
/* This assumes two's complement. */
#define __portable_define_parse_hex_signed(NAME, TYPE, LIMIT) \
static inline const char *parse_hex_ ## NAME \
(const char *buf, size_t len, TYPE *value, int *status) \
{ \
int status_ = 0; \
uint64_t x; \
\
if (!status) { \
status = &status_; \
} \
buf = parse_hex_integer(buf, len, &x, status); \
switch (*status) { \
case PARSE_INTEGER_UNSIGNED: \
if (x <= LIMIT) { \
*value = (TYPE)x; \
return buf; \
} \
*status = PARSE_INTEGER_OVERFLOW; \
return 0; \
case PARSE_INTEGER_SIGNED: \
if (x <= (uint64_t)(LIMIT) + 1) { \
*value = (TYPE)-(int64_t)x; \
return buf; \
} \
*status = PARSE_INTEGER_UNDERFLOW; \
return 0; \
default: \
return buf; \
} \
}
static inline const char *parse_uint64(const char *buf, size_t len, uint64_t *value, int *status)
{
buf = parse_integer(buf, len, value, status);
if (*status == PARSE_INTEGER_SIGNED) {
*status = PARSE_INTEGER_UNDERFLOW;
return 0;
}
return buf;
}
static inline const char *parse_hex_uint64(const char *buf, size_t len, uint64_t *value, int *status)
{
buf = parse_hex_integer(buf, len, value, status);
if (*status == PARSE_INTEGER_SIGNED) {
*status = PARSE_INTEGER_UNDERFLOW;
return 0;
}
return buf;
}
__portable_define_parse_signed(int64, int64_t, INT64_MAX)
__portable_define_parse_signed(int32, int32_t, INT32_MAX)
__portable_define_parse_unsigned(uint16, uint16_t, UINT16_MAX)
__portable_define_parse_signed(int16, int16_t, INT16_MAX)
__portable_define_parse_unsigned(uint8, uint8_t, UINT8_MAX)
__portable_define_parse_signed(int8, int8_t, INT8_MAX)
__portable_define_parse_hex_signed(int64, int64_t, INT64_MAX)
__portable_define_parse_hex_signed(int32, int32_t, INT32_MAX)
__portable_define_parse_hex_unsigned(uint16, uint16_t, UINT16_MAX)
__portable_define_parse_hex_signed(int16, int16_t, INT16_MAX)
__portable_define_parse_hex_unsigned(uint8, uint8_t, UINT8_MAX)
__portable_define_parse_hex_signed(int8, int8_t, INT8_MAX)
__portable_define_parse_unsigned(ushort, unsigned short, USHRT_MAX)
__portable_define_parse_signed(short, short, SHRT_MAX)
__portable_define_parse_unsigned(uint, unsigned int, UINT_MAX)
__portable_define_parse_signed(int, int, INT_MAX)
__portable_define_parse_unsigned(ulong, unsigned long, ULONG_MAX)
__portable_define_parse_signed(long, unsigned long, LONG_MAX)
__portable_define_parse_hex_unsigned(ushort, unsigned short, USHRT_MAX)
__portable_define_parse_hex_signed(short, short, SHRT_MAX)
__portable_define_parse_hex_unsigned(uint, unsigned int, UINT_MAX)
__portable_define_parse_hex_signed(int, int, INT_MAX)
__portable_define_parse_hex_unsigned(ulong, unsigned long, ULONG_MAX)
__portable_define_parse_hex_signed(long, unsigned long, LONG_MAX)
#ifdef __cplusplus
}
#endif
#endif /* PPARSEINT_H */

View File

@@ -0,0 +1,39 @@
#ifndef PPRINTFP_H
#define PPRINTFP_H
#ifdef __cplusplus
extern "C" {
#endif
#define PDIAGNOSTIC_IGNORE_UNUSED_FUNCTION
#include "pdiagnostic_push.h"
#ifndef PORTABLE_USE_GRISU3
#define PORTABLE_USE_GRISU3 1
#endif
#if PORTABLE_USE_GRISU3
#include "grisu3_print.h"
#endif
#ifdef grisu3_print_double_is_defined
/* Currently there is not special support for floats. */
#define print_float(n, p) grisu3_print_double((float)(n), (p))
#define print_double(n, p) grisu3_print_double((double)(n), (p))
#else
#include <stdio.h>
#define print_float(n, p) sprintf(p, "%.9g", (float)(n))
#define print_double(n, p) sprintf(p, "%.17g", (double)(n))
#endif
#define print_hex_float(n, p) sprintf(p, "%a", (float)(n))
#define print_hex_double(n, p) sprintf(p, "%a", (double)(n))
#include "pdiagnostic_pop.h"
#ifdef __cplusplus
}
#endif
#endif /* PPRINTFP_H */

View File

@@ -0,0 +1,628 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Mikkel F. Jørgensen, dvide.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.
*
*
* Fast printing of (u)int8/16/32/64_t, (u)int, (u)long.
*
* Functions take for the
*
* int print_<type>(type value, char *buf);
*
* and returns number of characters printed, excluding trailing '\0'
* which is also printed. Prints at most 21 characters including zero-
* termination.
*
* The function `print_bool` is a bit different - it simply prints "true\0" for
* non-zero integers, and "false\0" otherwise.
*
* The general algorithm is in-place formatting using binary search log10
* followed by duff device loop unrolling div / 100 stages.
*
* The simpler post copy algorithm also provided for fmt_(u)int uses a
* temp buffer and loops over div/100 and post copy to target buffer.
*
*
* Benchmarks on core-i7, 2.2GHz, 64-bit clang/OS-X -O2:
*
* print_int64: avg 15ns for values between INT64_MIN + (10^7/2 .. 10^7/2)
* print_int64: avg 11ns for values between 10^9 + (0..10,000,000).
* print_int32: avg 7ns for values cast from INT64_MIN + (10^7/2 .. 10^7/2)
* print_int32: avg 7ns for values between 10^9 + (0..10,000,000).
* print_int64: avg 13ns for values between 10^16 + (0..10,000,000).
* print_int64: avg 5ns for values between 0 and 10,000,000.
* print_int32: avg 5ns for values between 0 and 10,000,000.
* print_int16: avg 10ns for values cast from 0 and 10,000,000.
* print_int8: avg 4ns for values cast from 0 and 10,000,000.
*
* Post copy algorithm:
* print_int: avg 12ns for values between INT64_MIN + (10^7/2 .. 10^7/2)
* print_int: avg 14ns for values between 10^9 + (0..10,000,000).
* print_long: avg 29ns for values between INT64_MIN + (10^7/2 .. 10^7/2)
*
* The post copy algorithm is nearly half as fast as the in-place
* algorithm, but can also be faster occasionally - possibly because the
* optimizer being able to skip the copy step.
*/
#ifndef PPRINTINT_H
#define PPRINTINT_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef UINT8_MAX
#include <stdint.h>
#endif
#include "pattributes.h" /* fallthrough */
#define PDIAGNOSTIC_IGNORE_UNUSED_FUNCTION
#include "pdiagnostic_push.h"
static int print_bool(int n, char *p);
static int print_uint8(uint8_t n, char *p);
static int print_uint16(uint16_t n, char *p);
static int print_uint32(uint32_t n, char *p);
static int print_uint64(uint64_t n, char *p);
static int print_int8(int8_t n, char *p);
static int print_int16(int16_t n, char *p);
static int print_int32(int32_t n, char *p);
static int print_int64(int64_t n, char *p);
/*
* Uses slightly slower, but more compact alogrithm
* that is not hardcoded to implementation size.
* Other types may be defined using macros below.
*/
static int print_ulong(unsigned long n, char *p);
static int print_uint(unsigned int n, char *p);
static int print_int(int n, char *p);
static int print_long(long n, char *p);
#if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
#define __print_unaligned_copy_16(p, q) (*(uint16_t*)(p) = *(uint16_t*)(q))
#else
#define __print_unaligned_copy_16(p, q) \
((((uint8_t*)(p))[0] = ((uint8_t*)(q))[0]), \
(((uint8_t*)(p))[1] = ((uint8_t*)(q))[1]))
#endif
static const char __print_digit_pairs[] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
#define __print_stage() \
p -= 2; \
dp = __print_digit_pairs + (n % 100) * 2; \
n /= 100; \
__print_unaligned_copy_16(p, dp);
#define __print_long_stage() \
__print_stage() \
__print_stage()
#define __print_short_stage() \
*--p = (n % 10) + '0'; \
n /= 10;
static int print_bool(int n, char *buf)
{
if (n) {
memcpy(buf, "true\0", 5);
return 4;
} else {
memcpy(buf, "false\0", 6);
return 5;
}
}
static int print_uint8(uint8_t n, char *p)
{
const char *dp;
if (n >= 100) {
p += 3;
*p = '\0';
__print_stage();
p[-1] = (char)n + '0';
return 3;
}
if (n >= 10) {
p += 2;
*p = '\0';
__print_stage();
return 2;
}
p[1] = '\0';
p[0] = (char)n + '0';
return 1;
}
static int print_uint16(uint16_t n, char *p)
{
int k = 0;
const char *dp;
if (n >= 1000) {
if(n >= 10000) {
k = 5;
} else {
k = 4;
}
} else {
if(n >= 100) {
k = 3;
} else if(n >= 10) {
k = 2;
} else {
k = 1;
}
}
p += k;
*p = '\0';
if (k & 1) {
switch (k) {
case 5:
__print_stage();
pattribute(fallthrough);
case 3:
__print_stage();
pattribute(fallthrough);
case 1:
p[-1] = (char)n + '0';
}
} else {
switch (k) {
case 4:
__print_stage();
pattribute(fallthrough);
case 2:
__print_stage();
}
}
return k;
}
static int print_uint32(uint32_t n, char *p)
{
int k = 0;
const char *dp;
if(n >= 10000UL) {
if(n >= 10000000UL) {
if(n >= 1000000000UL) {
k = 10;
} else if(n >= 100000000UL) {
k = 9;
} else {
k = 8;
}
} else {
if(n >= 1000000UL) {
k = 7;
} else if(n >= 100000UL) {
k = 6;
} else {
k = 5;
}
}
} else {
if(n >= 100UL) {
if(n >= 1000UL) {
k = 4;
} else {
k = 3;
}
} else {
if(n >= 10UL) {
k = 2;
} else {
k = 1UL;
}
}
}
p += k;
*p = '\0';
if (k & 1) {
switch (k) {
case 9:
__print_stage();
pattribute(fallthrough);
case 7:
__print_stage();
pattribute(fallthrough);
case 5:
__print_stage();
pattribute(fallthrough);
case 3:
__print_stage();
pattribute(fallthrough);
case 1:
p[-1] = (char)n + '0';
}
} else {
switch (k) {
case 10:
__print_stage();
pattribute(fallthrough);
case 8:
__print_stage();
pattribute(fallthrough);
case 6:
__print_stage();
pattribute(fallthrough);
case 4:
__print_stage();
pattribute(fallthrough);
case 2:
__print_stage();
}
}
return k;
}
static int print_uint64(uint64_t n, char *p)
{
int k = 0;
const char *dp;
const uint64_t x = 1000000000ULL;
if (n < x) {
return print_uint32((uint32_t)n, p);
}
if(n >= 10000ULL * x) {
if(n >= 10000000ULL * x) {
if(n >= 1000000000ULL * x) {
if (n >= 10000000000ULL * x) {
k = 11 + 9;
} else {
k = 10 + 9;
}
} else if(n >= 100000000ULL * x) {
k = 9 + 9;
} else {
k = 8 + 9;
}
} else {
if(n >= 1000000ULL * x) {
k = 7 + 9;
} else if(n >= 100000ULL * x) {
k = 6 + 9;
} else {
k = 5 + 9;
}
}
} else {
if(n >= 100ULL * x) {
if(n >= 1000ULL * x) {
k = 4 + 9;
} else {
k = 3 + 9;
}
} else {
if(n >= 10ULL * x) {
k = 2 + 9;
} else {
k = 1 + 9;
}
}
}
p += k;
*p = '\0';
if (k & 1) {
switch (k) {
case 19:
__print_stage();
pattribute(fallthrough);
case 17:
__print_stage();
pattribute(fallthrough);
case 15:
__print_stage();
pattribute(fallthrough);
case 13:
__print_stage();
pattribute(fallthrough);
case 11:
__print_stage()
__print_short_stage();
}
} else {
switch (k) {
case 20:
__print_stage();
pattribute(fallthrough);
case 18:
__print_stage();
pattribute(fallthrough);
case 16:
__print_stage();
pattribute(fallthrough);
case 14:
__print_stage();
pattribute(fallthrough);
case 12:
__print_stage();
pattribute(fallthrough);
case 10:
__print_stage();
}
}
__print_long_stage()
__print_long_stage()
return k;
}
static int print_int8(int8_t n, char *p)
{
int sign;
if ((sign = n < 0)) {
*p++ = '-';
n = -n;
}
return print_uint8((uint8_t)n, p) + sign;
}
static int print_int16(int16_t n, char *p)
{
int sign;
if ((sign = n < 0)) {
*p++ = '-';
n = -n;
}
return print_uint16((uint16_t)n, p) + sign;
}
static int print_int32(int32_t n, char *p)
{
int sign;
if ((sign = n < 0)) {
*p++ = '-';
n = -n;
}
return print_uint32((uint32_t)n, p) + sign;
}
static int print_int64(int64_t n, char *p)
{
int sign;
if ((sign = n < 0)) {
*p++ = '-';
n = -n;
}
return print_uint64((uint64_t)n, p) + sign;
}
#define __define_print_int_simple(NAME, UNAME, T, UT) \
static int UNAME(UT n, char *buf) \
{ \
char tmp[20]; \
char* p = tmp + 20; \
char* q = p; \
unsigned int k, m; \
\
while (n >= 100) { \
p -= 2; \
m = (unsigned int)(n % 100) * 2; \
n /= 100; \
__print_unaligned_copy_16(p, __print_digit_pairs + m); \
} \
p -= 2; \
m = (unsigned int)n * 2; \
__print_unaligned_copy_16(p, __print_digit_pairs + m); \
if (n < 10) { \
++p; \
} \
k = (unsigned int)(q - p); \
while (p != q) { \
*buf++ = *p++; \
} \
*buf = '\0'; \
return (int)k; \
} \
\
static int NAME(T n, char *buf) \
{ \
int sign = n < 0; \
\
if (sign) { \
*buf++ = '-'; \
n = -n; \
} \
return UNAME((UT)n, buf) + sign; \
}
__define_print_int_simple(print_int, print_uint, int, unsigned int)
__define_print_int_simple(print_long, print_ulong, long, unsigned long)
#ifdef PPRINTINT_BENCH
int main() {
int64_t count = 10000000; /* 10^7 */
#if 0
int64_t base = 0;
int64_t base = 10000000000000000; /* 10^16 */
int64_t base = 1000000000; /* 10^9 */
#endif
int64_t base = INT64_MIN - count/2;
char buf[100];
int i, k = 0, n = 0;
for (i = 0; i < count; i++) {
k = print_int64(i + base, buf);
n += buf[0] + buf[k - 1];
}
return n;
}
/* Call with time on executable, multiply time in seconds by 100 to get time unit in ns/number. */
#endif /* PPRINTINT_BENCH */
#ifdef PPRINTINT_TEST
#include <stdio.h>
#include <string.h>
int main()
{
char buf[21];
int failed = 0;
int k;
k = print_uint64(UINT64_MAX, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("18446744073709551615", buf)) {
printf("UINT64_MAX didn't print correctly, got:\n'%s'\n", buf);
++failed;
}
k = print_int64(INT64_MAX, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("9223372036854775807", buf)) {
printf("INT64_MAX didn't print correctly, got:\n'%s'\n", buf);
++failed;
}
k = print_int64(INT64_MIN, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("-9223372036854775808", buf)) {
printf("INT64_MIN didn't print correctly, got:\n'%s'\n", buf);
++failed;
}
k = print_uint32(UINT32_MAX, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("4294967295", buf)) {
printf("UINT32_MAX didn't print correctly, got:\n'%s'\n", buf);
++failed;
}
k = print_int32(INT32_MAX, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("2147483647", buf)) {
printf("INT32_MAX didn't print correctly, got:\n'%s'\n", buf);
++failed;
}
k = print_int32(INT32_MIN, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("-2147483648", buf)) {
printf("INT32_MIN didn't print correctly, got:\n'%s'\n", buf);
++failed;
}
k = print_uint16(UINT16_MAX, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("65535", buf)) {
printf("UINT16_MAX didn't print correctly, got:\n'%s'\n", buf);
++failed;
}
k = print_int16(INT16_MAX, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("32767", buf)) {
printf("INT16_MAX didn't print correctly, got:\n'%s'\n", buf);
++failed;
}
k = print_int16(INT16_MIN, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("-32768", buf)) {
printf("INT16_MIN didn't print correctly, got:\n'%s'\n", buf);
++failed;
}
k = print_uint8(UINT8_MAX, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("255", buf)) {
printf("INT8_MAX didn't print correctly, got:\n'%s'\n", buf);
++failed;
}
k = print_int8(INT8_MAX, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("127", buf)) {
printf("INT8_MAX didn't print correctly, got:\n'%s'\n", buf);
++failed;
}
k = print_int8(INT8_MIN, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("-128", buf)) {
printf("INT8_MIN didn't print correctly, got:\n'%s'\n", buf);
++failed;
}
k = print_int(INT32_MAX, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("2147483647", buf)) {
printf("INT32_MAX didn't print correctly with k = print_int, got:\n'%s'\n", buf);
++failed;
}
k = print_int(INT32_MIN, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("-2147483648", buf)) {
printf("INT32_MIN didn't print correctly k = print_int, got:\n'%s'\n", buf);
++failed;
}
k = print_long(INT32_MAX, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("2147483647", buf)) {
printf("INT32_MAX didn't print correctly with fmt_long, got:\n'%s'\n", buf);
++failed;
}
k = print_long(INT32_MIN, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("-2147483648", buf)) {
printf("INT32_MIN didn't print correctly fmt_long, got:\n'%s'\n", buf);
++failed;
}
k = print_bool(1, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("true", buf) {
printf("1 didn't print 'true' as expected, got:\n'%s'\n", buf);
++failed;
}
k = print_bool(-1, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("true", buf) {
printf("-1 didn't print 'true' as expected, got:\n'%s'\n", buf);
++failed;
}
k = print_bool(, buf);
if (strlen(buf) != k) printf("length error\n");
if (strcmp("false", buf) {
printf("0 didn't print 'false' as expected, got:\n'%s'\n", buf);
++failed;
}
if (failed) {
printf("FAILED\n");
return -1;
}
printf("SUCCESS\n");
return 0;
}
#endif /* PPRINTINT_TEST */
#include "pdiagnostic_pop.h"
#ifdef __cplusplus
}
#endif
#endif /* PPRINTINT_H */

View File

@@ -0,0 +1,67 @@
#ifndef PSTATIC_ASSERT_H
#define PSTATIC_ASSERT_H
#include <assert.h>
/* Handle clang */
#ifndef __has_feature
#define __has_feature(x) 0
#endif
#if defined(static_assert)
#ifndef __static_assert_is_defined
#define __static_assert_is_defined 1
#endif
#endif
/* Handle static_assert as a keyword in C++ and compiler specifics. */
#if !defined(__static_assert_is_defined)
#if defined(__cplusplus)
#if __cplusplus >= 201103L
#define __static_assert_is_defined 1
#elif __has_feature(cxx_static_assert)
#define __static_assert_is_defined 1
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
#define __static_assert_is_defined 1
#endif
#else
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
#define __static_assert_is_defined 1
#elif __has_feature(c_static_assert)
#define static_assert(pred, msg) _Static_assert(pred, msg)
#define __static_assert_is_defined 1
#elif defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
/* In case the clib headers are not compliant. */
#define static_assert(pred, msg) _Static_assert(pred, msg)
#define __static_assert_is_defined 1
#endif
#endif /* __cplusplus */
#endif /* __static_assert_is_defined */
#if !defined(__static_assert_is_defined)
#define __PSTATIC_ASSERT_CONCAT_(a, b) static_assert_scope_##a##_line_##b
#define __PSTATIC_ASSERT_CONCAT(a, b) __PSTATIC_ASSERT_CONCAT_(a, b)
#ifdef __COUNTER__
#define static_assert(e, msg) enum { __PSTATIC_ASSERT_CONCAT(__COUNTER__, __LINE__) = 1/(!!(e)) }
#else
#include "pstatic_assert_scope.h"
#define static_assert(e, msg) enum { __PSTATIC_ASSERT_CONCAT(__PSTATIC_ASSERT_COUNTER, __LINE__) = 1/(int)(!!(e)) }
#endif
#define __static_assert_is_defined 1
#endif /* __static_assert_is_defined */
#endif /* PSTATIC_ASSERT_H */
/* Update scope counter outside of include guard. */
#ifdef __PSTATIC_ASSERT_COUNTER
#include "pstatic_assert_scope.h"
#endif

View File

@@ -0,0 +1,280 @@
/*
* january, 2017, ported to portable library by mikkelfj.
* Based on dbgtools static assert counter, but with renamed macros.
*/
/*
dbgtools - platform independent wrapping of "nice to have" debug functions.
version 0.1, october, 2013
https://github.com/wc-duck/dbgtools
Copyright (C) 2013- Fredrik Kihlander
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Fredrik Kihlander
*/
/**
* Auto-generated header implementing a counter that increases by each include of the file.
*
* This header will define the macro __PSTATIC_ASSERT_COUNTER to be increased for each inclusion of the file.
*
* It has been generated with 3 amount of digits resulting in the counter wrapping around after
* 10000 inclusions.
*
* Usage:
*
* #include "this_header.h"
* int a = __PSTATIC_ASSERT_COUNTER; // 0
* #include "this_header.h"
* int b = __PSTATIC_ASSERT_COUNTER; // 1
* #include "this_header.h"
* int c = __PSTATIC_ASSERT_COUNTER; // 2
* #include "this_header.h"
* int d = __PSTATIC_ASSERT_COUNTER; // 3
*/
#ifndef __PSTATIC_ASSERT_COUNTER
# define __PSTATIC_ASSERT_COUNTER_0 0
# define __PSTATIC_ASSERT_COUNTER_1
# define __PSTATIC_ASSERT_COUNTER_2
# define __PSTATIC_ASSERT_COUNTER_3
# define __PSTATIC_ASSERT_COUNTER_D1_0
# define __PSTATIC_ASSERT_COUNTER_D2_0
# define __PSTATIC_ASSERT_COUNTER_D3_0
#endif /* __PSTATIC_ASSERT_COUNTER */
#if !defined( __PSTATIC_ASSERT_COUNTER_D0_0 )
# define __PSTATIC_ASSERT_COUNTER_D0_0
# undef __PSTATIC_ASSERT_COUNTER_0
# define __PSTATIC_ASSERT_COUNTER_0 0
#elif !defined( __PSTATIC_ASSERT_COUNTER_D0_1 )
# define __PSTATIC_ASSERT_COUNTER_D0_1
# undef __PSTATIC_ASSERT_COUNTER_0
# define __PSTATIC_ASSERT_COUNTER_0 1
#elif !defined( __PSTATIC_ASSERT_COUNTER_D0_2 )
# define __PSTATIC_ASSERT_COUNTER_D0_2
# undef __PSTATIC_ASSERT_COUNTER_0
# define __PSTATIC_ASSERT_COUNTER_0 2
#elif !defined( __PSTATIC_ASSERT_COUNTER_D0_3 )
# define __PSTATIC_ASSERT_COUNTER_D0_3
# undef __PSTATIC_ASSERT_COUNTER_0
# define __PSTATIC_ASSERT_COUNTER_0 3
#elif !defined( __PSTATIC_ASSERT_COUNTER_D0_4 )
# define __PSTATIC_ASSERT_COUNTER_D0_4
# undef __PSTATIC_ASSERT_COUNTER_0
# define __PSTATIC_ASSERT_COUNTER_0 4
#elif !defined( __PSTATIC_ASSERT_COUNTER_D0_5 )
# define __PSTATIC_ASSERT_COUNTER_D0_5
# undef __PSTATIC_ASSERT_COUNTER_0
# define __PSTATIC_ASSERT_COUNTER_0 5
#elif !defined( __PSTATIC_ASSERT_COUNTER_D0_6 )
# define __PSTATIC_ASSERT_COUNTER_D0_6
# undef __PSTATIC_ASSERT_COUNTER_0
# define __PSTATIC_ASSERT_COUNTER_0 6
#elif !defined( __PSTATIC_ASSERT_COUNTER_D0_7 )
# define __PSTATIC_ASSERT_COUNTER_D0_7
# undef __PSTATIC_ASSERT_COUNTER_0
# define __PSTATIC_ASSERT_COUNTER_0 7
#elif !defined( __PSTATIC_ASSERT_COUNTER_D0_8 )
# define __PSTATIC_ASSERT_COUNTER_D0_8
# undef __PSTATIC_ASSERT_COUNTER_0
# define __PSTATIC_ASSERT_COUNTER_0 8
#elif !defined( __PSTATIC_ASSERT_COUNTER_D0_9 )
# define __PSTATIC_ASSERT_COUNTER_D0_9
# undef __PSTATIC_ASSERT_COUNTER_0
# define __PSTATIC_ASSERT_COUNTER_0 9
#else
# undef __PSTATIC_ASSERT_COUNTER_D0_1
# undef __PSTATIC_ASSERT_COUNTER_D0_2
# undef __PSTATIC_ASSERT_COUNTER_D0_3
# undef __PSTATIC_ASSERT_COUNTER_D0_4
# undef __PSTATIC_ASSERT_COUNTER_D0_5
# undef __PSTATIC_ASSERT_COUNTER_D0_6
# undef __PSTATIC_ASSERT_COUNTER_D0_7
# undef __PSTATIC_ASSERT_COUNTER_D0_8
# undef __PSTATIC_ASSERT_COUNTER_D0_9
# undef __PSTATIC_ASSERT_COUNTER_0
# define __PSTATIC_ASSERT_COUNTER_0 0
# if !defined( __PSTATIC_ASSERT_COUNTER_D1_0 )
# define __PSTATIC_ASSERT_COUNTER_D1_0
# undef __PSTATIC_ASSERT_COUNTER_1
# define __PSTATIC_ASSERT_COUNTER_1 0
# elif !defined( __PSTATIC_ASSERT_COUNTER_D1_1 )
# define __PSTATIC_ASSERT_COUNTER_D1_1
# undef __PSTATIC_ASSERT_COUNTER_1
# define __PSTATIC_ASSERT_COUNTER_1 1
# elif !defined( __PSTATIC_ASSERT_COUNTER_D1_2 )
# define __PSTATIC_ASSERT_COUNTER_D1_2
# undef __PSTATIC_ASSERT_COUNTER_1
# define __PSTATIC_ASSERT_COUNTER_1 2
# elif !defined( __PSTATIC_ASSERT_COUNTER_D1_3 )
# define __PSTATIC_ASSERT_COUNTER_D1_3
# undef __PSTATIC_ASSERT_COUNTER_1
# define __PSTATIC_ASSERT_COUNTER_1 3
# elif !defined( __PSTATIC_ASSERT_COUNTER_D1_4 )
# define __PSTATIC_ASSERT_COUNTER_D1_4
# undef __PSTATIC_ASSERT_COUNTER_1
# define __PSTATIC_ASSERT_COUNTER_1 4
# elif !defined( __PSTATIC_ASSERT_COUNTER_D1_5 )
# define __PSTATIC_ASSERT_COUNTER_D1_5
# undef __PSTATIC_ASSERT_COUNTER_1
# define __PSTATIC_ASSERT_COUNTER_1 5
# elif !defined( __PSTATIC_ASSERT_COUNTER_D1_6 )
# define __PSTATIC_ASSERT_COUNTER_D1_6
# undef __PSTATIC_ASSERT_COUNTER_1
# define __PSTATIC_ASSERT_COUNTER_1 6
# elif !defined( __PSTATIC_ASSERT_COUNTER_D1_7 )
# define __PSTATIC_ASSERT_COUNTER_D1_7
# undef __PSTATIC_ASSERT_COUNTER_1
# define __PSTATIC_ASSERT_COUNTER_1 7
# elif !defined( __PSTATIC_ASSERT_COUNTER_D1_8 )
# define __PSTATIC_ASSERT_COUNTER_D1_8
# undef __PSTATIC_ASSERT_COUNTER_1
# define __PSTATIC_ASSERT_COUNTER_1 8
# elif !defined( __PSTATIC_ASSERT_COUNTER_D1_9 )
# define __PSTATIC_ASSERT_COUNTER_D1_9
# undef __PSTATIC_ASSERT_COUNTER_1
# define __PSTATIC_ASSERT_COUNTER_1 9
# else
# undef __PSTATIC_ASSERT_COUNTER_D1_1
# undef __PSTATIC_ASSERT_COUNTER_D1_2
# undef __PSTATIC_ASSERT_COUNTER_D1_3
# undef __PSTATIC_ASSERT_COUNTER_D1_4
# undef __PSTATIC_ASSERT_COUNTER_D1_5
# undef __PSTATIC_ASSERT_COUNTER_D1_6
# undef __PSTATIC_ASSERT_COUNTER_D1_7
# undef __PSTATIC_ASSERT_COUNTER_D1_8
# undef __PSTATIC_ASSERT_COUNTER_D1_9
# undef __PSTATIC_ASSERT_COUNTER_1
# define __PSTATIC_ASSERT_COUNTER_1 0
# if !defined( __PSTATIC_ASSERT_COUNTER_D2_0 )
# define __PSTATIC_ASSERT_COUNTER_D2_0
# undef __PSTATIC_ASSERT_COUNTER_2
# define __PSTATIC_ASSERT_COUNTER_2 0
# elif !defined( __PSTATIC_ASSERT_COUNTER_D2_1 )
# define __PSTATIC_ASSERT_COUNTER_D2_1
# undef __PSTATIC_ASSERT_COUNTER_2
# define __PSTATIC_ASSERT_COUNTER_2 1
# elif !defined( __PSTATIC_ASSERT_COUNTER_D2_2 )
# define __PSTATIC_ASSERT_COUNTER_D2_2
# undef __PSTATIC_ASSERT_COUNTER_2
# define __PSTATIC_ASSERT_COUNTER_2 2
# elif !defined( __PSTATIC_ASSERT_COUNTER_D2_3 )
# define __PSTATIC_ASSERT_COUNTER_D2_3
# undef __PSTATIC_ASSERT_COUNTER_2
# define __PSTATIC_ASSERT_COUNTER_2 3
# elif !defined( __PSTATIC_ASSERT_COUNTER_D2_4 )
# define __PSTATIC_ASSERT_COUNTER_D2_4
# undef __PSTATIC_ASSERT_COUNTER_2
# define __PSTATIC_ASSERT_COUNTER_2 4
# elif !defined( __PSTATIC_ASSERT_COUNTER_D2_5 )
# define __PSTATIC_ASSERT_COUNTER_D2_5
# undef __PSTATIC_ASSERT_COUNTER_2
# define __PSTATIC_ASSERT_COUNTER_2 5
# elif !defined( __PSTATIC_ASSERT_COUNTER_D2_6 )
# define __PSTATIC_ASSERT_COUNTER_D2_6
# undef __PSTATIC_ASSERT_COUNTER_2
# define __PSTATIC_ASSERT_COUNTER_2 6
# elif !defined( __PSTATIC_ASSERT_COUNTER_D2_7 )
# define __PSTATIC_ASSERT_COUNTER_D2_7
# undef __PSTATIC_ASSERT_COUNTER_2
# define __PSTATIC_ASSERT_COUNTER_2 7
# elif !defined( __PSTATIC_ASSERT_COUNTER_D2_8 )
# define __PSTATIC_ASSERT_COUNTER_D2_8
# undef __PSTATIC_ASSERT_COUNTER_2
# define __PSTATIC_ASSERT_COUNTER_2 8
# elif !defined( __PSTATIC_ASSERT_COUNTER_D2_9 )
# define __PSTATIC_ASSERT_COUNTER_D2_9
# undef __PSTATIC_ASSERT_COUNTER_2
# define __PSTATIC_ASSERT_COUNTER_2 9
# else
# undef __PSTATIC_ASSERT_COUNTER_D2_1
# undef __PSTATIC_ASSERT_COUNTER_D2_2
# undef __PSTATIC_ASSERT_COUNTER_D2_3
# undef __PSTATIC_ASSERT_COUNTER_D2_4
# undef __PSTATIC_ASSERT_COUNTER_D2_5
# undef __PSTATIC_ASSERT_COUNTER_D2_6
# undef __PSTATIC_ASSERT_COUNTER_D2_7
# undef __PSTATIC_ASSERT_COUNTER_D2_8
# undef __PSTATIC_ASSERT_COUNTER_D2_9
# undef __PSTATIC_ASSERT_COUNTER_2
# define __PSTATIC_ASSERT_COUNTER_2 0
# if !defined( __PSTATIC_ASSERT_COUNTER_D3_0 )
# define __PSTATIC_ASSERT_COUNTER_D3_0
# undef __PSTATIC_ASSERT_COUNTER_3
# define __PSTATIC_ASSERT_COUNTER_3 0
# elif !defined( __PSTATIC_ASSERT_COUNTER_D3_1 )
# define __PSTATIC_ASSERT_COUNTER_D3_1
# undef __PSTATIC_ASSERT_COUNTER_3
# define __PSTATIC_ASSERT_COUNTER_3 1
# elif !defined( __PSTATIC_ASSERT_COUNTER_D3_2 )
# define __PSTATIC_ASSERT_COUNTER_D3_2
# undef __PSTATIC_ASSERT_COUNTER_3
# define __PSTATIC_ASSERT_COUNTER_3 2
# elif !defined( __PSTATIC_ASSERT_COUNTER_D3_3 )
# define __PSTATIC_ASSERT_COUNTER_D3_3
# undef __PSTATIC_ASSERT_COUNTER_3
# define __PSTATIC_ASSERT_COUNTER_3 3
# elif !defined( __PSTATIC_ASSERT_COUNTER_D3_4 )
# define __PSTATIC_ASSERT_COUNTER_D3_4
# undef __PSTATIC_ASSERT_COUNTER_3
# define __PSTATIC_ASSERT_COUNTER_3 4
# elif !defined( __PSTATIC_ASSERT_COUNTER_D3_5 )
# define __PSTATIC_ASSERT_COUNTER_D3_5
# undef __PSTATIC_ASSERT_COUNTER_3
# define __PSTATIC_ASSERT_COUNTER_3 5
# elif !defined( __PSTATIC_ASSERT_COUNTER_D3_6 )
# define __PSTATIC_ASSERT_COUNTER_D3_6
# undef __PSTATIC_ASSERT_COUNTER_3
# define __PSTATIC_ASSERT_COUNTER_3 6
# elif !defined( __PSTATIC_ASSERT_COUNTER_D3_7 )
# define __PSTATIC_ASSERT_COUNTER_D3_7
# undef __PSTATIC_ASSERT_COUNTER_3
# define __PSTATIC_ASSERT_COUNTER_3 7
# elif !defined( __PSTATIC_ASSERT_COUNTER_D3_8 )
# define __PSTATIC_ASSERT_COUNTER_D3_8
# undef __PSTATIC_ASSERT_COUNTER_3
# define __PSTATIC_ASSERT_COUNTER_3 8
# elif !defined( __PSTATIC_ASSERT_COUNTER_D3_9 )
# define __PSTATIC_ASSERT_COUNTER_D3_9
# undef __PSTATIC_ASSERT_COUNTER_3
# define __PSTATIC_ASSERT_COUNTER_3 9
# else
# undef __PSTATIC_ASSERT_COUNTER_D3_1
# undef __PSTATIC_ASSERT_COUNTER_D3_2
# undef __PSTATIC_ASSERT_COUNTER_D3_3
# undef __PSTATIC_ASSERT_COUNTER_D3_4
# undef __PSTATIC_ASSERT_COUNTER_D3_5
# undef __PSTATIC_ASSERT_COUNTER_D3_6
# undef __PSTATIC_ASSERT_COUNTER_D3_7
# undef __PSTATIC_ASSERT_COUNTER_D3_8
# undef __PSTATIC_ASSERT_COUNTER_D3_9
# undef __PSTATIC_ASSERT_COUNTER_3
# define __PSTATIC_ASSERT_COUNTER_3 0
# endif
# endif
# endif
#endif
#define __PSTATIC_ASSERT_COUNTER_JOIN_DIGITS_MACRO_(digit0,digit1,digit2,digit3) digit0##digit1##digit2##digit3
#define __PSTATIC_ASSERT_COUNTER_JOIN_DIGITS_MACRO(digit0,digit1,digit2,digit3) __PSTATIC_ASSERT_COUNTER_JOIN_DIGITS_MACRO_(digit0,digit1,digit2,digit3)
#undef __PSTATIC_ASSERT_COUNTER
#define __PSTATIC_ASSERT_COUNTER __PSTATIC_ASSERT_COUNTER_JOIN_DIGITS_MACRO(__PSTATIC_ASSERT_COUNTER_3,__PSTATIC_ASSERT_COUNTER_2,__PSTATIC_ASSERT_COUNTER_1,__PSTATIC_ASSERT_COUNTER_0)

View File

@@ -0,0 +1,162 @@
#ifndef PSTDALIGN_H
#define PSTDALIGN_H
/*
* NOTE: aligned_alloc is defined via paligned_alloc.h
* and requires aligned_free to be fully portable although
* free also works on C11 and platforms with posix_memalign.
*
* NOTE: C++11 defines alignas as a keyword but then also defines
* __alignas_is_defined.
*
* C++14 does not define __alignas_is_defined, at least sometimes.
*
* GCC 8.3 reverts on this and makes C++11 behave the same as C++14
* preventing a simple __cplusplus version check from working.
*
* Clang C++ without std=c++11 or std=c++14 does define alignas
* but does so incorrectly wrt. C11 and C++11 semantics because
* `alignas(4) float x;` is not recognized.
* To fix such issues, either move to a std version, or
* include a working stdalign.h for the given compiler before
* this file.
*
* newlib defines _Alignas and _Alignof in sys/cdefs but rely on
* gcc version for <stdaligh.h> which can lead to conflicts if
* stdalign is not included.
*
* newlibs need for <stdalign.h> conflicts with broken C++ stdalign
* but this can be fixed be using std=C++11 or newer.
*
* MSVC does not support <stdalign.h> at least up to MSVC 2015,
* but does appear to support alignas and alignof keywords in
* recent standard C++.
*
* TCC only supports alignas with a numeric argument like
* `alignas(4)`, but not `alignas(float)`.
*
* If stdalign.h is supported but heuristics in this file are
* insufficient to detect this, try including <stdaligh.h> manually
* or define HAVE_STDALIGN_H.
*/
/* https://github.com/dvidelabs/flatcc/issues/130 */
#ifndef __alignas_is_defined
#if defined(__cplusplus)
#if __cplusplus == 201103 && !defined(__clang__) && ((__GNUC__ > 8) || (__GNUC__ == 8 && __GNUC_MINOR__ >= 3))
#define __alignas_is_defined 1
#define __alignof_is_defined 1
#include <stdalign.h>
#endif
#endif
#endif
/* Allow for alternative solution to be included first. */
#ifndef __alignas_is_defined
#ifdef __cplusplus
#if defined(PORTABLE_PATCH_CPLUSPLUS_STDALIGN)
#include <stdalign.h>
#undef alignas
#define alignas(t) __attribute__((__aligned__(t)))
#endif
#endif
#if !defined(PORTABLE_HAS_INCLUDE_STDALIGN)
#if defined(__has_include)
#if __has_include(<stdalign.h>)
#define PORTABLE_HAS_INCLUDE_STDALIGN 1
#else
#define PORTABLE_HAS_INCLUDE_STDALIGN 0
#endif
#endif
#endif
/* https://lists.gnu.org/archive/html/bug-gnulib/2015-08/msg00003.html */
#if defined(__cplusplus)
#if !defined(_MSC_VER)
#include <stdalign.h>
#endif
#if __cplusplus > 201103
#define __alignas_is_defined 1
#define __alignof_is_defined 1
#endif
#elif PORTABLE_HAS_INCLUDE_STDALIGN
#include <stdalign.h>
#elif !defined(__clang__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
#include <stdalign.h>
#elif defined(HAVE_STDALIGN_H)
#include <stdaligh.h>
#endif
#endif /* __alignas_is_defined */
#ifndef __alignas_is_defined
#ifdef __cplusplus
extern "C" {
#endif
#if (!defined(__clang__) && defined(__GNUC__) && \
((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)))
#undef PORTABLE_C11_STDALIGN_MISSING
#define PORTABLE_C11_STDALIGN_MISSING
#endif
#if defined(__IBMC__)
#undef PORTABLE_C11_STDALIGN_MISSING
#define PORTABLE_C11_STDALIGN_MISSING
#endif
#if ((defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) && \
!defined(PORTABLE_C11_STDALIGN_MISSING))
/* C11 or newer */
#include <stdalign.h>
#else
#if defined(__GNUC__) || defined(__IBM_ALIGNOF__) || defined(__clang__)
#ifndef _Alignas
#define _Alignas(t) __attribute__((__aligned__(t)))
#endif
#ifndef _Alignof
#define _Alignof(t) __alignof__(t)
#endif
#elif defined(_MSC_VER)
#define _Alignas(t) __declspec (align(t))
#define _Alignof(t) __alignof(t)
#elif defined(__TINYC__)
/* Supports `_Alignas(integer-expression)`, but not `_Alignas(type)`. */
#define _Alignas(t) __attribute__(aligned(t))
#define _Alignof(t) __alignof__(t)
#else
#error please update pstdalign.h with support for current compiler and library
#endif
#endif /* __STDC__ */
#ifndef alignas
#define alignas _Alignas
#endif
#ifndef alignof
#define alignof _Alignof
#endif
#define __alignas_is_defined 1
#define __alignof_is_defined 1
#ifdef __cplusplus
}
#endif
#endif /* __alignas__is_defined */
#include "paligned_alloc.h"
#endif /* PSTDALIGN_H */

View File

@@ -0,0 +1,37 @@
#ifndef PSTDBOOL_H
#define PSTDBOOL_H
#if !defined(__cplusplus) && !__bool_true_false_are_defined && !defined(bool) && !defined(__STDBOOL_H)
#ifdef HAVE_STDBOOL_H
#include <stdbool.h>
#elif (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
/* C99 or newer */
#define bool _Bool
#define true 1
#define false 0
#define __bool_true_false_are_defined 1
#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define bool bool
#define true true
#define false false
#define __bool_true_false_are_defined 1
#else
typedef unsigned char _Portable_bool;
#define bool _Portable_bool
#define true 1
#define false 0
#define __bool_true_false_are_defined 1
#endif
#endif
#endif /* PSTDBOOL_H */

View File

@@ -0,0 +1,898 @@
/* A portable stdint.h
****************************************************************************
* BSD License:
****************************************************************************
*
* Copyright (c) 2005-2016 Paul Hsieh
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************
*
* Version 0.1.15.2
*
* The ANSI C standard committee, for the C99 standard, specified the
* inclusion of a new standard include file called stdint.h. This is
* a very useful and long desired include file which contains several
* very precise definitions for integer scalar types that is
* critically important for making portable several classes of
* applications including cryptography, hashing, variable length
* integer libraries and so on. But for most developers its likely
* useful just for programming sanity.
*
* The problem is that some compiler vendors chose to ignore the C99
* standard and some older compilers have no opportunity to be updated.
* Because of this situation, simply including stdint.h in your code
* makes it unportable.
*
* So that's what this file is all about. Its an attempt to build a
* single universal include file that works on as many platforms as
* possible to deliver what stdint.h is supposed to. Even compilers
* that already come with stdint.h can use this file instead without
* any loss of functionality. A few things that should be noted about
* this file:
*
* 1) It is not guaranteed to be portable and/or present an identical
* interface on all platforms. The extreme variability of the
* ANSI C standard makes this an impossibility right from the
* very get go. Its really only meant to be useful for the vast
* majority of platforms that possess the capability of
* implementing usefully and precisely defined, standard sized
* integer scalars. Systems which are not intrinsically 2s
* complement may produce invalid constants.
*
* 2) There is an unavoidable use of non-reserved symbols.
*
* 3) Other standard include files are invoked.
*
* 4) This file may come in conflict with future platforms that do
* include stdint.h. The hope is that one or the other can be
* used with no real difference.
*
* 5) In the current verison, if your platform can't represent
* int32_t, int16_t and int8_t, it just dumps out with a compiler
* error.
*
* 6) 64 bit integers may or may not be defined. Test for their
* presence with the test: #ifdef INT64_MAX or #ifdef UINT64_MAX.
* Note that this is different from the C99 specification which
* requires the existence of 64 bit support in the compiler. If
* this is not defined for your platform, yet it is capable of
* dealing with 64 bits then it is because this file has not yet
* been extended to cover all of your system's capabilities.
*
* 7) (u)intptr_t may or may not be defined. Test for its presence
* with the test: #ifdef PTRDIFF_MAX. If this is not defined
* for your platform, then it is because this file has not yet
* been extended to cover all of your system's capabilities, not
* because its optional.
*
* 8) The following might not been defined even if your platform is
* capable of defining it:
*
* WCHAR_MIN
* WCHAR_MAX
* (u)int64_t
* PTRDIFF_MIN
* PTRDIFF_MAX
* (u)intptr_t
*
* 9) The following have not been defined:
*
* WINT_MIN
* WINT_MAX
*
* 10) The criteria for defining (u)int_least(*)_t isn't clear,
* except for systems which don't have a type that precisely
* defined 8, 16, or 32 bit types (which this include file does
* not support anyways). Default definitions have been given.
*
* 11) The criteria for defining (u)int_fast(*)_t isn't something I
* would trust to any particular compiler vendor or the ANSI C
* committee. It is well known that "compatible systems" are
* commonly created that have very different performance
* characteristics from the systems they are compatible with,
* especially those whose vendors make both the compiler and the
* system. Default definitions have been given, but its strongly
* recommended that users never use these definitions for any
* reason (they do *NOT* deliver any serious guarantee of
* improved performance -- not in this file, nor any vendor's
* stdint.h).
*
* 12) The following macros:
*
* PRINTF_INTMAX_MODIFIER
* PRINTF_INT64_MODIFIER
* PRINTF_INT32_MODIFIER
* PRINTF_INT16_MODIFIER
* PRINTF_LEAST64_MODIFIER
* PRINTF_LEAST32_MODIFIER
* PRINTF_LEAST16_MODIFIER
* PRINTF_INTPTR_MODIFIER
*
* are strings which have been defined as the modifiers required
* for the "d", "u" and "x" printf formats to correctly output
* (u)intmax_t, (u)int64_t, (u)int32_t, (u)int16_t, (u)least64_t,
* (u)least32_t, (u)least16_t and (u)intptr_t types respectively.
* PRINTF_INTPTR_MODIFIER is not defined for some systems which
* provide their own stdint.h. PRINTF_INT64_MODIFIER is not
* defined if INT64_MAX is not defined. These are an extension
* beyond what C99 specifies must be in stdint.h.
*
* In addition, the following macros are defined:
*
* PRINTF_INTMAX_HEX_WIDTH
* PRINTF_INT64_HEX_WIDTH
* PRINTF_INT32_HEX_WIDTH
* PRINTF_INT16_HEX_WIDTH
* PRINTF_INT8_HEX_WIDTH
* PRINTF_INTMAX_DEC_WIDTH
* PRINTF_INT64_DEC_WIDTH
* PRINTF_INT32_DEC_WIDTH
* PRINTF_INT16_DEC_WIDTH
* PRINTF_UINT8_DEC_WIDTH
* PRINTF_UINTMAX_DEC_WIDTH
* PRINTF_UINT64_DEC_WIDTH
* PRINTF_UINT32_DEC_WIDTH
* PRINTF_UINT16_DEC_WIDTH
* PRINTF_UINT8_DEC_WIDTH
*
* Which specifies the maximum number of characters required to
* print the number of that type in either hexadecimal or decimal.
* These are an extension beyond what C99 specifies must be in
* stdint.h.
*
* Compilers tested (all with 0 warnings at their highest respective
* settings): Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32
* bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio
* .net (VC7), Intel C++ 4.0, GNU gcc v3.3.3
*
* This file should be considered a work in progress. Suggestions for
* improvements, especially those which increase coverage are strongly
* encouraged.
*
* Acknowledgements
*
* The following people have made significant contributions to the
* development and testing of this file:
*
* Chris Howie
* John Steele Scott
* Dave Thorup
* John Dill
* Florian Wobbe
* Christopher Sean Morrison
* Mikkel Fahnoe Jorgensen
*
*/
#include <stddef.h>
#include <limits.h>
#include <signal.h>
/*
* For gcc with _STDINT_H, fill in the PRINTF_INT*_MODIFIER macros, and
* do nothing else. On the Mac OS X version of gcc this is _STDINT_H_.
*/
#if ((defined(_MSC_VER) && _MSC_VER >= 1600) || (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (__GNUC__ > 3 || defined(_STDINT_H) || defined(_STDINT_H_) || defined (__UINT_FAST64_TYPE__)) )) && !defined (_PSTDINT_H_INCLUDED)
#include <stdint.h>
#define _PSTDINT_H_INCLUDED
# if defined(__GNUC__) && (defined(__x86_64__) || defined(__ppc64__)) && !(defined(__APPLE__) && defined(__MACH__))
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "l"
# endif
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
# else
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# ifndef PRINTF_INT32_MODIFIER
# if (UINT_MAX == UINT32_MAX)
# define PRINTF_INT32_MODIFIER ""
# else
# define PRINTF_INT32_MODIFIER "l"
# endif
# endif
# endif
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER "h"
# endif
# ifndef PRINTF_INTMAX_MODIFIER
# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
# endif
# ifndef PRINTF_INT64_HEX_WIDTH
# define PRINTF_INT64_HEX_WIDTH "16"
# endif
# ifndef PRINTF_UINT64_HEX_WIDTH
# define PRINTF_UINT64_HEX_WIDTH "16"
# endif
# ifndef PRINTF_INT32_HEX_WIDTH
# define PRINTF_INT32_HEX_WIDTH "8"
# endif
# ifndef PRINTF_UINT32_HEX_WIDTH
# define PRINTF_UINT32_HEX_WIDTH "8"
# endif
# ifndef PRINTF_INT16_HEX_WIDTH
# define PRINTF_INT16_HEX_WIDTH "4"
# endif
# ifndef PRINTF_UINT16_HEX_WIDTH
# define PRINTF_UINT16_HEX_WIDTH "4"
# endif
# ifndef PRINTF_INT8_HEX_WIDTH
# define PRINTF_INT8_HEX_WIDTH "2"
# endif
# ifndef PRINTF_UINT8_HEX_WIDTH
# define PRINTF_UINT8_HEX_WIDTH "2"
# endif
# ifndef PRINTF_INT64_DEC_WIDTH
# define PRINTF_INT64_DEC_WIDTH "19"
# endif
# ifndef PRINTF_UINT64_DEC_WIDTH
# define PRINTF_UINT64_DEC_WIDTH "20"
# endif
# ifndef PRINTF_INT32_DEC_WIDTH
# define PRINTF_INT32_DEC_WIDTH "10"
# endif
# ifndef PRINTF_UINT32_DEC_WIDTH
# define PRINTF_UINT32_DEC_WIDTH "10"
# endif
# ifndef PRINTF_INT16_DEC_WIDTH
# define PRINTF_INT16_DEC_WIDTH "5"
# endif
# ifndef PRINTF_UINT16_DEC_WIDTH
# define PRINTF_UINT16_DEC_WIDTH "5"
# endif
# ifndef PRINTF_INT8_DEC_WIDTH
# define PRINTF_INT8_DEC_WIDTH "3"
# endif
# ifndef PRINTF_UINT8_DEC_WIDTH
# define PRINTF_UINT8_DEC_WIDTH "3"
# endif
# ifndef PRINTF_INTMAX_HEX_WIDTH
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_UINT64_HEX_WIDTH
# endif
# ifndef PRINTF_UINTMAX_HEX_WIDTH
# define PRINTF_UINTMAX_HEX_WIDTH PRINTF_UINT64_HEX_WIDTH
# endif
# ifndef PRINTF_INTMAX_DEC_WIDTH
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_UINT64_DEC_WIDTH
# endif
# ifndef PRINTF_UINTMAX_DEC_WIDTH
# define PRINTF_UINTMAX_DEC_WIDTH PRINTF_UINT64_DEC_WIDTH
# endif
/*
* Something really weird is going on with Open Watcom. Just pull some of
* these duplicated definitions from Open Watcom's stdint.h file for now.
*/
# if defined (__WATCOMC__) && __WATCOMC__ >= 1250
# if !defined (INT64_C)
# define INT64_C(x) (x + (INT64_MAX - INT64_MAX))
# endif
# if !defined (UINT64_C)
# define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
# endif
# if !defined (INT32_C)
# define INT32_C(x) (x + (INT32_MAX - INT32_MAX))
# endif
# if !defined (UINT32_C)
# define UINT32_C(x) (x + (UINT32_MAX - UINT32_MAX))
# endif
# if !defined (INT16_C)
# define INT16_C(x) (x)
# endif
# if !defined (UINT16_C)
# define UINT16_C(x) (x)
# endif
# if !defined (INT8_C)
# define INT8_C(x) (x)
# endif
# if !defined (UINT8_C)
# define UINT8_C(x) (x)
# endif
# if !defined (UINT64_MAX)
# define UINT64_MAX 18446744073709551615ULL
# endif
# if !defined (INT64_MAX)
# define INT64_MAX 9223372036854775807LL
# endif
# if !defined (UINT32_MAX)
# define UINT32_MAX 4294967295UL
# endif
# if !defined (INT32_MAX)
# define INT32_MAX 2147483647L
# endif
# if !defined (INTMAX_MAX)
# define INTMAX_MAX INT64_MAX
# endif
# if !defined (INTMAX_MIN)
# define INTMAX_MIN INT64_MIN
# endif
# endif
#endif
#ifndef _PSTDINT_H_INCLUDED
#define _PSTDINT_H_INCLUDED
#ifndef SIZE_MAX
# define SIZE_MAX (~(size_t)0)
#endif
/*
* Deduce the type assignments from limits.h under the assumption that
* integer sizes in bits are powers of 2, and follow the ANSI
* definitions.
*/
#ifndef UINT8_MAX
# define UINT8_MAX 0xff
#endif
#if !defined(uint8_t) && !defined(_UINT8_T)
# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S)
typedef unsigned char uint8_t;
# define UINT8_C(v) ((uint8_t) v)
# else
# error "Platform not supported"
# endif
#endif
#ifndef INT8_MAX
# define INT8_MAX 0x7f
#endif
#ifndef INT8_MIN
# define INT8_MIN INT8_C(0x80)
#endif
#if !defined(int8_t) && !defined(_INT8_T)
# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S)
typedef signed char int8_t;
# define INT8_C(v) ((int8_t) v)
# else
# error "Platform not supported"
# endif
#endif
#ifndef UINT16_MAX
# define UINT16_MAX 0xffff
#endif
#if !defined(uint16_t) && !defined(_UINT16_T)
#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S)
typedef unsigned int uint16_t;
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER ""
# endif
# define UINT16_C(v) ((uint16_t) (v))
#elif (USHRT_MAX == UINT16_MAX)
typedef unsigned short uint16_t;
# define UINT16_C(v) ((uint16_t) (v))
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER "h"
# endif
#else
#error "Platform not supported"
#endif
#endif
#ifndef INT16_MAX
# define INT16_MAX 0x7fff
#endif
#ifndef INT16_MIN
# define INT16_MIN INT16_C(0x8000)
#endif
#if !defined(int16_t) && !defined(_INT16_T)
#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S)
typedef signed int int16_t;
# define INT16_C(v) ((int16_t) (v))
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER ""
# endif
#elif (SHRT_MAX == INT16_MAX)
typedef signed short int16_t;
# define INT16_C(v) ((int16_t) (v))
# ifndef PRINTF_INT16_MODIFIER
# define PRINTF_INT16_MODIFIER "h"
# endif
#else
#error "Platform not supported"
#endif
#endif
#ifndef UINT32_MAX
# define UINT32_MAX (0xffffffffUL)
#endif
#if !defined(uint32_t) && !defined(_UINT32_T)
#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S)
typedef unsigned long uint32_t;
# define UINT32_C(v) v ## UL
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER "l"
# endif
#elif (UINT_MAX == UINT32_MAX)
typedef unsigned int uint32_t;
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
# define UINT32_C(v) v ## U
#elif (USHRT_MAX == UINT32_MAX)
typedef unsigned short uint32_t;
# define UINT32_C(v) ((unsigned short) (v))
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
#else
#error "Platform not supported"
#endif
#endif
#ifndef INT32_MAX
# define INT32_MAX (0x7fffffffL)
#endif
#ifndef INT32_MIN
# define INT32_MIN INT32_C(0x80000000)
#endif
#if !defined(int32_t) && !defined(_INT32_T)
#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S)
typedef signed long int32_t;
# define INT32_C(v) v ## L
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER "l"
# endif
#elif (INT_MAX == INT32_MAX)
typedef signed int int32_t;
# define INT32_C(v) v
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
#elif (SHRT_MAX == INT32_MAX)
typedef signed short int32_t;
# define INT32_C(v) ((short) (v))
# ifndef PRINTF_INT32_MODIFIER
# define PRINTF_INT32_MODIFIER ""
# endif
#else
#error "Platform not supported"
#endif
#endif
/*
* The macro stdint_int64_defined is temporarily used to record
* whether or not 64 integer support is available. It must be
* defined for any 64 integer extensions for new platforms that are
* added.
*/
#undef stdint_int64_defined
#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S)
# if (__STDC__ && __STDC_VERSION__ >= 199901L) || defined (S_SPLINT_S)
# define stdint_int64_defined
typedef long long int64_t;
typedef unsigned long long uint64_t;
# define UINT64_C(v) v ## ULL
# define INT64_C(v) v ## LL
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# endif
#endif
#if !defined (stdint_int64_defined)
# if defined(__GNUC__)
# define stdint_int64_defined
__extension__ typedef long long int64_t;
__extension__ typedef unsigned long long uint64_t;
# define UINT64_C(v) v ## ULL
# define INT64_C(v) v ## LL
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S)
# define stdint_int64_defined
typedef long long int64_t;
typedef unsigned long long uint64_t;
# define UINT64_C(v) v ## ULL
# define INT64_C(v) v ## LL
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "ll"
# endif
# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC)
# define stdint_int64_defined
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
# define UINT64_C(v) v ## UI64
# define INT64_C(v) v ## I64
# ifndef PRINTF_INT64_MODIFIER
# define PRINTF_INT64_MODIFIER "I64"
# endif
# endif
#endif
#if !defined (LONG_LONG_MAX) && defined (INT64_C)
# define LONG_LONG_MAX INT64_C (9223372036854775807)
#endif
#ifndef ULONG_LONG_MAX
# define ULONG_LONG_MAX UINT64_C (18446744073709551615)
#endif
#if !defined (INT64_MAX) && defined (INT64_C)
# define INT64_MAX INT64_C (9223372036854775807)
#endif
#if !defined (INT64_MIN) && defined (INT64_C)
# define INT64_MIN INT64_C (-9223372036854775808)
#endif
#if !defined (UINT64_MAX) && defined (INT64_C)
# define UINT64_MAX UINT64_C (18446744073709551615)
#endif
/*
* Width of hexadecimal for number field.
*/
#ifndef PRINTF_INT64_HEX_WIDTH
# define PRINTF_INT64_HEX_WIDTH "16"
#endif
#ifndef PRINTF_INT32_HEX_WIDTH
# define PRINTF_INT32_HEX_WIDTH "8"
#endif
#ifndef PRINTF_INT16_HEX_WIDTH
# define PRINTF_INT16_HEX_WIDTH "4"
#endif
#ifndef PRINTF_INT8_HEX_WIDTH
# define PRINTF_INT8_HEX_WIDTH "2"
#endif
#ifndef PRINTF_INT64_DEC_WIDTH
# define PRINTF_INT64_DEC_WIDTH "19"
#endif
#ifndef PRINTF_INT32_DEC_WIDTH
# define PRINTF_INT32_DEC_WIDTH "10"
#endif
#ifndef PRINTF_INT16_DEC_WIDTH
# define PRINTF_INT16_DEC_WIDTH "5"
#endif
#ifndef PRINTF_INT8_DEC_WIDTH
# define PRINTF_INT8_DEC_WIDTH "3"
#endif
#ifndef PRINTF_UINT64_DEC_WIDTH
# define PRINTF_UINT64_DEC_WIDTH "20"
#endif
#ifndef PRINTF_UINT32_DEC_WIDTH
# define PRINTF_UINT32_DEC_WIDTH "10"
#endif
#ifndef PRINTF_UINT16_DEC_WIDTH
# define PRINTF_UINT16_DEC_WIDTH "5"
#endif
#ifndef PRINTF_UINT8_DEC_WIDTH
# define PRINTF_UINT8_DEC_WIDTH "3"
#endif
/*
* Ok, lets not worry about 128 bit integers for now. Moore's law says
* we don't need to worry about that until about 2040 at which point
* we'll have bigger things to worry about.
*/
#ifdef stdint_int64_defined
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
# define INTMAX_MAX INT64_MAX
# define INTMAX_MIN INT64_MIN
# define UINTMAX_MAX UINT64_MAX
# define UINTMAX_C(v) UINT64_C(v)
# define INTMAX_C(v) INT64_C(v)
# ifndef PRINTF_INTMAX_MODIFIER
# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
# endif
# ifndef PRINTF_INTMAX_HEX_WIDTH
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
# endif
# ifndef PRINTF_INTMAX_DEC_WIDTH
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
# endif
#else
typedef int32_t intmax_t;
typedef uint32_t uintmax_t;
# define INTMAX_MAX INT32_MAX
# define UINTMAX_MAX UINT32_MAX
# define UINTMAX_C(v) UINT32_C(v)
# define INTMAX_C(v) INT32_C(v)
# ifndef PRINTF_INTMAX_MODIFIER
# define PRINTF_INTMAX_MODIFIER PRINTF_INT32_MODIFIER
# endif
# ifndef PRINTF_INTMAX_HEX_WIDTH
# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT32_HEX_WIDTH
# endif
# ifndef PRINTF_INTMAX_DEC_WIDTH
# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT32_DEC_WIDTH
# endif
#endif
/*
* Because this file currently only supports platforms which have
* precise powers of 2 as bit sizes for the default integers, the
* least definitions are all trivial. Its possible that a future
* version of this file could have different definitions.
*/
#ifndef stdint_least_defined
typedef int8_t int_least8_t;
typedef uint8_t uint_least8_t;
typedef int16_t int_least16_t;
typedef uint16_t uint_least16_t;
typedef int32_t int_least32_t;
typedef uint32_t uint_least32_t;
# define PRINTF_LEAST32_MODIFIER PRINTF_INT32_MODIFIER
# define PRINTF_LEAST16_MODIFIER PRINTF_INT16_MODIFIER
# define UINT_LEAST8_MAX UINT8_MAX
# define INT_LEAST8_MAX INT8_MAX
# define UINT_LEAST16_MAX UINT16_MAX
# define INT_LEAST16_MAX INT16_MAX
# define UINT_LEAST32_MAX UINT32_MAX
# define INT_LEAST32_MAX INT32_MAX
# define INT_LEAST8_MIN INT8_MIN
# define INT_LEAST16_MIN INT16_MIN
# define INT_LEAST32_MIN INT32_MIN
# ifdef stdint_int64_defined
typedef int64_t int_least64_t;
typedef uint64_t uint_least64_t;
# define PRINTF_LEAST64_MODIFIER PRINTF_INT64_MODIFIER
# define UINT_LEAST64_MAX UINT64_MAX
# define INT_LEAST64_MAX INT64_MAX
# define INT_LEAST64_MIN INT64_MIN
# endif
#endif
#undef stdint_least_defined
/*
* The ANSI C committee pretending to know or specify anything about
* performance is the epitome of misguided arrogance. The mandate of
* this file is to *ONLY* ever support that absolute minimum
* definition of the fast integer types, for compatibility purposes.
* No extensions, and no attempt to suggest what may or may not be a
* faster integer type will ever be made in this file. Developers are
* warned to stay away from these types when using this or any other
* stdint.h.
*/
typedef int_least8_t int_fast8_t;
typedef uint_least8_t uint_fast8_t;
typedef int_least16_t int_fast16_t;
typedef uint_least16_t uint_fast16_t;
typedef int_least32_t int_fast32_t;
typedef uint_least32_t uint_fast32_t;
#define UINT_FAST8_MAX UINT_LEAST8_MAX
#define INT_FAST8_MAX INT_LEAST8_MAX
#define UINT_FAST16_MAX UINT_LEAST16_MAX
#define INT_FAST16_MAX INT_LEAST16_MAX
#define UINT_FAST32_MAX UINT_LEAST32_MAX
#define INT_FAST32_MAX INT_LEAST32_MAX
#define INT_FAST8_MIN INT_LEAST8_MIN
#define INT_FAST16_MIN INT_LEAST16_MIN
#define INT_FAST32_MIN INT_LEAST32_MIN
#ifdef stdint_int64_defined
typedef int_least64_t int_fast64_t;
typedef uint_least64_t uint_fast64_t;
# define UINT_FAST64_MAX UINT_LEAST64_MAX
# define INT_FAST64_MAX INT_LEAST64_MAX
# define INT_FAST64_MIN INT_LEAST64_MIN
#endif
#undef stdint_int64_defined
/*
* Whatever piecemeal, per compiler thing we can do about the wchar_t
* type limits.
*/
#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__)
# include <wchar.h>
# ifndef WCHAR_MIN
# define WCHAR_MIN 0
# endif
# ifndef WCHAR_MAX
# define WCHAR_MAX ((wchar_t)-1)
# endif
#endif
/*
* Whatever piecemeal, per compiler/platform thing we can do about the
* (u)intptr_t types and limits.
*/
#if (defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED)) || defined (_UINTPTR_T)
# define STDINT_H_UINTPTR_T_DEFINED
#endif
#ifndef STDINT_H_UINTPTR_T_DEFINED
# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64) || defined (__ppc64__)
# define stdint_intptr_bits 64
# elif defined (__WATCOMC__) || defined (__TURBOC__)
# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
# define stdint_intptr_bits 16
# else
# define stdint_intptr_bits 32
# endif
# elif defined (__i386__) || defined (_WIN32) || defined (WIN32) || defined (__ppc64__)
# define stdint_intptr_bits 32
# elif defined (__INTEL_COMPILER)
/* TODO -- what did Intel do about x86-64? */
# else
/* #error "This platform might not be supported yet" */
# endif
# ifdef stdint_intptr_bits
# define stdint_intptr_glue3_i(a,b,c) a##b##c
# define stdint_intptr_glue3(a,b,c) stdint_intptr_glue3_i(a,b,c)
# ifndef PRINTF_INTPTR_MODIFIER
# define PRINTF_INTPTR_MODIFIER stdint_intptr_glue3(PRINTF_INT,stdint_intptr_bits,_MODIFIER)
# endif
# ifndef PTRDIFF_MAX
# define PTRDIFF_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
# endif
# ifndef PTRDIFF_MIN
# define PTRDIFF_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
# endif
# ifndef UINTPTR_MAX
# define UINTPTR_MAX stdint_intptr_glue3(UINT,stdint_intptr_bits,_MAX)
# endif
# ifndef INTPTR_MAX
# define INTPTR_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
# endif
# ifndef INTPTR_MIN
# define INTPTR_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
# endif
# ifndef INTPTR_C
# define INTPTR_C(x) stdint_intptr_glue3(INT,stdint_intptr_bits,_C)(x)
# endif
# ifndef UINTPTR_C
# define UINTPTR_C(x) stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x)
# endif
typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t;
typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t) intptr_t;
# else
/* TODO -- This following is likely wrong for some platforms, and does
nothing for the definition of uintptr_t. */
typedef ptrdiff_t intptr_t;
# endif
# define STDINT_H_UINTPTR_T_DEFINED
#endif
/*
* Assumes sig_atomic_t is signed and we have a 2s complement machine.
*/
#ifndef SIG_ATOMIC_MAX
# define SIG_ATOMIC_MAX ((((sig_atomic_t) 1) << (sizeof (sig_atomic_t)*CHAR_BIT-1)) - 1)
#endif
#endif
#if defined (__TEST_PSTDINT_FOR_CORRECTNESS)
/*
* Please compile with the maximum warning settings to make sure macros are
* not defined more than once.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define glue3_aux(x,y,z) x ## y ## z
#define glue3(x,y,z) glue3_aux(x,y,z)
#define DECLU(bits) glue3(uint,bits,_t) glue3(u,bits,) = glue3(UINT,bits,_C) (0);
#define DECLI(bits) glue3(int,bits,_t) glue3(i,bits,) = glue3(INT,bits,_C) (0);
#define DECL(us,bits) glue3(DECL,us,) (bits)
#define TESTUMAX(bits) glue3(u,bits,) = ~glue3(u,bits,); if (glue3(UINT,bits,_MAX) != glue3(u,bits,)) printf ("Something wrong with UINT%d_MAX\n", bits)
#define REPORTERROR(msg) { err_n++; if (err_first <= 0) err_first = __LINE__; printf msg; }
int main () {
int err_n = 0;
int err_first = 0;
DECL(I,8)
DECL(U,8)
DECL(I,16)
DECL(U,16)
DECL(I,32)
DECL(U,32)
#ifdef INT64_MAX
DECL(I,64)
DECL(U,64)
#endif
intmax_t imax = INTMAX_C(0);
uintmax_t umax = UINTMAX_C(0);
char str0[256], str1[256];
sprintf (str0, "%" PRINTF_INT32_MODIFIER "d", INT32_C(2147483647));
if (0 != strcmp (str0, "2147483647")) REPORTERROR (("Something wrong with PRINTF_INT32_MODIFIER : %s\n", str0));
if (atoi(PRINTF_INT32_DEC_WIDTH) != (int) strlen(str0)) REPORTERROR (("Something wrong with PRINTF_INT32_DEC_WIDTH : %s\n", PRINTF_INT32_DEC_WIDTH));
sprintf (str0, "%" PRINTF_INT32_MODIFIER "u", UINT32_C(4294967295));
if (0 != strcmp (str0, "4294967295")) REPORTERROR (("Something wrong with PRINTF_INT32_MODIFIER : %s\n", str0));
if (atoi(PRINTF_UINT32_DEC_WIDTH) != (int) strlen(str0)) REPORTERROR (("Something wrong with PRINTF_UINT32_DEC_WIDTH : %s\n", PRINTF_UINT32_DEC_WIDTH));
#ifdef INT64_MAX
sprintf (str1, "%" PRINTF_INT64_MODIFIER "d", INT64_C(9223372036854775807));
if (0 != strcmp (str1, "9223372036854775807")) REPORTERROR (("Something wrong with PRINTF_INT32_MODIFIER : %s\n", str1));
if (atoi(PRINTF_INT64_DEC_WIDTH) != (int) strlen(str1)) REPORTERROR (("Something wrong with PRINTF_INT64_DEC_WIDTH : %s, %d\n", PRINTF_INT64_DEC_WIDTH, (int) strlen(str1)));
sprintf (str1, "%" PRINTF_INT64_MODIFIER "u", UINT64_C(18446744073709550591));
if (0 != strcmp (str1, "18446744073709550591")) REPORTERROR (("Something wrong with PRINTF_INT32_MODIFIER : %s\n", str1));
if (atoi(PRINTF_UINT64_DEC_WIDTH) != (int) strlen(str1)) REPORTERROR (("Something wrong with PRINTF_UINT64_DEC_WIDTH : %s, %d\n", PRINTF_UINT64_DEC_WIDTH, (int) strlen(str1)));
#endif
sprintf (str0, "%d %x\n", 0, ~0);
sprintf (str1, "%d %x\n", i8, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with i8 : %s\n", str1));
sprintf (str1, "%u %x\n", u8, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with u8 : %s\n", str1));
sprintf (str1, "%d %x\n", i16, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with i16 : %s\n", str1));
sprintf (str1, "%u %x\n", u16, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with u16 : %s\n", str1));
sprintf (str1, "%" PRINTF_INT32_MODIFIER "d %x\n", i32, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with i32 : %s\n", str1));
sprintf (str1, "%" PRINTF_INT32_MODIFIER "u %x\n", u32, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with u32 : %s\n", str1));
#ifdef INT64_MAX
sprintf (str1, "%" PRINTF_INT64_MODIFIER "d %x\n", i64, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with i64 : %s\n", str1));
#endif
sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "d %x\n", imax, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with imax : %s\n", str1));
sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "u %x\n", umax, ~0);
if (0 != strcmp (str0, str1)) REPORTERROR (("Something wrong with umax : %s\n", str1));
TESTUMAX(8);
TESTUMAX(16);
TESTUMAX(32);
#ifdef INT64_MAX
TESTUMAX(64);
#endif
#define STR(v) #v
#define Q(v) printf ("sizeof " STR(v) " = %u\n", (unsigned) sizeof (v));
if (err_n) {
printf ("pstdint.h is not correct. Please use sizes below to correct it:\n");
}
Q(int)
Q(unsigned)
Q(long int)
Q(short int)
Q(int8_t)
Q(int16_t)
Q(int32_t)
#ifdef INT64_MAX
Q(int64_t)
#endif
return EXIT_SUCCESS;
}
#endif

View File

@@ -0,0 +1,190 @@
/*
* Copyright (c) 2016 Mikkel Fahnøe Jørgensen, dvide.com
*
* (MIT License)
* 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.
*/
#ifndef PUNLIGNED_H
#define PUNLIGNED_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef PORTABLE_UNALIGNED_ACCESS
#if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
#define PORTABLE_UNALIGNED_ACCESS 1
#else
#define PORTABLE_UNALIGNED_ACCESS 0
#endif
#endif
/* `unaligned_read_16` might not be defined if endianness was not determined. */
#if !defined(unaligned_read_le16toh)
#include "pendian.h"
#ifndef UINT8_MAX
#include <stdint.h>
#endif
#if PORTABLE_UNALIGNED_ACCESS
#define unaligned_read_16(p) (*(uint16_t*)(p))
#define unaligned_read_32(p) (*(uint32_t*)(p))
#define unaligned_read_64(p) (*(uint64_t*)(p))
#define unaligned_read_le16toh(p) le16toh(*(uint16_t*)(p))
#define unaligned_read_le32toh(p) le32toh(*(uint32_t*)(p))
#define unaligned_read_le64toh(p) le64toh(*(uint64_t*)(p))
#define unaligned_read_be16toh(p) be16toh(*(uint16_t*)(p))
#define unaligned_read_be32toh(p) be32toh(*(uint32_t*)(p))
#define unaligned_read_be64toh(p) be64toh(*(uint64_t*)(p))
#define unaligned_write_16(p, v) (*(uint16_t*)(p) = (uint16_t)(v))
#define unaligned_write_32(p, v) (*(uint32_t*)(p) = (uint32_t)(v))
#define unaligned_write_64(p, v) (*(uint64_t*)(p) = (uint64_t)(v))
#define unaligned_write_htole16(p, v) (*(uint16_t*)(p) = htole16(v))
#define unaligned_write_htole32(p, v) (*(uint32_t*)(p) = htole32(v))
#define unaligned_write_htole64(p, v) (*(uint64_t*)(p) = htole64(v))
#define unaligned_write_htobe16(p, v) (*(uint16_t*)(p) = htobe16(v))
#define unaligned_write_htobe32(p, v) (*(uint32_t*)(p) = htobe32(v))
#define unaligned_write_htobe64(p, v) (*(uint64_t*)(p) = htobe64(v))
#else
#define unaligned_read_le16toh(p) ( \
(((uint16_t)(((uint8_t *)(p))[0])) << 0) | \
(((uint16_t)(((uint8_t *)(p))[1])) << 8))
#define unaligned_read_le32toh(p) ( \
(((uint32_t)(((uint8_t *)(p))[0])) << 0) | \
(((uint32_t)(((uint8_t *)(p))[1])) << 8) | \
(((uint32_t)(((uint8_t *)(p))[2])) << 16) | \
(((uint32_t)(((uint8_t *)(p))[3])) << 24))
#define unaligned_read_le64toh(p) ( \
(((uint64_t)(((uint8_t *)(p))[0])) << 0) | \
(((uint64_t)(((uint8_t *)(p))[1])) << 8) | \
(((uint64_t)(((uint8_t *)(p))[2])) << 16) | \
(((uint64_t)(((uint8_t *)(p))[3])) << 24) | \
(((uint64_t)(((uint8_t *)(p))[4])) << 32) | \
(((uint64_t)(((uint8_t *)(p))[5])) << 40) | \
(((uint64_t)(((uint8_t *)(p))[6])) << 48) | \
(((uint64_t)(((uint8_t *)(p))[7])) << 56))
#define unaligned_read_be16toh(p) ( \
(((uint16_t)(((uint8_t *)(p))[0])) << 8) | \
(((uint16_t)(((uint8_t *)(p))[1])) << 0))
#define unaligned_read_be32toh(p) ( \
(((uint32_t)(((uint8_t *)(p))[0])) << 24) | \
(((uint32_t)(((uint8_t *)(p))[1])) << 16) | \
(((uint32_t)(((uint8_t *)(p))[2])) << 8) | \
(((uint32_t)(((uint8_t *)(p))[3])) << 0))
#define unaligned_read_be64toh(p) ( \
(((uint64_t)(((uint8_t *)(p))[0])) << 56) | \
(((uint64_t)(((uint8_t *)(p))[1])) << 48) | \
(((uint64_t)(((uint8_t *)(p))[2])) << 40) | \
(((uint64_t)(((uint8_t *)(p))[3])) << 32) | \
(((uint64_t)(((uint8_t *)(p))[4])) << 24) | \
(((uint64_t)(((uint8_t *)(p))[5])) << 16) | \
(((uint64_t)(((uint8_t *)(p))[6])) << 8) | \
(((uint64_t)(((uint8_t *)(p))[7])) << 0))
#define unaligned_write_htole16(p, v) do { \
((uint8_t *)(p))[0] = (uint8_t)(((uint16_t)(v)) >> 0); \
((uint8_t *)(p))[1] = (uint8_t)(((uint16_t)(v)) >> 8); \
} while (0)
#define unaligned_write_htole32(p, v) do { \
((uint8_t *)(p))[0] = (uint8_t)(((uint32_t)(v)) >> 0); \
((uint8_t *)(p))[1] = (uint8_t)(((uint32_t)(v)) >> 8); \
((uint8_t *)(p))[2] = (uint8_t)(((uint32_t)(v)) >> 16); \
((uint8_t *)(p))[3] = (uint8_t)(((uint32_t)(v)) >> 24); \
} while (0)
#define unaligned_write_htole64(p) do { \
((uint8_t *)(p))[0] = (uint8_t)(((uint64_t)(v)) >> 0); \
((uint8_t *)(p))[1] = (uint8_t)(((uint64_t)(v)) >> 8); \
((uint8_t *)(p))[2] = (uint8_t)(((uint64_t)(v)) >> 16); \
((uint8_t *)(p))[3] = (uint8_t)(((uint64_t)(v)) >> 24); \
((uint8_t *)(p))[4] = (uint8_t)(((uint64_t)(v)) >> 32); \
((uint8_t *)(p))[5] = (uint8_t)(((uint64_t)(v)) >> 40); \
((uint8_t *)(p))[6] = (uint8_t)(((uint64_t)(v)) >> 48); \
((uint8_t *)(p))[7] = (uint8_t)(((uint64_t)(v)) >> 56); \
} while (0)
#define unaligned_write_htobe16(p, v) do { \
((uint8_t *)(p))[0] = (uint8_t)(((uint16_t)(v)) >> 8); \
((uint8_t *)(p))[1] = (uint8_t)(((uint16_t)(v)) >> 0); \
} while (0)
#define unaligned_write_htobe32(p, v) do { \
((uint8_t *)(p))[0] = (uint8_t)(((uint32_t)(v)) >> 24); \
((uint8_t *)(p))[1] = (uint8_t)(((uint32_t)(v)) >> 16); \
((uint8_t *)(p))[2] = (uint8_t)(((uint32_t)(v)) >> 8); \
((uint8_t *)(p))[3] = (uint8_t)(((uint32_t)(v)) >> 0); \
} while (0)
#define unaligned_write_htobe64(p) do { \
((uint8_t *)(p))[0] = (uint8_t)(((uint64_t)(v)) >> 56); \
((uint8_t *)(p))[1] = (uint8_t)(((uint64_t)(v)) >> 48); \
((uint8_t *)(p))[2] = (uint8_t)(((uint64_t)(v)) >> 40); \
((uint8_t *)(p))[3] = (uint8_t)(((uint64_t)(v)) >> 32); \
((uint8_t *)(p))[4] = (uint8_t)(((uint64_t)(v)) >> 24); \
((uint8_t *)(p))[5] = (uint8_t)(((uint64_t)(v)) >> 16); \
((uint8_t *)(p))[6] = (uint8_t)(((uint64_t)(v)) >> 8); \
((uint8_t *)(p))[7] = (uint8_t)(((uint64_t)(v)) >> 0); \
} while (0)
#if __LITTLE_ENDIAN__
#define unaligned_read_16(p) unaligned_read_le16toh(p)
#define unaligned_read_32(p) unaligned_read_le32toh(p)
#define unaligned_read_64(p) unaligned_read_le64toh(p)
#define unaligned_write_16(p) unaligned_write_htole16(p)
#define unaligned_write_32(p) unaligned_write_htole32(p)
#define unaligned_write_64(p) unaligned_write_htole64(p)
#endif
#if __BIG_ENDIAN__
#define unaligned_read_16(p) unaligned_read_be16toh(p)
#define unaligned_read_32(p) unaligned_read_be32toh(p)
#define unaligned_read_64(p) unaligned_read_be64toh(p)
#define unaligned_write_16(p) unaligned_write_htobe16(p)
#define unaligned_write_32(p) unaligned_write_htobe32(p)
#define unaligned_write_64(p) unaligned_write_htobe64(p)
#endif
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif /* PUNALIGNED_H */

View File

@@ -0,0 +1,6 @@
#define PORTABLE_VERSION_TEXT "0.2.6-pre"
#define PORTABLE_VERSION_MAJOR 0
#define PORTABLE_VERSION_MINOR 2
#define PORTABLE_VERSION_PATCH 6
/* 1 or 0 */
#define PORTABLE_VERSION_RELEASED 0

View File

@@ -0,0 +1,52 @@
#ifndef PWARNINGS_H
#define PWARNINGS_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* See also pdiagnostics.h headers for per file control of common
* warnings.
*
* This file is intended for global disabling of warnings that shouldn't
* be present in C11 or perhaps C99, or a generally just noise where
* recent clang / gcc compile cleanly with high warning levels.
*/
#if defined(_MSC_VER)
/* Needed when flagging code in or out and more. */
#pragma warning(disable: 4127) /* conditional expression is constant */
/* happens also in MS's own headers. */
#pragma warning(disable: 4668) /* preprocessor name not defined */
/* MSVC does not respect double parenthesis for intent */
#pragma warning(disable: 4706) /* assignment within conditional expression */
/* `inline` only advisory anyway. */
#pragma warning(disable: 4710) /* function not inlined */
/* Well, we don't intend to add the padding manually. */
#pragma warning(disable: 4820) /* x bytes padding added in struct */
/*
* Don't warn that fopen etc. are unsafe
*
* Define a compiler flag like `-D_CRT_SECURE_NO_WARNINGS` in the build.
* For some reason it doesn't work when defined here.
*
* #define _CRT_SECURE_NO_WARNINGS
*/
/*
* Anonymous union in struct is valid in C11 and has been supported in
* GCC and Clang for a while, but it is not C99. MSVC also handles it,
* but warns. Truly portable code should perhaps not use this feature,
* but this is not the place to complain about it.
*/
#pragma warning(disable: 4201) /* nonstandard extension used: nameless struct/union */
#endif /* _MSV_VER */
#ifdef __cplusplus
}
#endif
#endif /* PWARNINGS_H */