forked from laurynas-biveinis/unodb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathportability_builtins.hpp
110 lines (99 loc) · 3.44 KB
/
portability_builtins.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// Copyright 2022-2025 UnoDB contributors
#ifndef UNODB_DETAIL_PORTABILITY_BUILTINS_HPP
#define UNODB_DETAIL_PORTABILITY_BUILTINS_HPP
/// \file
/// Definitions to abstract differences between different compiler builtins and
/// intrinsics.
/// \ingroup internal
// Should be the first include
#include "global.hpp" // IWYU pragma: keep
#include <cstdint>
#include <type_traits>
#ifdef UNODB_DETAIL_MSVC
#include <intrin.h>
#endif
namespace unodb::detail {
/// Reverse the order of bytes in \a x.
template <typename T>
T bswap(T x) {
#ifdef UNODB_DETAIL_MSVC
static_assert(sizeof(std::uint32_t) ==
sizeof(unsigned long)); // NOLINT(runtime/int)
static_assert(std::is_same_v<unsigned short, T> || // NOLINT(runtime/int)
std::is_same_v<std::uint32_t, T> ||
std::is_same_v<std::uint64_t, T>);
if constexpr (std::is_same_v<unsigned short, T>) { // NOLINT(runtime/int)
return _byteswap_ushort(x);
}
if constexpr (std::is_same_v<std::uint32_t, T>) {
return _byteswap_ulong(x);
}
if constexpr (std::is_same_v<std::uint64_t, T>) {
return _byteswap_uint64(x);
}
#else // UNODB_DETAIL_MSVC
static_assert(std::is_same_v<std::uint16_t, T> ||
std::is_same_v<std::uint32_t, T> ||
std::is_same_v<std::uint64_t, T>);
if constexpr (std::is_same_v<std::uint16_t, T>) {
return __builtin_bswap16(x);
}
if constexpr (std::is_same_v<std::uint32_t, T>) {
return __builtin_bswap32(x);
}
if constexpr (std::is_same_v<std::uint64_t, T>) {
return __builtin_bswap64(x);
} // cppcheck-suppress missingReturn
#endif // UNODB_DETAIL_MSVC
}
/// Return the number of trailing zero bits in \a x.
/// \pre Argument may not be zero
template <typename T>
[[nodiscard, gnu::pure]] UNODB_DETAIL_CONSTEXPR_NOT_MSVC std::uint8_t ctz(
T x) noexcept {
static_assert(std::is_same_v<unsigned, T> ||
// NOLINTNEXTLINE(google-runtime-int)
std::is_same_v<unsigned long, T> || // NOLINT(runtime/int)
// NOLINTNEXTLINE(google-runtime-int)
std::is_same_v<unsigned long long, T>); // NOLINT(runtime/int)
if constexpr (std::is_same_v<unsigned, T>) {
#ifndef UNODB_DETAIL_MSVC
return static_cast<std::uint8_t>(__builtin_ctz(x));
#else
unsigned long result; // NOLINT(runtime/int)
_BitScanForward(&result, x);
return static_cast<std::uint8_t>(result);
#endif
}
// NOLINTNEXTLINE(google-runtime-int)
if constexpr (std::is_same_v<unsigned long, T>) { // NOLINT(runtime/int)
#ifndef UNODB_DETAIL_MSVC
return static_cast<std::uint8_t>(__builtin_ctzl(x));
#else
unsigned long result; // NOLINT(runtime/int)
_BitScanForward(&result, x);
return static_cast<std::uint8_t>(result);
#endif
}
// NOLINTNEXTLINE(google-runtime-int)
if constexpr (std::is_same_v<unsigned long long, T>) { // NOLINT(runtime/int)
#ifndef UNODB_DETAIL_MSVC
return static_cast<std::uint8_t>(__builtin_ctzll(x));
#else
unsigned long result; // NOLINT(runtime/int)
_BitScanForward64(&result, x);
return static_cast<std::uint8_t>(result);
#endif
} // cppcheck-suppress missingReturn
}
/// Return the number of one bits in \a x.
[[nodiscard, gnu::pure]] UNODB_DETAIL_CONSTEXPR_NOT_MSVC unsigned popcount(
unsigned x) noexcept {
#ifndef UNODB_DETAIL_MSVC
return static_cast<unsigned>(__builtin_popcount(x));
#else
return static_cast<unsigned>(__popcnt(x));
#endif
}
} // namespace unodb::detail
#endif