239 lines
9.1 KiB
C++
239 lines
9.1 KiB
C++
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// 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
|
|
|
|
#include <cstdint>
|
|
|
|
#define ARROW_EXPAND(x) x
|
|
#define ARROW_STRINGIFY(x) #x
|
|
#define ARROW_CONCAT(x, y) x##y
|
|
|
|
// From Google gutil
|
|
#ifndef ARROW_DISALLOW_COPY_AND_ASSIGN
|
|
# define ARROW_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
|
TypeName(const TypeName&) = delete; \
|
|
void operator=(const TypeName&) = delete
|
|
#endif
|
|
|
|
#ifndef ARROW_DEFAULT_MOVE_AND_ASSIGN
|
|
# define ARROW_DEFAULT_MOVE_AND_ASSIGN(TypeName) \
|
|
TypeName(TypeName&&) = default; \
|
|
TypeName& operator=(TypeName&&) = default
|
|
#endif
|
|
|
|
// With ARROW_PREDICT_FALSE, GCC and clang can be told that a certain branch is
|
|
// not likely to be taken (for instance, a CHECK failure), and use that information in
|
|
// static analysis. Giving the compiler this information can affect the generated code
|
|
// layout in the absence of better information (i.e. -fprofile-arcs). [1] explains how
|
|
// this feature can be used to improve code generation. It was written as a positive
|
|
// comment to a negative article about the use of these annotations.
|
|
//
|
|
// ARROW_COMPILER_ASSUME allows the compiler to assume that a given expression is
|
|
// true, without evaluating it, and to optimise based on this assumption [2]. If this
|
|
// condition is violated at runtime, the behavior is undefined. This can be useful to
|
|
// generate both faster and smaller code in compute kernels.
|
|
//
|
|
// IMPORTANT: Different optimisers are likely to react differently to this annotation!
|
|
// It should be used with care when we can prove by some means that the assumption
|
|
// is (1) guaranteed to always hold and (2) is useful for optimization [3]. If the
|
|
// assumption is pessimistic, it might even block the compiler from decisions that
|
|
// could lead to better code [4]. If you have a good intuition for what the compiler
|
|
// can do with assumptions [5], you can use this macro to guide it and end up with
|
|
// results you would only get with more complex code transformations.
|
|
// `clang -S -emit-llvm` can be used to check how the generated code changes with
|
|
// your specific use of this macro.
|
|
//
|
|
// [1] https://lobste.rs/s/uwgtkt/don_t_use_likely_unlikely_attributes#c_xi3wmc
|
|
// [2] "Portable assumptions"
|
|
// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1774r4.pdf
|
|
// [3] "Assertions Are Pessimistic, Assumptions Are Optimistic"
|
|
// https://blog.regehr.org/archives/1096
|
|
// [4] https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609
|
|
// [5] J. Doerfert et al. 2019. "Performance Exploration Through Optimistic Static
|
|
// Program Annotations". https://github.com/jdoerfert/PETOSPA/blob/master/ISC19.pdf
|
|
#define ARROW_UNUSED(x) (void)(x)
|
|
#ifdef ARROW_WARN_DOCUMENTATION
|
|
# define ARROW_ARG_UNUSED(x) x
|
|
#else
|
|
# define ARROW_ARG_UNUSED(x)
|
|
#endif
|
|
#if defined(__GNUC__) // GCC and compatible compilers (clang, Intel ICC)
|
|
# define ARROW_NORETURN __attribute__((noreturn))
|
|
# define ARROW_NOINLINE __attribute__((noinline))
|
|
# define ARROW_FORCE_INLINE __attribute__((always_inline))
|
|
# define ARROW_PREDICT_FALSE(x) (__builtin_expect(!!(x), 0))
|
|
# define ARROW_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
|
|
# define ARROW_RESTRICT __restrict
|
|
# if defined(__clang__) // clang-specific
|
|
# define ARROW_COMPILER_ASSUME(expr) __builtin_assume(expr)
|
|
# else // GCC-specific
|
|
# if __GNUC__ >= 13
|
|
# define ARROW_COMPILER_ASSUME(expr) __attribute__((assume(expr)))
|
|
# else
|
|
// GCC does not have a built-in assume intrinsic before GCC 13, so we use an
|
|
// if statement and __builtin_unreachable() to achieve the same effect [2].
|
|
// Unlike clang's __builtin_assume and C++23's [[assume(expr)]], using this
|
|
// on GCC won't warn about side-effects in the expression, so make sure expr
|
|
// is side-effect free when working with GCC versions before 13 (Jan-2024),
|
|
// otherwise clang/MSVC builds will fail in CI.
|
|
# define ARROW_COMPILER_ASSUME(expr) \
|
|
if (expr) { \
|
|
} else { \
|
|
__builtin_unreachable(); \
|
|
}
|
|
# endif // __GNUC__ >= 13
|
|
# endif
|
|
#elif defined(_MSC_VER) // MSVC
|
|
# define ARROW_NORETURN __declspec(noreturn)
|
|
# define ARROW_NOINLINE __declspec(noinline)
|
|
# define ARROW_FORCE_INLINE __forceinline
|
|
# define ARROW_PREDICT_FALSE(x) (x)
|
|
# define ARROW_PREDICT_TRUE(x) (x)
|
|
# define ARROW_RESTRICT __restrict
|
|
# define ARROW_COMPILER_ASSUME(expr) __assume(expr)
|
|
#else
|
|
# define ARROW_NORETURN
|
|
# define ARROW_NOINLINE
|
|
# define ARROW_FORCE_INLINE
|
|
# define ARROW_PREDICT_FALSE(x) (x)
|
|
# define ARROW_PREDICT_TRUE(x) (x)
|
|
# define ARROW_RESTRICT
|
|
# define ARROW_COMPILER_ASSUME(expr)
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------
|
|
// C++/CLI support macros (see ARROW-1134)
|
|
|
|
#ifndef NULLPTR
|
|
|
|
# ifdef __cplusplus_cli
|
|
# define NULLPTR __nullptr
|
|
# else
|
|
# define NULLPTR nullptr
|
|
# endif
|
|
|
|
#endif // ifndef NULLPTR
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
// clang-format off
|
|
// [[deprecated]] is only available in C++14, use this for the time being
|
|
// This macro takes an optional deprecation message
|
|
#ifdef __COVERITY__
|
|
# define ARROW_DEPRECATED(...)
|
|
#else
|
|
# define ARROW_DEPRECATED(...) [[deprecated(__VA_ARGS__)]]
|
|
#endif
|
|
|
|
#ifdef __COVERITY__
|
|
# define ARROW_DEPRECATED_ENUM_VALUE(...)
|
|
#else
|
|
# define ARROW_DEPRECATED_ENUM_VALUE(...) [[deprecated(__VA_ARGS__)]]
|
|
#endif
|
|
|
|
// clang-format on
|
|
|
|
// Macros to disable deprecation warnings
|
|
|
|
#ifdef __clang__
|
|
# define ARROW_SUPPRESS_DEPRECATION_WARNING \
|
|
_Pragma("clang diagnostic push"); \
|
|
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
|
|
# define ARROW_UNSUPPRESS_DEPRECATION_WARNING _Pragma("clang diagnostic pop")
|
|
#elif defined(__GNUC__)
|
|
# define ARROW_SUPPRESS_DEPRECATION_WARNING \
|
|
_Pragma("GCC diagnostic push"); \
|
|
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
|
|
# define ARROW_UNSUPPRESS_DEPRECATION_WARNING _Pragma("GCC diagnostic pop")
|
|
#elif defined(_MSC_VER)
|
|
# define ARROW_SUPPRESS_DEPRECATION_WARNING \
|
|
__pragma(warning(push)) __pragma(warning(disable : 4996))
|
|
# define ARROW_UNSUPPRESS_DEPRECATION_WARNING __pragma(warning(pop))
|
|
#else
|
|
# define ARROW_SUPPRESS_DEPRECATION_WARNING
|
|
# define ARROW_UNSUPPRESS_DEPRECATION_WARNING
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
// macros to disable padding
|
|
// these macros are portable across different compilers and platforms
|
|
//[https://github.com/google/flatbuffers/blob/master/include/flatbuffers/flatbuffers.h#L1355]
|
|
#if !defined(MANUALLY_ALIGNED_STRUCT)
|
|
# if defined(_MSC_VER)
|
|
# define MANUALLY_ALIGNED_STRUCT(alignment) \
|
|
__pragma(pack(1)); \
|
|
struct __declspec(align(alignment))
|
|
# define STRUCT_END(name, size) \
|
|
__pragma(pack()); \
|
|
static_assert(sizeof(name) == size, "compiler breaks packing rules")
|
|
# elif defined(__GNUC__) || defined(__clang__)
|
|
# define MANUALLY_ALIGNED_STRUCT(alignment) \
|
|
_Pragma("pack(1)") struct __attribute__((aligned(alignment)))
|
|
# define STRUCT_END(name, size) \
|
|
_Pragma("pack()") static_assert(sizeof(name) == size, \
|
|
"compiler breaks packing rules")
|
|
# else
|
|
# error Unknown compiler, please define structure alignment macros
|
|
# endif
|
|
#endif // !defined(MANUALLY_ALIGNED_STRUCT)
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Convenience macro disabling a particular UBSan check in a function
|
|
|
|
#if defined(__clang__)
|
|
# define ARROW_DISABLE_UBSAN(feature) __attribute__((no_sanitize(feature)))
|
|
#else
|
|
# define ARROW_DISABLE_UBSAN(feature)
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Machine information
|
|
|
|
#if INTPTR_MAX == INT64_MAX
|
|
# define ARROW_BITNESS 64
|
|
#elif INTPTR_MAX == INT32_MAX
|
|
# define ARROW_BITNESS 32
|
|
#else
|
|
# error Unexpected INTPTR_MAX
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------
|
|
// From googletest
|
|
// (also in parquet-cpp)
|
|
|
|
// When you need to test the private or protected members of a class,
|
|
// use the FRIEND_TEST macro to declare your tests as friends of the
|
|
// class. For example:
|
|
//
|
|
// class MyClass {
|
|
// private:
|
|
// void MyMethod();
|
|
// FRIEND_TEST(MyClassTest, MyMethod);
|
|
// };
|
|
//
|
|
// class MyClassTest : public testing::Test {
|
|
// // ...
|
|
// };
|
|
//
|
|
// TEST_F(MyClassTest, MyMethod) {
|
|
// // Can call MyClass::MyMethod() here.
|
|
// }
|
|
|
|
#define FRIEND_TEST(test_case_name, test_name) \
|
|
friend class test_case_name##_##test_name##_Test
|