godot/thirdparty/misc/r128.h

/*
r128.h: 128-bit (64.64) signed fixed-point arithmetic. Version 1.6.0

COMPILATION
-----------
Drop this header file somewhere in your project and include it wherever it is
needed. There is no separate .c file for this library. To get the code, in ONE
file in your project, put:

#define R128_IMPLEMENTATION

before you include this file. You may also provide a definition for R128_ASSERT
to force the library to use a custom assert macro.

COMPILER/LIBRARY SUPPORT
------------------------
This library requires a C89 compiler with support for 64-bit integers. If your
compiler does not support the long long data type, the R128_U64, etc. macros
must be set appropriately. On x86 and x64 targets, Intel intrinsics are used
for speed. If your compiler does not support these intrinsics, you can add
#define R128_STDC_ONLY
in your implementation file before including r128.h.

The only C runtime library functionality used by this library is <assert.h>.
This can be avoided by defining an R128_ASSERT macro in your implementation
file. Since this library uses 64-bit arithmetic, this may implicitly add a
runtime library dependency on 32-bit platforms.

C++ SUPPORT
-----------
Operator overloads are supplied for C++ files that include this file. Since all
C++ functions are declared inline (or static inline), the R128_IMPLEMENTATION
file can be either C++ or C.

LICENSE
-------
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

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 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 H_R128_H
#define H_R128_H

#include <stddef.h>

// 64-bit integer support
// If your compiler does not have stdint.h, add appropriate defines for these macros.
#if defined(_MSC_VER) && (_MSC_VER < 1600)
#define R128_S32
#define R128_U32
#define R128_S64
#define R128_U64
#define R128_LIT_S64
#define R128_LIT_U64
#else
#  include <stdint.h>
#define R128_S32
#define R128_U32
#define R128_S64
#define R128_U64
#define R128_LIT_S64(x)
#define R128_LIT_U64(x)
#endif

#ifdef __cplusplus
extern "C" {
#endif

R128;

// Type conversion
extern void r128FromInt(R128 *dst, R128_S64 v);
extern void r128FromFloat(R128 *dst, double v);
extern R128_S64 r128ToInt(const R128 *v);
extern double r128ToFloat(const R128 *v);

// Copy
extern void r128Copy(R128 *dst, const R128 *src);

// Sign manipulation
extern void r128Neg(R128 *dst, const R128 *v);   // -v
extern void r128Abs(R128* dst, const R128* v);   // abs(v)
extern void r128Nabs(R128* dst, const R128* v);  // -abs(v)

// Bitwise operations
extern void r128Not(R128 *dst, const R128 *src);               // ~a
extern void r128Or(R128 *dst, const R128 *a, const R128 *b);   // a | b
extern void r128And(R128 *dst, const R128 *a, const R128 *b);  // a & b
extern void r128Xor(R128 *dst, const R128 *a, const R128 *b);  // a ^ b
extern void r128Shl(R128 *dst, const R128 *src, int amount);   // shift left by amount mod 128
extern void r128Shr(R128 *dst, const R128 *src, int amount);   // shift right logical by amount mod 128
extern void r128Sar(R128 *dst, const R128 *src, int amount);   // shift right arithmetic by amount mod 128

// Arithmetic
extern void r128Add(R128 *dst, const R128 *a, const R128 *b);  // a + b
extern void r128Sub(R128 *dst, const R128 *a, const R128 *b);  // a - b
extern void r128Mul(R128 *dst, const R128 *a, const R128 *b);  // a * b
extern void r128Div(R128 *dst, const R128 *a, const R128 *b);  // a / b
extern void r128Mod(R128 *dst, const R128 *a, const R128 *b);  // a - toInt(a / b) * b

extern void r128Sqrt(R128 *dst, const R128 *v);  // sqrt(v)
extern void r128Rsqrt(R128 *dst, const R128 *v); // 1 / sqrt(v)

// Comparison
extern int  r128Cmp(const R128 *a, const R128 *b);  // sign of a-b
extern void r128Min(R128 *dst, const R128 *a, const R128 *b);
extern void r128Max(R128 *dst, const R128 *a, const R128 *b);
extern void r128Floor(R128 *dst, const R128 *v);
extern void r128Ceil(R128 *dst, const R128 *v);
extern void r128Round(R128 *dst, const R128 *v);    // round to nearest, rounding halfway values away from zero
extern int  r128IsNeg(const R128 *v); // quick check for < 0

// String conversion
//
R128ToStringSign;

// Formatting options for use with r128ToStringOpt. The "defaults" correspond
// to a format string of "%f".
//
R128ToStringFormat;

// r128ToStringOpt: convert R128 to a decimal string, with formatting.
//
// dst and dstSize: specify the buffer to write into. At most dstSize bytes will be written
// (including null terminator). No additional rounding is performed if dstSize is not large
// enough to hold the entire string.
//
// opt: an R128ToStringFormat struct (q.v.) with formatting options.
//
// Uses the R128_decimal global as the decimal point character.
// Always writes a null terminator, even if the destination buffer is not large enough.
//
// Number of bytes that will be written (i.e. how big does dst need to be?):
// If width is specified: width + 1 bytes.
// If precision is specified: at most precision + 22 bytes.
// If neither is specified: at most 42 bytes.
//
// Returns the number of bytes that would have been written if dst was sufficiently large,
// not including the final null terminator.
//
extern int r128ToStringOpt(char *dst, size_t dstSize, const R128 *v, const R128ToStringFormat *opt);

// r128ToStringf: convert R128 to a decimal string, with formatting.
//
// dst and dstSize: specify the buffer to write into. At most dstSize bytes will be written
// (including null terminator).
//
// format: a printf-style format specifier, as one would use with floating point types.
//    e.g. "%+5.2f". (The leading % and trailing f are optional.)
//    NOTE: This is NOT a full replacement for sprintf. Any characters in the format string
//       that do not correspond to a format placeholder are ignored.
//
// Uses the R128_decimal global as the decimal point character.
// Always writes a null terminator, even if the destination buffer is not large enough.
//
// Number of bytes that will be written (i.e. how big does dst need to be?):
// If the precision field is specified: at most max(width, precision + 21) + 1 bytes
// Otherwise: at most max(width, 41) + 1 bytes.
//
// Returns the number of bytes that would have been written if dst was sufficiently large,
// not including the final null terminator.
//
extern int r128ToStringf(char *dst, size_t dstSize, const char *format, const R128 *v);

// r128ToString: convert R128 to a decimal string, with default formatting.
// Equivalent to r128ToStringf(dst, dstSize, "%f", v).
//
// Uses the R128_decimal global as the decimal point character.
// Always writes a null terminator, even if the destination buffer is not large enough.
//
// Will write at most 42 bytes (including NUL) to dst.
//
// Returns the number of bytes that would have been written if dst was sufficiently large,
// not including the final null terminator.
//
extern int r128ToString(char *dst, size_t dstSize, const R128 *v);

// r128FromString: Convert string to R128.
//
// The string can be formatted either as a decimal number with optional sign
// or as hexadecimal with a prefix of 0x or 0X.
//
// endptr, if not NULL, is set to the character following the last character
//   used in the conversion.
//
extern void r128FromString(R128 *dst, const char *s, char **endptr);

// Constants
extern const R128 R128_min;      // minimum (most negative) value
extern const R128 R128_max;      // maximum (most positive) value
extern const R128 R128_smallest; // smallest positive value
extern const R128 R128_zero;     // zero
extern const R128 R128_one;      // 1.0

extern char R128_decimal;        // decimal point character used by r128From/ToString. defaults to '.'

#ifdef __cplusplus
}

#include <limits>
namespace std {
template<>
struct numeric_limits<R128>
{
   static const bool is_specialized = true;

   static R128 min() throw() { return R128_min; }
   static R128 max() throw() { return R128_max; }

   static const int digits = 127;
   static const int digits10 = 38;
   static const bool is_signed = true;
   static const bool is_integer = false;
   static const bool is_exact = false;
   static const int radix = 2;
   static R128 epsilon() throw() { return R128_smallest; }
   static R128 round_error() throw() { return R128_one; }

   static const int min_exponent = 0;
   static const int min_exponent10 = 0;
   static const int max_exponent = 0;
   static const int max_exponent10 = 0;

   static const bool has_infinity = false;
   static const bool has_quiet_NaN = false;
   static const bool has_signaling_NaN = false;
   static const float_denorm_style has_denorm = denorm_absent;
   static const bool has_denorm_loss = false;

   static R128 infinity() throw() { return R128_zero; }
   static R128 quiet_NaN() throw() { return R128_zero; }
   static R128 signaling_NaN() throw() { return R128_zero; }
   static R128 denorm_min() throw() { return R128_zero; }

   static const bool is_iec559 = false;
   static const bool is_bounded = true;
   static const bool is_modulo = true;

   static const bool traps = numeric_limits<R128_U64>::traps;
   static const bool tinyness_before = false;
   static const float_round_style round_style = round_toward_zero;
};
}  //namespace std

inline R128::R128() {}

inline R128::R128(double v)
{
   r128FromFloat(this, v);
}

inline R128::R128(int v)
{
   r128FromInt(this, v);
}

inline R128::R128(R128_S64 v)
{
   r128FromInt(this, v);
}

inline R128::R128(R128_U64 low, R128_U64 high)
{
   lo = low;
   hi = high;
}

inline R128::operator double() const
{
   return r128ToFloat(this);
}

inline R128::operator R128_S64() const
{
   return r128ToInt(this);
}

inline R128::operator int() const
{
   return (int) r128ToInt(this);
}

inline R128::operator bool() const
{
   return lo || hi;
}

inline bool R128::operator!() const
{
   return !lo && !hi;
}

inline R128 R128::operator~() const
{
   R128 r;
   r128Not(&r, this);
   return r;
}

inline R128 R128::operator-() const
{
   R128 r;
   r128Neg(&r, this);
   return r;
}

inline R128 &R128::operator|=(const R128 &rhs)
{
   r128Or(this, this, &rhs);
   return *this;
}

inline R128 &R128::operator&=(const R128 &rhs)
{
   r128And(this, this, &rhs);
   return *this;
}

inline R128 &R128::operator^=(const R128 &rhs)
{
   r128Xor(this, this, &rhs);
   return *this;
}

inline R128 &R128::operator+=(const R128 &rhs)
{
   r128Add(this, this, &rhs);
   return *this;
}

inline R128 &R128::operator-=(const R128 &rhs)
{
   r128Sub(this, this, &rhs);
   return *this;
}

inline R128 &R128::operator*=(const R128 &rhs)
{
   r128Mul(this, this, &rhs);
   return *this;
}

inline R128 &R128::operator/=(const R128 &rhs)
{
   r128Div(this, this, &rhs);
   return *this;
}

inline R128 &R128::operator%=(const R128 &rhs)
{
   r128Mod(this, this, &rhs);
   return *this;
}

inline R128 &R128::operator<<=(int amount)
{
   r128Shl(this, this, amount);
   return *this;
}

inline R128 &R128::operator>>=(int amount)
{
   r128Sar(this, this, amount);
   return *this;
}

static inline R128 operator|(const R128 &lhs, const R128 &rhs)
{
   R128 r(lhs);
   return r |= rhs;
}

static inline R128 operator&(const R128 &lhs, const R128 &rhs)
{
   R128 r(lhs);
   return r &= rhs;
}

static inline R128 operator^(const R128 &lhs, const R128 &rhs)
{
   R128 r(lhs);
   return r ^= rhs;
}

static inline R128 operator+(const R128 &lhs, const R128 &rhs)
{
   R128 r(lhs);
   return r += rhs;
}

static inline R128 operator-(const R128 &lhs, const R128 &rhs)
{
   R128 r(lhs);
   return r -= rhs;
}

static inline R128 operator*(const R128 &lhs, const R128 &rhs)
{
   R128 r(lhs);
   return r *= rhs;
}

static inline R128 operator/(const R128 &lhs, const R128 &rhs)
{
   R128 r(lhs);
   return r /= rhs;
}

static inline R128 operator%(const R128 &lhs, const R128 &rhs)
{
   R128 r(lhs);
   return r %= rhs;
}

static inline R128 operator<<(const R128 &lhs, int amount)
{
   R128 r(lhs);
   return r <<= amount;
}

static inline R128 operator>>(const R128 &lhs, int amount)
{
   R128 r(lhs);
   return r >>= amount;
}

static inline bool operator<(const R128 &lhs, const R128 &rhs)
{
   return r128Cmp(&lhs, &rhs) < 0;
}

static inline bool operator>(const R128 &lhs, const R128 &rhs)
{
   return r128Cmp(&lhs, &rhs) > 0;
}

static inline bool operator<=(const R128 &lhs, const R128 &rhs)
{
   return r128Cmp(&lhs, &rhs) <= 0;
}

static inline bool operator>=(const R128 &lhs, const R128 &rhs)
{
   return r128Cmp(&lhs, &rhs) >= 0;
}

static inline bool operator==(const R128 &lhs, const R128 &rhs)
{
   return lhs.lo == rhs.lo && lhs.hi == rhs.hi;
}

static inline bool operator!=(const R128 &lhs, const R128 &rhs)
{
   return lhs.lo != rhs.lo || lhs.hi != rhs.hi;
}

#endif   //__cplusplus
#endif   //H_R128_H

#ifdef R128_IMPLEMENTATION

#ifdef R128_DEBUG_VIS
#define R128_DEBUG_SET
#else
#define R128_DEBUG_SET(x)
#endif

#define R128_SET2(x, l, h)
#define R128_R0(x)
#define R128_R2(x)
#if defined(_M_IX86)
// workaround: MSVC x86's handling of 64-bit values is not great
#define R128_SET4
#define R128_R1
#define R128_R3
#else
#define R128_SET4(x, r0, r1, r2, r3)
#define R128_R1(x)
#define R128_R3(x)
#endif

#if defined(_M_X64)
#define R128_INTEL
#define R128_64BIT
#  ifndef R128_STDC_ONLY
#     include <intrin.h>
#  endif
#elif defined(__x86_64__)
#define R128_INTEL
#define R128_64BIT
#  ifndef R128_STDC_ONLY
#     include <x86intrin.h>
#  endif
#elif defined(_M_IX86)
#define R128_INTEL
#  ifndef R128_STDC_ONLY
#     include <intrin.h>
#  endif
#elif defined(__i386__)
#define R128_INTEL
#  ifndef R128_STDC_ONLY
#     include <x86intrin.h>
#  endif
#elif defined(_M_ARM)
#  ifndef R128_STDC_ONLY
#     include <intrin.h>
#  endif
#elif defined(_M_ARM64)
#define R128_64BIT
#  ifndef R128_STDC_ONLY
#     include <intrin.h>
#  endif
#elif defined(__aarch64__)
#define R128_64BIT
#endif

#ifndef R128_INTEL
#define R128_INTEL
#endif

#ifndef R128_64BIT
#define R128_64BIT
#endif

#ifndef R128_ASSERT
#  include <assert.h>
#define R128_ASSERT(x)
#endif

#include <stdlib.h>  // for NULL

static const R128ToStringFormat R128__defaultFormat =;

const R128 R128_min =;
const R128 R128_max =;
const R128 R128_smallest =;
const R128 R128_zero =;
const R128 R128_one =;
char R128_decimal =;
#ifdef R128_DEBUG_VIS
char R128_last[42];
#endif

static int r128__clz64(R128_U64 x)
{}

#if !R128_64BIT
// 32*32->64
static R128_U64 r128__umul64(R128_U32 a, R128_U32 b)
{
#  if defined(_M_IX86) && !defined(R128_STDC_ONLY) && !defined(__MINGW32__)
   return __emulu(a, b);
#  elif defined(_M_ARM) && !defined(R128_STDC_ONLY)
   return _arm_umull(a, b);
#  else
   return a * (R128_U64)b;
#  endif
}

// 64/32->32
static R128_U32 r128__udiv64(R128_U32 nlo, R128_U32 nhi, R128_U32 d, R128_U32 *rem)
{
#  if defined(_M_IX86) && (_MSC_VER >= 1920) && !defined(R128_STDC_ONLY)
   unsigned __int64 n = ((unsigned __int64)nhi << 32) | nlo;
   return _udiv64(n, d, rem);
#  elif defined(_M_IX86) && !defined(R128_STDC_ONLY) && !defined(__MINGW32__)
   __asm {
      mov eax, nlo
      mov edx, nhi
      div d
      mov ecx, rem
      mov dword ptr [ecx], edx
   }
#  elif defined(__i386__) && !defined(R128_STDC_ONLY)
   R128_U32 q, r;
   __asm("divl %4"
      : "=a"(q), "=d"(r)
      : "a"(nlo), "d"(nhi), "X"(d));
   *rem = r;
   return q;
#  else
   R128_U64 n64 = ((R128_U64)nhi << 32) | nlo;
   *rem = (R128_U32)(n64 % d);
   return (R128_U32)(n64 / d);
#  endif
}
#elif defined(R128_STDC_ONLY) || !R128_INTEL
#define r128__umul64
static R128_U32 r128__udiv64(R128_U32 nlo, R128_U32 nhi, R128_U32 d, R128_U32 *rem)
{
   R128_U64 n64 = ((R128_U64)nhi << 32) | nlo;
   *rem = (R128_U32)(n64 % d);
   return (R128_U32)(n64 / d);
}
#endif   //!R128_64BIT

static void r128__neg(R128 *dst, const R128 *src)
{}

// 64*64->128
static void r128__umul128(R128 *dst, R128_U64 a, R128_U64 b)
{}

// 128/64->64
#if defined(_M_X64) && (_MSC_VER < 1920) && !defined(R128_STDC_ONLY) && !defined(__MINGW32__)
// MSVC x64 provides neither inline assembly nor (pre-2019) a div intrinsic, so we do fake
// "inline assembly" to avoid long division or outline assembly.
#pragma code_seg(".text")
__declspec(allocate(".text") align(16)) static const unsigned char r128__udiv128Code[] = {
   0x48, 0x8B, 0xC1,       //mov  rax, rcx
   0x49, 0xF7, 0xF0,       //div  rax, r8
   0x49, 0x89, 0x11,       //mov  qword ptr [r9], rdx
   0xC3                    //ret
};
typedef R128_U64 (*r128__udiv128Proc)(R128_U64 nlo, R128_U64 nhi, R128_U64 d, R128_U64 *rem);
static const r128__udiv128Proc r128__udiv128 = (r128__udiv128Proc)(void*)r128__udiv128Code;
#else
static R128_U64 r128__udiv128(R128_U64 nlo, R128_U64 nhi, R128_U64 d, R128_U64 *rem)
{}
#endif

static int r128__ucmp(const R128 *a, const R128 *b)
{}

static void r128__umul(R128 *dst, const R128 *a, const R128 *b)
{}

// Shift d left until the high bit is set, and shift n left by the same amount.
// returns non-zero on overflow.
static int r128__norm(R128 *n, R128 *d, R128_U64 *n2)
{}

static void r128__udiv(R128 *quotient, const R128 *dividend, const R128 *divisor)
{}

static R128_U64 r128__umod(R128 *n, R128 *d)
{}

static int r128__format(char *dst, size_t dstSize, const R128 *v, const R128ToStringFormat *format)
{}

void r128FromInt(R128 *dst, R128_S64 v)
{}

void r128FromFloat(R128 *dst, double v)
{}

void r128FromString(R128 *dst, const char *s, char **endptr)
{}

R128_S64 r128ToInt(const R128 *v)
{}

double r128ToFloat(const R128 *v)
{}

int r128ToStringOpt(char *dst, size_t dstSize, const R128 *v, const R128ToStringFormat *opt)
{}

int r128ToStringf(char *dst, size_t dstSize, const char *format, const R128 *v)
{}

int r128ToString(char *dst, size_t dstSize, const R128 *v)
{}

void r128Copy(R128 *dst, const R128 *src)
{}

void r128Neg(R128 *dst, const R128 *v)
{}

void r128Abs(R128* dst, const R128* v)
{}

void r128Nabs(R128* dst, const R128* v)
{}

void r128Not(R128 *dst, const R128 *src)
{}

void r128Or(R128 *dst, const R128 *a, const R128 *b)
{}

void r128And(R128 *dst, const R128 *a, const R128 *b)
{}

void r128Xor(R128 *dst, const R128 *a, const R128 *b)
{}

void r128Shl(R128 *dst, const R128 *src, int amount)
{}

void r128Shr(R128 *dst, const R128 *src, int amount)
{}

void r128Sar(R128 *dst, const R128 *src, int amount)
{}

void r128Add(R128 *dst, const R128 *a, const R128 *b)
{}

void r128Sub(R128 *dst, const R128 *a, const R128 *b)
{}

void r128Mul(R128 *dst, const R128 *a, const R128 *b)
{}

void r128Div(R128 *dst, const R128 *a, const R128 *b)
{}

void r128Mod(R128 *dst, const R128 *a, const R128 *b)
{}

void r128Rsqrt(R128 *dst, const R128 *v)
{}

void r128Sqrt(R128 *dst, const R128 *v)
{}

int r128Cmp(const R128 *a, const R128 *b)
{}

int r128IsNeg(const R128 *v)
{}

void r128Min(R128 *dst, const R128 *a, const R128 *b)
{}

void r128Max(R128 *dst, const R128 *a, const R128 *b)
{}

void r128Floor(R128 *dst, const R128 *v)
{}

void r128Ceil(R128 *dst, const R128 *v)
{}

void r128Round(R128* dst, const R128* v)
{}

#endif   //R128_IMPLEMENTATION