2019-06-29 00:27:49 +02:00
# pragma once
2015-12-02 10:23:25 +01:00
2016-08-14 02:22:19 +02:00
# ifdef _MSC_VER
# include <intrin.h>
# else
# include <x86intrin.h>
# endif
# include <immintrin.h>
# include <emmintrin.h>
2015-10-04 00:45:26 +02:00
# include <cstdint>
2018-08-24 18:07:38 +02:00
# include <cstddef>
2019-05-10 19:24:14 +02:00
# include <cstring>
2016-04-27 00:27:24 +02:00
# include <type_traits>
2016-08-14 02:22:19 +02:00
# include <utility>
2017-01-29 00:00:49 +01:00
# include <chrono>
2018-09-05 21:28:37 +02:00
# include <limits>
2017-04-19 13:31:56 +02:00
# include <array>
2016-08-14 02:22:19 +02:00
// Assume little-endian
# define IS_LE_MACHINE 1
# define IS_BE_MACHINE 0
2019-02-27 21:10:40 +01:00
# ifndef __has_builtin
# define __has_builtin(x) 0
# endif
2016-08-14 02:22:19 +02:00
# ifdef _MSC_VER
2018-09-06 23:04:26 +02:00
# define ASSUME(...) __assume(__VA_ARGS__) // MSVC __assume ignores side-effects
2016-08-17 18:50:20 +02:00
# define LIKELY
# define UNLIKELY
2016-08-14 02:22:19 +02:00
# define SAFE_BUFFERS __declspec(safebuffers)
# define NEVER_INLINE __declspec(noinline)
# define FORCE_INLINE __forceinline
2019-07-08 17:16:05 +02:00
# define RESTRICT __restrict
2018-09-06 23:04:26 +02:00
# else // not _MSC_VER
# ifdef __clang__
# if defined(__has_builtin) && __has_builtin(__builtin_assume)
# pragma clang diagnostic ignored "-Wassume" // ignore the clang "side-effects ignored" warning
# define ASSUME(...) __builtin_assume(!!(__VA_ARGS__)) // __builtin_assume (supported by modern clang) ignores side-effects
# endif
# endif
# ifndef ASSUME // gcc and old clang
# define ASSUME(...) do { if (!(__VA_ARGS__)) __builtin_unreachable(); } while (0) // note: the compiler will generate code to evaluate "cond" if the expression is opaque
# endif
# define LIKELY(...) __builtin_expect(!!(__VA_ARGS__), 1)
# define UNLIKELY(...) __builtin_expect(!!(__VA_ARGS__), 0)
2016-08-14 02:22:19 +02:00
# define SAFE_BUFFERS
# define NEVER_INLINE __attribute__((noinline))
# define FORCE_INLINE __attribute__((always_inline)) inline
2019-07-08 17:16:05 +02:00
# define RESTRICT __restrict__
2018-09-06 23:04:26 +02:00
# endif // _MSC_VER
2016-08-14 02:22:19 +02:00
# define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, "Invalid " #type " type size")
# define CHECK_ALIGN(type, align) static_assert(alignof(type) == align, "Invalid " #type " type alignment")
# define CHECK_MAX_SIZE(type, size) static_assert(sizeof(type) <= size, #type " type size is too big")
# define CHECK_SIZE_ALIGN(type, size, align) CHECK_SIZE(type, size); CHECK_ALIGN(type, align)
2018-08-23 23:31:48 +02:00
// Variant pattern matching helper
# define MATCH(arg, ...) constexpr(std::is_same_v<std::decay_t<decltype(arg)>, __VA_ARGS__>)
2016-08-14 02:22:19 +02:00
# define CONCATENATE_DETAIL(x, y) x ## y
# define CONCATENATE(x, y) CONCATENATE_DETAIL(x, y)
2017-10-16 06:52:11 +02:00
# define STRINGIZE_DETAIL(x) #x ""
2016-08-14 02:22:19 +02:00
# define STRINGIZE(x) STRINGIZE_DETAIL(x)
# define HERE "\n(in file " __FILE__ ":" STRINGIZE(__LINE__) ")"
# define DECLARE(...) decltype(__VA_ARGS__) __VA_ARGS__
# define STR_CASE(...) case __VA_ARGS__: return #__VA_ARGS__
2016-02-01 22:55:43 +01:00
2018-09-06 23:04:26 +02:00
# define ASSERT(...) do { if(!(__VA_ARGS__)) fmt::raw_error("Assertion failed: " STRINGIZE(__VA_ARGS__) HERE); } while(0)
# if defined(_DEBUG) || defined(_AUDIT)
# define AUDIT(...) ASSERT(__VA_ARGS__)
# else
# define AUDIT(...) ((void)0)
# endif
2019-06-01 23:12:17 +02:00
# if defined(__cpp_lib_bit_cast) && (__cpp_lib_bit_cast >= 201806L)
# include <bit>
# else
namespace std
{
template < class To , class From , typename = std : : enable_if_t < sizeof ( To ) = = sizeof ( From ) > >
constexpr To bit_cast ( const From & from ) noexcept
{
static_assert ( sizeof ( To ) = = sizeof ( From ) , " std::bit_cast<>: incompatible type size " ) ;
To result ;
std : : memcpy ( & result , & from , sizeof ( From ) ) ;
return result ;
}
}
# endif
2018-09-06 23:04:26 +02:00
2016-08-13 15:36:04 +02:00
using schar = signed char ;
using uchar = unsigned char ;
2015-10-04 00:45:26 +02:00
using ushort = unsigned short ;
2016-08-13 15:36:04 +02:00
using uint = unsigned int ;
using ulong = unsigned long ;
2015-10-04 00:45:26 +02:00
using ullong = unsigned long long ;
2016-08-13 15:36:04 +02:00
using llong = long long ;
2015-10-04 00:45:26 +02:00
2018-08-18 03:13:25 +02:00
# if __APPLE__
using uptr = std : : uint64_t ;
# else
2017-06-22 23:39:31 +02:00
using uptr = std : : uintptr_t ;
2018-08-18 03:13:25 +02:00
# endif
2017-06-22 23:39:31 +02:00
2016-08-13 15:36:04 +02:00
using u8 = std : : uint8_t ;
2015-12-02 10:23:25 +01:00
using u16 = std : : uint16_t ;
using u32 = std : : uint32_t ;
using u64 = std : : uint64_t ;
2015-10-04 00:45:26 +02:00
2016-08-13 15:36:04 +02:00
using s8 = std : : int8_t ;
2015-12-02 10:23:25 +01:00
using s16 = std : : int16_t ;
using s32 = std : : int32_t ;
using s64 = std : : int64_t ;
2015-10-04 00:45:26 +02:00
2017-01-29 00:00:49 +01:00
using steady_clock = std : : conditional <
std : : chrono : : high_resolution_clock : : is_steady ,
std : : chrono : : high_resolution_clock , std : : chrono : : steady_clock > : : type ;
2019-07-26 18:00:56 +02:00
// Get integral type from type size
template < std : : size_t N >
2019-07-07 10:53:07 +02:00
struct get_int_impl
{
} ;
2019-07-26 18:00:56 +02:00
template < >
2019-07-07 10:53:07 +02:00
struct get_int_impl < sizeof ( u8 ) >
{
2019-07-26 18:00:56 +02:00
using utype = u8 ;
using stype = s8 ;
2019-07-07 10:53:07 +02:00
} ;
2019-07-26 18:00:56 +02:00
template < >
2019-07-07 10:53:07 +02:00
struct get_int_impl < sizeof ( u16 ) >
{
2019-07-26 18:00:56 +02:00
using utype = u16 ;
using stype = s16 ;
2019-07-07 10:53:07 +02:00
} ;
2019-07-26 18:00:56 +02:00
template < >
2019-07-07 10:53:07 +02:00
struct get_int_impl < sizeof ( u32 ) >
{
2019-07-26 18:00:56 +02:00
using utype = u32 ;
using stype = s32 ;
2019-07-07 10:53:07 +02:00
} ;
2019-07-26 18:00:56 +02:00
template < >
2019-07-07 10:53:07 +02:00
struct get_int_impl < sizeof ( u64 ) >
{
2019-07-26 18:00:56 +02:00
using utype = u64 ;
using stype = s64 ;
2019-07-07 10:53:07 +02:00
} ;
2019-07-26 18:00:56 +02:00
template < std : : size_t N >
using get_uint_t = typename get_int_impl < N > : : utype ;
template < std : : size_t N >
using get_sint_t = typename get_int_impl < N > : : stype ;
2019-07-07 10:53:07 +02:00
2016-04-20 01:32:27 +02:00
namespace gsl
{
2018-08-24 18:07:38 +02:00
using std : : byte ;
2016-04-20 01:32:27 +02:00
}
2016-08-03 22:51:05 +02:00
// Formatting helper, type-specific preprocessing for improving safety and functionality
2016-08-13 15:36:04 +02:00
template < typename T , typename = void >
2016-08-03 22:51:05 +02:00
struct fmt_unveil ;
2016-04-27 00:27:24 +02:00
2016-08-15 12:18:47 +02:00
template < typename Arg >
using fmt_unveil_t = typename fmt_unveil < Arg > : : type ;
2016-08-08 18:01:06 +02:00
struct fmt_type_info ;
namespace fmt
{
2016-08-13 15:36:04 +02:00
template < typename . . . Args >
2016-08-08 18:01:06 +02:00
const fmt_type_info * get_type_info ( ) ;
}
2016-08-13 15:36:04 +02:00
template < typename T , std : : size_t Align = alignof ( T ) , std : : size_t Size = sizeof ( T ) >
2016-05-26 17:06:06 +02:00
struct se_storage ;
2016-08-13 15:36:04 +02:00
template < typename T , bool Se = true , std : : size_t Align = alignof ( T ) >
2016-05-26 17:06:06 +02:00
class se_t ;
2016-08-13 15:36:04 +02:00
template < typename T >
2016-02-01 22:55:43 +01:00
class atomic_t ;
// Extract T::simple_type if available, remove cv qualifiers
2016-08-13 15:36:04 +02:00
template < typename T , typename = void >
2016-02-01 22:55:43 +01:00
struct simple_type_helper
{
using type = typename std : : remove_cv < T > : : type ;
} ;
2016-08-13 15:36:04 +02:00
template < typename T >
2018-08-23 23:31:27 +02:00
struct simple_type_helper < T , std : : void_t < typename T : : simple_type > >
2016-02-01 22:55:43 +01:00
{
using type = typename T : : simple_type ;
} ;
2016-08-13 15:36:04 +02:00
template < typename T >
using simple_t = typename simple_type_helper < T > : : type ;
2016-02-01 22:55:43 +01:00
// Bool type equivalent
class b8
{
2016-04-27 00:27:24 +02:00
u8 m_value ;
2016-02-01 22:55:43 +01:00
public :
b8 ( ) = default ;
constexpr b8 ( bool value )
: m_value ( value )
{
}
constexpr operator bool ( ) const
{
return m_value ! = 0 ;
}
} ;
# ifndef _MSC_VER
using u128 = __uint128_t ;
using s128 = __int128_t ;
# else
// Unsigned 128-bit integer implementation (TODO)
struct alignas ( 16 ) u128
{
2016-04-27 00:27:24 +02:00
u64 lo , hi ;
2016-02-01 22:55:43 +01:00
u128 ( ) = default ;
2016-04-27 00:27:24 +02:00
constexpr u128 ( u64 l )
2016-02-01 22:55:43 +01:00
: lo ( l )
, hi ( 0 )
{
}
2016-08-13 15:36:04 +02:00
friend u128 operator + ( const u128 & l , const u128 & r )
2016-02-01 22:55:43 +01:00
{
u128 value ;
_addcarry_u64 ( _addcarry_u64 ( 0 , r . lo , l . lo , & value . lo ) , r . hi , l . hi , & value . hi ) ;
return value ;
}
2016-08-13 15:36:04 +02:00
friend u128 operator + ( const u128 & l , u64 r )
2016-02-01 22:55:43 +01:00
{
u128 value ;
_addcarry_u64 ( _addcarry_u64 ( 0 , r , l . lo , & value . lo ) , l . hi , 0 , & value . hi ) ;
return value ;
}
2016-08-13 15:36:04 +02:00
friend u128 operator + ( u64 l , const u128 & r )
2016-02-01 22:55:43 +01:00
{
u128 value ;
_addcarry_u64 ( _addcarry_u64 ( 0 , r . lo , l , & value . lo ) , 0 , r . hi , & value . hi ) ;
return value ;
}
2016-08-13 15:36:04 +02:00
friend u128 operator - ( const u128 & l , const u128 & r )
2016-02-01 22:55:43 +01:00
{
u128 value ;
_subborrow_u64 ( _subborrow_u64 ( 0 , r . lo , l . lo , & value . lo ) , r . hi , l . hi , & value . hi ) ;
return value ;
}
2016-08-13 15:36:04 +02:00
friend u128 operator - ( const u128 & l , u64 r )
2016-02-01 22:55:43 +01:00
{
u128 value ;
_subborrow_u64 ( _subborrow_u64 ( 0 , r , l . lo , & value . lo ) , 0 , l . hi , & value . hi ) ;
return value ;
}
2016-08-13 15:36:04 +02:00
friend u128 operator - ( u64 l , const u128 & r )
2016-02-01 22:55:43 +01:00
{
u128 value ;
_subborrow_u64 ( _subborrow_u64 ( 0 , r . lo , l , & value . lo ) , r . hi , 0 , & value . hi ) ;
return value ;
}
2016-08-13 15:36:04 +02:00
u128 operator + ( ) const
2016-02-01 22:55:43 +01:00
{
return * this ;
}
2016-08-13 15:36:04 +02:00
u128 operator - ( ) const
2016-02-01 22:55:43 +01:00
{
u128 value ;
_subborrow_u64 ( _subborrow_u64 ( 0 , lo , 0 , & value . lo ) , hi , 0 , & value . hi ) ;
return value ;
}
2016-08-13 15:36:04 +02:00
u128 & operator + + ( )
2016-02-01 22:55:43 +01:00
{
_addcarry_u64 ( _addcarry_u64 ( 0 , 1 , lo , & lo ) , 0 , hi , & hi ) ;
return * this ;
}
2016-08-13 15:36:04 +02:00
u128 operator + + ( int )
2016-02-01 22:55:43 +01:00
{
u128 value = * this ;
_addcarry_u64 ( _addcarry_u64 ( 0 , 1 , lo , & lo ) , 0 , hi , & hi ) ;
return value ;
}
2016-08-13 15:36:04 +02:00
u128 & operator - - ( )
2016-02-01 22:55:43 +01:00
{
_subborrow_u64 ( _subborrow_u64 ( 0 , 1 , lo , & lo ) , 0 , hi , & hi ) ;
return * this ;
}
2016-08-13 15:36:04 +02:00
u128 operator - - ( int )
2016-02-01 22:55:43 +01:00
{
u128 value = * this ;
_subborrow_u64 ( _subborrow_u64 ( 0 , 1 , lo , & lo ) , 0 , hi , & hi ) ;
return value ;
}
2016-08-13 15:36:04 +02:00
u128 operator ~ ( ) const
2016-02-01 22:55:43 +01:00
{
u128 value ;
value . lo = ~ lo ;
value . hi = ~ hi ;
return value ;
}
2016-08-13 15:36:04 +02:00
friend u128 operator & ( const u128 & l , const u128 & r )
2016-02-01 22:55:43 +01:00
{
u128 value ;
value . lo = l . lo & r . lo ;
value . hi = l . hi & r . hi ;
return value ;
}
2016-08-13 15:36:04 +02:00
friend u128 operator | ( const u128 & l , const u128 & r )
2016-02-01 22:55:43 +01:00
{
u128 value ;
value . lo = l . lo | r . lo ;
value . hi = l . hi | r . hi ;
return value ;
}
2016-08-13 15:36:04 +02:00
friend u128 operator ^ ( const u128 & l , const u128 & r )
2016-02-01 22:55:43 +01:00
{
u128 value ;
value . lo = l . lo ^ r . lo ;
value . hi = l . hi ^ r . hi ;
return value ;
}
2016-08-13 15:36:04 +02:00
u128 & operator + = ( const u128 & r )
2016-02-01 22:55:43 +01:00
{
_addcarry_u64 ( _addcarry_u64 ( 0 , r . lo , lo , & lo ) , r . hi , hi , & hi ) ;
return * this ;
}
2016-08-13 15:36:04 +02:00
u128 & operator + = ( uint64_t r )
2016-02-01 22:55:43 +01:00
{
_addcarry_u64 ( _addcarry_u64 ( 0 , r , lo , & lo ) , 0 , hi , & hi ) ;
return * this ;
}
2016-08-13 15:36:04 +02:00
u128 & operator & = ( const u128 & r )
2016-02-01 22:55:43 +01:00
{
lo & = r . lo ;
hi & = r . hi ;
return * this ;
}
2016-08-13 15:36:04 +02:00
u128 & operator | = ( const u128 & r )
2016-02-01 22:55:43 +01:00
{
lo | = r . lo ;
hi | = r . hi ;
return * this ;
}
2016-08-13 15:36:04 +02:00
u128 & operator ^ = ( const u128 & r )
2016-02-01 22:55:43 +01:00
{
lo ^ = r . lo ;
hi ^ = r . hi ;
return * this ;
}
} ;
// Signed 128-bit integer implementation (TODO)
struct alignas ( 16 ) s128
{
2016-04-27 00:27:24 +02:00
u64 lo ;
s64 hi ;
2016-02-01 22:55:43 +01:00
s128 ( ) = default ;
2016-04-27 00:27:24 +02:00
constexpr s128 ( s64 l )
2016-02-01 22:55:43 +01:00
: hi ( l > > 63 )
, lo ( l )
{
}
2016-04-27 00:27:24 +02:00
constexpr s128 ( u64 l )
2016-02-01 22:55:43 +01:00
: hi ( 0 )
, lo ( l )
{
}
} ;
# endif
2016-08-14 02:22:19 +02:00
CHECK_SIZE_ALIGN ( u128 , 16 , 16 ) ;
CHECK_SIZE_ALIGN ( s128 , 16 , 16 ) ;
2016-02-01 22:55:43 +01:00
2019-05-10 19:24:14 +02:00
using f32 = float ;
using f64 = double ;
2015-10-04 00:45:26 +02:00
union alignas ( 2 ) f16
{
u16 _u16 ;
u8 _u8 [ 2 ] ;
2015-10-25 23:40:02 +01:00
explicit f16 ( u16 raw )
{
_u16 = raw ;
}
2019-05-10 19:24:14 +02:00
explicit operator f32 ( ) const
2015-10-25 23:40:02 +01:00
{
// See http://stackoverflow.com/a/26779139
// The conversion doesn't handle NaN/Inf
2016-08-13 15:36:04 +02:00
u32 raw = ( ( _u16 & 0x8000 ) < < 16 ) | // Sign (just moved)
( ( ( _u16 & 0x7c00 ) + 0x1C000 ) < < 13 ) | // Exponent ( exp - 15 + 127)
( ( _u16 & 0x03FF ) < < 13 ) ; // Mantissa
2019-05-10 19:24:14 +02:00
2019-06-01 23:12:17 +02:00
return std : : bit_cast < f32 > ( raw ) ;
2015-10-25 23:40:02 +01:00
}
2015-10-04 00:45:26 +02:00
} ;
2016-08-14 02:22:19 +02:00
CHECK_SIZE_ALIGN ( f16 , 2 , 2 ) ;
2016-08-13 15:36:04 +02:00
template < typename T , typename = std : : enable_if_t < std : : is_integral < T > : : value > >
2016-08-15 12:18:47 +02:00
constexpr T align ( const T & value , ullong align )
2016-08-08 18:01:06 +02:00
{
return static_cast < T > ( ( value + ( align - 1 ) ) & ~ ( align - 1 ) ) ;
}
2017-04-19 13:31:56 +02:00
template < typename T , typename T2 >
inline u32 offset32 ( T T2 : : * const mptr )
{
# ifdef _MSC_VER
2019-06-01 23:12:17 +02:00
return std : : bit_cast < u32 > ( mptr ) ;
2017-04-19 13:31:56 +02:00
# elif __GNUG__
2019-06-01 23:12:17 +02:00
return std : : bit_cast < std : : size_t > ( mptr ) ;
2017-04-19 13:31:56 +02:00
# else
2019-06-01 23:12:17 +02:00
static_assert ( sizeof ( mptr ) = = 0 , " Unsupported pointer-to-member size " ) ;
2017-04-19 13:31:56 +02:00
# endif
}
template < typename T >
struct offset32_array
{
static_assert ( std : : is_array < T > : : value , " Invalid pointer-to-member type (array expected) " ) ;
template < typename Arg >
static inline u32 index32 ( const Arg & arg )
{
2018-09-03 17:46:14 +02:00
return u32 { sizeof ( std : : remove_extent_t < T > ) } * static_cast < u32 > ( arg ) ;
2017-04-19 13:31:56 +02:00
}
} ;
template < typename T , std : : size_t N >
struct offset32_array < std : : array < T , N > >
{
template < typename Arg >
static inline u32 index32 ( const Arg & arg )
{
2018-09-03 17:46:14 +02:00
return u32 { sizeof ( T ) } * static_cast < u32 > ( arg ) ;
2017-04-19 13:31:56 +02:00
}
} ;
template < typename Arg >
struct offset32_detail ;
template < typename T , typename T2 , typename Arg , typename . . . Args >
inline u32 offset32 ( T T2 : : * const mptr , const Arg & arg , const Args & . . . args )
{
return offset32_detail < Arg > : : offset32 ( mptr , arg , args . . . ) ;
}
template < typename Arg >
struct offset32_detail
{
template < typename T , typename T2 , typename . . . Args >
static inline u32 offset32 ( T T2 : : * const mptr , const Arg & arg , const Args & . . . args )
{
return : : offset32 ( mptr , args . . . ) + offset32_array < T > : : index32 ( arg ) ;
}
} ;
template < typename T3 , typename T4 >
struct offset32_detail < T3 T4 : : * >
{
template < typename T , typename T2 , typename . . . Args >
static inline u32 offset32 ( T T2 : : * const mptr , T3 T4 : : * const mptr2 , const Args & . . . args )
{
return : : offset32 ( mptr ) + : : offset32 ( mptr2 , args . . . ) ;
}
} ;
2016-08-14 02:22:19 +02:00
// Helper function, used by ""_u16, ""_u32, ""_u64
2016-08-15 12:18:47 +02:00
constexpr u8 to_u8 ( char c )
2016-08-14 02:22:19 +02:00
{
2016-08-15 12:18:47 +02:00
return static_cast < u8 > ( c ) ;
2016-08-14 02:22:19 +02:00
}
// Convert 2-byte string to u16 value like reinterpret_cast does
2016-08-15 12:18:47 +02:00
constexpr u16 operator " " _u16 ( const char * s , std : : size_t length )
2016-08-14 02:22:19 +02:00
{
return length ! = 2 ? throw s :
# if IS_LE_MACHINE == 1
to_u8 ( s [ 1 ] ) < < 8 | to_u8 ( s [ 0 ] ) ;
# endif
}
// Convert 4-byte string to u32 value like reinterpret_cast does
2016-08-15 12:18:47 +02:00
constexpr u32 operator " " _u32 ( const char * s , std : : size_t length )
2016-08-14 02:22:19 +02:00
{
return length ! = 4 ? throw s :
# if IS_LE_MACHINE == 1
to_u8 ( s [ 3 ] ) < < 24 | to_u8 ( s [ 2 ] ) < < 16 | to_u8 ( s [ 1 ] ) < < 8 | to_u8 ( s [ 0 ] ) ;
# endif
}
// Convert 8-byte string to u64 value like reinterpret_cast does
2016-08-15 12:18:47 +02:00
constexpr u64 operator " " _u64 ( const char * s , std : : size_t length )
2016-08-14 02:22:19 +02:00
{
return length ! = 8 ? throw s :
# if IS_LE_MACHINE == 1
2016-08-15 12:18:47 +02:00
static_cast < u64 > ( to_u8 ( s [ 7 ] ) < < 24 | to_u8 ( s [ 6 ] ) < < 16 | to_u8 ( s [ 5 ] ) < < 8 | to_u8 ( s [ 4 ] ) ) < < 32 | to_u8 ( s [ 3 ] ) < < 24 | to_u8 ( s [ 2 ] ) < < 16 | to_u8 ( s [ 1 ] ) < < 8 | to_u8 ( s [ 0 ] ) ;
2016-08-14 02:22:19 +02:00
# endif
}
2016-08-08 18:01:06 +02:00
namespace fmt
{
[ [ noreturn ] ] void raw_error ( const char * msg ) ;
2016-08-15 12:18:47 +02:00
[ [ noreturn ] ] void raw_verify_error ( const char * msg , const fmt_type_info * sup , u64 arg ) ;
2016-08-08 18:01:06 +02:00
[ [ noreturn ] ] void raw_narrow_error ( const char * msg , const fmt_type_info * sup , u64 arg ) ;
}
2016-08-13 15:36:04 +02:00
struct verify_func
{
template < typename T >
bool operator ( ) ( T & & value ) const
{
if ( std : : forward < T > ( value ) )
{
return true ;
}
return false ;
}
} ;
template < uint N >
struct verify_impl
{
const char * cause ;
template < typename T >
auto operator , ( T & & value ) const
{
// Verification (can be safely disabled)
if ( ! verify_func ( ) ( std : : forward < T > ( value ) ) )
{
2017-01-24 21:19:52 +01:00
fmt : : raw_verify_error ( cause , nullptr , N ) ;
2016-08-13 15:36:04 +02:00
}
return verify_impl < N + 1 > { cause } ;
}
} ;
// Verification helper, checks several conditions delimited with comma operator
inline auto verify ( const char * cause )
{
return verify_impl < 0 > { cause } ;
}
// Verification helper (returns value or lvalue reference, may require to use verify_move instead)
template < typename F = verify_func , typename T >
2016-08-15 12:18:47 +02:00
inline T verify ( const char * cause , T & & value , F & & pred = F ( ) )
2016-08-13 15:36:04 +02:00
{
2016-08-15 12:18:47 +02:00
if ( ! pred ( std : : forward < T > ( value ) ) )
2016-08-13 15:36:04 +02:00
{
2016-08-15 12:18:47 +02:00
using unref = std : : remove_const_t < std : : remove_reference_t < T > > ;
fmt : : raw_verify_error ( cause , fmt : : get_type_info < fmt_unveil_t < unref > > ( ) , fmt_unveil < unref > : : get ( value ) ) ;
2016-08-13 15:36:04 +02:00
}
return std : : forward < T > ( value ) ;
}
// Verification helper (must be used in return expression or in place of std::move)
template < typename F = verify_func , typename T >
2016-08-15 12:18:47 +02:00
inline std : : remove_reference_t < T > & & verify_move ( const char * cause , T & & value , F & & pred = F ( ) )
2016-08-13 15:36:04 +02:00
{
2016-08-15 12:18:47 +02:00
if ( ! pred ( std : : forward < T > ( value ) ) )
2016-08-13 15:36:04 +02:00
{
2016-08-15 12:18:47 +02:00
using unref = std : : remove_const_t < std : : remove_reference_t < T > > ;
fmt : : raw_verify_error ( cause , fmt : : get_type_info < fmt_unveil_t < unref > > ( ) , fmt_unveil < unref > : : get ( value ) ) ;
2016-08-13 15:36:04 +02:00
}
return std : : move ( value ) ;
}
2016-08-14 19:22:07 +02:00
// narrow() function details
template < typename From , typename To = void , typename = void >
struct narrow_impl
{
// Temporarily (diagnostic)
static_assert ( std : : is_void < To > : : value , " narrow_impl<> specialization not found " ) ;
// Returns true if value cannot be represented in type To
static constexpr bool test ( const From & value )
{
// Unspecialized cases (including cast to void) always considered narrowing
return true ;
}
} ;
// Unsigned to unsigned narrowing
template < typename From , typename To >
struct narrow_impl < From , To , std : : enable_if_t < std : : is_unsigned < From > : : value & & std : : is_unsigned < To > : : value > >
{
static constexpr bool test ( const From & value )
{
return sizeof ( To ) < sizeof ( From ) & & static_cast < To > ( value ) ! = value ;
}
} ;
// Signed to signed narrowing
template < typename From , typename To >
struct narrow_impl < From , To , std : : enable_if_t < std : : is_signed < From > : : value & & std : : is_signed < To > : : value > >
{
static constexpr bool test ( const From & value )
{
return sizeof ( To ) < sizeof ( From ) & & static_cast < To > ( value ) ! = value ;
}
} ;
// Unsigned to signed narrowing
template < typename From , typename To >
struct narrow_impl < From , To , std : : enable_if_t < std : : is_unsigned < From > : : value & & std : : is_signed < To > : : value > >
{
static constexpr bool test ( const From & value )
{
return sizeof ( To ) < = sizeof ( From ) & & value > ( static_cast < std : : make_unsigned_t < To > > ( - 1 ) > > 1 ) ;
}
} ;
// Signed to unsigned narrowing (I)
template < typename From , typename To >
struct narrow_impl < From , To , std : : enable_if_t < std : : is_signed < From > : : value & & std : : is_unsigned < To > : : value & & sizeof ( To ) > = sizeof ( From ) > >
{
static constexpr bool test ( const From & value )
{
return value < static_cast < From > ( 0 ) ;
}
} ;
// Signed to unsigned narrowing (II)
template < typename From , typename To >
struct narrow_impl < From , To , std : : enable_if_t < std : : is_signed < From > : : value & & std : : is_unsigned < To > : : value & & sizeof ( To ) < sizeof ( From ) > >
{
static constexpr bool test ( const From & value )
{
return static_cast < std : : make_unsigned_t < From > > ( value ) > static_cast < To > ( - 1 ) ;
}
} ;
2016-08-15 12:18:47 +02:00
// Simple type enabled (TODO: allow for To as well)
2016-08-14 19:22:07 +02:00
template < typename From , typename To >
2018-08-23 23:31:27 +02:00
struct narrow_impl < From , To , std : : void_t < typename From : : simple_type > >
2016-08-14 19:22:07 +02:00
: narrow_impl < simple_t < From > , To >
{
} ;
2016-08-13 15:36:04 +02:00
template < typename To = void , typename From , typename = decltype ( static_cast < To > ( std : : declval < From > ( ) ) ) >
2016-08-08 18:01:06 +02:00
inline To narrow ( const From & value , const char * msg = nullptr )
{
2016-08-14 19:22:07 +02:00
// Narrow check
if ( narrow_impl < From , To > : : test ( value ) )
2016-08-08 18:01:06 +02:00
{
// Pack value as formatting argument
2016-08-15 12:18:47 +02:00
fmt : : raw_narrow_error ( msg , fmt : : get_type_info < fmt_unveil_t < From > > ( ) , fmt_unveil < From > : : get ( value ) ) ;
2016-08-08 18:01:06 +02:00
}
2016-08-14 19:22:07 +02:00
return static_cast < To > ( value ) ;
2016-08-08 18:01:06 +02:00
}
// Returns u32 size() for container
2016-08-13 15:36:04 +02:00
template < typename CT , typename = decltype ( static_cast < u32 > ( std : : declval < CT > ( ) . size ( ) ) ) >
2016-08-08 18:01:06 +02:00
inline u32 size32 ( const CT & container , const char * msg = nullptr )
{
return narrow < u32 > ( container . size ( ) , msg ) ;
}
// Returns u32 size for an array
2016-08-13 15:36:04 +02:00
template < typename T , std : : size_t Size >
constexpr u32 size32 ( const T ( & ) [ Size ] , const char * msg = nullptr )
2016-08-08 18:01:06 +02:00
{
return static_cast < u32 > ( Size ) ;
}
2016-05-13 16:01:48 +02:00
// Simplified hash algorithm for pointers. May be used in std::unordered_(map|set).
2016-08-13 15:36:04 +02:00
template < typename T , std : : size_t Align = alignof ( T ) >
2016-05-13 16:01:48 +02:00
struct pointer_hash
{
std : : size_t operator ( ) ( T * ptr ) const
{
return reinterpret_cast < std : : uintptr_t > ( ptr ) / Align ;
}
} ;
2016-08-13 15:36:04 +02:00
template < typename T , std : : size_t Shift = 0 >
2016-06-02 17:16:01 +02:00
struct value_hash
{
std : : size_t operator ( ) ( T value ) const
{
return static_cast < std : : size_t > ( value ) > > Shift ;
}
} ;
2016-04-25 12:49:12 +02:00
// Contains value of any POD type with fixed size and alignment. TT<> is the type converter applied.
// For example, `simple_t` may be used to remove endianness.
2016-08-13 15:36:04 +02:00
template < template < typename > class TT , std : : size_t S , std : : size_t A = S >
2016-04-25 12:49:12 +02:00
struct alignas ( A ) any_pod
{
2018-08-25 14:47:03 +02:00
alignas ( A ) std : : byte data [ S ] ;
2016-04-25 12:49:12 +02:00
any_pod ( ) = default ;
2016-08-13 15:36:04 +02:00
template < typename T , typename T2 = TT < T > , typename = std : : enable_if_t < std : : is_pod < T2 > : : value & & sizeof ( T2 ) = = S & & alignof ( T2 ) < = A > >
2016-04-25 12:49:12 +02:00
any_pod ( const T & value )
{
reinterpret_cast < T2 & > ( data ) = value ;
}
2016-08-13 15:36:04 +02:00
template < typename T , typename T2 = TT < T > , typename = std : : enable_if_t < std : : is_pod < T2 > : : value & & sizeof ( T2 ) = = S & & alignof ( T2 ) < = A > >
2016-04-25 12:49:12 +02:00
T2 & as ( )
{
return reinterpret_cast < T2 & > ( data ) ;
}
2016-08-13 15:36:04 +02:00
template < typename T , typename T2 = TT < T > , typename = std : : enable_if_t < std : : is_pod < T2 > : : value & & sizeof ( T2 ) = = S & & alignof ( T2 ) < = A > >
2016-04-25 12:49:12 +02:00
const T2 & as ( ) const
{
return reinterpret_cast < const T2 & > ( data ) ;
}
} ;
using any16 = any_pod < simple_t , sizeof ( u16 ) > ;
using any32 = any_pod < simple_t , sizeof ( u32 ) > ;
using any64 = any_pod < simple_t , sizeof ( u64 ) > ;
2016-08-09 16:14:41 +02:00
struct cmd64 : any64
{
struct pair_t
{
any32 arg1 ;
any32 arg2 ;
} ;
cmd64 ( ) = default ;
2016-08-13 15:36:04 +02:00
template < typename T >
2016-08-09 16:14:41 +02:00
cmd64 ( const T & value )
: any64 ( value )
{
}
2016-08-13 15:36:04 +02:00
template < typename T1 , typename T2 >
2016-08-09 16:14:41 +02:00
cmd64 ( const T1 & arg1 , const T2 & arg2 )
: any64 ( pair_t { arg1 , arg2 } )
{
}
explicit operator bool ( ) const
{
return as < u64 > ( ) ! = 0 ;
}
// TODO: compatibility with std::pair/std::tuple?
2016-08-13 15:36:04 +02:00
template < typename T >
2016-08-09 16:14:41 +02:00
decltype ( auto ) arg1 ( )
{
return as < pair_t > ( ) . arg1 . as < T > ( ) ;
}
2016-08-13 15:36:04 +02:00
template < typename T >
2016-08-09 16:14:41 +02:00
decltype ( auto ) arg1 ( ) const
{
return as < const pair_t > ( ) . arg1 . as < const T > ( ) ;
}
2016-08-13 15:36:04 +02:00
template < typename T >
2016-08-09 16:14:41 +02:00
decltype ( auto ) arg2 ( )
{
return as < pair_t > ( ) . arg2 . as < T > ( ) ;
}
2016-08-13 15:36:04 +02:00
template < typename T >
2016-08-09 16:14:41 +02:00
decltype ( auto ) arg2 ( ) const
{
return as < const pair_t > ( ) . arg2 . as < const T > ( ) ;
}
} ;
static_assert ( sizeof ( cmd64 ) = = 8 & & std : : is_pod < cmd64 > : : value , " Incorrect cmd64 type " ) ;
2016-08-17 18:50:20 +02:00
// Error code type (return type), implements error reporting. Could be a template.
2016-08-16 17:46:24 +02:00
struct error_code
2016-08-15 17:30:33 +02:00
{
2016-08-17 18:50:20 +02:00
// Use fixed s32 type for now
2016-08-16 17:46:24 +02:00
s32 value ;
error_code ( ) = default ;
2016-08-17 18:50:20 +02:00
// Implementation must be provided specially
2017-08-08 21:13:48 +02:00
static s32 error_report ( const fmt_type_info * sup , u64 arg , const fmt_type_info * sup2 , u64 arg2 ) ;
2016-08-16 17:46:24 +02:00
2016-08-17 18:50:20 +02:00
// Helper type
enum class not_an_error : s32
2016-08-16 17:46:24 +02:00
{
__not_an_error // SFINAE marker
} ;
// __not_an_error tester
template < typename ET , typename = void >
struct is_error : std : : integral_constant < bool , std : : is_enum < ET > : : value | | std : : is_integral < ET > : : value >
{
} ;
template < typename ET >
2018-08-24 13:01:53 +02:00
struct is_error < ET , std : : enable_if_t < sizeof ( ET : : __not_an_error ) ! = 0 > > : std : : false_type
2016-08-16 17:46:24 +02:00
{
} ;
2018-08-24 13:01:53 +02:00
// Common constructor
template < typename ET >
2016-08-16 17:46:24 +02:00
error_code ( const ET & value )
2018-08-24 13:01:53 +02:00
: value ( static_cast < s32 > ( value ) )
2017-08-08 21:13:48 +02:00
{
2018-08-24 13:01:53 +02:00
if constexpr ( is_error < ET > : : value )
{
this - > value = error_report ( fmt : : get_type_info < fmt_unveil_t < ET > > ( ) , fmt_unveil < ET > : : get ( value ) , nullptr , 0 ) ;
}
2017-08-08 21:13:48 +02:00
}
// Error constructor (2 args)
2018-08-24 13:01:53 +02:00
template < typename ET , typename T2 >
2017-08-08 21:13:48 +02:00
error_code ( const ET & value , const T2 & value2 )
: value ( error_report ( fmt : : get_type_info < fmt_unveil_t < ET > > ( ) , fmt_unveil < ET > : : get ( value ) , fmt : : get_type_info < fmt_unveil_t < T2 > > ( ) , fmt_unveil < T2 > : : get ( value2 ) ) )
2016-08-16 17:46:24 +02:00
{
}
operator s32 ( ) const
{
return value ;
}
2016-08-15 17:30:33 +02:00
} ;
2016-08-16 17:46:24 +02:00
// Helper function for error_code
2016-08-15 17:30:33 +02:00
template < typename T >
2016-08-16 17:46:24 +02:00
constexpr FORCE_INLINE error_code : : not_an_error not_an_error ( const T & value )
2016-08-15 17:30:33 +02:00
{
2016-08-16 17:46:24 +02:00
return static_cast < error_code : : not_an_error > ( static_cast < s32 > ( value ) ) ;
2016-08-15 17:30:33 +02:00
}
2017-02-15 16:07:42 +01:00
// Synchronization helper (cache-friendly busy waiting)
2018-04-03 21:42:47 +02:00
inline void busy_wait ( std : : size_t cycles = 3000 )
2017-02-15 16:07:42 +01:00
{
2018-04-03 21:42:47 +02:00
const u64 s = __rdtsc ( ) ;
do _mm_pause ( ) ; while ( __rdtsc ( ) - s < cycles ) ;
2017-02-15 16:07:42 +01:00
}
2019-07-07 10:53:07 +02:00
// TODO: Remove when moving to c++20
template < typename T >
inline constexpr uintmax_t floor2 ( T value )
{
value > > = 1 ;
for ( uintmax_t i = 0 ; ; i + + , value > > = 1 )
{
if ( value = = 0 )
{
return i ;
}
}
}
template < typename T >
inline constexpr uintmax_t ceil2 ( T value )
{
const uintmax_t ispow2 = value & ( value - 1 ) ; // if power of 2 the result is 0
value > > = 1 ;
for ( uintmax_t i = 0 ; ; i + + , value > > = 1 )
{
if ( value = = 0 )
{
return i + std : : min < uintmax_t > ( ispow2 , 1 ) ;
}
}
}