* Add compiler abstractions over fast fail. * Fix MSVC / GCC's disagreement over inline. * Rework the inline definitions. * Use _snprintf_s_l.
172 lines
4.7 KiB
C++
172 lines
4.7 KiB
C++
#pragma once
|
|
|
|
#if defined(_MSC_VER) && !defined(__clang__)
|
|
// 28 is FAST_FAIL_INVALID_BUFFER_ACCESS. Not using the symbolic constant to
|
|
// avoid depending on winnt.h
|
|
# define SNMALLOC_FAST_FAIL() __fastfail(28)
|
|
# define ALWAYSINLINE __forceinline
|
|
# define NOINLINE __declspec(noinline)
|
|
# define likely(x) !!(x)
|
|
# define unlikely(x) !!(x)
|
|
# define SNMALLOC_SLOW_PATH NOINLINE
|
|
# define SNMALLOC_FAST_PATH ALWAYSINLINE
|
|
/**
|
|
* Fast path with inline linkage. MSVC assumes that `__forceinline` implies
|
|
* `inline` and complains if you specify `SNMALLOC_FAST_PATH` and `inline`.
|
|
*/
|
|
# define SNMALLOC_FAST_PATH_INLINE ALWAYSINLINE
|
|
# if _MSC_VER >= 1927 && !defined(SNMALLOC_USE_CXX17)
|
|
# define SNMALLOC_FAST_PATH_LAMBDA [[msvc::forceinline]]
|
|
# else
|
|
# define SNMALLOC_FAST_PATH_LAMBDA
|
|
# endif
|
|
# define SNMALLOC_PURE
|
|
# define SNMALLOC_COLD
|
|
# define SNMALLOC_REQUIRE_CONSTINIT
|
|
# define SNMALLOC_UNUSED_FUNCTION
|
|
#else
|
|
# define SNMALLOC_FAST_FAIL() __builtin_trap()
|
|
# define likely(x) __builtin_expect(!!(x), 1)
|
|
# define unlikely(x) __builtin_expect(!!(x), 0)
|
|
# define ALWAYSINLINE __attribute__((always_inline))
|
|
# define NOINLINE __attribute__((noinline))
|
|
# define SNMALLOC_SLOW_PATH NOINLINE
|
|
# define SNMALLOC_FAST_PATH ALWAYSINLINE
|
|
/**
|
|
* Fast path with inline linkage. GCC assumes that
|
|
* `__attribute__((always_inline))` is orthogonal to `inline` and complains if
|
|
* you specify `SNMALLOC_FAST_PATH` and don't specify `inline` in places where
|
|
* `inline` would be required for the one definition rule. The error message
|
|
* in this case is confusing: always-inline function may not be inlined. If
|
|
* you see this error message when using `SNMALLOC_FAST_PATH` then switch to
|
|
* `SNMALLOC_FAST_PATH_INLINE`.
|
|
*/
|
|
# define SNMALLOC_FAST_PATH_INLINE ALWAYSINLINE inline
|
|
# define SNMALLOC_FAST_PATH_LAMBDA SNMALLOC_FAST_PATH
|
|
# define SNMALLOC_PURE __attribute__((const))
|
|
# define SNMALLOC_COLD __attribute__((cold))
|
|
# define SNMALLOC_UNUSED_FUNCTION __attribute((unused))
|
|
# ifdef __clang__
|
|
# define SNMALLOC_REQUIRE_CONSTINIT \
|
|
[[clang::require_constant_initialization]]
|
|
# else
|
|
# define SNMALLOC_REQUIRE_CONSTINIT
|
|
# endif
|
|
#endif
|
|
|
|
#if defined(__cpp_constinit) && __cpp_constinit >= 201907
|
|
# define SNMALLOC_CONSTINIT_FN constinit
|
|
# define SNMALLOC_CONSTINIT_STATIC constinit const
|
|
#else
|
|
# define SNMALLOC_CONSTINIT_FN constexpr
|
|
# define SNMALLOC_CONSTINIT_STATIC constexpr
|
|
#endif
|
|
|
|
#if defined(__cpp_consteval)
|
|
# define SNMALLOC_CONSTEVAL consteval
|
|
#else
|
|
# define SNMALLOC_CONSTEVAL constexpr
|
|
#endif
|
|
|
|
#if !defined(__clang__) && defined(__GNUC__)
|
|
# define GCC_NOT_CLANG
|
|
#endif
|
|
|
|
#ifdef GCC_NOT_CLANG
|
|
# if __GNUC__ >= 8
|
|
# define GCC_VERSION_EIGHT_PLUS
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef __APPLE__
|
|
# define SNMALLOC_FORCE_BSS __attribute__((section("__DATA,__bss")))
|
|
#elif defined(__ELF__)
|
|
# define SNMALLOC_FORCE_BSS __attribute__((section(".bss")))
|
|
#else
|
|
# define SNMALLOC_FORCE_BSS
|
|
#endif
|
|
|
|
#ifndef __has_builtin
|
|
# define __has_builtin(x) 0
|
|
#endif
|
|
|
|
#define UNUSED(x) ((void)(x))
|
|
|
|
namespace snmalloc
|
|
{
|
|
// Forwards reference so that the platform can define how to handle errors.
|
|
[[noreturn]] SNMALLOC_COLD void error(const char* const str);
|
|
} // namespace snmalloc
|
|
|
|
#define TOSTRING(expr) TOSTRING2(expr)
|
|
#define TOSTRING2(expr) #expr
|
|
|
|
#ifdef NDEBUG
|
|
# define SNMALLOC_ASSERT(expr) \
|
|
{}
|
|
#else
|
|
# define SNMALLOC_ASSERT(expr) \
|
|
{ \
|
|
if (!(expr)) \
|
|
{ \
|
|
snmalloc::error("assert fail: " #expr " in " __FILE__ \
|
|
" on " TOSTRING(__LINE__)); \
|
|
} \
|
|
}
|
|
#endif
|
|
|
|
#define SNMALLOC_CHECK(expr) \
|
|
{ \
|
|
if (!(expr)) \
|
|
{ \
|
|
snmalloc::error("Check fail: " #expr " in " __FILE__ \
|
|
" on " TOSTRING(__LINE__)); \
|
|
} \
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
# define SNMALLOC_ASSUME(x) SNMALLOC_ASSERT(x)
|
|
#else
|
|
# if __has_builtin(__builtin_assume)
|
|
# define SNMALLOC_ASSUME(x) __builtin_assume((x))
|
|
# elif defined(_MSC_VER)
|
|
# define SNMALLOC_ASSUME(x) __assume((x));
|
|
# elif defined(__GNUC__)
|
|
# define SNMALLOC_ASSUME(x) \
|
|
if (!(x)) \
|
|
__builtin_unreachable();
|
|
# else
|
|
# define SNMALLOC_ASSUME(x) \
|
|
do \
|
|
{ \
|
|
} while (0)
|
|
# endif
|
|
#endif
|
|
|
|
inline SNMALLOC_FAST_PATH void check_client_error(const char* const str)
|
|
{
|
|
//[[clang::musttail]]
|
|
return snmalloc::error(str);
|
|
}
|
|
|
|
inline SNMALLOC_FAST_PATH void
|
|
check_client_impl(bool test, const char* const str)
|
|
{
|
|
if (unlikely(!test))
|
|
check_client_error(str);
|
|
}
|
|
#ifdef SNMALLOC_CHECK_CLIENT
|
|
# define check_client(test, str) check_client_impl(test, str)
|
|
#else
|
|
# define check_client(test, str)
|
|
#endif
|
|
|
|
namespace snmalloc
|
|
{
|
|
#ifdef SNMALLOC_CHECK_CLIENT
|
|
static constexpr bool CHECK_CLIENT = true;
|
|
#else
|
|
static constexpr bool CHECK_CLIENT = false;
|
|
#endif
|
|
} // namespace snmalloc
|