Yzena
/
Yc
2
1
Fork 0
C Utils for Yzena https://docs.yzena.com/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1763 lines
59 KiB

/**
* ***** BEGIN LICENSE BLOCK *****
*
* Copyright 2017-2022 Yzena Tech
*
Add the actual license(s) to the repo These are the actual licenses to use the software: Yzena Viral User License, the Affero General Public License, and the Server Side Public License. Users and distributors must comply with all three. There may be those that think that they can use previous commits to this repo under just the Yzena Network License, which is what the headers said in those commits. However, this repo was not public at the time. It was public before, but it was under the Apache 2.0, and that was many commits ago, where there was really nothing interesting beyond what had been public. So since the code was not public, I could change the license freely, and I did, and I retroactively apply the licenses I am using now to previous versions. I can do that because I either wrote the code from scratch, or it was licensed such that I could relicense it. So if you think you might be sneaky, don't get any ideas; I *will* sue you if you violate any one of these three licenses. That said, I put this software under these licenses to make them radioactive to companies for long enough to establish myself and this software. I plan on relaxing these restrictions over time, in an intentional manner to follow the licensing arc described in <https://writing.kemitchell.com/2020/03/07/No-Posse.html>. After my Yzena licenses are improved and approved by a lawyer, I'll probably remove the SSPL first, then the AGPL, then I'll progressively move to freer Yzena licenses, though I may stay on the User series of licenses. So if you want to use this software, but it's too radioactive; give it time. Oh, and email me letting me know you're interested, but why you can't use it. Signed-off-by: Gavin Howard <gavin@yzena.com>
3 months ago
* Licensed under the Yzena Viral User License, Version 0.1 (the "Yzena Viral
* User License" or "YVUL"), the GNU Affero General Public License (the "GNU
* AGPL"), Version 3.0, and the Server Side Public License (the "SSPL"),
* Version 1. You may not use this file except in compliance with all of those
* licenses.
*
Add the actual license(s) to the repo These are the actual licenses to use the software: Yzena Viral User License, the Affero General Public License, and the Server Side Public License. Users and distributors must comply with all three. There may be those that think that they can use previous commits to this repo under just the Yzena Network License, which is what the headers said in those commits. However, this repo was not public at the time. It was public before, but it was under the Apache 2.0, and that was many commits ago, where there was really nothing interesting beyond what had been public. So since the code was not public, I could change the license freely, and I did, and I retroactively apply the licenses I am using now to previous versions. I can do that because I either wrote the code from scratch, or it was licensed such that I could relicense it. So if you think you might be sneaky, don't get any ideas; I *will* sue you if you violate any one of these three licenses. That said, I put this software under these licenses to make them radioactive to companies for long enough to establish myself and this software. I plan on relaxing these restrictions over time, in an intentional manner to follow the licensing arc described in <https://writing.kemitchell.com/2020/03/07/No-Posse.html>. After my Yzena licenses are improved and approved by a lawyer, I'll probably remove the SSPL first, then the AGPL, then I'll progressively move to freer Yzena licenses, though I may stay on the User series of licenses. So if you want to use this software, but it's too radioactive; give it time. Oh, and email me letting me know you're interested, but why you can't use it. Signed-off-by: Gavin Howard <gavin@yzena.com>
3 months ago
* You may obtain a copy of the Yzena Viral User License at
*
Add the actual license(s) to the repo These are the actual licenses to use the software: Yzena Viral User License, the Affero General Public License, and the Server Side Public License. Users and distributors must comply with all three. There may be those that think that they can use previous commits to this repo under just the Yzena Network License, which is what the headers said in those commits. However, this repo was not public at the time. It was public before, but it was under the Apache 2.0, and that was many commits ago, where there was really nothing interesting beyond what had been public. So since the code was not public, I could change the license freely, and I did, and I retroactively apply the licenses I am using now to previous versions. I can do that because I either wrote the code from scratch, or it was licensed such that I could relicense it. So if you think you might be sneaky, don't get any ideas; I *will* sue you if you violate any one of these three licenses. That said, I put this software under these licenses to make them radioactive to companies for long enough to establish myself and this software. I plan on relaxing these restrictions over time, in an intentional manner to follow the licensing arc described in <https://writing.kemitchell.com/2020/03/07/No-Posse.html>. After my Yzena licenses are improved and approved by a lawyer, I'll probably remove the SSPL first, then the AGPL, then I'll progressively move to freer Yzena licenses, though I may stay on the User series of licenses. So if you want to use this software, but it's too radioactive; give it time. Oh, and email me letting me know you're interested, but why you can't use it. Signed-off-by: Gavin Howard <gavin@yzena.com>
3 months ago
* https://yzena.com/yzena-viral-user-license/
*
* Unless required by applicable law or agreed to in writing, software
Add the actual license(s) to the repo These are the actual licenses to use the software: Yzena Viral User License, the Affero General Public License, and the Server Side Public License. Users and distributors must comply with all three. There may be those that think that they can use previous commits to this repo under just the Yzena Network License, which is what the headers said in those commits. However, this repo was not public at the time. It was public before, but it was under the Apache 2.0, and that was many commits ago, where there was really nothing interesting beyond what had been public. So since the code was not public, I could change the license freely, and I did, and I retroactively apply the licenses I am using now to previous versions. I can do that because I either wrote the code from scratch, or it was licensed such that I could relicense it. So if you think you might be sneaky, don't get any ideas; I *will* sue you if you violate any one of these three licenses. That said, I put this software under these licenses to make them radioactive to companies for long enough to establish myself and this software. I plan on relaxing these restrictions over time, in an intentional manner to follow the licensing arc described in <https://writing.kemitchell.com/2020/03/07/No-Posse.html>. After my Yzena licenses are improved and approved by a lawyer, I'll probably remove the SSPL first, then the AGPL, then I'll progressively move to freer Yzena licenses, though I may stay on the User series of licenses. So if you want to use this software, but it's too radioactive; give it time. Oh, and email me letting me know you're interested, but why you can't use it. Signed-off-by: Gavin Howard <gavin@yzena.com>
3 months ago
* distributed under the Yzena Viral User License is distributed under the
* following disclaimer:
*
* As far as the law allows, this software comes as is, without any
* warranty or condition, and no contributor will be liable to anyone for
* any damages related to this software or this license, under any kind of
* legal claim.
*
Add the actual license(s) to the repo These are the actual licenses to use the software: Yzena Viral User License, the Affero General Public License, and the Server Side Public License. Users and distributors must comply with all three. There may be those that think that they can use previous commits to this repo under just the Yzena Network License, which is what the headers said in those commits. However, this repo was not public at the time. It was public before, but it was under the Apache 2.0, and that was many commits ago, where there was really nothing interesting beyond what had been public. So since the code was not public, I could change the license freely, and I did, and I retroactively apply the licenses I am using now to previous versions. I can do that because I either wrote the code from scratch, or it was licensed such that I could relicense it. So if you think you might be sneaky, don't get any ideas; I *will* sue you if you violate any one of these three licenses. That said, I put this software under these licenses to make them radioactive to companies for long enough to establish myself and this software. I plan on relaxing these restrictions over time, in an intentional manner to follow the licensing arc described in <https://writing.kemitchell.com/2020/03/07/No-Posse.html>. After my Yzena licenses are improved and approved by a lawyer, I'll probably remove the SSPL first, then the AGPL, then I'll progressively move to freer Yzena licenses, though I may stay on the User series of licenses. So if you want to use this software, but it's too radioactive; give it time. Oh, and email me letting me know you're interested, but why you can't use it. Signed-off-by: Gavin Howard <gavin@yzena.com>
3 months ago
* You may obtain a copy of the GNU Affero General Public License at
*
* https://www.gnu.org/licenses/agpl-3.0.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the GNU Affero General Public License is distributed under
* the following disclaimer:
*
* This software is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
* General Public License for more details.
*
* You may obtain a copy of the Server Side Public License at
*
* https://www.mongodb.com/licensing/server-side-public-license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Server Side Public License is distributed under the
* following disclaimer:
*
* This software is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Server
* Side Public License for more details.
*
* ****** END LICENSE BLOCK ******
*
* *****************************************************************
*
* ******* BEGIN FILE DESCRIPTION *******
*
* Public header file for safe arithmetic.
*
* ******** END FILE DESCRIPTION ********
*/
#ifndef YC_ARITH_H
#define YC_ARITH_H
/* For C++ compatibility */
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @file yc/arith.h
*/
/**
* @defgroup arith arith
* Public function definitions and types for Yc's safe arithmetic.
* @{
*/
//! @cond Doxygen suppress.
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
//! @endcond
#include <yc/assert.h>
#include <yc/yc.h>
//! @cond Doxygen suppress.
// Workarounds for AIX's POSIX incompatibility
#ifndef SIZE_MAX
#define SIZE_MAX __SIZE_MAX__
#endif // SIZE_MAX
#ifndef UINTMAX_C
#define UINTMAX_C __UINTMAX_C
#endif // UINTMAX_C
#ifndef UINT32_C
#define UINT32_C __UINT32_C
#endif // UINT32_C
#ifndef UINT_FAST32_MAX
#define UINT_FAST32_MAX __UINT_FAST32_MAX__
#endif // UINT_FAST32_MAX
#ifndef UINT16_MAX
#define UINT16_MAX __UINT16_MAX__
#endif // UINT16_MAX
#ifndef SIG_ATOMIC_MAX
#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
#endif // SIG_ATOMIC_MAX
#if YC_64BIT
#ifdef y_NO_BUILTIN_128
#define YC_INT128_STRUCT
#else // y_NO_BUILTIN_128
#ifndef __SIZEOF_INT128__
#define YC_INT128_STRUCT
#else // __SIZEOF_INT128__
#if __SIZEOF_INT128__ == 0
#define YC_INT128_STRUCT
#endif // __SIZEOF_INT128__ == 0
#endif // __SIZEOF_INT128__
#endif // y_NO_BUILTIN_128
#ifdef YC_INT128_STRUCT
#define YC_BOTTOM32 (((uint_fast64_t) 0xffffffffULL))
#define YC_TRUNC32(n) ((n) & (YC_BOTTOM32))
#define YC_CHOP32(n) ((n) >> 32)
/**
* @typedef uint128_t
* A 128-bit integer.
*/
typedef struct uint128_t
{
uint64_t l;
uint64_t h;
} uint128_t;
typedef uint128_t int128_t;
typedef int128_t y_s128;
typedef uint128_t y_u128;
extern const y_s128 y_s128_max;
extern const y_s128 y_s128_min;
extern const y_u128 y_u128_max;
y_inline static inline uint128_t
yc_a128(const uint64_t a, const uint64_t b);
y_inline static inline uint128_t
yc_s128(const uint64_t a, const uint64_t b);
y_inline static inline uint128_t
yc_m128(const uint64_t a, const uint64_t b);
y_inline static inline uint128_t
yc_n128(const uint128_t a);
y_inline static inline uint128_t
yc_sn128(const uint128_t a);
y_inline static inline bool
yc_eq128(const uint128_t a, const uint128_t b);
y_inline static inline bool
yc_ne128(const uint128_t a, const uint128_t b);
y_inline static inline bool
yc_ult128(const uint128_t a, const uint128_t b);
y_inline static inline bool
yc_ule128(const uint128_t a, const uint128_t b);
y_inline static inline bool
yc_ugt128(const uint128_t a, const uint128_t b);
y_inline static inline bool
yc_uge128(const uint128_t a, const uint128_t b);
y_inline static inline bool
yc_slt128(const uint128_t a, const uint128_t b);
y_inline static inline bool
yc_sle128(const uint128_t a, const uint128_t b);
y_inline static inline bool
yc_sgt128(const uint128_t a, const uint128_t b);
y_inline static inline bool
yc_sge128(const uint128_t a, const uint128_t b);
1 year ago
#else // YC_INT128_STRUCT
/**
* @typedef uint128_t
* A 128-bit integer.
*/
typedef __uint128_t uint128_t;
#endif // YC_INT128_STRUCT
#endif // YC_64BIT
//! @endcond
/**
* @typedef llong
* A single word typedef for long long.
*/
typedef long long llong;
// clang-format off
//! @cond Doxygen suppress.
#define y_MAX_8 (255ULL)
#define y_MAX_16 (65535ULL)
#define y_MAX_32 (4294967295ULL)
#define y_MAX_64 (18446744073709551615ULL)
#ifdef YC_INT128_STRUCT
#define y_MAX_128 ({ .l = y_MAX_64, .h = y_MAX_64 })
#else // YC_INT128_STRUCT
#define y_MAX_128 (340282366920938463463374607431768211455ULL)
#endif // YC_INT128_STRUCT
#define yc_int1(a, t) \
typedef t a; \
typedef struct { a n; a o; } a ## o; \
typedef struct { a q; a r; } a ## dres; \
typedef struct { a q; a r; bool o; } a ## dreso; \
extern const size_t a ## _bits; \
extern const a a ## _min; \
extern const a a ## _max;
#define yc_sn(t) \
y_inline static inline \
t \
t ## sn(const t a) \
{ \
return a >= t ## _min; \
}
#define yc_eq(t) \
y_inline static inline \
bool \
t ## eq(const t a, const t b) \
{ \
return a == b; \
}
#define yc_ne(t) \
y_inline static inline \
bool \
t ## ne(const t a, const t b) \
{ \
return a != b; \
}
#define yc_slt(t) \
y_inline static inline \
bool \
t ## slt(const t a, const t b) \
{ \
if (a >= t ## _min) \
{ \
return b >= t ## _min ? a < b : true; \
} \
else \
{ \
return b >= t ## _min ? false : a < b; \
} \
}
#define yc_ult(t) \
y_inline static inline \
bool \
t ## ult(const t a, const t b) \
{ \
return a < b; \
}
#define yc_sle(t) \
y_inline static inline \
bool \
t ## sle(const t a, const t b) \
{ \
if (a >= t ## _min) \
{ \
return b >= t ## _min ? a <= b : true; \
} \
else \
{ \
return b >= t ## _min ? false : a <= b; \
} \
}
#define yc_ule(t) \
y_inline static inline \
bool \
t ## ule(const t a, const t b) \
{ \
return a <= b; \
}
#define yc_sgt(t) \
y_inline static inline \
bool \
t ## sgt(const t a, const t b) \
{ \
if (a >= t ## _min) \
{ \
return b >= t ## _min ? a > b : false; \
} \
else \
{ \
return b >= t ## _min ? true : a > b; \
} \
}
#define yc_ugt(t) \
y_inline static inline \
bool \
t ## ugt(const t a, const t b) \
{ \
return a > b; \
}
#define yc_sge(t) \
y_inline static inline \
bool \
t ## sge(const t a, const t b) \
{ \
if (a >= t ## _min) \
{ \
return b >= t ## _min ? a >= b : false; \
} \
else \
{ \
return b >= t ## _min ? true : a >= b; \
} \
}
#define yc_uge(t) \
y_inline static inline \
bool \
t ## uge(const t a, const t b) \
{ \
return a >= b; \
}
#define yc_neg(t) \
y_inline static inline \
t \
t ## neg(const t a) \
{ \
return (~(a)); \
}
#define yc_sneg(t) \
y_inline static inline \
t \
t ## sneg(const t a) \
{ \
return (~(a)) + 1; \
}
#define yc_shl(t, z) \
y_inline static inline \
t \
t ## shl(const t a, const t b) \
{ \
t i; \
if (b >= z) i = 0; \
else i = (t) (((t) a) << ((t) b)); \
return i; \
}
#define yc_sshr(t, z) \
y_inline static inline \
t \
t ## shr(const t a, const t b) \
{ \
t i; \
bool sign = ((a & t ## _min) != 0); \
if (b >= z) i = (t) (sign ? y_u ## z ## _max : 0); \
else \
{ \
i = (t) ((t) a) >> ((t) b); \
if (sign) \
{ \
t ext = (t) (((((t) 1) << b) - 1) << ((t) (((t) z) - ((t) b)))); \
i |= ext; \
} \
} \
return i; \
}
#define yc_ushr(t, z) \
y_inline static inline \
t \
t ## shr(const t a, const t b) \
{ \
t i; \
if (b >= z) i = 0; \
else i = a >> b; \
return i; \
}
#define yc_and(t) \
y_inline static inline \
t \
t ## and(const t a, const t b) \
{ \
return a & b; \
}
#define yc_or(t) \
y_inline static inline \
t \
t ## or(const t a, const t b) \
{ \
return a | b; \
}
#define yc_xor(t) \
y_inline static inline \
t \
t ## xor(const t a, const t b) \
{ \
return a ^ b; \
}
#define yc_trunc(t, z2) \
y_inline static inline \
t \
t ## trunc(const t a) \
{ \
return (t) (uint ## z2 ## _t) a; \
}
#define yc_sext(t, z, z2) \
y_inline static inline \
uint ## z2 ## _t \
t ## sext(const t a) \
{ \
const uint ## z2 ## _t bit = \
(uint ## z2 ## _t) (t ## _min & a ? t ## _min : 0); \
const uint ## z2 ## _t sext = (uint ## z2 ## _t) (((bit << 1) - 1) << z); \
return sext | ((uint ## z2 ## _t) a); \
}
#ifdef YC_INT128_STRUCT
#define yc_sext64(t, z, z2) \
y_inline static inline \
uint ## z2 ## _t \
t ## sext(const t a) \
{ \
const t bit = ((t ## _min & a) != 0); \
const uint ## z2 ## _t sext = \
{ .l = a, .h = ((t) 0) - bit }; \
return sext; \
}
#endif // YC_INT128_STRUCT
#define yc_uext(t, z2) \
y_inline static inline \
uint ## z2 ## _t \
t ## uext(const t a) \
{ \
return (uint ## z2 ## _t) a; \
}
#ifdef YC_INT128_STRUCT
#define yc_uext64(t, z2) \
y_inline static inline \
uint ## z2 ## _t \
t ## uext(const t a) \
{ \
uint ## z2 ## _t r = { .l = a, .h = 0 }; \
return r; \
}
#endif // YC_INT128_STRUCT
#define yc_addw(t) \
y_inline static inline \
t \
t ## aw(const t a, const t b) \
{ \
return a + b; \
}
#define yc_saddo(t) \
y_inline static inline \
t ## o \
t ## ao(const t a, const t b) \
{ \
t ## o i; \
i.n = t ## aw(a, b); \
i.o = ((a & t ## _min) == (b & t ## _min)) & \
((i.n & t ## _min) != (a & t ## _min)); \
return i; \
}
#define yc_uaddo(t) \
y_inline static inline \
t ## o \
t ## ao(const t a, const t b) \
{ \
t ## o i; \
i.n = t ## aw(a, b); \
i.o = (a >= i.n); \
return i; \
}
#define yc_sadds(t) \
y_inline static inline \
t \
t ## as(const t a, const t b) \
{ \
t ## o i; \
i = t ## ao(a, b); \
if (i.o) i.n = t ## _min - ((a & t ## _min) == 0); \
return i.n; \
}
#define yc_uadds(t) \
y_inline static inline \
t \
t ## as(const t a, const t b) \
{ \
t ## o i; \
i = t ## ao(a, b); \
if (i.o) i.n = t ## _max; \
return i.n; \
}
#define yc_sadd(t) \
y_inline static inline \
t \
t ## a(const t a, const t b) \
{ \
t ## o i; \
i = t ## ao(a, b); \
if (y_unlikely(i.o)) \
{ \
y_panicva("signed overflow on add with params: 0x%llx, 0x%llx", \
(unsigned long long) a, (unsigned long long) b); \
} \
return i.n; \
}
#define yc_uadd(t) \
y_inline static inline \
t \
t ## a(const t a, const t b) \
{ \
t ## o i; \
i = t ## ao(a, b); \
if (y_unlikely(i.o)) \
{ \
y_panicva("unsigned overflow on add with params: 0x%llx, 0x%llx", \
(unsigned long long) a, (unsigned long long) b); \
} \
return i.n; \
}
#define yc_subw(t) \
y_inline static inline \
t \
t ## sw(const t a, const t b) \
{ \
return a - b; \
}
#define yc_ssubo(t) \
y_inline static inline \
t ## o \
t ## so(const t a, const t b) \
{ \
t ## o i; \
i.n = t ## sw(a, b); \
i.o = ((a & t ## _min) != (b & t ## _min)) & \
((i.n & t ## _min) != (a & t ## _min)); \
return i; \
}
#define yc_usubo(t) \
y_inline static inline \
t ## o \
t ## so(const t a, const t b) \
{ \
t ## o i; \
i.n = t ## sw(a, b); \
i.o = (a <= i.n); \
return i; \
}
#define yc_ssubs(t) \
y_inline static inline \
t \
t ## ss(const t a, const t b) \
{ \
t ## o i; \
i = t ## so(a, b); \
if (i.o) i.n = t ## _min - ((a & t ## _min) == 0); \
return i.n; \
}
#define yc_usubs(t) \
y_inline static inline \
t \
t ## ss(const t a, const t b) \
{ \
t ## o i; \
i = t ## so(a, b); \
if (i.o) i.n = 0; \
return i.n; \
}
#define yc_ssub(t) \
y_inline static inline \
t \
t ## s(const t a, const t b) \
{ \
t ## o i; \
i = t ## so(a, b); \
if (y_unlikely(i.o)) \
{ \
y_panicva("signed overflow on subtract with params: 0x%llx, 0x%llx", \
(unsigned long long) a, (unsigned long long) b); \
} \
return i.n; \
}
#define yc_usub(t) \
y_inline static inline \
t \
t ## s(const t a, const t b) \
{ \
t ## o i; \
i = t ## so(a, b); \
if (y_unlikely(i.o)) \
{ \
y_panicva("unsigned overflow on subtract with params: 0x%llx, 0x%llx", \
(unsigned long long) a, (unsigned long long) b); \
} \
return i.n; \
}
#define yc_mulw(t) \
y_inline static inline \
t \
t ## mw(const t a, const t b) \
{ \
t i; \
i = a * b; \
return i; \
}
#define yc_smulo(t, z, z2) \
y_inline static inline \
t ## o \
t ## mo(const t a, const t b) \
{ \
const uint ## z2 ## _t r = ((uint ## z2 ## _t) a) * b; \
const uint ## z2 ## _t r2 = ((uint ## z2 ## _t) y_u ## z ## _max); \
t ## o i; \
i.n = (t) (r & r2); \
i.o = (r >= r2) || ((a & t ## _min) == (b & t ## _min)) & \
((i.n & t ## _min) != (a & t ## _min)); \
return i; \
}
#ifdef YC_INT128_STRUCT
#define yc_smulo64(t, z2) \
y_inline static inline \
t ## o \
t ## mo(const t a, const t b) \
{ \
const uint ## z2 ## _t r = yc_m128(a, b); \
t ## o i; \
i.n = (t) (r.l); \
i.o = (r.h != 0) || ((a & t ## _min) == (b & t ## _min)) & \
((i.n & t ## _min) != (a & t ## _min)); \
return i; \
}
#endif // YC_INT128_STRUCT
#define yc_umulo(t, z, z2) \
y_inline static inline \
t ## o \
t ## mo(const t a, const t b) \
{ \
const uint ## z2 ## _t r = ((uint ## z2 ## _t) a) * b; \
const uint ## z2 ## _t r2 = ((uint ## z2 ## _t) t ## _max); \
t ## o i; \
i.n = (uint ## z #