2025-01-12 19:51:34 +08:00

257 lines
8.6 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License Version 2.0 with LLVM Exceptions
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://llvm.org/LICENSE.txt
*
* 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.
*/
#pragma once
// Get the library feature test macros:
#if __has_include(<version>)
# include <version>
#elif __has_include(<ciso646>)
# include <ciso646>
#endif
#include <cassert>
// the configured options and settings for unifex
#define UNIFEX_VERSION_MAJOR 0
#define UNIFEX_VERSION_MINOR 1
#define UNIFEX_NO_MEMORY_RESOURCE 0
#define UNIFEX_MEMORY_RESOURCE_HEADER <memory_resource>
#define UNIFEX_MEMORY_RESOURCE_NAMESPACE std::pmr
#if !defined(__has_cpp_attribute)
#define UNIFEX_NO_UNIQUE_ADDRESS
#elif !__has_cpp_attribute(no_unique_address)
#define UNIFEX_NO_UNIQUE_ADDRESS
// prior to clang-10, [[no_unique_address]] leads to bad codegen
#elif defined(__clang__) && __clang_major__ < 10
#define UNIFEX_NO_UNIQUE_ADDRESS
// GCC 10.3/11 introduced bug 98995, which fails to compile with no_uniq_addr.
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98995
// For simplicity, assume anything above 9 is broken.
#elif !defined(__clang__) && defined(__GNUC__) && (__GNUC__ > 9)
#define UNIFEX_NO_UNIQUE_ADDRESS
#else
#define UNIFEX_NO_UNIQUE_ADDRESS [[no_unique_address]]
#endif
#if !defined(UNIFEX_NO_COROUTINES)
# if defined(__cpp_impl_coroutine) || defined(__cpp_coroutines)
# define UNIFEX_NO_COROUTINES 0
# else
# define UNIFEX_NO_COROUTINES 1
# endif
#endif
#if !UNIFEX_NO_COROUTINES
# if __has_include(<coroutine>) && defined(__cpp_lib_coroutine)
# define UNIFEX_COROUTINES_HEADER <coroutine>
# define UNIFEX_COROUTINES_NAMESPACE std
# elif __has_include(<experimental/coroutine>) && \
!(defined(_MSC_VER) && defined(__clang__)) // clang-cl.exe
# define UNIFEX_COROUTINES_HEADER <experimental/coroutine>
# define UNIFEX_COROUTINES_NAMESPACE std::experimental
# else
# undef UNIFEX_NO_COROUTINES
# define UNIFEX_NO_COROUTINES 1
# endif
#endif
#if !defined(UNIFEX_NO_EPOLL)
# if defined(__ANDROID_API__) && __ANDROID_API__ < 19
// Android makes timerfd_create and friend available as of API version 19;
// before that, the epoll API exists but it's insufficient for our purposes.
// https://android.googlesource.com/platform/bionic/+/master/libc/include/sys/timerfd.h#56
# define UNIFEX_NO_EPOLL 1
# endif
#endif
#if !defined(UNIFEX_NO_EPOLL)
#define UNIFEX_NO_EPOLL 1
#endif
#if !defined(UNIFEX_NO_LIBURING)
#define UNIFEX_NO_LIBURING 1
#endif
// UNIFEX_DECLARE_NON_DEDUCED_TYPE(type)
// UNIFEX_USE_NON_DEDUCED_TYPE(type)
//
// These macros work around a bug in MSVC that causes it to try to specialize
// all found function templates for which it can successfully deduce template
// arguments even if there are parameters that do not participate in template
// parameter deduction for which there is no conversion possible from the argument.
//
// This is most likely related to the core issue CWG1391 [*] which MSVC has not
// yet implemented as of VS 2019.4.
//
// These macros are intended to be used in template functions, typically tag_invoke()
// overloads, as follows.
//
// Where you would normally write:
//
// class foo_sender {
// template<
// typename Receiver,
// std::enable_if_t<is_callable_v<tag_t<set_value>, Receiver, foo>, int> = 0>
// friend auto tag_invoke(tag_t<connect>, foo_sender&& s, Receiver&& r) -> foo_operation<Receiver> {
// return ...;
// }
// };
//
// You would instead write
//
// class foo_sender {
// template<
// typename Receiver,
// UNIFEX_DECLARE_NON_DEDUCED_TYPE(CPO, tag_t<connect>),
// UNIFEX_DECLARE_NON_DEDUCED_TYPE(S, foo_sender),
// std::enable_if_t<is_callable_v<tag_t<set_value>, Receiver, foo>, int> = 0?
// friend auto tag_invoke(
// UNIFEX_USE_NON_DEDUCED_TYPE(CPO, tag_t<connect>),
// UNIFEX_USE_NON_DEDUCED_TYPE(S, foo_sender)&& s,
// Receiver&& r) -> foo_operation<Receiver> {
// return ...;
// }
// };
#if defined(_MSC_VER)
# define UNIFEX_DECLARE_NON_DEDUCED_TYPE(NAME, ...) \
typename NAME = void, \
std::enable_if_t<std::is_same_v<NAME, __VA_ARGS__>, int> = 0
# define UNIFEX_USE_NON_DEDUCED_TYPE(NAME, ...) NAME
#else
# define UNIFEX_DECLARE_NON_DEDUCED_TYPE(NAME, ...) typename NAME = __VA_ARGS__
# define UNIFEX_USE_NON_DEDUCED_TYPE(NAME, ...) __VA_ARGS__
#endif
#if !defined(UNIFEX_CXX_CONCEPTS)
#ifdef UNIFEX_DOXYGEN_INVOKED
#define UNIFEX_CXX_CONCEPTS 201800L
#elif defined(__cpp_concepts) && __cpp_concepts > 0
#define UNIFEX_CXX_CONCEPTS __cpp_concepts
#else
#define UNIFEX_CXX_CONCEPTS 0L
#endif
#endif
#if __cpp_rtti >= 199711
# define UNIFEX_NO_RTTI 0
#else
# define UNIFEX_NO_RTTI 1
#endif
#if __cpp_exceptions >= 199711
# define UNIFEX_NO_EXCEPTIONS 0
# define UNIFEX_TRY try
# define UNIFEX_CATCH(...) catch (__VA_ARGS__)
# define UNIFEX_RETHROW() throw
#else
# define UNIFEX_NO_EXCEPTIONS 1
# define UNIFEX_TRY
# define UNIFEX_CATCH(...) if constexpr (true) {} else
# define UNIFEX_RETHROW() ((void)0)
#endif
#if defined(_MSC_VER) && !defined(__clang__)
#define UNIFEX_DIAGNOSTIC_PUSH __pragma(warning(push))
#define UNIFEX_DIAGNOSTIC_POP __pragma(warning(pop))
#define UNIFEX_DIAGNOSTIC_IGNORE_INIT_LIST_LIFETIME
#define UNIFEX_DIAGNOSTIC_IGNORE_FLOAT_EQUAL
#define UNIFEX_DIAGNOSTIC_IGNORE_CPP2A_COMPAT
#else // ^^^ defined(_MSC_VER) ^^^ / vvv !defined(_MSC_VER) vvv
#if defined(__GNUC__) || defined(__clang__)
#define UNIFEX_PRAGMA(X) _Pragma(#X)
#define UNIFEX_DIAGNOSTIC_PUSH UNIFEX_PRAGMA(GCC diagnostic push)
#define UNIFEX_DIAGNOSTIC_POP UNIFEX_PRAGMA(GCC diagnostic pop)
#define UNIFEX_DIAGNOSTIC_IGNORE_PRAGMAS \
UNIFEX_PRAGMA(GCC diagnostic ignored "-Wpragmas")
#define UNIFEX_DIAGNOSTIC_IGNORE(X) \
UNIFEX_DIAGNOSTIC_IGNORE_PRAGMAS \
UNIFEX_PRAGMA(GCC diagnostic ignored "-Wunknown-pragmas") \
UNIFEX_PRAGMA(GCC diagnostic ignored X)
#define UNIFEX_DIAGNOSTIC_IGNORE_INIT_LIST_LIFETIME \
UNIFEX_DIAGNOSTIC_IGNORE("-Wunknown-warning-option") \
UNIFEX_DIAGNOSTIC_IGNORE("-Winit-list-lifetime")
#define UNIFEX_DIAGNOSTIC_IGNORE_FLOAT_EQUAL \
UNIFEX_DIAGNOSTIC_IGNORE("-Wfloat-equal")
#define UNIFEX_DIAGNOSTIC_IGNORE_CPP2A_COMPAT \
UNIFEX_DIAGNOSTIC_IGNORE("-Wc++2a-compat")
#else
#define UNIFEX_DIAGNOSTIC_PUSH
#define UNIFEX_DIAGNOSTIC_POP
#define UNIFEX_DIAGNOSTIC_IGNORE_INIT_LIST_LIFETIME
#define UNIFEX_DIAGNOSTIC_IGNORE_FLOAT_EQUAL
#define UNIFEX_DIAGNOSTIC_IGNORE_CPP2A_COMPAT
#endif
#endif // MSVC/Generic configuration switch
#if defined(__GNUC__) || defined(__clang__)
#define UNIFEX_ALWAYS_INLINE \
__attribute__((__always_inline__)) __attribute__((__visibility__("hidden"))) inline
#elif defined(_MSC_VER)
#define UNIFEX_ALWAYS_INLINE __forceinline
#else
#define UNIFEX_ALWAYS_INLINE inline
#endif
#if defined(__GNUC__) || defined(__clang__)
#define UNIFEX_NO_INLINE __attribute__((__noinline__))
#elif defined(_MSC_VER)
#define UNIFEX_NO_INLINE __declspec(noinline)
#else
#define UNIFEX_NO_INLINE
#endif
#if defined(__GNUC__) || defined(__clang__)
#define UNIFEX_ASSUME_UNREACHABLE __builtin_unreachable()
#elif defined(_MSC_VER)
#define UNIFEX_ASSUME_UNREACHABLE __assume(0)
#else
#define UNIFEX_ASSUME_UNREACHABLE std::terminate()
#endif
#ifndef UNIFEX_ASSERT
# define UNIFEX_ASSERT assert
#endif
#if defined(__clang__)
// Clang's optimizer interacts badly with its address sanitizer. Certain
// functions must have optimizations disabled in order to avoid triggering
// stack-use-after-scope-exit errors.
#if __has_feature(address_sanitizer)
#define UNIFEX_CLANG_DISABLE_OPTIMIZATION __attribute__((__optnone__))
#else
#define UNIFEX_CLANG_DISABLE_OPTIMIZATION
#endif
#else
#define UNIFEX_CLANG_DISABLE_OPTIMIZATION
#endif
#if !defined(UNIFEX_DEPRECATED_HEADER)
#ifdef __GNUC__
#define UNIFEX_PRAGMA(X) _Pragma(#X)
#define UNIFEX_DEPRECATED_HEADER(MSG) UNIFEX_PRAGMA(GCC warning MSG)
#elif defined(_MSC_VER)
#define UNIFEX_STRINGIZE_(MSG) #MSG
#define UNIFEX_STRINGIZE(MSG) UNIFEX_STRINGIZE_(MSG)
#define UNIFEX_DEPRECATED_HEADER(MSG) \
__pragma(message(__FILE__ "(" UNIFEX_STRINGIZE(__LINE__) ") : Warning: " MSG))
#endif
#else
#define UNIFEX_DEPRECATED_HEADER(MSG) /**/
#endif