-
-
Save jimwwalker/d62677965feb347f50c4c11bddc7ab6f to your computer and use it in GitHub Desktop.
Reproducer for gcc 10 template issue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <algorithm> | |
#include <atomic> | |
#include <chrono> | |
#include <cmath> | |
#include <condition_variable> | |
#include <cstddef> | |
#include <cstring> | |
#include <iostream> | |
#include <limits> | |
#include <map> | |
#include <memory> | |
#include <mutex> | |
#include <new> | |
#include <sstream> | |
#include <string_view> | |
#include <thread> | |
#include <type_traits> | |
#include <vector> | |
#include <arpa/inet.h> | |
#include <assert.h> | |
#include <netinet/in.h> | |
#include <netinet/ip.h> | |
#include <poll.h> | |
#include <sys/resource.h> | |
#include <sys/socket.h> | |
#include <sys/time.h> | |
#include <unistd.h> | |
// # 1 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/dcp/producer.cc" | |
// # 1 "/home/couchbase/couchbase//" | |
// # 1 "<built-in>" | |
// # 1 "<command-line>" | |
// # 1 "<command-line>" 2 | |
// # 1 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/dcp/producer.cc" | |
// # 12 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/dcp/producer.cc" | |
// # 1 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/dcp/producer.h" 1 | |
// # 11 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/dcp/producer.h" | |
// # 1 "/mnt/Code/couchbase/docker/kv_engine/include/memcached/vbucket.h" 1 | |
// # 12 "/mnt/Code/couchbase/docker/kv_engine/include/memcached/vbucket.h" | |
// # 1 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" 1 | |
// # 17 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
// # 1 "/mnt/Code/couchbase/docker/platform/include/platform/platform_socket.h" | |
// 1 # 14 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/platform_socket.h" | |
// # 1 "platform/include/platform/dynamic.h" 1 | |
// # 17 "/mnt/Code/couchbase/docker/platform/include/platform/platform_socket.h" | |
// 2 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/Sockets.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/Sockets.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Portability.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/Portability.h" 3 4 | |
static_assert(201703L >= 201402L, "__cplusplus >= 201402L"); | |
static_assert(10 >= 5, "__GNUC__ >= 5"); | |
// # 30 "tlm/deps/folly.exploded/include/folly/Portability.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/CPortability.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/CPortability.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/Config.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/Config.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/folly-config.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/folly-config.h" 3 4 | |
// # 21 "tlm/deps/folly.exploded/include/folly/portability/Config.h" 2 3 4 | |
// # 23 "tlm/deps/folly.exploded/include/folly/CPortability.h" 2 3 4 | |
// # 32 "tlm/deps/folly.exploded/include/folly/Portability.h" 2 3 4 | |
namespace folly { | |
constexpr bool kHasUnalignedAccess = true; | |
} | |
// # 116 "tlm/deps/folly.exploded/include/folly/Portability.h" 3 4 | |
namespace folly { | |
constexpr bool kIsArchArm = 0 == 1; | |
constexpr bool kIsArchAmd64 = 1 == 1; | |
constexpr bool kIsArchAArch64 = 0 == 1; | |
constexpr bool kIsArchPPC64 = 0 == 1; | |
constexpr bool kIsArchS390X = 0 == 1; | |
} // namespace folly | |
namespace folly { | |
// # 135 "tlm/deps/folly.exploded/include/folly/Portability.h" 3 4 | |
constexpr bool kIsLibrarySanitizeAddress = false; | |
constexpr bool kIsSanitizeAddress = false; | |
constexpr bool kIsSanitizeThread = false; | |
constexpr bool kIsSanitize = false; | |
} // namespace folly | |
// # 305 "tlm/deps/folly.exploded/include/folly/Portability.h" 3 4 | |
namespace folly { | |
constexpr auto kIsDebug = true; | |
} | |
namespace folly { | |
constexpr auto kHasExceptions = true; | |
} | |
namespace folly { | |
// # 332 "tlm/deps/folly.exploded/include/folly/Portability.h" 3 4 | |
constexpr auto kIsLittleEndian = 1234 == 1234; | |
constexpr auto kIsBigEndian = !kIsLittleEndian; | |
} // namespace folly | |
// # 399 "tlm/deps/folly.exploded/include/folly/Portability.h" 3 4 | |
namespace folly { | |
constexpr bool const kHasRtti = 1; | |
} | |
// # 412 "tlm/deps/folly.exploded/include/folly/Portability.h" 3 4 | |
namespace folly { | |
constexpr auto kIsObjC = false; | |
constexpr auto kIsMobile = false; | |
constexpr auto kIsLinux = true; | |
constexpr auto kIsWindows = false; | |
constexpr auto kIsGlibcxx = true; | |
constexpr auto kGlibcxxVer = 10; | |
constexpr auto kIsLibcpp = false; | |
constexpr auto kIsLibstdcpp = true; | |
constexpr auto kMscVer = 0; | |
constexpr auto kGnuc = 10; | |
constexpr auto kIsClang = false; | |
constexpr auto kMicrosoftAbiVer = 0; | |
constexpr auto kCpplibVer = 0; | |
} // namespace folly | |
// # 22 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/net/NetworkSocket.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/net/NetworkSocket.h" 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/net/NetworkSocket.h" 2 3 4 | |
// # 1 | |
// "tlm/deps/folly.exploded/include/folly/net/detail/SocketFileDescriptorMap.h" | |
// 1 3 4 # 17 | |
// "tlm/deps/folly.exploded/include/folly/net/detail/SocketFileDescriptorMap.h" | |
// 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/Windows.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/Windows.h" 3 4 | |
// # 20 | |
// "tlm/deps/folly.exploded/include/folly/net/detail/SocketFileDescriptorMap.h" | |
// 2 3 4 | |
// # 25 | |
// "tlm/deps/folly.exploded/include/folly/net/detail/SocketFileDescriptorMap.h" | |
// 2 3 4 | |
namespace folly { | |
namespace netops { | |
namespace detail { | |
struct SocketFileDescriptorMap { | |
static int close(int fd) noexcept { | |
return ::close(fd); | |
} | |
static int fdToSocket(int fd) noexcept { | |
return fd; | |
} | |
static int socketToFd(int sock) noexcept { | |
return sock; | |
} | |
}; | |
} // namespace detail | |
} // namespace netops | |
} // namespace folly | |
// # 22 "tlm/deps/folly.exploded/include/folly/net/NetworkSocket.h" 2 3 4 | |
namespace folly { | |
struct NetworkSocket { | |
using native_handle_type = int; | |
static constexpr native_handle_type invalid_handle_value = -1; | |
native_handle_type data; | |
constexpr NetworkSocket() : data(invalid_handle_value) { | |
} | |
constexpr explicit NetworkSocket(native_handle_type d) : data(d) { | |
} | |
template <typename T> | |
static NetworkSocket fromFd(T) = delete; | |
static NetworkSocket fromFd(int fd) { | |
return NetworkSocket( | |
netops::detail::SocketFileDescriptorMap::fdToSocket(fd)); | |
} | |
int toFd() const { | |
return netops::detail::SocketFileDescriptorMap::socketToFd(data); | |
} | |
friend constexpr bool operator==(const NetworkSocket& a, | |
const NetworkSocket& b) noexcept { | |
return a.data == b.data; | |
} | |
friend constexpr bool operator!=(const NetworkSocket& a, | |
const NetworkSocket& b) noexcept { | |
return !(a == b); | |
} | |
}; | |
template <class CharT, class Traits> | |
inline std::basic_ostream<CharT, Traits>& operator<<( | |
std::basic_ostream<CharT, Traits>& os, const NetworkSocket& addr) { | |
os << "folly::NetworkSocket(" << addr.data << ")"; | |
return os; | |
} | |
} // namespace folly | |
namespace std { | |
template <> | |
struct hash<folly::NetworkSocket> { | |
size_t operator()(const folly::NetworkSocket& s) const noexcept { | |
return std::hash<folly::NetworkSocket::native_handle_type>()(s.data); | |
} | |
}; | |
} // namespace std | |
// # 23 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/IOVec.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/IOVec.h" 3 4 | |
// # 23 "tlm/deps/folly.exploded/include/folly/portability/IOVec.h" 2 3 4 | |
// # 24 "tlm/deps/folly.exploded/include/folly/portability/IOVec.h" 2 3 4 | |
// # 24 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/SysTypes.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/SysTypes.h" 3 4 | |
// # 25 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/Time.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/Time.h" 3 4 | |
// # 26 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 2 3 4 | |
// # 30 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 2 3 4 | |
// # 31 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 2 3 4 | |
// # 33 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 2 3 4 | |
// # 35 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 2 3 4 | |
// # 36 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 2 3 4 | |
// # 38 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 2 3 4 | |
// # 43 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 2 3 4 | |
// # 156 "tlm/deps/folly.exploded/include/folly/net/NetOps.h" 3 4 | |
namespace folly { | |
namespace netops { | |
struct PollDescriptor { | |
NetworkSocket fd; | |
int16_t events; | |
int16_t revents; | |
}; | |
NetworkSocket accept(NetworkSocket s, sockaddr* addr, socklen_t* addrlen); | |
int bind(NetworkSocket s, const sockaddr* name, socklen_t namelen); | |
int close(NetworkSocket s); | |
int connect(NetworkSocket s, const sockaddr* name, socklen_t namelen); | |
int getpeername(NetworkSocket s, sockaddr* name, socklen_t* namelen); | |
int getsockname(NetworkSocket s, sockaddr* name, socklen_t* namelen); | |
int getsockopt(NetworkSocket s, | |
int level, | |
int optname, | |
void* optval, | |
socklen_t* optlen); | |
int inet_aton(const char* cp, in_addr* inp); | |
int listen(NetworkSocket s, int backlog); | |
int poll(PollDescriptor fds[], nfds_t nfds, int timeout); | |
ssize_t recv(NetworkSocket s, void* buf, size_t len, int flags); | |
ssize_t recvfrom(NetworkSocket s, | |
void* buf, | |
size_t len, | |
int flags, | |
sockaddr* from, | |
socklen_t* fromlen); | |
ssize_t recvmsg(NetworkSocket s, msghdr* message, int flags); | |
int recvmmsg(NetworkSocket s, | |
mmsghdr* msgvec, | |
unsigned int vlen, | |
unsigned int flags, | |
timespec* timeout); | |
ssize_t send(NetworkSocket s, const void* buf, size_t len, int flags); | |
ssize_t sendto(NetworkSocket s, | |
const void* buf, | |
size_t len, | |
int flags, | |
const sockaddr* to, | |
socklen_t tolen); | |
ssize_t sendmsg(NetworkSocket socket, const msghdr* message, int flags); | |
int sendmmsg(NetworkSocket socket, | |
mmsghdr* msgvec, | |
unsigned int vlen, | |
int flags); | |
int setsockopt(NetworkSocket s, | |
int level, | |
int optname, | |
const void* optval, | |
socklen_t optlen); | |
int shutdown(NetworkSocket s, int how); | |
NetworkSocket socket(int af, int type, int protocol); | |
int socketpair(int domain, int type, int protocol, NetworkSocket sv[2]); | |
int set_socket_non_blocking(NetworkSocket s); | |
int set_socket_close_on_exec(NetworkSocket s); | |
} // namespace netops | |
} // namespace folly | |
// # 20 "tlm/deps/folly.exploded/include/folly/portability/Sockets.h" 2 3 4 | |
namespace folly { | |
namespace portability { | |
namespace sockets { | |
using ::accept; | |
using ::bind; | |
using ::connect; | |
using ::getpeername; | |
using ::getsockname; | |
using ::getsockopt; | |
using ::inet_ntop; | |
using ::listen; | |
using ::poll; | |
using ::recv; | |
using ::recvfrom; | |
using ::send; | |
using ::sendmsg; | |
using ::sendto; | |
using ::setsockopt; | |
using ::shutdown; | |
using ::socket; | |
// # 143 "tlm/deps/folly.exploded/include/folly/portability/Sockets.h" 3 4 | |
} // namespace sockets | |
} // namespace portability | |
} // namespace folly | |
// # 19 "/mnt/Code/couchbase/docker/platform/include/platform/platform_socket.h" | |
// 2 | |
// # 21 "/mnt/Code/couchbase/docker/platform/include/platform/platform_socket.h" | |
extern "C" { | |
// # 38 "/mnt/Code/couchbase/docker/platform/include/platform/platform_socket.h" | |
} | |
// # 1 "tlm/deps/folly.exploded/include/folly/Bits.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/Bits.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 1 3 4 | |
// # 54 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 3 4 | |
// # 57 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 2 3 4 | |
// # 58 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 2 3 4 | |
// # 60 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 2 3 4 | |
// # 61 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/ConstexprMath.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/ConstexprMath.h" 3 4 | |
// # 21 "tlm/deps/folly.exploded/include/folly/ConstexprMath.h" 2 3 4 | |
namespace folly { | |
template <typename T> | |
constexpr T constexpr_max(T a) { | |
return a; | |
} | |
template <typename T, typename... Ts> | |
constexpr T constexpr_max(T a, T b, Ts... ts) { | |
return b < a ? constexpr_max(a, ts...) : constexpr_max(b, ts...); | |
} | |
template <typename T> | |
constexpr T constexpr_min(T a) { | |
return a; | |
} | |
template <typename T, typename... Ts> | |
constexpr T constexpr_min(T a, T b, Ts... ts) { | |
return b < a ? constexpr_min(b, ts...) : constexpr_min(a, ts...); | |
} | |
template <typename T, typename Less> | |
constexpr T const& constexpr_clamp(T const& v, | |
T const& lo, | |
T const& hi, | |
Less less) { | |
return less(v, lo) ? lo : less(hi, v) ? hi : v; | |
} | |
template <typename T> | |
constexpr T const& constexpr_clamp(T const& v, T const& lo, T const& hi) { | |
return constexpr_clamp(v, lo, hi, std::less<T>{}); | |
} | |
namespace detail { | |
template <typename T, typename = void> | |
struct constexpr_abs_helper {}; | |
template <typename T> | |
struct constexpr_abs_helper< | |
T, | |
typename std::enable_if<std::is_floating_point<T>::value>::type> { | |
static constexpr T go(T t) { | |
return t < static_cast<T>(0) ? -t : t; | |
} | |
}; | |
template <typename T> | |
struct constexpr_abs_helper< | |
T, | |
typename std::enable_if<std::is_integral<T>::value && | |
!std::is_same<T, bool>::value && | |
std::is_unsigned<T>::value>::type> { | |
static constexpr T go(T t) { | |
return t; | |
} | |
}; | |
template <typename T> | |
struct constexpr_abs_helper< | |
T, | |
typename std::enable_if<std::is_integral<T>::value && | |
!std::is_same<T, bool>::value && | |
std::is_signed<T>::value>::type> { | |
static constexpr typename std::make_unsigned<T>::type go(T t) { | |
return typename std::make_unsigned<T>::type(t < static_cast<T>(0) ? -t | |
: t); | |
} | |
}; | |
} // namespace detail | |
template <typename T> | |
constexpr auto constexpr_abs(T t) | |
-> decltype(detail::constexpr_abs_helper<T>::go(t)) { | |
return detail::constexpr_abs_helper<T>::go(t); | |
} | |
namespace detail { | |
template <typename T> | |
constexpr T constexpr_log2_(T a, T e) { | |
return e == T(1) ? a : constexpr_log2_(a + T(1), e / T(2)); | |
} | |
template <typename T> | |
constexpr T constexpr_log2_ceil_(T l2, T t) { | |
return l2 + T(T(1) << l2 < t ? 1 : 0); | |
} | |
template <typename T> | |
constexpr T constexpr_square_(T t) { | |
return t * t; | |
} | |
} // namespace detail | |
template <typename T> | |
constexpr T constexpr_log2(T t) { | |
return detail::constexpr_log2_(T(0), t); | |
} | |
template <typename T> | |
constexpr T constexpr_log2_ceil(T t) { | |
return detail::constexpr_log2_ceil_(constexpr_log2(t), t); | |
} | |
template <typename T> | |
constexpr T constexpr_ceil(T t, T round) { | |
return round == T(0) | |
? t | |
: ((t + (t < T(0) ? T(0) : round - T(1))) / round) * round; | |
} | |
template <typename T> | |
constexpr T constexpr_pow(T base, std::size_t exp) { | |
return exp == 0 ? T(1) | |
: exp == 1 ? base | |
: detail::constexpr_square_( | |
constexpr_pow(base, exp / 2)) * | |
(exp % 2 ? base : T(1)); | |
} | |
template <typename T> | |
constexpr std::size_t constexpr_find_last_set(T const t) { | |
using U = std::make_unsigned_t<T>; | |
return t == T(0) ? 0 : 1 + constexpr_log2(static_cast<U>(t)); | |
} | |
namespace detail { | |
template <typename U> | |
constexpr std::size_t constexpr_find_first_set_(std::size_t s, | |
std::size_t a, | |
U const u) { | |
return s == 0 ? a | |
: constexpr_find_first_set_( | |
s / 2, | |
a + s * bool((u >> a) % (U(1) << s) == U(0)), | |
u); | |
} | |
} // namespace detail | |
template <typename T> | |
constexpr std::size_t constexpr_find_first_set(T t) { | |
using U = std::make_unsigned_t<T>; | |
using size = std::integral_constant<std::size_t, sizeof(T) * 4>; | |
return t == T(0) ? 0 | |
: 1 + detail::constexpr_find_first_set_( | |
size{}, 0, static_cast<U>(t)); | |
} | |
template <typename T> | |
constexpr T constexpr_add_overflow_clamped(T a, T b) { | |
using L = std::numeric_limits<T>; | |
using M = std::intmax_t; | |
static_assert(!std::is_integral<T>::value || sizeof(T) <= sizeof(M), | |
"Integral type too large!"); | |
return | |
!std::is_integral<T>::value | |
? a + b | |
: | |
sizeof(T) < sizeof(M) | |
? T(constexpr_clamp( | |
M(a) + M(b), M(L::min()), M(L::max()))) | |
: | |
!(a < 0) ? a + constexpr_min(b, T(L::max() - a)) : | |
!(b < 0) ? a + b : | |
a + constexpr_max( | |
b, T(L::min() - a)); | |
} | |
template <typename T> | |
constexpr T constexpr_sub_overflow_clamped(T a, T b) { | |
using L = std::numeric_limits<T>; | |
using M = std::intmax_t; | |
static_assert(!std::is_integral<T>::value || sizeof(T) <= sizeof(M), | |
"Integral type too large!"); | |
return | |
!std::is_integral<T>::value | |
? a - b | |
: | |
std::is_unsigned<T>::value | |
? (a < b ? 0 : a - b) | |
: | |
sizeof(T) < sizeof(M) | |
? T(constexpr_clamp(M(a) - M(b), | |
M(L::min()), | |
M(L::max()))) | |
: | |
(a < 0) == (b < 0) | |
? a - b | |
: | |
L::min() < b | |
? constexpr_add_overflow_clamped( | |
a, T(-b)) | |
: | |
a < 0 ? a - b : | |
L::max(); | |
} | |
// # 263 "tlm/deps/folly.exploded/include/folly/ConstexprMath.h" 3 4 | |
template <typename Dst, typename Src> | |
constexpr typename std::enable_if<std::is_integral<Src>::value, Dst>::type | |
constexpr_clamp_cast(Src src) { | |
static_assert( | |
std::is_integral<Dst>::value && sizeof(Dst) <= sizeof(int64_t), | |
"constexpr_clamp_cast can only cast into integral type (up to " | |
"64bit)"); | |
using L = std::numeric_limits<Dst>; | |
return | |
std::is_signed<Src>::value == std::is_signed<Dst>::value | |
? ( | |
sizeof(Src) <= sizeof(Dst) | |
? Dst(src) | |
: | |
Dst(constexpr_clamp(src, | |
Src(L::min()), | |
Src(L::max())))) | |
: std::is_signed<Src>::value && std::is_unsigned<Dst>::value | |
? ( | |
src < 0 ? Dst(0) : | |
sizeof(Src) <= sizeof(Dst) | |
? Dst(src) | |
: | |
Dst(constexpr_min( | |
src, | |
Src(L::max())))) | |
: ( | |
sizeof(Src) < sizeof(Dst) | |
? Dst(src) | |
: | |
Dst(constexpr_min( | |
src, Src(L::max())))); | |
} | |
namespace detail { | |
constexpr double kClampCastLowerBoundDoubleToInt64F = -9223372036854774784.0; | |
constexpr double kClampCastUpperBoundDoubleToInt64F = 9223372036854774784.0; | |
constexpr double kClampCastUpperBoundDoubleToUInt64F = 18446744073709549568.0; | |
constexpr float kClampCastLowerBoundFloatToInt32F = -2147483520.0f; | |
constexpr float kClampCastUpperBoundFloatToInt32F = 2147483520.0f; | |
constexpr float kClampCastUpperBoundFloatToUInt32F = 4294967040.0f; | |
template <typename D, typename S> | |
constexpr D constexpr_clamp_cast_helper(S src, S sl, S su, D dl, D du) { | |
return src < sl ? dl : (src > su ? du : D(src)); | |
} | |
} // namespace detail | |
template <typename Dst, typename Src> | |
constexpr typename std::enable_if<std::is_floating_point<Src>::value, Dst>::type | |
constexpr_clamp_cast(Src src) { | |
static_assert( | |
std::is_integral<Dst>::value && sizeof(Dst) <= sizeof(int64_t), | |
"constexpr_clamp_cast can only cast into integral type (up to " | |
"64bit)"); | |
using L = std::numeric_limits<Dst>; | |
return | |
(src != src) | |
? Dst(0) | |
: | |
sizeof(Src) > sizeof(Dst) | |
? detail::constexpr_clamp_cast_helper(src, | |
Src(L::min()), | |
Src(L::max()), | |
L::min(), | |
L::max()) | |
: | |
sizeof(Src) < sizeof(Dst) | |
? (src >= 0.0 | |
? constexpr_clamp_cast<Dst>( | |
constexpr_clamp_cast< | |
std::uint64_t>( | |
double(src))) | |
: constexpr_clamp_cast<Dst>( | |
constexpr_clamp_cast< | |
std::int64_t>( | |
double(src)))) | |
: | |
std::is_same<Src, double>::value && | |
std::is_same<Dst, | |
int64_t>::value | |
? detail::constexpr_clamp_cast_helper( | |
double(src), | |
detail::kClampCastLowerBoundDoubleToInt64F, | |
detail::kClampCastUpperBoundDoubleToInt64F, | |
L::min(), | |
L::max()) | |
: std::is_same<Src, | |
double>::value && | |
std::is_same< | |
Dst, | |
uint64_t>:: | |
value | |
? detail::constexpr_clamp_cast_helper( | |
double(src), | |
0.0, | |
detail::kClampCastUpperBoundDoubleToUInt64F, | |
L::min(), | |
L::max()) | |
: std::is_same< | |
Src, | |
float>::value && | |
std::is_same< | |
Dst, | |
int32_t>:: | |
value | |
? detail::constexpr_clamp_cast_helper( | |
float(src), | |
detail::kClampCastLowerBoundFloatToInt32F, | |
detail::kClampCastUpperBoundFloatToInt32F, | |
L::min(), | |
L::max()) | |
: detail::constexpr_clamp_cast_helper( | |
float(src), | |
0.0f, | |
detail::kClampCastUpperBoundFloatToUInt32F, | |
L::min(), | |
L::max()); | |
} | |
} // namespace folly | |
// # 64 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Traits.h" 1 3 4 | |
// # 19 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
// # 24 "tlm/deps/folly.exploded/include/folly/Traits.h" 2 3 4 | |
// # 125 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
namespace folly { | |
template <typename...> | |
struct tag_t {}; | |
template <typename... T> | |
inline constexpr tag_t<T...> tag; | |
using std::bool_constant; | |
// # 149 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
template <std::size_t I> | |
using index_constant = std::integral_constant<std::size_t, I>; | |
namespace detail { | |
// # 162 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
template <template <typename...> class, typename> | |
struct is_instantiation_of : std::false_type {}; | |
template <template <typename...> class C, typename... T> | |
struct is_instantiation_of<C, C<T...>> : std::true_type {}; | |
template <template <typename...> class C, typename T> | |
constexpr bool is_instantiation_of_v = is_instantiation_of<C, T>::value; | |
} // namespace detail | |
namespace detail { | |
template <bool, typename T> | |
struct is_constexpr_default_constructible_; | |
template <typename T> | |
struct is_constexpr_default_constructible_<false, T> { | |
using type = std::false_type; | |
}; | |
template <typename T> | |
struct is_constexpr_default_constructible_<true, T> { | |
static constexpr int take(T) { | |
return 0; | |
} | |
template <int = take(T{})> | |
static std::true_type sfinae(int); | |
static std::false_type sfinae(...); | |
using type = decltype(sfinae(0)); | |
}; | |
} // namespace detail | |
// # 201 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
template <typename T> | |
struct is_constexpr_default_constructible | |
: detail::is_constexpr_default_constructible_< | |
std::is_default_constructible<T>::value, | |
T>::type {}; | |
template <typename T> | |
inline constexpr bool is_constexpr_default_constructible_v = | |
is_constexpr_default_constructible<T>::value; | |
// # 228 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
template <typename T> | |
using _t = typename T::type; | |
template <typename T> | |
struct remove_cvref { | |
using type = typename std::remove_cv< | |
typename std::remove_reference<T>::type>::type; | |
}; | |
template <typename T> | |
using remove_cvref_t = typename remove_cvref<T>::type; | |
namespace detail { | |
template <typename Src> | |
struct like_ { | |
template <typename Dst> | |
using apply = Dst; | |
}; | |
template <typename Src> | |
struct like_<Src const> { | |
template <typename Dst> | |
using apply = Dst const; | |
}; | |
template <typename Src> | |
struct like_<Src volatile> { | |
template <typename Dst> | |
using apply = Dst volatile; | |
}; | |
template <typename Src> | |
struct like_<Src const volatile> { | |
template <typename Dst> | |
using apply = Dst const volatile; | |
}; | |
template <typename Src> | |
struct like_<Src&> { | |
template <typename Dst> | |
using apply = typename like_<Src>::template apply<Dst>&; | |
}; | |
template <typename Src> | |
struct like_<Src&&> { | |
template <typename Dst> | |
using apply = typename like_<Src>::template apply<Dst>&&; | |
}; | |
} // namespace detail | |
template <typename Src, typename Dst> | |
using like_t = typename detail::like_<Src>::template apply<remove_cvref_t<Dst>>; | |
template <typename Src, typename Dst> | |
struct like { | |
using type = like_t<Src, Dst>; | |
}; | |
// # 350 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
namespace traits_detail { | |
template <class T, class...> | |
struct type_t_ { | |
using type = T; | |
}; | |
} // namespace traits_detail | |
template <class T, class... Ts> | |
using type_t = typename traits_detail::type_t_<T, Ts...>::type; | |
template <class... Ts> | |
using void_t = type_t<void, Ts...>; | |
template <typename T> | |
using aligned_storage_for_t = | |
typename std::aligned_storage<sizeof(T), alignof(T)>::type; | |
template <class T> | |
using is_trivially_copyable = std::is_trivially_copyable<T>; | |
template <class T> | |
inline constexpr bool is_trivially_copyable_v = is_trivially_copyable<T>::value; | |
// # 421 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
namespace traits_detail { | |
// # 433 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
template <typename TTheClass_> | |
struct has_IsRelocatable__folly_traits_impl__ { | |
template <typename UTheClass_> | |
static constexpr bool test(typename UTheClass_::IsRelocatable*) { | |
return true; | |
} | |
template <typename> | |
static constexpr bool test(...) { | |
return false; | |
} | |
}; | |
template <typename TTheClass_> | |
using has_IsRelocatable = typename std::conditional< | |
has_IsRelocatable__folly_traits_impl__<TTheClass_>::template test< | |
TTheClass_>(nullptr), | |
std::true_type, | |
std::false_type>::type; | |
template <class T> | |
struct IsRelocatable_is_true | |
: std::is_same<typename T::IsRelocatable, std::true_type> {}; | |
template <class T> | |
struct has_true_IsRelocatable : std::conditional<has_IsRelocatable<T>::value, | |
IsRelocatable_is_true<T>, | |
std::false_type>::type {}; | |
template <typename TTheClass_> | |
struct has_IsZeroInitializable__folly_traits_impl__ { | |
template <typename UTheClass_> | |
static constexpr bool test(typename UTheClass_::IsZeroInitializable*) { | |
return true; | |
} | |
template <typename> | |
static constexpr bool test(...) { | |
return false; | |
} | |
}; | |
template <typename TTheClass_> | |
using has_IsZeroInitializable = typename std::conditional< | |
has_IsZeroInitializable__folly_traits_impl__<TTheClass_>::template test< | |
TTheClass_>(nullptr), | |
std::true_type, | |
std::false_type>::type; | |
template <class T> | |
struct IsZeroInitializable_is_true | |
: std::is_same<typename T::IsZeroInitializable, std::true_type> {}; | |
template <class T> | |
struct has_true_IsZeroInitializable | |
: std::conditional<has_IsZeroInitializable<T>::value, | |
IsZeroInitializable_is_true<T>, | |
std::false_type>::type {}; | |
} // namespace traits_detail | |
struct Ignore { | |
Ignore() = default; | |
template <class T> | |
constexpr Ignore(const T&) { | |
} | |
template <class T> | |
const Ignore& operator=(T const&) const { | |
return *this; | |
} | |
}; | |
template <class...> | |
using Ignored = Ignore; | |
namespace traits_detail_IsEqualityComparable { | |
Ignore operator==(Ignore, Ignore); | |
template <class T, class U = T> | |
struct IsEqualityComparable | |
: std::is_convertible<decltype(std::declval<T>() == std::declval<U>()), | |
bool> {}; | |
} // namespace traits_detail_IsEqualityComparable | |
using traits_detail_IsEqualityComparable::IsEqualityComparable; | |
namespace traits_detail_IsLessThanComparable { | |
Ignore operator<(Ignore, Ignore); | |
template <class T, class U = T> | |
struct IsLessThanComparable | |
: std::is_convertible<decltype(std::declval<T>() < std::declval<U>()), | |
bool> {}; | |
} // namespace traits_detail_IsLessThanComparable | |
using traits_detail_IsLessThanComparable::IsLessThanComparable; | |
namespace traits_detail_IsNothrowSwappable { | |
template <typename T> | |
using IsNothrowSwappable = std::is_nothrow_swappable<T>; | |
// # 500 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
} // namespace traits_detail_IsNothrowSwappable | |
using traits_detail_IsNothrowSwappable::IsNothrowSwappable; | |
template <class T> | |
struct IsRelocatable | |
: std::conditional<traits_detail::has_IsRelocatable<T>::value, | |
traits_detail::has_true_IsRelocatable<T>, | |
is_trivially_copyable<T>>::type {}; | |
template <class T> | |
struct IsZeroInitializable | |
: std::conditional<traits_detail::has_IsZeroInitializable<T>::value, | |
traits_detail::has_true_IsZeroInitializable<T>, | |
bool_constant<!std::is_class<T>::value>>::type {}; | |
namespace detail { | |
template <bool> | |
struct conditional_; | |
template <> | |
struct conditional_<false> { | |
template <typename, typename T> | |
using apply = T; | |
}; | |
template <> | |
struct conditional_<true> { | |
template <typename T, typename> | |
using apply = T; | |
}; | |
} // namespace detail | |
// # 542 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
template <bool V, typename T, typename F> | |
using conditional_t = typename detail::conditional_<V>::template apply<T, F>; | |
template <typename...> | |
struct Conjunction : std::true_type {}; | |
template <typename T> | |
struct Conjunction<T> : T {}; | |
template <typename T, typename... TList> | |
struct Conjunction<T, TList...> | |
: std::conditional<T::value, Conjunction<TList...>, T>::type {}; | |
template <typename...> | |
struct Disjunction : std::false_type {}; | |
template <typename T> | |
struct Disjunction<T> : T {}; | |
template <typename T, typename... TList> | |
struct Disjunction<T, TList...> | |
: std::conditional<T::value, T, Disjunction<TList...>>::type {}; | |
template <typename T> | |
struct Negation : bool_constant<!T::value> {}; | |
template <bool... Bs> | |
struct Bools { | |
using valid_type = bool; | |
static constexpr std::size_t size() { | |
return sizeof...(Bs); | |
} | |
}; | |
template <class... Ts> | |
struct StrictConjunction | |
: std::is_same<Bools<Ts::value...>, Bools<(Ts::value || true)...>> {}; | |
template <class... Ts> | |
struct StrictDisjunction | |
: Negation<std::is_same<Bools<Ts::value...>, | |
Bools<(Ts::value && false)...>>> {}; | |
namespace detail { | |
template <typename, typename> | |
struct is_transparent_ : std::false_type {}; | |
template <typename T> | |
struct is_transparent_<void_t<typename T::is_transparent>, T> : std::true_type { | |
}; | |
} // namespace detail | |
template <typename T> | |
struct is_transparent : detail::is_transparent_<void, T> {}; | |
} // namespace folly | |
// # 670 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
namespace folly { | |
template <class T, class U> | |
struct IsRelocatable<std::pair<T, U>> | |
: bool_constant<IsRelocatable<T>::value && IsRelocatable<U>::value> {}; | |
template <typename T, typename... Ts> | |
using IsOneOf = StrictDisjunction<std::is_same<T, Ts>...>; | |
// # 692 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
template <typename T> | |
constexpr bool is_negative(T x) { | |
return std::is_signed<T>::value && x < T(0); | |
} | |
template <typename T> | |
constexpr bool is_non_positive(T x) { | |
return !x || folly::is_negative(x); | |
} | |
template <typename T> | |
constexpr bool is_positive(T x) { | |
return !is_non_positive(x); | |
} | |
template <typename T> | |
constexpr bool is_non_negative(T x) { | |
return !x || is_positive(x); | |
} | |
namespace detail { | |
// # 721 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
#pragma GCC diagnostic push | |
// # 721 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
// # 722 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
#pragma GCC diagnostic ignored "-Wsign-compare" | |
// # 722 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
// # 723 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
#pragma GCC diagnostic ignored "-Wbool-compare" | |
// # 723 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
template <typename RHS, RHS rhs, typename LHS> | |
bool less_than_impl(LHS const lhs) { | |
return | |
(!std::is_signed<RHS>::value && is_negative(lhs)) | |
? true | |
: (!std::is_signed<LHS>::value && is_negative(rhs)) | |
? false | |
: rhs > std::numeric_limits<LHS>::max() | |
? true | |
: rhs <= std::numeric_limits<LHS>::min() | |
? false | |
: lhs < rhs; | |
} | |
template <typename RHS, RHS rhs, typename LHS> | |
bool greater_than_impl(LHS const lhs) { | |
return | |
(!std::is_signed<RHS>::value && is_negative(lhs)) | |
? false | |
: (!std::is_signed<LHS>::value && is_negative(rhs)) | |
? true | |
: rhs > std::numeric_limits<LHS>::max() | |
? false | |
: rhs < std::numeric_limits<LHS>::min() | |
? true | |
: lhs > rhs; | |
} | |
// # 754 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
#pragma GCC diagnostic pop | |
// # 754 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
} // namespace detail | |
template <typename RHS, RHS rhs, typename LHS> | |
bool less_than(LHS const lhs) { | |
return detail:: | |
less_than_impl<RHS, rhs, typename std::remove_reference<LHS>::type>( | |
lhs); | |
} | |
template <typename RHS, RHS rhs, typename LHS> | |
bool greater_than(LHS const lhs) { | |
return detail::greater_than_impl<RHS, | |
rhs, | |
typename std::remove_reference<LHS>::type>( | |
lhs); | |
} | |
} // namespace folly | |
namespace folly { | |
template <class T1, class T2> | |
struct IsRelocatable<std::unique_ptr<T1, T2>> : std::true_type {}; | |
} // namespace folly | |
namespace folly { | |
template <class T1> | |
struct IsRelocatable<std::shared_ptr<T1>> : std::true_type {}; | |
} // namespace folly | |
// # 820 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
namespace folly { | |
// # 833 "tlm/deps/folly.exploded/include/folly/Traits.h" 3 4 | |
template <typename Container> | |
const Container& order_preserving_reinsertion_view(const Container& container) { | |
return container; | |
} | |
} // namespace folly | |
// # 66 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Utility.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
// # 28 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
namespace folly { | |
// # 72 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
template <typename T> | |
constexpr typename std::decay<T>::type copy(T&& value) noexcept( | |
noexcept(typename std::decay<T>::type(std::forward<T>(value)))) { | |
return std::forward<T>(value); | |
} | |
// # 92 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
using std::as_const; | |
// # 107 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
template <typename Src, typename Dst> | |
constexpr like_t<Src, Dst>&& forward_like(Dst&& dst) noexcept { | |
return static_cast<like_t<Src, Dst>&&>(std::forward<Dst>(dst)); | |
} | |
// # 122 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
struct in_place_tag {}; | |
template <class> | |
struct in_place_type_tag {}; | |
template <std::size_t> | |
struct in_place_index_tag {}; | |
using in_place_t = in_place_tag (&)(in_place_tag); | |
template <class T> | |
using in_place_type_t = in_place_type_tag<T> (&)(in_place_type_tag<T>); | |
template <std::size_t I> | |
using in_place_index_t = in_place_index_tag<I> (&)(in_place_index_tag<I>); | |
inline in_place_tag in_place(in_place_tag = {}) { | |
return {}; | |
} | |
template <class T> | |
inline in_place_type_tag<T> in_place_type(in_place_type_tag<T> = {}) { | |
return {}; | |
} | |
template <std::size_t I> | |
inline in_place_index_tag<I> in_place_index(in_place_index_tag<I> = {}) { | |
return {}; | |
} | |
// # 188 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
struct initlist_construct_t {}; | |
constexpr initlist_construct_t initlist_construct{}; | |
// # 212 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
struct sorted_unique_t {}; | |
constexpr sorted_unique_t sorted_unique; | |
// # 235 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
struct sorted_equivalent_t {}; | |
constexpr sorted_equivalent_t sorted_equivalent; | |
template <typename T> | |
struct transparent : T { | |
using is_transparent = void; | |
using T::T; | |
}; | |
// # 263 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
struct identity_fn { | |
template <class T> | |
constexpr T&& operator()(T&& x) const noexcept { | |
return static_cast<T&&>(x); | |
} | |
}; | |
using Identity = identity_fn; | |
inline constexpr identity_fn identity; | |
namespace moveonly_ { | |
class MoveOnly { | |
protected: | |
constexpr MoveOnly() = default; | |
~MoveOnly() = default; | |
MoveOnly(MoveOnly&&) = default; | |
MoveOnly& operator=(MoveOnly&&) = default; | |
MoveOnly(const MoveOnly&) = delete; | |
MoveOnly& operator=(const MoveOnly&) = delete; | |
}; | |
} // namespace moveonly_ | |
using MoveOnly = moveonly_::MoveOnly; | |
template <typename T> | |
constexpr auto to_signed(T const& t) -> typename std::make_signed<T>::type { | |
using S = typename std::make_signed<T>::type; | |
constexpr auto m = static_cast<T>(std::numeric_limits<S>::max()); | |
return m < t ? -static_cast<S>(~t) + S{-1} : static_cast<S>(t); | |
} | |
template <typename T> | |
constexpr auto to_unsigned(T const& t) -> typename std::make_unsigned<T>::type { | |
using U = typename std::make_unsigned<T>::type; | |
return static_cast<U>(t); | |
} | |
template <typename Src> | |
class to_narrow_convertible { | |
public: | |
static_assert(std::is_integral<Src>::value, "not an integer"); | |
explicit constexpr to_narrow_convertible(Src const& value) noexcept | |
: value_(value) { | |
} | |
explicit to_narrow_convertible(to_narrow_convertible const&) = default; | |
explicit to_narrow_convertible(to_narrow_convertible&&) = default; | |
to_narrow_convertible& operator=(to_narrow_convertible const&) = default; | |
to_narrow_convertible& operator=(to_narrow_convertible&&) = default; | |
template <typename Dst, | |
std::enable_if_t<std::is_integral<Dst>::value && | |
std::is_signed<Dst>::value == | |
std::is_signed<Src>::value, | |
int> = 0> | |
constexpr operator Dst() const noexcept { | |
// # 334 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
#pragma GCC diagnostic push | |
// # 334 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
// # 337 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
#pragma GCC diagnostic ignored "-Wconversion" | |
// # 337 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
return value_; | |
// # 339 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
#pragma GCC diagnostic pop | |
// # 339 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
} | |
private: | |
Src value_; | |
}; | |
// # 359 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
template <typename Src> | |
constexpr auto to_narrow(Src const& src) -> to_narrow_convertible<Src> { | |
return to_narrow_convertible<Src>{src}; | |
} | |
template <class E> | |
constexpr std::underlying_type_t<E> to_underlying(E e) noexcept { | |
static_assert(std::is_enum<E>::value, "not an enum type"); | |
return static_cast<std::underlying_type_t<E>>(e); | |
} | |
// # 403 "tlm/deps/folly.exploded/include/folly/Utility.h" 3 4 | |
} // namespace folly | |
// # 67 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/lang/Assume.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/lang/Assume.h" 3 4 | |
namespace folly { | |
// # 54 "tlm/deps/folly.exploded/include/folly/lang/Assume.h" 3 4 | |
inline __attribute__((__always_inline__)) void assume(bool cond); | |
// # 65 "tlm/deps/folly.exploded/include/folly/lang/Assume.h" 3 4 | |
[[noreturn]] inline __attribute__((__always_inline__)) void | |
assume_unreachable(); | |
} // namespace folly | |
// # 1 "tlm/deps/folly.exploded/include/folly/lang/Assume-inl.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/lang/Assume-inl.h" 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/lang/Assume-inl.h" 2 3 4 | |
namespace folly { | |
namespace detail { | |
extern void assume_check(bool cond); | |
} | |
inline __attribute__((__always_inline__)) void assume(bool cond) { | |
if (kIsDebug) { | |
detail::assume_check(cond); | |
} else { | |
if (!cond) { | |
__builtin_unreachable(); | |
} | |
} | |
} | |
[[noreturn]] inline __attribute__((__always_inline__)) void | |
assume_unreachable() { | |
assume(false); | |
__builtin_unreachable(); | |
} | |
} // namespace folly | |
// # 70 "tlm/deps/folly.exploded/include/folly/lang/Assume.h" 2 3 4 | |
// # 68 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/Builtins.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/Builtins.h" 3 4 | |
// # 69 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 2 3 4 | |
// # 72 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 2 3 4 | |
namespace folly { | |
// # 83 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 3 4 | |
template <typename To, | |
typename From, | |
std::enable_if_t<sizeof(From) == sizeof(To) && | |
is_trivially_copyable<To>::value && | |
is_trivially_copyable<From>::value, | |
int> = 0> | |
To bit_cast(const From& src) noexcept { | |
aligned_storage_for_t<To> storage; | |
std::memcpy(&storage, &src, sizeof(From)); | |
return reinterpret_cast<To&>(storage); | |
} | |
namespace detail { | |
template <typename Dst, typename Src> | |
constexpr std::make_signed_t<Dst> bits_to_signed(Src const s) { | |
static_assert(std::is_signed<Dst>::value, "unsigned type"); | |
return to_signed(static_cast<std::make_unsigned_t<Dst>>(to_unsigned(s))); | |
} | |
template <typename Dst, typename Src> | |
constexpr std::make_unsigned_t<Dst> bits_to_unsigned(Src const s) { | |
static_assert(std::is_unsigned<Dst>::value, "signed type"); | |
return static_cast<Dst>(to_unsigned(s)); | |
} | |
} // namespace detail | |
template <typename T> | |
inline constexpr unsigned int findFirstSet(T const v) { | |
using S0 = int; | |
using S1 = long int; | |
using S2 = long long int; | |
using detail::bits_to_signed; | |
static_assert(sizeof(T) <= sizeof(S2), "over-sized type"); | |
static_assert(std::is_integral<T>::value, "non-integral type"); | |
static_assert(!std::is_same<T, bool>::value, "bool type"); | |
return static_cast<unsigned int>( | |
sizeof(T) <= sizeof(S0) | |
? __builtin_ffs(bits_to_signed<S0>(v)) | |
: sizeof(T) <= sizeof(S1) | |
? __builtin_ffsl(bits_to_signed<S1>(v)) | |
: sizeof(T) <= sizeof(S2) | |
? __builtin_ffsll(bits_to_signed<S2>(v)) | |
: 0); | |
} | |
template <typename T> | |
inline constexpr unsigned int findLastSet(T const v) { | |
using U0 = unsigned int; | |
using U1 = unsigned long int; | |
using U2 = unsigned long long int; | |
using detail::bits_to_unsigned; | |
static_assert(sizeof(T) <= sizeof(U2), "over-sized type"); | |
static_assert(std::is_integral<T>::value, "non-integral type"); | |
static_assert(!std::is_same<T, bool>::value, "bool type"); | |
using size = index_constant<constexpr_max(sizeof(T), sizeof(U0))>; | |
return v ? 1u + static_cast<unsigned int>( | |
(8u * size{} - 1u) ^ | |
(sizeof(T) <= sizeof(U0) | |
? __builtin_clz(bits_to_unsigned<U0>(v)) | |
: sizeof(T) <= sizeof(U1) | |
? __builtin_clzl( | |
bits_to_unsigned<U1>( | |
v)) | |
: sizeof(T) <= sizeof(U2) | |
? __builtin_clzll( | |
bits_to_unsigned< | |
U2>( | |
v)) | |
: 0)) | |
: 0u; | |
} | |
template <typename T> | |
inline constexpr T extractFirstSet(T const v) { | |
static_assert(std::is_integral<T>::value, "non-integral type"); | |
static_assert(std::is_unsigned<T>::value, "signed type"); | |
static_assert(!std::is_same<T, bool>::value, "bool type"); | |
return v & -v; | |
} | |
template <typename T> | |
inline constexpr unsigned int popcount(T const v) { | |
using U0 = unsigned int; | |
using U1 = unsigned long int; | |
using U2 = unsigned long long int; | |
using detail::bits_to_unsigned; | |
static_assert(sizeof(T) <= sizeof(U2), "over-sized type"); | |
static_assert(std::is_integral<T>::value, "non-integral type"); | |
static_assert(!std::is_same<T, bool>::value, "bool type"); | |
return static_cast<unsigned int>( | |
sizeof(T) <= sizeof(U0) | |
? __builtin_popcount(bits_to_unsigned<U0>(v)) | |
: sizeof(T) <= sizeof(U1) | |
? __builtin_popcountl(bits_to_unsigned<U1>(v)) | |
: sizeof(T) <= sizeof(U2) | |
? __builtin_popcountll( | |
bits_to_unsigned<U2>(v)) | |
: 0); | |
} | |
template <class T> | |
inline constexpr T nextPowTwo(T const v) { | |
static_assert(std::is_unsigned<T>::value, "signed type"); | |
return v ? (T(1) << findLastSet(v - 1)) : T(1); | |
} | |
template <class T> | |
inline constexpr T prevPowTwo(T const v) { | |
static_assert(std::is_unsigned<T>::value, "signed type"); | |
return v ? (T(1) << (findLastSet(v) - 1)) : T(0); | |
} | |
template <class T> | |
inline constexpr bool isPowTwo(T const v) { | |
static_assert(std::is_integral<T>::value, "non-integral type"); | |
static_assert(std::is_unsigned<T>::value, "signed type"); | |
static_assert(!std::is_same<T, bool>::value, "bool type"); | |
return (v != 0) && !(v & (v - 1)); | |
} | |
template <class T> | |
inline constexpr T strictNextPowTwo(T const v) { | |
static_assert(std::is_unsigned<T>::value, "signed type"); | |
return nextPowTwo(T(v + 1)); | |
} | |
template <class T> | |
inline constexpr T strictPrevPowTwo(T const v) { | |
static_assert(std::is_unsigned<T>::value, "signed type"); | |
return v > 1 ? prevPowTwo(T(v - 1)) : T(0); | |
} | |
namespace detail { | |
template <size_t Size> | |
struct uint_types_by_size; | |
// # 243 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 3 4 | |
static inline uint8_t byteswap_gen(uint8_t v) { | |
return uint8_t(v); | |
} | |
template <> | |
struct uint_types_by_size<8 / 8> { | |
using type = uint8_t; | |
}; | |
static inline uint64_t byteswap_gen(uint64_t v) { | |
return __builtin_bswap64(v); | |
} | |
template <> | |
struct uint_types_by_size<64 / 8> { | |
using type = uint64_t; | |
}; | |
static inline uint32_t byteswap_gen(uint32_t v) { | |
return __builtin_bswap32(v); | |
} | |
template <> | |
struct uint_types_by_size<32 / 8> { | |
using type = uint32_t; | |
}; | |
static inline uint16_t byteswap_gen(uint16_t v) { | |
return __builtin_bswap16(v); | |
} | |
template <> | |
struct uint_types_by_size<16 / 8> { | |
using type = uint16_t; | |
}; | |
template <class T> | |
struct EndianInt { | |
static_assert((std::is_integral<T>::value && | |
!std::is_same<T, bool>::value) || | |
std::is_floating_point<T>::value, | |
"template type parameter must be non-bool integral or " | |
"floating point"); | |
static T swap(T x) { | |
constexpr auto s = sizeof(T); | |
using B = typename uint_types_by_size<s>::type; | |
return bit_cast<T>(byteswap_gen(bit_cast<B>(x))); | |
} | |
static T big(T x) { | |
return kIsLittleEndian ? EndianInt::swap(x) : x; | |
} | |
static T little(T x) { | |
return kIsBigEndian ? EndianInt::swap(x) : x; | |
} | |
}; | |
} // namespace detail | |
// # 299 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 3 4 | |
class Endian { | |
public: | |
enum class Order : uint8_t { | |
LITTLE, | |
BIG, | |
}; | |
static constexpr Order order = kIsLittleEndian ? Order::LITTLE : Order::BIG; | |
template <class T> | |
static T swap(T x) { | |
return folly::detail::EndianInt<T>::swap(x); | |
} | |
template <class T> | |
static T big(T x) { | |
return folly::detail::EndianInt<T>::big(x); | |
} | |
template <class T> | |
static T little(T x) { | |
return folly::detail::EndianInt<T>::little(x); | |
} | |
static uint64_t swap64(uint64_t x) { | |
return swap<uint64_t>(x); | |
} | |
static uint64_t big64(uint64_t x) { | |
return big<uint64_t>(x); | |
} | |
static uint64_t little64(uint64_t x) { | |
return little<uint64_t>(x); | |
} | |
static int64_t swap64(int64_t x) { | |
return swap<int64_t>(x); | |
} | |
static int64_t big64(int64_t x) { | |
return big<int64_t>(x); | |
} | |
static int64_t little64(int64_t x) { | |
return little<int64_t>(x); | |
} | |
static uint32_t swap32(uint32_t x) { | |
return swap<uint32_t>(x); | |
} | |
static uint32_t big32(uint32_t x) { | |
return big<uint32_t>(x); | |
} | |
static uint32_t little32(uint32_t x) { | |
return little<uint32_t>(x); | |
} | |
static int32_t swap32(int32_t x) { | |
return swap<int32_t>(x); | |
} | |
static int32_t big32(int32_t x) { | |
return big<int32_t>(x); | |
} | |
static int32_t little32(int32_t x) { | |
return little<int32_t>(x); | |
} | |
static uint16_t swap16(uint16_t x) { | |
return swap<uint16_t>(x); | |
} | |
static uint16_t big16(uint16_t x) { | |
return big<uint16_t>(x); | |
} | |
static uint16_t little16(uint16_t x) { | |
return little<uint16_t>(x); | |
} | |
static int16_t swap16(int16_t x) { | |
return swap<int16_t>(x); | |
} | |
static int16_t big16(int16_t x) { | |
return big<int16_t>(x); | |
} | |
static int16_t little16(int16_t x) { | |
return little<int16_t>(x); | |
} | |
static uint8_t swap8(uint8_t x) { | |
return swap<uint8_t>(x); | |
} | |
static uint8_t big8(uint8_t x) { | |
return big<uint8_t>(x); | |
} | |
static uint8_t little8(uint8_t x) { | |
return little<uint8_t>(x); | |
} | |
static int8_t swap8(int8_t x) { | |
return swap<int8_t>(x); | |
} | |
static int8_t big8(int8_t x) { | |
return big<int8_t>(x); | |
} | |
static int8_t little8(int8_t x) { | |
return little<int8_t>(x); | |
} | |
}; | |
template <class T, class Enable = void> | |
struct Unaligned; | |
// # 339 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 3 4 | |
#pragma GCC diagnostic push | |
// # 339 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 3 4 | |
template <class T> | |
struct Unaligned<T, typename std::enable_if<std::is_pod<T>::value>::type> { | |
Unaligned() = default; | |
Unaligned(T v) : value(v) { | |
} | |
T value; | |
} __attribute__((__packed__)); | |
// # 349 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 3 4 | |
#pragma GCC diagnostic pop | |
// # 349 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 3 4 | |
template <class T> | |
inline T loadUnaligned(const void* p) { | |
static_assert(sizeof(Unaligned<T>) == sizeof(T), "Invalid unaligned size"); | |
static_assert(alignof(Unaligned<T>) == 1, "Invalid alignment"); | |
if (kHasUnalignedAccess) { | |
return static_cast<const Unaligned<T>*>(p)->value; | |
} else { | |
T value; | |
memcpy(&value, p, sizeof(T)); | |
return value; | |
} | |
} | |
// # 374 "tlm/deps/folly.exploded/include/folly/lang/Bits.h" 3 4 | |
template <class T> | |
inline T partialLoadUnaligned(const void* p, size_t l) { | |
static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value && | |
sizeof(T) <= 8, | |
"Invalid type"); | |
assume(l < sizeof(T)); | |
auto cp = static_cast<const char*>(p); | |
T value = 0; | |
if (!kHasUnalignedAccess || !kIsLittleEndian) { | |
memcpy(&value, cp, l); | |
return value; | |
} | |
auto avail = l; | |
if (l & 4) { | |
avail -= 4; | |
value = static_cast<T>(loadUnaligned<uint32_t>(cp + avail)) | |
<< (avail * 8); | |
} | |
if (l & 2) { | |
avail -= 2; | |
value |= static_cast<T>(loadUnaligned<uint16_t>(cp + avail)) | |
<< (avail * 8); | |
} | |
if (l & 1) { | |
value |= loadUnaligned<uint8_t>(cp); | |
} | |
return value; | |
} | |
template <class T> | |
inline void storeUnaligned(void* p, T value) { | |
static_assert(sizeof(Unaligned<T>) == sizeof(T), "Invalid unaligned size"); | |
static_assert(alignof(Unaligned<T>) == 1, "Invalid alignment"); | |
if (kHasUnalignedAccess) { | |
assume(p != nullptr); | |
new (p) Unaligned<T>(value); | |
} else { | |
memcpy(p, &value, sizeof(T)); | |
} | |
} | |
template <typename T> | |
T bitReverse(T n) { | |
auto m = static_cast<typename std::make_unsigned<T>::type>(n); | |
m = ((m & 0xAAAAAAAAAAAAAAAA) >> 1) | ((m & 0x5555555555555555) << 1); | |
m = ((m & 0xCCCCCCCCCCCCCCCC) >> 2) | ((m & 0x3333333333333333) << 2); | |
m = ((m & 0xF0F0F0F0F0F0F0F0) >> 4) | ((m & 0x0F0F0F0F0F0F0F0F) << 4); | |
return static_cast<T>(Endian::swap(m)); | |
} | |
} // namespace folly | |
// # 18 "tlm/deps/folly.exploded/include/folly/Bits.h" 2 3 4 | |
// # 43 "/mnt/Code/couchbase/docker/platform/include/platform/platform_socket.h" | |
// 2 | |
// # 44 "/mnt/Code/couchbase/docker/platform/include/platform/platform_socket.h" | |
inline uint64_t ntohll(uint64_t x) { | |
return folly::Endian::big(x); | |
} | |
inline uint64_t htonll(uint64_t x) { | |
return folly::Endian::big(x); | |
} | |
// # 20 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" 2 | |
typedef int SOCKET; | |
// # 1 "tlm/deps/json.exploded/include/nlohmann/json_fwd.hpp" 1 3 4 | |
// # 6 "tlm/deps/json.exploded/include/nlohmann/json_fwd.hpp" 2 3 4 | |
// # 15 "tlm/deps/json.exploded/include/nlohmann/json_fwd.hpp" 3 4 | |
namespace nlohmann { | |
template <typename T = void, typename SFINAE = void> | |
struct adl_serializer; | |
template <template <typename U, typename V, typename... Args> class ObjectType = | |
std::map, | |
template <typename U, typename... Args> class ArrayType = std::vector, | |
class StringType = std::string, | |
class BooleanType = bool, | |
class NumberIntegerType = std::int64_t, | |
class NumberUnsignedType = std::uint64_t, | |
class NumberFloatType = double, | |
template <typename U> class AllocatorType = std::allocator, | |
template <typename T, typename SFINAE = void> class JSONSerializer = | |
adl_serializer> | |
class basic_json; | |
// # 50 "tlm/deps/json.exploded/include/nlohmann/json_fwd.hpp" 3 4 | |
template <typename BasicJsonType> | |
class json_pointer; | |
// # 61 "tlm/deps/json.exploded/include/nlohmann/json_fwd.hpp" 3 4 | |
using json = basic_json<>; | |
} // namespace nlohmann | |
// # 33 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" 2 | |
// # 34 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" 2 | |
// # 37 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
namespace cb::net { | |
int closesocket(SOCKET s); | |
int get_socket_error(); | |
int bind(SOCKET sock, const struct sockaddr* name, socklen_t namelen); | |
SOCKET accept(SOCKET sock, struct sockaddr* addr, socklen_t* addrlen); | |
int connect(SOCKET sock, const struct sockaddr* name, size_t namelen); | |
SOCKET socket(int domain, int type, int protocol); | |
int shutdown(SOCKET sock, int how); | |
ssize_t send(SOCKET sock, const void* buffer, size_t length, int flags); | |
ssize_t sendmsg(SOCKET sock, const struct msghdr* message, int flags); | |
ssize_t sendto(SOCKET sock, | |
const void* buffer, | |
size_t length, | |
int flags, | |
const struct sockaddr* dest_addr, | |
socklen_t dest_len); | |
ssize_t recv(SOCKET sock, void* buffer, size_t length, int flags); | |
ssize_t recvfrom(SOCKET sock, | |
void* buffer, | |
size_t length, | |
int flags, | |
struct sockaddr* address, | |
socklen_t* address_len); | |
ssize_t recvmsg(SOCKET sock, struct msghdr* message, int flags); | |
int getsockopt(SOCKET sock, | |
int level, | |
int option_name, | |
void* option_value, | |
socklen_t* option_len); | |
int setsockopt(SOCKET sock, | |
int level, | |
int option_name, | |
const void* option_value, | |
socklen_t option_len); | |
int socketpair(int domain, int type, int protocol, SOCKET socket_vector[2]); | |
int set_socket_noblocking(SOCKET sock); | |
int listen(SOCKET sock, int backlog); | |
// # 117 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
inline int is_blocking(int dw = get_socket_error()) { | |
return (dw == | |
// # 118 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
// 3 4 | |
11 | |
// # 118 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
|| | |
dw == | |
// # 118 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
// 3 4 | |
11 | |
// # 118 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
); | |
} | |
inline int is_interrupted(int dw = get_socket_error()) { | |
return (dw == | |
// # 121 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
// 3 4 | |
4 | |
// # 121 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
|| | |
dw == | |
// # 121 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
// 3 4 | |
11 | |
// # 121 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
); | |
} | |
inline int is_emfile(int dw = get_socket_error()) { | |
return (dw == | |
// # 124 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" 3 | |
// 4 | |
24 | |
// # 124 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
); | |
} | |
inline int is_closed_conn(int dw = get_socket_error()) { | |
return (dw == | |
// # 127 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
// 3 4 | |
107 | |
// # 127 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
|| | |
dw == | |
// # 127 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
// 3 4 | |
104 | |
// # 127 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
); | |
} | |
inline int is_addrinuse(int dw = get_socket_error()) { | |
return (dw == | |
// # 130 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" 3 | |
// 4 | |
98 | |
// # 130 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
); | |
} | |
inline void set_ewouldblock() { | |
// # 133 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" 3 4 | |
(*__errno_location()) | |
// # 133 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
= | |
// # 133 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
// 3 4 | |
11 | |
// # 133 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
; | |
} | |
inline void set_econnreset() { | |
// # 136 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" 3 4 | |
(*__errno_location()) | |
// # 136 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
= | |
// # 136 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
// 3 4 | |
104 | |
// # 136 | |
// "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
; | |
} | |
std::string to_string(const struct sockaddr_storage* addr, socklen_t addr_len); | |
nlohmann::json to_json(const struct sockaddr_storage* addr, socklen_t addr_len); | |
// # 157 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
std::string getsockname(SOCKET sfd); | |
// # 168 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
nlohmann::json getSockNameAsJson(SOCKET sfd); | |
// # 180 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
std::string getpeername(SOCKET sfd); | |
// # 191 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
nlohmann::json getPeerNameAsJson(SOCKET sfd); | |
// # 200 "/mnt/Code/couchbase/docker/platform/include/platform/socket.h" | |
std::pair<std::vector<std::string>, std::vector<std::string>> getIpAddresses( | |
bool skipLoopback); | |
std::string getHostname(); | |
} // namespace cb::net | |
// # 15 "/mnt/Code/couchbase/docker/kv_engine/include/memcached/vbucket.h" 2 | |
enum vbucket_state_t : int { | |
vbucket_state_active = 1, | |
vbucket_state_replica, | |
vbucket_state_pending, | |
vbucket_state_dead | |
}; | |
enum class RequestedVBState : int { | |
Alive = 0, | |
Active = vbucket_state_active, | |
Replica = vbucket_state_replica, | |
Pending = vbucket_state_pending, | |
Dead = vbucket_state_dead, | |
}; | |
struct vbucket_failover_t { | |
uint64_t uuid; | |
uint64_t seqno; | |
}; | |
class Vbid { | |
public: | |
using id_type = uint16_t; | |
Vbid() = default; | |
explicit Vbid(id_type vbidParam) : vbid(vbidParam){}; | |
id_type get() const { | |
return vbid; | |
} | |
std::string to_string() const { | |
return "vb:" + std::to_string(vbid); | |
} | |
Vbid ntoh() const { | |
return Vbid(ntohs(vbid)); | |
} | |
Vbid hton() const { | |
return Vbid(htons(vbid)); | |
} | |
bool operator<(const Vbid& other) const { | |
return (vbid < other.get()); | |
} | |
bool operator<=(const Vbid& other) const { | |
return (vbid <= other.get()); | |
} | |
bool operator>(const Vbid& other) const { | |
return (vbid > other.get()); | |
} | |
bool operator>=(const Vbid& other) const { | |
return (vbid >= other.get()); | |
} | |
bool operator==(const Vbid& other) const { | |
return (vbid == other.get()); | |
} | |
bool operator!=(const Vbid& other) const { | |
return (vbid != other.get()); | |
} | |
Vbid operator++() { | |
return Vbid(++vbid); | |
} | |
Vbid operator++(int) { | |
return Vbid(vbid++); | |
} | |
protected: | |
id_type vbid; | |
}; | |
std::ostream& operator<<(std::ostream& os, const Vbid& d); | |
std::string to_string(const Vbid& vbucket); | |
namespace std { | |
template <> | |
struct hash<Vbid> { | |
public: | |
size_t operator()(const Vbid& d) const { | |
return static_cast<size_t>(d.get()); | |
} | |
}; | |
} // namespace std | |
// # 16 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/dcp/producer.h" 2 | |
class BucketLogger; | |
class DcpProducer { | |
public: | |
std::shared_ptr<BucketLogger> logger; | |
void bufferAcknowledgement(uint32_t opaque, Vbid vbucket); | |
}; | |
// # 13 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/dcp/producer.cc" 2 | |
// # 1 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger.h" 1 | |
// # 12 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger.h" | |
// # 1 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/logger.h" 1 | |
// # 17 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/logger.h" | |
// # 1 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/common.h" 1 | |
// # 1 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/tweakme.h" | |
// 1 | |
// # 7 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/common.h" 2 | |
// # 1 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/null_mutex.h" | |
// 1 | |
// # 7 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/null_mutex.h" | |
// 2 | |
// # 10 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/null_mutex.h" | |
namespace spdlog { | |
namespace details { | |
struct null_mutex { | |
void lock() const { | |
} | |
void unlock() const { | |
} | |
bool try_lock() const { | |
return true; | |
} | |
}; | |
struct null_atomic_int { | |
int value; | |
null_atomic_int() = default; | |
explicit null_atomic_int(int new_value) : value(new_value) { | |
} | |
int load(std::memory_order = std::memory_order_relaxed) const { | |
return value; | |
} | |
void store(int new_value, std::memory_order = std::memory_order_relaxed) { | |
value = new_value; | |
} | |
int exchange(int new_value, std::memory_order = std::memory_order_relaxed) { | |
std::swap(new_value, value); | |
return new_value; | |
} | |
}; | |
} // namespace details | |
} // namespace spdlog | |
// # 8 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/common.h" 2 | |
// # 11 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/common.h" | |
// 2 # 36 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/common.h" # 1 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/fmt/fmt.h" 1 | |
// # 25 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/fmt/fmt.h" | |
// # 1 "tlm/deps/fmt.exploded/include/fmt/core.h" 1 3 4 | |
// # 11 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
// # 12 "tlm/deps/fmt.exploded/include/fmt/core.h" 2 3 4 | |
// # 13 "tlm/deps/fmt.exploded/include/fmt/core.h" 2 3 4 | |
// # 15 "tlm/deps/fmt.exploded/include/fmt/core.h" 2 3 4 | |
// # 255 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
namespace fmt { | |
inline namespace v7 { | |
template <bool B, class T = void> | |
using enable_if_t = typename std::enable_if<B, T>::type; | |
template <bool B, class T, class F> | |
using conditional_t = typename std::conditional<B, T, F>::type; | |
template <bool B> | |
using bool_constant = std::integral_constant<bool, B>; | |
template <typename T> | |
using remove_reference_t = typename std::remove_reference<T>::type; | |
template <typename T> | |
using remove_const_t = typename std::remove_const<T>::type; | |
template <typename T> | |
using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type; | |
template <typename T> | |
struct type_identity { | |
using type = T; | |
}; | |
template <typename T> | |
using type_identity_t = typename type_identity<T>::type; | |
struct monostate {}; | |
namespace detail { | |
template <typename T> | |
constexpr T const_check(T value) { | |
return value; | |
} | |
[[noreturn]] void assert_fail(const char* file, int line, const char* message); | |
// # 300 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename Char> | |
using std_string_view = std::basic_string_view<Char>; | |
// # 313 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
using int128_t = __int128_t; | |
using uint128_t = __uint128_t; | |
// # 324 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename Int> | |
constexpr typename std::make_unsigned<Int>::type to_unsigned(Int value) { | |
((value >= 0) ? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/core.h", | |
326, | |
("negative value"))); | |
return static_cast<typename std::make_unsigned<Int>::type>(value); | |
} | |
constexpr unsigned char micro[] = "\u00B5"; | |
template <typename Char> | |
constexpr bool is_unicode() { | |
return !0 || sizeof(Char) != 1 || | |
(sizeof(micro) == 3 && micro[0] == 0xC2 && micro[1] == 0xB5); | |
} | |
enum char8_type : unsigned char {}; | |
} // namespace detail | |
// # 355 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename Char> | |
class basic_string_view { | |
private: | |
const Char* data_; | |
size_t size_; | |
public: | |
using value_type = Char; | |
using iterator = const Char*; | |
constexpr basic_string_view() noexcept : data_(nullptr), size_(0) { | |
} | |
constexpr basic_string_view(const Char* s, size_t count) noexcept | |
: data_(s), size_(count) { | |
} | |
// # 378 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
constexpr | |
basic_string_view(const Char* s) | |
: data_(s), size_(std::char_traits<Char>::length(s)) { | |
} | |
template <typename Traits, typename Alloc> | |
constexpr basic_string_view( | |
const std::basic_string<Char, Traits, Alloc>& s) noexcept | |
: data_(s.data()), size_(s.size()) { | |
} | |
template < | |
typename S, | |
enable_if_t<(std::is_same<S, detail::std_string_view<Char>>::value), | |
int> = 0> | |
constexpr basic_string_view(S s) noexcept | |
: data_(s.data()), size_(s.size()) { | |
} | |
constexpr const Char* data() const { | |
return data_; | |
} | |
constexpr size_t size() const { | |
return size_; | |
} | |
constexpr iterator begin() const { | |
return data_; | |
} | |
constexpr iterator end() const { | |
return data_ + size_; | |
} | |
constexpr const Char& operator[](size_t pos) const { | |
return data_[pos]; | |
} | |
constexpr void remove_prefix(size_t n) { | |
data_ += n; | |
size_ -= n; | |
} | |
int compare(basic_string_view other) const { | |
size_t str_size = size_ < other.size_ ? size_ : other.size_; | |
int result = | |
std::char_traits<Char>::compare(data_, other.data_, str_size); | |
if (result == 0) | |
result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); | |
return result; | |
} | |
friend bool operator==(basic_string_view lhs, basic_string_view rhs) { | |
return lhs.compare(rhs) == 0; | |
} | |
friend bool operator!=(basic_string_view lhs, basic_string_view rhs) { | |
return lhs.compare(rhs) != 0; | |
} | |
friend bool operator<(basic_string_view lhs, basic_string_view rhs) { | |
return lhs.compare(rhs) < 0; | |
} | |
friend bool operator<=(basic_string_view lhs, basic_string_view rhs) { | |
return lhs.compare(rhs) <= 0; | |
} | |
friend bool operator>(basic_string_view lhs, basic_string_view rhs) { | |
return lhs.compare(rhs) > 0; | |
} | |
friend bool operator>=(basic_string_view lhs, basic_string_view rhs) { | |
return lhs.compare(rhs) >= 0; | |
} | |
}; | |
using string_view = basic_string_view<char>; | |
using wstring_view = basic_string_view<wchar_t>; | |
template <typename T> | |
struct is_char : std::false_type {}; | |
template <> | |
struct is_char<char> : std::true_type {}; | |
template <> | |
struct is_char<wchar_t> : std::true_type {}; | |
template <> | |
struct is_char<detail::char8_type> : std::true_type {}; | |
template <> | |
struct is_char<char16_t> : std::true_type {}; | |
template <> | |
struct is_char<char32_t> : std::true_type {}; | |
// # 467 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename Char, enable_if_t<(is_char<Char>::value), int> = 0> | |
inline basic_string_view<Char> to_string_view(const Char* s) { | |
return s; | |
} | |
template <typename Char, typename Traits, typename Alloc> | |
inline basic_string_view<Char> to_string_view( | |
const std::basic_string<Char, Traits, Alloc>& s) { | |
return s; | |
} | |
template <typename Char> | |
inline basic_string_view<Char> to_string_view(basic_string_view<Char> s) { | |
return s; | |
} | |
template <typename Char, | |
enable_if_t<(!std::is_empty<detail::std_string_view<Char>>::value), | |
int> = 0> | |
inline basic_string_view<Char> to_string_view(detail::std_string_view<Char> s) { | |
return s; | |
} | |
struct compile_string {}; | |
template <typename S> | |
struct is_compile_string : std::is_base_of<compile_string, S> {}; | |
template <typename S, enable_if_t<(is_compile_string<S>::value), int> = 0> | |
constexpr basic_string_view<typename S::char_type> to_string_view(const S& s) { | |
return s; | |
} | |
namespace detail { | |
void to_string_view(...); | |
using fmt::v7::to_string_view; | |
template <typename S> | |
struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> { | |
}; | |
template <typename S, typename = void> | |
struct char_t_impl {}; | |
template <typename S> | |
struct char_t_impl<S, enable_if_t<is_string<S>::value>> { | |
using result = decltype(to_string_view(std::declval<S>())); | |
using type = typename result::value_type; | |
}; | |
template <typename..., | |
typename S, | |
enable_if_t<(!is_compile_string<S>::value), int> = 0> | |
inline __attribute__((always_inline)) void check_format_string(const S&) { | |
} | |
template <typename..., | |
typename S, | |
enable_if_t<(is_compile_string<S>::value), int> = 0> | |
void check_format_string(S); | |
struct error_handler { | |
constexpr error_handler() = default; | |
constexpr error_handler(const error_handler&) = default; | |
[[noreturn]] void on_error(const char* message); | |
}; | |
} // namespace detail | |
template <typename S> | |
using char_t = typename detail::char_t_impl<S>::type; | |
// # 558 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename Char, typename ErrorHandler = detail::error_handler> | |
class basic_format_parse_context : private ErrorHandler { | |
private: | |
basic_string_view<Char> format_str_; | |
int next_arg_id_; | |
public: | |
using char_type = Char; | |
using iterator = typename basic_string_view<Char>::iterator; | |
explicit constexpr basic_format_parse_context( | |
basic_string_view<Char> format_str, | |
ErrorHandler eh = {}, | |
int next_arg_id = 0) | |
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) { | |
} | |
constexpr iterator begin() const noexcept { | |
return format_str_.begin(); | |
} | |
constexpr iterator end() const noexcept { | |
return format_str_.end(); | |
} | |
constexpr void advance_to(iterator it) { | |
format_str_.remove_prefix(detail::to_unsigned(it - begin())); | |
} | |
constexpr int next_arg_id() { | |
if (next_arg_id_ >= 0) | |
return next_arg_id_++; | |
on_error("cannot switch from manual to automatic argument indexing"); | |
return 0; | |
} | |
constexpr void check_arg_id(int) { | |
if (next_arg_id_ > 0) | |
on_error( | |
"cannot switch from automatic to manual argument indexing"); | |
else | |
next_arg_id_ = -1; | |
} | |
constexpr void check_arg_id(basic_string_view<Char>) { | |
} | |
constexpr void on_error(const char* message) { | |
ErrorHandler::on_error(message); | |
} | |
constexpr ErrorHandler error_handler() const { | |
return *this; | |
} | |
}; | |
using format_parse_context = basic_format_parse_context<char>; | |
using wformat_parse_context = basic_format_parse_context<wchar_t>; | |
template <typename Context> | |
class basic_format_arg; | |
template <typename Context> | |
class basic_format_args; | |
template <typename Context> | |
class dynamic_format_arg_store; | |
template <typename T, typename Char = char, typename Enable = void> | |
struct formatter { | |
formatter() = delete; | |
}; | |
template <typename T, typename Context> | |
using has_formatter = | |
std::is_constructible<typename Context::template formatter_type<T>>; | |
template <typename T> | |
struct is_contiguous : std::false_type {}; | |
template <typename Char> | |
struct is_contiguous<std::basic_string<Char>> : std::true_type {}; | |
namespace detail { | |
template <typename Container> | |
inline Container& get_container(std::back_insert_iterator<Container> it) { | |
using bi_iterator = std::back_insert_iterator<Container>; | |
struct accessor : bi_iterator { | |
accessor(bi_iterator iter) : bi_iterator(iter) { | |
} | |
using bi_iterator::container; | |
}; | |
return *accessor(it).container; | |
} | |
template <typename T> | |
class buffer { | |
private: | |
T* ptr_; | |
size_t size_; | |
size_t capacity_; | |
protected: | |
buffer(size_t sz) noexcept : size_(sz), capacity_(sz) { | |
} | |
buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) noexcept | |
: ptr_(p), size_(sz), capacity_(cap) { | |
} | |
~buffer() = default; | |
void set(T* buf_data, size_t buf_capacity) noexcept { | |
ptr_ = buf_data; | |
capacity_ = buf_capacity; | |
} | |
virtual void grow(size_t capacity) = 0; | |
public: | |
using value_type = T; | |
using const_reference = const T&; | |
buffer(const buffer&) = delete; | |
void operator=(const buffer&) = delete; | |
T* begin() noexcept { | |
return ptr_; | |
} | |
T* end() noexcept { | |
return ptr_ + size_; | |
} | |
const T* begin() const noexcept { | |
return ptr_; | |
} | |
const T* end() const noexcept { | |
return ptr_ + size_; | |
} | |
size_t size() const noexcept { | |
return size_; | |
} | |
size_t capacity() const noexcept { | |
return capacity_; | |
} | |
T* data() noexcept { | |
return ptr_; | |
} | |
const T* data() const noexcept { | |
return ptr_; | |
} | |
void clear() { | |
size_ = 0; | |
} | |
void try_resize(size_t count) { | |
try_reserve(count); | |
size_ = count <= capacity_ ? count : capacity_; | |
} | |
void try_reserve(size_t new_capacity) { | |
if (new_capacity > capacity_) | |
grow(new_capacity); | |
} | |
void push_back(const T& value) { | |
try_reserve(size_ + 1); | |
ptr_[size_++] = value; | |
} | |
template <typename U> | |
void append(const U* begin, const U* end); | |
template <typename I> | |
T& operator[](I index) { | |
return ptr_[index]; | |
} | |
template <typename I> | |
const T& operator[](I index) const { | |
return ptr_[index]; | |
} | |
}; | |
struct buffer_traits { | |
explicit buffer_traits(size_t) { | |
} | |
size_t count() const { | |
return 0; | |
} | |
size_t limit(size_t size) { | |
return size; | |
} | |
}; | |
class fixed_buffer_traits { | |
private: | |
size_t count_ = 0; | |
size_t limit_; | |
public: | |
explicit fixed_buffer_traits(size_t limit) : limit_(limit) { | |
} | |
size_t count() const { | |
return count_; | |
} | |
size_t limit(size_t size) { | |
size_t n = limit_ > count_ ? limit_ - count_ : 0; | |
count_ += size; | |
return size < n ? size : n; | |
} | |
}; | |
template <typename OutputIt, typename T, typename Traits = buffer_traits> | |
class iterator_buffer final : public Traits, public buffer<T> { | |
private: | |
OutputIt out_; | |
enum { buffer_size = 256 }; | |
T data_[buffer_size]; | |
protected: | |
void grow(size_t) final override { | |
if (this->size() == buffer_size) | |
flush(); | |
} | |
void flush(); | |
public: | |
explicit iterator_buffer(OutputIt out, size_t n = buffer_size) | |
: Traits(n), buffer<T>(data_, 0, buffer_size), out_(out) { | |
} | |
~iterator_buffer() { | |
flush(); | |
} | |
OutputIt out() { | |
flush(); | |
return out_; | |
} | |
size_t count() const { | |
return Traits::count() + this->size(); | |
} | |
}; | |
template <typename T> | |
class iterator_buffer<T*, T> final : public buffer<T> { | |
protected: | |
void grow(size_t) final override { | |
} | |
public: | |
explicit iterator_buffer(T* out, size_t = 0) | |
: buffer<T>(out, 0, ~size_t()) { | |
} | |
T* out() { | |
return &*this->end(); | |
} | |
}; | |
template <typename Container> | |
class iterator_buffer<std::back_insert_iterator<Container>, | |
enable_if_t<is_contiguous<Container>::value, | |
typename Container::value_type>> | |
final : public buffer<typename Container::value_type> { | |
private: | |
Container& container_; | |
protected: | |
void grow(size_t capacity) final override { | |
container_.resize(capacity); | |
this->set(&container_[0], capacity); | |
} | |
public: | |
explicit iterator_buffer(Container& c) | |
: buffer<typename Container::value_type>(c.size()), container_(c) { | |
} | |
explicit iterator_buffer(std::back_insert_iterator<Container> out, | |
size_t = 0) | |
: iterator_buffer(get_container(out)) { | |
} | |
std::back_insert_iterator<Container> out() { | |
return std::back_inserter(container_); | |
} | |
}; | |
template <typename T = char> | |
class counting_buffer final : public buffer<T> { | |
private: | |
enum { buffer_size = 256 }; | |
T data_[buffer_size]; | |
size_t count_ = 0; | |
protected: | |
void grow(size_t) final override { | |
if (this->size() != buffer_size) | |
return; | |
count_ += this->size(); | |
this->clear(); | |
} | |
public: | |
counting_buffer() : buffer<T>(data_, 0, buffer_size) { | |
} | |
size_t count() { | |
return count_ + this->size(); | |
} | |
}; | |
template <typename T> | |
class buffer_appender : public std::back_insert_iterator<buffer<T>> { | |
using base = std::back_insert_iterator<buffer<T>>; | |
public: | |
explicit buffer_appender(buffer<T>& buf) : base(buf) { | |
} | |
buffer_appender(base it) : base(it) { | |
} | |
buffer_appender& operator++() { | |
base::operator++(); | |
return *this; | |
} | |
buffer_appender operator++(int) { | |
buffer_appender tmp = *this; | |
++*this; | |
return tmp; | |
} | |
}; | |
template <typename T, typename OutputIt> | |
iterator_buffer<OutputIt, T> get_buffer(OutputIt); | |
template <typename T> | |
buffer<T>& get_buffer(buffer_appender<T>); | |
template <typename OutputIt> | |
OutputIt get_buffer_init(OutputIt out) { | |
return out; | |
} | |
template <typename T> | |
buffer<T>& get_buffer_init(buffer_appender<T> out) { | |
return get_container(out); | |
} | |
template <typename Buffer> | |
auto get_iterator(Buffer& buf) -> decltype(buf.out()) { | |
return buf.out(); | |
} | |
template <typename T> | |
buffer_appender<T> get_iterator(buffer<T>& buf) { | |
return buffer_appender<T>(buf); | |
} | |
template <typename T, typename Char = char, typename Enable = void> | |
struct fallback_formatter { | |
fallback_formatter() = delete; | |
}; | |
template <typename T, typename Context> | |
using has_fallback_formatter = std::is_constructible< | |
fallback_formatter<T, typename Context::char_type>>; | |
struct view {}; | |
template <typename Char, typename T> | |
struct named_arg : view { | |
const Char* name; | |
const T& value; | |
named_arg(const Char* n, const T& v) : name(n), value(v) { | |
} | |
}; | |
template <typename Char> | |
struct named_arg_info { | |
const Char* name; | |
int id; | |
}; | |
template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS> | |
struct arg_data { | |
T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)]; | |
named_arg_info<Char> named_args_[NUM_NAMED_ARGS]; | |
template <typename... U> | |
arg_data(const U&... init) | |
: args_{T(named_args_, NUM_NAMED_ARGS), init...} { | |
} | |
arg_data(const arg_data& other) = delete; | |
const T* args() const { | |
return args_ + 1; | |
} | |
named_arg_info<Char>* named_args() { | |
return named_args_; | |
} | |
}; | |
template <typename T, typename Char, size_t NUM_ARGS> | |
struct arg_data<T, Char, NUM_ARGS, 0> { | |
T args_[NUM_ARGS != 0 ? NUM_ARGS : +1]; | |
template <typename... U> | |
inline __attribute__((always_inline)) arg_data(const U&... init) | |
: args_{init...} { | |
} | |
inline __attribute__((always_inline)) const T* args() const { | |
return args_; | |
} | |
inline __attribute__((always_inline)) std::nullptr_t named_args() { | |
return nullptr; | |
} | |
}; | |
template <typename Char> | |
inline void init_named_args(named_arg_info<Char>*, int, int) { | |
} | |
template <typename Char, typename T, typename... Tail> | |
void init_named_args(named_arg_info<Char>* named_args, | |
int arg_count, | |
int named_arg_count, | |
const T&, | |
const Tail&... args) { | |
init_named_args(named_args, arg_count + 1, named_arg_count, args...); | |
} | |
template <typename Char, typename T, typename... Tail> | |
void init_named_args(named_arg_info<Char>* named_args, | |
int arg_count, | |
int named_arg_count, | |
const named_arg<Char, T>& arg, | |
const Tail&... args) { | |
named_args[named_arg_count++] = {arg.name, arg_count}; | |
init_named_args(named_args, arg_count + 1, named_arg_count, args...); | |
} | |
template <typename... Args> | |
inline __attribute__((always_inline)) void init_named_args(std::nullptr_t, | |
int, | |
int, | |
const Args&...) { | |
} | |
template <typename T> | |
struct is_named_arg : std::false_type {}; | |
template <typename T, typename Char> | |
struct is_named_arg<named_arg<Char, T>> : std::true_type {}; | |
template <bool B = false> | |
constexpr size_t count() { | |
return B ? 1 : 0; | |
} | |
template <bool B1, bool B2, bool... Tail> | |
constexpr size_t count() { | |
return (B1 ? 1 : 0) + count<B2, Tail...>(); | |
} | |
template <typename... Args> | |
constexpr size_t count_named_args() { | |
return count<is_named_arg<Args>::value...>(); | |
} | |
enum class type { | |
none_type, | |
int_type, | |
uint_type, | |
long_long_type, | |
ulong_long_type, | |
int128_type, | |
uint128_type, | |
bool_type, | |
char_type, | |
last_integer_type = char_type, | |
float_type, | |
double_type, | |
long_double_type, | |
last_numeric_type = long_double_type, | |
cstring_type, | |
string_type, | |
pointer_type, | |
custom_type | |
}; | |
template <typename T, typename Char> | |
struct type_constant : std::integral_constant<type, type::custom_type> {}; | |
template <typename Char> | |
struct type_constant<int, Char> : std::integral_constant<type, type::int_type> { | |
}; | |
template <typename Char> | |
struct type_constant<unsigned, Char> | |
: std::integral_constant<type, type::uint_type> {}; | |
template <typename Char> | |
struct type_constant<long long, Char> | |
: std::integral_constant<type, type::long_long_type> {}; | |
template <typename Char> | |
struct type_constant<unsigned long long, Char> | |
: std::integral_constant<type, type::ulong_long_type> {}; | |
template <typename Char> | |
struct type_constant<int128_t, Char> | |
: std::integral_constant<type, type::int128_type> {}; | |
template <typename Char> | |
struct type_constant<uint128_t, Char> | |
: std::integral_constant<type, type::uint128_type> {}; | |
template <typename Char> | |
struct type_constant<bool, Char> | |
: std::integral_constant<type, type::bool_type> {}; | |
template <typename Char> | |
struct type_constant<Char, Char> | |
: std::integral_constant<type, type::char_type> {}; | |
template <typename Char> | |
struct type_constant<float, Char> | |
: std::integral_constant<type, type::float_type> {}; | |
template <typename Char> | |
struct type_constant<double, Char> | |
: std::integral_constant<type, type::double_type> {}; | |
template <typename Char> | |
struct type_constant<long double, Char> | |
: std::integral_constant<type, type::long_double_type> {}; | |
template <typename Char> | |
struct type_constant<const Char*, Char> | |
: std::integral_constant<type, type::cstring_type> {}; | |
template <typename Char> | |
struct type_constant<basic_string_view<Char>, Char> | |
: std::integral_constant<type, type::string_type> {}; | |
template <typename Char> | |
struct type_constant<const void*, Char> | |
: std::integral_constant<type, type::pointer_type> {}; | |
constexpr bool is_integral_type(type t) { | |
return t > type::none_type && t <= type::last_integer_type; | |
} | |
constexpr bool is_arithmetic_type(type t) { | |
return t > type::none_type && t <= type::last_numeric_type; | |
} | |
template <typename Char> | |
struct string_value { | |
const Char* data; | |
size_t size; | |
}; | |
template <typename Char> | |
struct named_arg_value { | |
const named_arg_info<Char>* data; | |
size_t size; | |
}; | |
template <typename Context> | |
struct custom_value { | |
using parse_context = typename Context::parse_context_type; | |
const void* value; | |
void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx); | |
}; | |
template <typename Context> | |
class value { | |
public: | |
using char_type = typename Context::char_type; | |
union { | |
int int_value; | |
unsigned uint_value; | |
long long long_long_value; | |
unsigned long long ulong_long_value; | |
int128_t int128_value; | |
uint128_t uint128_value; | |
bool bool_value; | |
char_type char_value; | |
float float_value; | |
double double_value; | |
long double long_double_value; | |
const void* pointer; | |
string_value<char_type> string; | |
custom_value<Context> custom; | |
named_arg_value<char_type> named_args; | |
}; | |
constexpr inline __attribute__((always_inline)) value(int val = 0) | |
: int_value(val) { | |
} | |
constexpr inline __attribute__((always_inline)) value(unsigned val) | |
: uint_value(val) { | |
} | |
inline __attribute__((always_inline)) value(long long val) | |
: long_long_value(val) { | |
} | |
inline __attribute__((always_inline)) value(unsigned long long val) | |
: ulong_long_value(val) { | |
} | |
inline __attribute__((always_inline)) value(int128_t val) | |
: int128_value(val) { | |
} | |
inline __attribute__((always_inline)) value(uint128_t val) | |
: uint128_value(val) { | |
} | |
inline __attribute__((always_inline)) value(float val) : float_value(val) { | |
} | |
inline __attribute__((always_inline)) value(double val) | |
: double_value(val) { | |
} | |
inline __attribute__((always_inline)) value(long double val) | |
: long_double_value(val) { | |
} | |
inline __attribute__((always_inline)) value(bool val) : bool_value(val) { | |
} | |
inline __attribute__((always_inline)) value(char_type val) | |
: char_value(val) { | |
} | |
inline __attribute__((always_inline)) value(const char_type* val) { | |
string.data = val; | |
} | |
inline __attribute__((always_inline)) | |
value(basic_string_view<char_type> val) { | |
string.data = val.data(); | |
string.size = val.size(); | |
} | |
inline __attribute__((always_inline)) value(const void* val) | |
: pointer(val) { | |
} | |
inline __attribute__((always_inline)) | |
value(const named_arg_info<char_type>* args, size_t size) | |
: named_args{args, size} { | |
} | |
template <typename T> | |
inline __attribute__((always_inline)) value(const T& val) { | |
custom.value = &val; | |
custom.format = format_custom_arg< | |
T, | |
conditional_t<has_formatter<T, Context>::value, | |
typename Context::template formatter_type<T>, | |
fallback_formatter<T, char_type>>>; | |
} | |
private: | |
template <typename T, typename Formatter> | |
static void format_custom_arg( | |
const void* arg, | |
typename Context::parse_context_type& parse_ctx, | |
Context& ctx) { | |
Formatter f; | |
parse_ctx.advance_to(f.parse(parse_ctx)); | |
ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx)); | |
} | |
}; | |
template <typename Context, typename T> | |
constexpr basic_format_arg<Context> make_arg(const T& value); | |
enum { long_short = sizeof(long) == sizeof(int) }; | |
using long_type = conditional_t<long_short, int, long long>; | |
using ulong_type = conditional_t<long_short, unsigned, unsigned long long>; | |
struct unformattable {}; | |
template <typename Context> | |
struct arg_mapper { | |
using char_type = typename Context::char_type; | |
constexpr int map(signed char val) { | |
return val; | |
} | |
constexpr unsigned map(unsigned char val) { | |
return val; | |
} | |
constexpr int map(short val) { | |
return val; | |
} | |
constexpr unsigned map(unsigned short val) { | |
return val; | |
} | |
constexpr int map(int val) { | |
return val; | |
} | |
constexpr unsigned map(unsigned val) { | |
return val; | |
} | |
constexpr long_type map(long val) { | |
return val; | |
} | |
constexpr ulong_type map(unsigned long val) { | |
return val; | |
} | |
constexpr long long map(long long val) { | |
return val; | |
} | |
constexpr unsigned long long map(unsigned long long val) { | |
return val; | |
} | |
constexpr int128_t map(int128_t val) { | |
return val; | |
} | |
constexpr uint128_t map(uint128_t val) { | |
return val; | |
} | |
constexpr bool map(bool val) { | |
return val; | |
} | |
template <typename T, enable_if_t<(is_char<T>::value), int> = 0> | |
constexpr char_type map(T val) { | |
static_assert(std::is_same<T, char>::value || | |
std::is_same<T, char_type>::value, | |
"mixing character types is disallowed"); | |
return val; | |
} | |
constexpr float map(float val) { | |
return val; | |
} | |
constexpr double map(double val) { | |
return val; | |
} | |
constexpr long double map(long double val) { | |
return val; | |
} | |
constexpr const char_type* map(char_type* val) { | |
return val; | |
} | |
constexpr const char_type* map(const char_type* val) { | |
return val; | |
} | |
template <typename T, enable_if_t<(is_string<T>::value), int> = 0> | |
constexpr basic_string_view<char_type> map(const T& val) { | |
static_assert(std::is_same<char_type, char_t<T>>::value, | |
"mixing character types is disallowed"); | |
return to_string_view(val); | |
} | |
template <typename T, | |
enable_if_t<(std::is_constructible<basic_string_view<char_type>, | |
T>::value && | |
!is_string<T>::value && | |
!has_formatter<T, Context>::value && | |
!has_fallback_formatter<T, Context>::value), | |
int> = 0 | |
> | |
constexpr basic_string_view<char_type> map(const T& val) { | |
return basic_string_view<char_type>(val); | |
} | |
template <typename T, | |
enable_if_t<(std::is_constructible<std_string_view<char_type>, | |
T>::value && | |
!std::is_constructible<basic_string_view<char_type>, | |
T>::value && | |
!is_string<T>::value && | |
!has_formatter<T, Context>::value && | |
!has_fallback_formatter<T, Context>::value), | |
int> = 0 | |
> | |
constexpr basic_string_view<char_type> map(const T& val) { | |
return std_string_view<char_type>(val); | |
} | |
constexpr const char* map(const signed char* val) { | |
static_assert(std::is_same<char_type, char>::value, | |
"invalid string type"); | |
return reinterpret_cast<const char*>(val); | |
} | |
constexpr const char* map(const unsigned char* val) { | |
static_assert(std::is_same<char_type, char>::value, | |
"invalid string type"); | |
return reinterpret_cast<const char*>(val); | |
} | |
constexpr const char* map(signed char* val) { | |
const auto* const_val = val; | |
return map(const_val); | |
} | |
constexpr const char* map(unsigned char* val) { | |
const auto* const_val = val; | |
return map(const_val); | |
} | |
constexpr const void* map(void* val) { | |
return val; | |
} | |
constexpr const void* map(const void* val) { | |
return val; | |
} | |
constexpr const void* map(std::nullptr_t val) { | |
return val; | |
} | |
template <typename T> | |
constexpr int map(const T*) { | |
static_assert(!sizeof(T), | |
"formatting of non-void pointers is disallowed"); | |
return 0; | |
} | |
template <typename T, | |
enable_if_t<(std::is_enum<T>::value && | |
!has_formatter<T, Context>::value && | |
!has_fallback_formatter<T, Context>::value), | |
int> = 0 | |
> | |
constexpr auto map(const T& val) -> decltype(std::declval<arg_mapper>().map( | |
static_cast<typename std::underlying_type<T>::type>(val))) { | |
return map(static_cast<typename std::underlying_type<T>::type>(val)); | |
} | |
template <typename T, | |
enable_if_t<(!is_string<T>::value && !is_char<T>::value && | |
(has_formatter<T, Context>::value || | |
has_fallback_formatter<T, Context>::value)), | |
int> = 0 | |
> | |
constexpr const T& map(const T& val) { | |
return val; | |
} | |
template <typename T> | |
constexpr auto map(const named_arg<char_type, T>& val) | |
-> decltype(std::declval<arg_mapper>().map(val.value)) { | |
return map(val.value); | |
} | |
unformattable map(...) { | |
return {}; | |
} | |
}; | |
template <typename T, typename Context> | |
using mapped_type_constant = type_constant<decltype(arg_mapper<Context>().map( | |
std::declval<const T&>())), | |
typename Context::char_type>; | |
enum { packed_arg_bits = 4 }; | |
enum { max_packed_args = 62 / packed_arg_bits }; | |
enum : unsigned long long { is_unpacked_bit = 1ULL << 63 }; | |
enum : unsigned long long { has_named_args_bit = 1ULL << 62 }; | |
} // namespace detail | |
template <typename Context> | |
class basic_format_arg { | |
private: | |
detail::value<Context> value_; | |
detail::type type_; | |
template <typename ContextType, typename T> | |
friend constexpr basic_format_arg<ContextType> detail::make_arg( | |
const T& value); | |
template <typename Visitor, typename Ctx> | |
friend constexpr auto visit_format_arg(Visitor&& vis, | |
const basic_format_arg<Ctx>& arg) | |
-> decltype(vis(0)); | |
friend class basic_format_args<Context>; | |
friend class dynamic_format_arg_store<Context>; | |
using char_type = typename Context::char_type; | |
template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS> | |
friend struct detail::arg_data; | |
basic_format_arg(const detail::named_arg_info<char_type>* args, size_t size) | |
: value_(args, size) { | |
} | |
public: | |
class handle { | |
public: | |
explicit handle(detail::custom_value<Context> custom) | |
: custom_(custom) { | |
} | |
void format(typename Context::parse_context_type& parse_ctx, | |
Context& ctx) const { | |
custom_.format(custom_.value, parse_ctx, ctx); | |
} | |
private: | |
detail::custom_value<Context> custom_; | |
}; | |
constexpr basic_format_arg() : type_(detail::type::none_type) { | |
} | |
constexpr explicit operator bool() const noexcept { | |
return type_ != detail::type::none_type; | |
} | |
detail::type type() const { | |
return type_; | |
} | |
bool is_integral() const { | |
return detail::is_integral_type(type_); | |
} | |
bool is_arithmetic() const { | |
return detail::is_arithmetic_type(type_); | |
} | |
}; | |
// # 1309 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename Visitor, typename Context> | |
constexpr inline __attribute__((always_inline)) auto visit_format_arg( | |
Visitor&& vis, const basic_format_arg<Context>& arg) | |
-> decltype(vis(0)) { | |
using char_type = typename Context::char_type; | |
switch (arg.type_) { | |
case detail::type::none_type: | |
break; | |
case detail::type::int_type: | |
return vis(arg.value_.int_value); | |
case detail::type::uint_type: | |
return vis(arg.value_.uint_value); | |
case detail::type::long_long_type: | |
return vis(arg.value_.long_long_value); | |
case detail::type::ulong_long_type: | |
return vis(arg.value_.ulong_long_value); | |
case detail::type::int128_type: | |
return vis(arg.value_.int128_value); | |
case detail::type::uint128_type: | |
return vis(arg.value_.uint128_value); | |
case detail::type::bool_type: | |
return vis(arg.value_.bool_value); | |
case detail::type::char_type: | |
return vis(arg.value_.char_value); | |
case detail::type::float_type: | |
return vis(arg.value_.float_value); | |
case detail::type::double_type: | |
return vis(arg.value_.double_value); | |
case detail::type::long_double_type: | |
return vis(arg.value_.long_double_value); | |
case detail::type::cstring_type: | |
return vis(arg.value_.string.data); | |
case detail::type::string_type: | |
return vis(basic_string_view<char_type>(arg.value_.string.data, | |
arg.value_.string.size)); | |
case detail::type::pointer_type: | |
return vis(arg.value_.pointer); | |
case detail::type::custom_type: | |
return vis( | |
typename basic_format_arg<Context>::handle(arg.value_.custom)); | |
} | |
return vis(monostate()); | |
} | |
template <typename T> | |
struct formattable : std::false_type {}; | |
namespace detail { | |
template <typename... Ts> | |
struct void_t_impl { | |
using type = void; | |
}; | |
template <typename... Ts> | |
using void_t = typename detail::void_t_impl<Ts...>::type; | |
template <typename It, typename T, typename Enable = void> | |
struct is_output_iterator : std::false_type {}; | |
template <typename It, typename T> | |
struct is_output_iterator< | |
It, | |
T, | |
void_t<typename std::iterator_traits<It>::iterator_category, | |
decltype(*std::declval<It>() = std::declval<T>())>> | |
: std::true_type {}; | |
template <typename OutputIt> | |
struct is_back_insert_iterator : std::false_type {}; | |
template <typename Container> | |
struct is_back_insert_iterator<std::back_insert_iterator<Container>> | |
: std::true_type {}; | |
template <typename OutputIt> | |
struct is_contiguous_back_insert_iterator : std::false_type {}; | |
template <typename Container> | |
struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>> | |
: is_contiguous<Container> {}; | |
template <typename Char> | |
struct is_contiguous_back_insert_iterator<buffer_appender<Char>> | |
: std::true_type {}; | |
class locale_ref { | |
private: | |
const void* locale_; | |
public: | |
locale_ref() : locale_(nullptr) { | |
} | |
template <typename Locale> | |
explicit locale_ref(const Locale& loc); | |
explicit operator bool() const noexcept { | |
return locale_ != nullptr; | |
} | |
template <typename Locale> | |
Locale get() const; | |
}; | |
template <typename> | |
constexpr unsigned long long encode_types() { | |
return 0; | |
} | |
template <typename Context, typename Arg, typename... Args> | |
constexpr unsigned long long encode_types() { | |
return static_cast<unsigned>(mapped_type_constant<Arg, Context>::value) | | |
(encode_types<Context, Args...>() << packed_arg_bits); | |
} | |
template <typename Context, typename T> | |
constexpr basic_format_arg<Context> make_arg(const T& value) { | |
basic_format_arg<Context> arg; | |
arg.type_ = mapped_type_constant<T, Context>::value; | |
arg.value_ = arg_mapper<Context>().map(value); | |
return arg; | |
} | |
template <typename T> | |
int check(unformattable) { | |
static_assert( | |
formattable<T>(), | |
"Cannot format an argument. To make type T formattable provide a " | |
"formatter<T> specialization: https://fmt.dev/latest/api.html#udt"); | |
return 0; | |
} | |
template <typename T, typename U> | |
inline const U& check(const U& val) { | |
return val; | |
} | |
template <bool IS_PACKED, | |
typename Context, | |
type, | |
typename T, | |
enable_if_t<(IS_PACKED), int> = 0> | |
inline value<Context> make_arg(const T& val) { | |
return check<T>(arg_mapper<Context>().map(val)); | |
} | |
template <bool IS_PACKED, | |
typename Context, | |
type, | |
typename T, | |
enable_if_t<(!IS_PACKED), int> = 0> | |
inline basic_format_arg<Context> make_arg(const T& value) { | |
return make_arg<Context>(value); | |
} | |
template <typename T> | |
struct is_reference_wrapper : std::false_type {}; | |
template <typename T> | |
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; | |
template <typename T> | |
const T& unwrap(const T& v) { | |
return v; | |
} | |
template <typename T> | |
const T& unwrap(const std::reference_wrapper<T>& v) { | |
return static_cast<const T&>(v); | |
} | |
class dynamic_arg_list { | |
template <typename = void> | |
struct node { | |
virtual ~node() = default; | |
std::unique_ptr<node<>> next; | |
}; | |
template <typename T> | |
struct typed_node : node<> { | |
T value; | |
template <typename Arg> | |
constexpr typed_node(const Arg& arg) : value(arg) { | |
} | |
template <typename Char> | |
constexpr typed_node(const basic_string_view<Char>& arg) | |
: value(arg.data(), arg.size()) { | |
} | |
}; | |
std::unique_ptr<node<>> head_; | |
public: | |
template <typename T, typename Arg> | |
const T& push(const Arg& arg) { | |
auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg)); | |
auto& value = new_node->value; | |
new_node->next = std::move(head_); | |
head_ = std::move(new_node); | |
return value; | |
} | |
}; | |
} // namespace detail | |
template <typename OutputIt, typename Char> | |
class basic_format_context { | |
public: | |
using char_type = Char; | |
private: | |
OutputIt out_; | |
basic_format_args<basic_format_context> args_; | |
detail::locale_ref loc_; | |
public: | |
using iterator = OutputIt; | |
using format_arg = basic_format_arg<basic_format_context>; | |
using parse_context_type = basic_format_parse_context<Char>; | |
template <typename T> | |
using formatter_type = formatter<T, char_type>; | |
basic_format_context(const basic_format_context&) = delete; | |
void operator=(const basic_format_context&) = delete; | |
basic_format_context(OutputIt out, | |
basic_format_args<basic_format_context> ctx_args, | |
detail::locale_ref loc = detail::locale_ref()) | |
: out_(out), args_(ctx_args), loc_(loc) { | |
} | |
format_arg arg(int id) const { | |
return args_.get(id); | |
} | |
format_arg arg(basic_string_view<char_type> name) { | |
return args_.get(name); | |
} | |
int arg_id(basic_string_view<char_type> name) { | |
return args_.get_id(name); | |
} | |
const basic_format_args<basic_format_context>& args() const { | |
return args_; | |
} | |
detail::error_handler error_handler() { | |
return {}; | |
} | |
void on_error(const char* message) { | |
error_handler().on_error(message); | |
} | |
iterator out() { | |
return out_; | |
} | |
void advance_to(iterator it) { | |
if (!detail::is_back_insert_iterator<iterator>()) | |
out_ = it; | |
} | |
detail::locale_ref locale() { | |
return loc_; | |
} | |
}; | |
template <typename Char> | |
using buffer_context = | |
basic_format_context<detail::buffer_appender<Char>, Char>; | |
using format_context = buffer_context<char>; | |
using wformat_context = buffer_context<wchar_t>; | |
// # 1553 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename Context, typename... Args> | |
class format_arg_store | |
{ | |
private: | |
static const size_t num_args = sizeof...(Args); | |
static const size_t num_named_args = detail::count_named_args<Args...>(); | |
static const bool is_packed = num_args <= detail::max_packed_args; | |
using value_type = conditional_t<is_packed, | |
detail::value<Context>, | |
basic_format_arg<Context>>; | |
detail::arg_data<value_type, | |
typename Context::char_type, | |
num_args, | |
num_named_args> | |
data_; | |
friend class basic_format_args<Context>; | |
static constexpr unsigned long long desc = | |
(is_packed ? detail::encode_types<Context, Args...>() | |
: detail::is_unpacked_bit | num_args) | | |
(num_named_args != 0 ? static_cast<unsigned long long>( | |
detail::has_named_args_bit) | |
: 0); | |
public: | |
format_arg_store(const Args&... args) | |
: | |
data_{detail::make_arg< | |
is_packed, | |
Context, | |
detail::mapped_type_constant<Args, Context>::value>( | |
args)...} { | |
detail::init_named_args(data_.named_args(), 0, 0, args...); | |
} | |
}; | |
// # 1602 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename Context = format_context, typename... Args> | |
inline format_arg_store<Context, Args...> make_format_args( | |
const Args&... args) { | |
return {args...}; | |
} | |
// # 1616 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename... Args, typename S, typename Char = char_t<S>> | |
inline auto make_args_checked(const S& format_str, | |
const remove_reference_t<Args>&... args) | |
-> format_arg_store<buffer_context<Char>, remove_reference_t<Args>...> { | |
static_assert( | |
detail::count<(std::is_base_of<detail::view, | |
remove_reference_t<Args>>::value && | |
std::is_reference<Args>::value)...>() == 0, | |
"passing views as lvalues is disallowed"); | |
detail::check_format_string<Args...>(format_str); | |
return {args...}; | |
} | |
// # 1639 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename Char, typename T> | |
inline detail::named_arg<Char, T> arg(const Char* name, const T& arg) { | |
static_assert(!detail::is_named_arg<T>(), "nested named arguments"); | |
return {name, arg}; | |
} | |
// # 1655 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename Context> | |
class dynamic_format_arg_store | |
{ | |
private: | |
using char_type = typename Context::char_type; | |
template <typename T> | |
struct need_copy { | |
static constexpr detail::type mapped_type = | |
detail::mapped_type_constant<T, Context>::value; | |
enum { | |
value = !(detail::is_reference_wrapper<T>::value || | |
std::is_same<T, basic_string_view<char_type>>::value || | |
std::is_same<T, | |
detail::std_string_view<char_type>>::value || | |
(mapped_type != detail::type::cstring_type && | |
mapped_type != detail::type::string_type && | |
mapped_type != detail::type::custom_type)) | |
}; | |
}; | |
template <typename T> | |
using stored_type = conditional_t<detail::is_string<T>::value, | |
std::basic_string<char_type>, | |
T>; | |
std::vector<basic_format_arg<Context>> data_; | |
std::vector<detail::named_arg_info<char_type>> named_info_; | |
detail::dynamic_arg_list dynamic_args_; | |
friend class basic_format_args<Context>; | |
unsigned long long get_types() const { | |
return detail::is_unpacked_bit | data_.size() | | |
(named_info_.empty() ? 0ULL | |
: static_cast<unsigned long long>( | |
detail::has_named_args_bit)); | |
} | |
const basic_format_arg<Context>* data() const { | |
return named_info_.empty() ? data_.data() : data_.data() + 1; | |
} | |
template <typename T> | |
void emplace_arg(const T& arg) { | |
data_.emplace_back(detail::make_arg<Context>(arg)); | |
} | |
template <typename T> | |
void emplace_arg(const detail::named_arg<char_type, T>& arg) { | |
if (named_info_.empty()) { | |
constexpr const detail::named_arg_info<char_type>* zero_ptr{ | |
nullptr}; | |
data_.insert(data_.begin(), {zero_ptr, 0}); | |
} | |
data_.emplace_back( | |
detail::make_arg<Context>(detail::unwrap(arg.value))); | |
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) { | |
data->pop_back(); | |
}; | |
std::unique_ptr<std::vector<basic_format_arg<Context>>, | |
decltype(pop_one)> | |
guard{&data_, pop_one}; | |
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)}); | |
data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; | |
guard.release(); | |
} | |
public: | |
// # 1743 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename T> | |
void push_back(const T& arg) { | |
if (detail::const_check(need_copy<T>::value)) | |
emplace_arg(dynamic_args_.push<stored_type<T>>(arg)); | |
else | |
emplace_arg(detail::unwrap(arg)); | |
} | |
// # 1772 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename T> | |
void push_back(std::reference_wrapper<T> arg) { | |
static_assert( | |
detail::is_named_arg<typename std::remove_cv<T>::type>::value || | |
need_copy<T>::value, | |
"objects of built-in types and string views are always copied"); | |
emplace_arg(arg.get()); | |
} | |
template <typename T> | |
void push_back(const detail::named_arg<char_type, T>& arg) { | |
const char_type* arg_name = | |
dynamic_args_.push<std::basic_string<char_type>>(arg.name) | |
.c_str(); | |
if (detail::const_check(need_copy<T>::value)) { | |
emplace_arg(fmt::arg( | |
arg_name, dynamic_args_.push<stored_type<T>>(arg.value))); | |
} else { | |
emplace_arg(fmt::arg(arg_name, arg.value)); | |
} | |
} | |
void clear() { | |
data_.clear(); | |
named_info_.clear(); | |
dynamic_args_ = detail::dynamic_arg_list(); | |
} | |
void reserve(size_t new_cap, size_t new_cap_named) { | |
((new_cap >= new_cap_named) | |
? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/core.h", | |
1811, | |
("Set of arguments includes set of named " | |
"arguments"))); | |
data_.reserve(new_cap); | |
named_info_.reserve(new_cap_named); | |
} | |
}; | |
// # 1828 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename Context> | |
class basic_format_args { | |
public: | |
using size_type = int; | |
using format_arg = basic_format_arg<Context>; | |
private: | |
unsigned long long desc_; | |
union { | |
const detail::value<Context>* values_; | |
const format_arg* args_; | |
}; | |
bool is_packed() const { | |
return (desc_ & detail::is_unpacked_bit) == 0; | |
} | |
bool has_named_args() const { | |
return (desc_ & detail::has_named_args_bit) != 0; | |
} | |
detail::type type(int index) const { | |
int shift = index * detail::packed_arg_bits; | |
unsigned int mask = (1 << detail::packed_arg_bits) - 1; | |
return static_cast<detail::type>((desc_ >> shift) & mask); | |
} | |
basic_format_args(unsigned long long desc, | |
const detail::value<Context>* values) | |
: desc_(desc), values_(values) { | |
} | |
basic_format_args(unsigned long long desc, const format_arg* args) | |
: desc_(desc), args_(args) { | |
} | |
public: | |
basic_format_args() : desc_(0) { | |
} | |
template <typename... Args> | |
inline __attribute__((always_inline)) | |
basic_format_args(const format_arg_store<Context, Args...>& store) | |
: basic_format_args(store.desc, store.data_.args()) { | |
} | |
inline __attribute__((always_inline)) | |
basic_format_args(const dynamic_format_arg_store<Context>& store) | |
: basic_format_args(store.get_types(), store.data()) { | |
} | |
basic_format_args(const format_arg* args, int count) | |
: basic_format_args( | |
detail::is_unpacked_bit | detail::to_unsigned(count), args) { | |
} | |
format_arg get(int id) const { | |
format_arg arg; | |
if (!is_packed()) { | |
if (id < max_size()) | |
arg = args_[id]; | |
return arg; | |
} | |
if (id >= detail::max_packed_args) | |
return arg; | |
arg.type_ = type(id); | |
if (arg.type_ == detail::type::none_type) | |
return arg; | |
arg.value_ = values_[id]; | |
return arg; | |
} | |
template <typename Char> | |
format_arg get(basic_string_view<Char> name) const { | |
int id = get_id(name); | |
return id >= 0 ? get(id) : format_arg(); | |
} | |
template <typename Char> | |
int get_id(basic_string_view<Char> name) const { | |
if (!has_named_args()) | |
return -1; | |
const auto& named_args = | |
(is_packed() ? values_[-1] : args_[-1].value_).named_args; | |
for (size_t i = 0; i < named_args.size; ++i) { | |
if (named_args.data[i].name == name) | |
return named_args.data[i].id; | |
} | |
return -1; | |
} | |
int max_size() const { | |
unsigned long long max_packed = detail::max_packed_args; | |
return static_cast<int>(is_packed() ? max_packed | |
: desc_ & ~detail::is_unpacked_bit); | |
} | |
}; | |
// # 1941 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
struct format_args : basic_format_args<format_context> { | |
template <typename... Args> | |
inline __attribute__((always_inline)) format_args(const Args&... args) | |
: basic_format_args(args...) { | |
} | |
}; | |
struct wformat_args : basic_format_args<wformat_context> { | |
using basic_format_args::basic_format_args; | |
}; | |
namespace detail { | |
template <typename Char, | |
enable_if_t<(!std::is_same<Char, char>::value), int> = 0> | |
std::basic_string<Char> vformat( | |
basic_string_view<Char> format_str, | |
basic_format_args<buffer_context<type_identity_t<Char>>> args); | |
std::string vformat(string_view format_str, format_args args); | |
template <typename Char> | |
void vformat_to(buffer<Char>& buf, | |
basic_string_view<Char> format_str, | |
basic_format_args<basic_format_context< | |
detail::buffer_appender<type_identity_t<Char>>, | |
type_identity_t<Char>>> args, | |
detail::locale_ref loc = {}); | |
template <typename Char, | |
typename Args, | |
enable_if_t<(!std::is_same<Char, char>::value), int> = 0> | |
inline void vprint_mojibake(std::FILE*, basic_string_view<Char>, const Args&) { | |
} | |
void vprint_mojibake(std::FILE*, string_view, format_args); | |
inline void vprint_mojibake(std::FILE*, string_view, format_args) { | |
} | |
} // namespace detail | |
template <typename OutputIt, | |
typename S, | |
typename Char = char_t<S>, | |
bool enable = detail::is_output_iterator<OutputIt, Char>::value> | |
auto vformat_to(OutputIt out, | |
const S& format_str, | |
basic_format_args<buffer_context<type_identity_t<Char>>> args) | |
-> typename std::enable_if<enable, OutputIt>::type { | |
decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out)); | |
detail::vformat_to(buf, to_string_view(format_str), args); | |
return detail::get_iterator(buf); | |
} | |
// # 2000 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename OutputIt, | |
typename S, | |
typename... Args, | |
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value> | |
inline auto format_to(OutputIt out, const S& format_str, Args&&... args) -> | |
typename std::enable_if<enable, OutputIt>::type { | |
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); | |
return vformat_to(out, to_string_view(format_str), vargs); | |
} | |
template <typename OutputIt> | |
struct format_to_n_result { | |
OutputIt out; | |
size_t size; | |
}; | |
template <typename OutputIt, | |
typename Char, | |
typename... Args, | |
enable_if_t<(detail::is_output_iterator<OutputIt, Char>::value), | |
int> = 0> | |
inline format_to_n_result<OutputIt> vformat_to_n( | |
OutputIt out, | |
size_t n, | |
basic_string_view<Char> format_str, | |
basic_format_args<buffer_context<type_identity_t<Char>>> args) { | |
detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf( | |
out, n); | |
detail::vformat_to(buf, format_str, args); | |
return {buf.out(), buf.count()}; | |
} | |
// # 2033 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename OutputIt, | |
typename S, | |
typename... Args, | |
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value> | |
inline auto format_to_n(OutputIt out, | |
size_t n, | |
const S& format_str, | |
const Args&... args) -> | |
typename std::enable_if<enable, format_to_n_result<OutputIt>>::type { | |
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); | |
return vformat_to_n(out, n, to_string_view(format_str), vargs); | |
} | |
template <typename... Args> | |
inline size_t formatted_size(string_view format_str, Args&&... args) { | |
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); | |
detail::counting_buffer<> buf; | |
detail::vformat_to(buf, format_str, vargs); | |
return buf.count(); | |
} | |
template <typename S, typename Char = char_t<S>> | |
inline __attribute__((always_inline)) std::basic_string<Char> vformat( | |
const S& format_str, | |
basic_format_args<buffer_context<type_identity_t<Char>>> args) { | |
return detail::vformat(to_string_view(format_str), args); | |
} | |
// # 2073 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename S, typename... Args, typename Char = char_t<S>> | |
inline __attribute__((always_inline)) std::basic_string<Char> format( | |
const S& format_str, Args&&... args) { | |
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); | |
return detail::vformat(to_string_view(format_str), vargs); | |
} | |
void vprint(string_view, format_args); | |
void vprint(std::FILE*, string_view, format_args); | |
// # 2093 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename S, typename... Args, typename Char = char_t<S>> | |
inline void print(std::FILE* f, const S& format_str, Args&&... args) { | |
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); | |
return detail::is_unicode<Char>() | |
? vprint(f, to_string_view(format_str), vargs) | |
: detail::vprint_mojibake( | |
f, to_string_view(format_str), vargs); | |
} | |
// # 2112 "tlm/deps/fmt.exploded/include/fmt/core.h" 3 4 | |
template <typename S, typename... Args, typename Char = char_t<S>> | |
inline void print(const S& format_str, Args&&... args) { | |
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); | |
return detail::is_unicode<Char>() | |
? vprint(to_string_view(format_str), vargs) | |
: detail::vprint_mojibake( | |
stdout, to_string_view(format_str), vargs); | |
} | |
} // namespace v7 | |
} // namespace fmt | |
// # 26 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/fmt/fmt.h" | |
// 2 # 1 "tlm/deps/fmt.exploded/include/fmt/format.h" 1 3 4 # 36 | |
// "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 # 37 | |
// "tlm/deps/fmt.exploded/include/fmt/format.h" 2 3 4 # 38 | |
// "tlm/deps/fmt.exploded/include/fmt/format.h" 2 3 4 # 39 | |
// "tlm/deps/fmt.exploded/include/fmt/format.h" 2 3 4 | |
// # 1 "tlm/deps/fmt.exploded/include/fmt/core.h" 1 3 4 | |
// # 45 "tlm/deps/fmt.exploded/include/fmt/format.h" 2 3 4 | |
// # 275 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
namespace fmt { | |
inline namespace v7 { | |
namespace detail { | |
template <typename Dest, typename Source> | |
inline Dest bit_cast(const Source& source) { | |
static_assert(sizeof(Dest) == sizeof(Source), "size mismatch"); | |
Dest dest; | |
std::memcpy(&dest, &source, sizeof(dest)); | |
return dest; | |
} | |
inline bool is_big_endian() { | |
const auto u = 1u; | |
struct bytes { | |
char data[sizeof(u)]; | |
}; | |
return bit_cast<bytes>(u).data[0] == 0; | |
} | |
struct fallback_uintptr { | |
unsigned char value[sizeof(void*)]; | |
fallback_uintptr() = default; | |
explicit fallback_uintptr(const void* p) { | |
*this = bit_cast<fallback_uintptr>(p); | |
if (is_big_endian()) { | |
for (size_t i = 0, j = sizeof(void*) - 1; i < j; ++i, --j) | |
std::swap(value[i], value[j]); | |
} | |
} | |
}; | |
using uintptr_t = ::uintptr_t; | |
inline uintptr_t to_uintptr(const void* p) { | |
return bit_cast<uintptr_t>(p); | |
} | |
// # 322 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
template <typename T> | |
constexpr T max_value() { | |
return (std::numeric_limits<T>::max)(); | |
} | |
template <typename T> | |
constexpr int num_bits() { | |
return std::numeric_limits<T>::digits; | |
} | |
template <> | |
constexpr int num_bits<int128_t>() { | |
return 128; | |
} | |
template <> | |
constexpr int num_bits<uint128_t>() { | |
return 128; | |
} | |
template <> | |
constexpr int num_bits<fallback_uintptr>() { | |
return static_cast<int>(sizeof(void*) * | |
std::numeric_limits<unsigned char>::digits); | |
} | |
inline __attribute__((always_inline)) void assume(bool condition) { | |
(void)condition; | |
} | |
template <typename T> | |
using iterator_t = decltype(std::begin(std::declval<T&>())); | |
template <typename T> | |
using sentinel_t = decltype(std::end(std::declval<T&>())); | |
template <typename Char> | |
inline Char* get_data(std::basic_string<Char>& s) { | |
return &s[0]; | |
} | |
template <typename Container> | |
inline typename Container::value_type* get_data(Container& c) { | |
return c.data(); | |
} | |
// # 364 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
template <typename T> | |
using checked_ptr = T*; | |
template <typename T> | |
inline T* make_checked(T* p, size_t) { | |
return p; | |
} | |
template <typename Container, | |
enable_if_t<(is_contiguous<Container>::value), int> = 0> | |
inline checked_ptr<typename Container::value_type> reserve( | |
std::back_insert_iterator<Container> it, size_t n) { | |
Container& c = get_container(it); | |
size_t size = c.size(); | |
c.resize(size + n); | |
return make_checked(get_data(c) + size, n); | |
} | |
template <typename T> | |
inline buffer_appender<T> reserve(buffer_appender<T> it, size_t n) { | |
buffer<T>& buf = get_container(it); | |
buf.try_reserve(buf.size() + n); | |
return it; | |
} | |
template <typename Iterator> | |
inline Iterator& reserve(Iterator& it, size_t) { | |
return it; | |
} | |
template <typename T, typename OutputIt> | |
constexpr T* to_pointer(OutputIt, size_t) { | |
return nullptr; | |
} | |
template <typename T> | |
T* to_pointer(buffer_appender<T> it, size_t n) { | |
buffer<T>& buf = get_container(it); | |
auto size = buf.size(); | |
if (buf.capacity() < size + n) | |
return nullptr; | |
buf.try_resize(size + n); | |
return buf.data() + size; | |
} | |
template <typename Container, | |
enable_if_t<(is_contiguous<Container>::value), int> = 0> | |
inline std::back_insert_iterator<Container> base_iterator( | |
std::back_insert_iterator<Container>& it, | |
checked_ptr<typename Container::value_type>) { | |
return it; | |
} | |
template <typename Iterator> | |
inline Iterator base_iterator(Iterator, Iterator it) { | |
return it; | |
} | |
class counting_iterator { | |
private: | |
size_t count_; | |
public: | |
using iterator_category = std::output_iterator_tag; | |
using difference_type = std::ptrdiff_t; | |
using pointer = void; | |
using reference = void; | |
using _Unchecked_type = counting_iterator; | |
struct value_type { | |
template <typename T> | |
void operator=(const T&) { | |
} | |
}; | |
counting_iterator() : count_(0) { | |
} | |
size_t count() const { | |
return count_; | |
} | |
counting_iterator& operator++() { | |
++count_; | |
return *this; | |
} | |
counting_iterator operator++(int) { | |
auto it = *this; | |
++*this; | |
return it; | |
} | |
friend counting_iterator operator+(counting_iterator it, | |
difference_type n) { | |
it.count_ += static_cast<size_t>(n); | |
return it; | |
} | |
value_type operator*() const { | |
return {}; | |
} | |
}; | |
template <typename OutputIt> | |
class truncating_iterator_base { | |
protected: | |
OutputIt out_; | |
size_t limit_; | |
size_t count_; | |
truncating_iterator_base(OutputIt out, size_t limit) | |
: out_(out), limit_(limit), count_(0) { | |
} | |
public: | |
using iterator_category = std::output_iterator_tag; | |
using value_type = typename std::iterator_traits<OutputIt>::value_type; | |
using difference_type = void; | |
using pointer = void; | |
using reference = void; | |
using _Unchecked_type = truncating_iterator_base; | |
OutputIt base() const { | |
return out_; | |
} | |
size_t count() const { | |
return count_; | |
} | |
}; | |
template <typename OutputIt, | |
typename Enable = typename std::is_void< | |
typename std::iterator_traits<OutputIt>::value_type>::type> | |
class truncating_iterator; | |
template <typename OutputIt> | |
class truncating_iterator<OutputIt, std::false_type> | |
: public truncating_iterator_base<OutputIt> { | |
mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_; | |
public: | |
using value_type = typename truncating_iterator_base<OutputIt>::value_type; | |
truncating_iterator(OutputIt out, size_t limit) | |
: truncating_iterator_base<OutputIt>(out, limit) { | |
} | |
truncating_iterator& operator++() { | |
if (this->count_++ < this->limit_) | |
++this->out_; | |
return *this; | |
} | |
truncating_iterator operator++(int) { | |
auto it = *this; | |
++*this; | |
return it; | |
} | |
value_type& operator*() const { | |
return this->count_ < this->limit_ ? *this->out_ : blackhole_; | |
} | |
}; | |
template <typename OutputIt> | |
class truncating_iterator<OutputIt, std::true_type> | |
: public truncating_iterator_base<OutputIt> { | |
public: | |
truncating_iterator(OutputIt out, size_t limit) | |
: truncating_iterator_base<OutputIt>(out, limit) { | |
} | |
template <typename T> | |
truncating_iterator& operator=(T val) { | |
if (this->count_++ < this->limit_) | |
*this->out_++ = val; | |
return *this; | |
} | |
truncating_iterator& operator++() { | |
return *this; | |
} | |
truncating_iterator& operator++(int) { | |
return *this; | |
} | |
truncating_iterator& operator*() { | |
return *this; | |
} | |
}; | |
template <typename Char> | |
inline size_t count_code_points(basic_string_view<Char> s) { | |
return s.size(); | |
} | |
inline size_t count_code_points(basic_string_view<char> s) { | |
const char* data = s.data(); | |
size_t num_code_points = 0; | |
for (size_t i = 0, size = s.size(); i != size; ++i) { | |
if ((data[i] & 0xc0) != 0x80) | |
++num_code_points; | |
} | |
return num_code_points; | |
} | |
inline size_t count_code_points(basic_string_view<char8_type> s) { | |
return count_code_points(basic_string_view<char>( | |
reinterpret_cast<const char*>(s.data()), s.size())); | |
} | |
template <typename Char> | |
inline size_t code_point_index(basic_string_view<Char> s, size_t n) { | |
size_t size = s.size(); | |
return n < size ? n : size; | |
} | |
inline size_t code_point_index(basic_string_view<char8_type> s, size_t n) { | |
const char8_type* data = s.data(); | |
size_t num_code_points = 0; | |
for (size_t i = 0, size = s.size(); i != size; ++i) { | |
if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) { | |
return i; | |
} | |
} | |
return s.size(); | |
} | |
template <typename InputIt, typename OutChar> | |
using needs_conversion = bool_constant< | |
std::is_same<typename std::iterator_traits<InputIt>::value_type, | |
char>::value && | |
std::is_same<OutChar, char8_type>::value>; | |
template <typename OutChar, | |
typename InputIt, | |
typename OutputIt, | |
enable_if_t<(!needs_conversion<InputIt, OutChar>::value), int> = 0> | |
OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) { | |
return std::copy(begin, end, it); | |
} | |
template <typename OutChar, | |
typename InputIt, | |
typename OutputIt, | |
enable_if_t<(needs_conversion<InputIt, OutChar>::value), int> = 0> | |
OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) { | |
return std::transform( | |
begin, end, it, [](char c) { return static_cast<char8_type>(c); }); | |
} | |
template <typename Char, typename InputIt> | |
inline counting_iterator copy_str(InputIt begin, | |
InputIt end, | |
counting_iterator it) { | |
return it + (end - begin); | |
} | |
template <typename T> | |
using is_fast_float = bool_constant<std::numeric_limits<T>::is_iec559 && | |
sizeof(T) <= sizeof(double)>; | |
template <typename T> | |
template <typename U> | |
void buffer<T>::append(const U* begin, const U* end) { | |
do { | |
auto count = to_unsigned(end - begin); | |
try_reserve(size_ + count); | |
auto free_cap = capacity_ - size_; | |
if (free_cap < count) | |
count = free_cap; | |
std::uninitialized_copy_n( | |
begin, count, make_checked(ptr_ + size_, count)); | |
size_ += count; | |
begin += count; | |
} while (begin != end); | |
} | |
template <typename OutputIt, typename T, typename Traits> | |
void iterator_buffer<OutputIt, T, Traits>::flush() { | |
out_ = std::copy_n(data_, this->limit(this->size()), out_); | |
this->clear(); | |
} | |
} // namespace detail | |
enum { inline_buffer_size = 500 }; | |
// # 652 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
template <typename T, | |
size_t SIZE = inline_buffer_size, | |
typename Allocator = std::allocator<T>> | |
class basic_memory_buffer final : public detail::buffer<T> { | |
private: | |
T store_[SIZE]; | |
Allocator alloc_; | |
void deallocate() { | |
T* data = this->data(); | |
if (data != store_) | |
alloc_.deallocate(data, this->capacity()); | |
} | |
protected: | |
void grow(size_t size) final override; | |
public: | |
using value_type = T; | |
using const_reference = const T&; | |
explicit basic_memory_buffer(const Allocator& alloc = Allocator()) | |
: alloc_(alloc) { | |
this->set(store_, SIZE); | |
} | |
~basic_memory_buffer() { | |
deallocate(); | |
} | |
private: | |
void move(basic_memory_buffer& other) { | |
alloc_ = std::move(other.alloc_); | |
T* data = other.data(); | |
size_t size = other.size(), capacity = other.capacity(); | |
if (data == other.store_) { | |
this->set(store_, capacity); | |
std::uninitialized_copy(other.store_, | |
other.store_ + size, | |
detail::make_checked(store_, capacity)); | |
} else { | |
this->set(data, capacity); | |
other.set(other.store_, 0); | |
} | |
this->resize(size); | |
} | |
public: | |
basic_memory_buffer(basic_memory_buffer&& other) noexcept { | |
move(other); | |
} | |
basic_memory_buffer& operator=(basic_memory_buffer&& other) noexcept { | |
((this != &other) | |
? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
714, | |
(""))); | |
deallocate(); | |
move(other); | |
return *this; | |
} | |
Allocator get_allocator() const { | |
return alloc_; | |
} | |
void resize(size_t count) { | |
this->try_resize(count); | |
} | |
void reserve(size_t new_capacity) { | |
this->try_reserve(new_capacity); | |
} | |
using detail::buffer<T>::append; | |
template <typename ContiguousRange> | |
void append(const ContiguousRange& range) { | |
append(range.data(), range.data() + range.size()); | |
} | |
}; | |
template <typename T, size_t SIZE, typename Allocator> | |
void basic_memory_buffer<T, SIZE, Allocator>::grow(size_t size) { | |
size_t old_capacity = this->capacity(); | |
size_t new_capacity = old_capacity + old_capacity / 2; | |
if (size > new_capacity) | |
new_capacity = size; | |
T* old_data = this->data(); | |
T* new_data = | |
std::allocator_traits<Allocator>::allocate(alloc_, new_capacity); | |
std::uninitialized_copy(old_data, | |
old_data + this->size(), | |
detail::make_checked(new_data, new_capacity)); | |
this->set(new_data, new_capacity); | |
if (old_data != store_) | |
alloc_.deallocate(old_data, old_capacity); | |
} | |
using memory_buffer = basic_memory_buffer<char>; | |
using wmemory_buffer = basic_memory_buffer<wchar_t>; | |
template <typename T, size_t SIZE, typename Allocator> | |
struct is_contiguous<basic_memory_buffer<T, SIZE, Allocator>> : std::true_type { | |
}; | |
class format_error : public std::runtime_error { | |
public: | |
explicit format_error(const char* message) : std::runtime_error(message) { | |
} | |
explicit format_error(const std::string& message) | |
: std::runtime_error(message) { | |
} | |
format_error(const format_error&) = default; | |
format_error& operator=(const format_error&) = default; | |
format_error(format_error&&) = default; | |
format_error& operator=(format_error&&) = default; | |
~format_error() noexcept override; | |
}; | |
namespace detail { | |
template <typename T> | |
using is_signed = | |
std::integral_constant<bool, | |
std::numeric_limits<T>::is_signed || | |
std::is_same<T, int128_t>::value>; | |
template <typename T, enable_if_t<(is_signed<T>::value), int> = 0> | |
constexpr bool is_negative(T value) { | |
return value < 0; | |
} | |
template <typename T, enable_if_t<(!is_signed<T>::value), int> = 0> | |
constexpr bool is_negative(T) { | |
return false; | |
} | |
template <typename T, enable_if_t<(std::is_floating_point<T>::value), int> = 0> | |
constexpr bool is_supported_floating_point(T) { | |
return (std::is_same<T, float>::value && 1) || | |
(std::is_same<T, double>::value && 1) || | |
(std::is_same<T, long double>::value && 1); | |
} | |
template <typename T> | |
using uint32_or_64_or_128_t = | |
conditional_t<num_bits<T>() <= 32 && !0, | |
uint32_t, | |
conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>; | |
struct uint128_wrapper { | |
uint128_wrapper() = default; | |
uint128_t internal_; | |
uint128_wrapper(uint64_t high, uint64_t low) noexcept | |
: internal_{static_cast<uint128_t>(low) | | |
(static_cast<uint128_t>(high) << 64)} { | |
} | |
uint128_wrapper(uint128_t u) : internal_{u} { | |
} | |
uint64_t high() const noexcept { | |
return uint64_t(internal_ >> 64); | |
} | |
uint64_t low() const noexcept { | |
return uint64_t(internal_); | |
} | |
uint128_wrapper& operator+=(uint64_t n) noexcept { | |
internal_ += n; | |
return *this; | |
} | |
// # 858 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
}; | |
template <typename T> | |
struct divtest_table_entry { | |
T mod_inv; | |
T max_quotient; | |
}; | |
template <typename T = void> | |
struct basic_data { | |
static const uint64_t powers_of_10_64[]; | |
static const uint32_t zero_or_powers_of_10_32_new[]; | |
static const uint64_t zero_or_powers_of_10_64_new[]; | |
static const uint64_t grisu_pow10_significands[]; | |
static const int16_t grisu_pow10_exponents[]; | |
static const divtest_table_entry<uint32_t> divtest_table_for_pow5_32[]; | |
static const divtest_table_entry<uint64_t> divtest_table_for_pow5_64[]; | |
static const uint64_t dragonbox_pow10_significands_64[]; | |
static const uint128_wrapper dragonbox_pow10_significands_128[]; | |
static const uint64_t log10_2_significand = 0x4d104d427de7fbcc; | |
static const uint64_t powers_of_5_64[]; | |
static const uint32_t dragonbox_pow10_recovery_errors[]; | |
using digit_pair = char[2]; | |
static const digit_pair digits[]; | |
static const char hex_digits[]; | |
static const char foreground_color[]; | |
static const char background_color[]; | |
static const char reset_color[5]; | |
static const wchar_t wreset_color[5]; | |
static const char signs[]; | |
static const char left_padding_shifts[5]; | |
static const char right_padding_shifts[5]; | |
static const uint32_t zero_or_powers_of_10_32[]; | |
static const uint64_t zero_or_powers_of_10_64[]; | |
}; | |
inline __attribute__((always_inline)) uint16_t bsr2log10(int bsr) { | |
static constexpr uint16_t data[] = { | |
1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, | |
6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, | |
10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, | |
15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; | |
return data[bsr]; | |
} | |
extern template struct basic_data<void>; | |
struct data : basic_data<> {}; | |
inline int count_digits(uint64_t n) { | |
auto t = bsr2log10(__builtin_clzll(n | 1) ^ 63); | |
return t - (n < data::zero_or_powers_of_10_64_new[t]); | |
} | |
// # 945 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
inline int count_digits(uint128_t n) { | |
int count = 1; | |
for (;;) { | |
if (n < 10) | |
return count; | |
if (n < 100) | |
return count + 1; | |
if (n < 1000) | |
return count + 2; | |
if (n < 10000) | |
return count + 3; | |
n /= 10000U; | |
count += 4; | |
} | |
} | |
template <unsigned BITS, typename UInt> | |
inline int count_digits(UInt n) { | |
int num_digits = 0; | |
do { | |
++num_digits; | |
} while ((n >>= BITS) != 0); | |
return num_digits; | |
} | |
template <> | |
int count_digits<4>(detail::fallback_uintptr n); | |
// # 989 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
inline int count_digits(uint32_t n) { | |
auto t = bsr2log10(__builtin_clz(n | 1) ^ 31); | |
return t - (n < data::zero_or_powers_of_10_32_new[t]); | |
} | |
template <typename Int> | |
constexpr int digits10() noexcept { | |
return std::numeric_limits<Int>::digits10; | |
} | |
template <> | |
constexpr int digits10<int128_t>() noexcept { | |
return 38; | |
} | |
template <> | |
constexpr int digits10<uint128_t>() noexcept { | |
return 38; | |
} | |
template <typename Char> | |
std::string grouping_impl(locale_ref loc); | |
template <typename Char> | |
inline std::string grouping(locale_ref loc) { | |
return grouping_impl<char>(loc); | |
} | |
template <> | |
inline std::string grouping<wchar_t>(locale_ref loc) { | |
return grouping_impl<wchar_t>(loc); | |
} | |
template <typename Char> | |
Char thousands_sep_impl(locale_ref loc); | |
template <typename Char> | |
inline Char thousands_sep(locale_ref loc) { | |
return Char(thousands_sep_impl<char>(loc)); | |
} | |
template <> | |
inline wchar_t thousands_sep(locale_ref loc) { | |
return thousands_sep_impl<wchar_t>(loc); | |
} | |
template <typename Char> | |
Char decimal_point_impl(locale_ref loc); | |
template <typename Char> | |
inline Char decimal_point(locale_ref loc) { | |
return Char(decimal_point_impl<char>(loc)); | |
} | |
template <> | |
inline wchar_t decimal_point(locale_ref loc) { | |
return decimal_point_impl<wchar_t>(loc); | |
} | |
template <typename Char> | |
bool equal2(const Char* lhs, const char* rhs) { | |
return lhs[0] == rhs[0] && lhs[1] == rhs[1]; | |
} | |
inline bool equal2(const char* lhs, const char* rhs) { | |
return memcmp(lhs, rhs, 2) == 0; | |
} | |
template <typename Char> | |
void copy2(Char* dst, const char* src) { | |
*dst++ = static_cast<Char>(*src++); | |
*dst = static_cast<Char>(*src); | |
} | |
inline __attribute__((always_inline)) void copy2(char* dst, const char* src) { | |
memcpy(dst, src, 2); | |
} | |
template <typename Iterator> | |
struct format_decimal_result { | |
Iterator begin; | |
Iterator end; | |
}; | |
template <typename Char, typename UInt> | |
inline format_decimal_result<Char*> format_decimal(Char* out, | |
UInt value, | |
int size) { | |
((size >= count_digits(value)) | |
? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
1051, | |
("invalid digit count"))); | |
out += size; | |
Char* end = out; | |
while (value >= 100) { | |
out -= 2; | |
copy2(out, data::digits[value % 100]); | |
value /= 100; | |
} | |
if (value < 10) { | |
*--out = static_cast<Char>('0' + value); | |
return {out, end}; | |
} | |
out -= 2; | |
copy2(out, data::digits[value]); | |
return {out, end}; | |
} | |
template <typename Char, | |
typename UInt, | |
typename Iterator, | |
enable_if_t<(!std::is_pointer<remove_cvref_t<Iterator>>::value), | |
int> = 0> | |
inline format_decimal_result<Iterator> format_decimal(Iterator out, | |
UInt value, | |
int size) { | |
Char buffer[digits10<UInt>() + 1]; | |
auto end = format_decimal(buffer, value, size).end; | |
return {out, detail::copy_str<Char>(buffer, end, out)}; | |
} | |
template <unsigned BASE_BITS, typename Char, typename UInt> | |
inline Char* format_uint(Char* buffer, | |
UInt value, | |
int num_digits, | |
bool upper = false) { | |
buffer += num_digits; | |
Char* end = buffer; | |
do { | |
const char* digits = upper ? "0123456789ABCDEF" : data::hex_digits; | |
unsigned digit = (value & ((1 << BASE_BITS) - 1)); | |
*--buffer = static_cast<Char>( | |
BASE_BITS < 4 ? static_cast<char>('0' + digit) : digits[digit]); | |
} while ((value >>= BASE_BITS) != 0); | |
return end; | |
} | |
template <unsigned BASE_BITS, typename Char> | |
Char* format_uint(Char* buffer, | |
detail::fallback_uintptr n, | |
int num_digits, | |
bool = false) { | |
auto char_digits = std::numeric_limits<unsigned char>::digits / 4; | |
int start = (num_digits + char_digits - 1) / char_digits - 1; | |
if (int start_digits = num_digits % char_digits) { | |
unsigned value = n.value[start--]; | |
buffer = format_uint<BASE_BITS>(buffer, value, start_digits); | |
} | |
for (; start >= 0; --start) { | |
unsigned value = n.value[start]; | |
buffer += char_digits; | |
auto p = buffer; | |
for (int i = 0; i < char_digits; ++i) { | |
unsigned digit = (value & ((1 << BASE_BITS) - 1)); | |
*--p = static_cast<Char>(data::hex_digits[digit]); | |
value >>= BASE_BITS; | |
} | |
} | |
return buffer; | |
} | |
template <unsigned BASE_BITS, typename Char, typename It, typename UInt> | |
inline It format_uint(It out, UInt value, int num_digits, bool upper = false) { | |
if (auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) { | |
format_uint<BASE_BITS>(ptr, value, num_digits, upper); | |
return out; | |
} | |
char buffer[num_bits<UInt>() / BASE_BITS + 1]; | |
format_uint<BASE_BITS>(buffer, value, num_digits, upper); | |
return detail::copy_str<Char>(buffer, buffer + num_digits, out); | |
} | |
class utf8_to_utf16 { | |
private: | |
wmemory_buffer buffer_; | |
public: | |
explicit utf8_to_utf16(string_view s); | |
operator wstring_view() const { | |
return {&buffer_[0], size()}; | |
} | |
size_t size() const { | |
return buffer_.size() - 1; | |
} | |
const wchar_t* c_str() const { | |
return &buffer_[0]; | |
} | |
std::wstring str() const { | |
return {&buffer_[0], size()}; | |
} | |
}; | |
template <typename T = void> | |
struct null {}; | |
template <typename Char> | |
struct fill_t { | |
private: | |
enum { max_size = 4 }; | |
Char data_[max_size] = {Char(' '), Char(0), Char(0), Char(0)}; | |
unsigned char size_ = 1; | |
public: | |
constexpr void operator=(basic_string_view<Char> s) { | |
auto size = s.size(); | |
if (size > max_size) { | |
throw format_error("invalid fill"); | |
return; | |
} | |
for (size_t i = 0; i < size; ++i) | |
data_[i] = s[i]; | |
size_ = static_cast<unsigned char>(size); | |
} | |
size_t size() const { | |
return size_; | |
} | |
const Char* data() const { | |
return data_; | |
} | |
constexpr Char& operator[](size_t index) { | |
return data_[index]; | |
} | |
constexpr const Char& operator[](size_t index) const { | |
return data_[index]; | |
} | |
}; | |
} // namespace detail | |
namespace align { | |
enum type { none, left, right, center, numeric }; | |
} | |
using align_t = align::type; | |
namespace sign { | |
enum type { none, minus, plus, space }; | |
} | |
using sign_t = sign::type; | |
template <typename Char> | |
struct basic_format_specs { | |
int width; | |
int precision; | |
char type; | |
align_t align : 4; | |
sign_t sign : 3; | |
bool alt : 1; | |
detail::fill_t<Char> fill; | |
constexpr basic_format_specs() | |
: width(0), | |
precision(-1), | |
type(0), | |
align(align::none), | |
sign(sign::none), | |
alt(false) { | |
} | |
}; | |
using format_specs = basic_format_specs<char>; | |
namespace detail { | |
namespace dragonbox { | |
template <class T> | |
struct float_info; | |
template <> | |
struct float_info<float> { | |
using carrier_uint = uint32_t; | |
static const int significand_bits = 23; | |
static const int exponent_bits = 8; | |
static const int min_exponent = -126; | |
static const int max_exponent = 127; | |
static const int exponent_bias = -127; | |
static const int decimal_digits = 9; | |
static const int kappa = 1; | |
static const int big_divisor = 100; | |
static const int small_divisor = 10; | |
static const int min_k = -31; | |
static const int max_k = 46; | |
static const int cache_bits = 64; | |
static const int divisibility_check_by_5_threshold = 39; | |
static const int case_fc_pm_half_lower_threshold = -1; | |
static const int case_fc_pm_half_upper_threshold = 6; | |
static const int case_fc_lower_threshold = -2; | |
static const int case_fc_upper_threshold = 6; | |
static const int case_shorter_interval_left_endpoint_lower_threshold = 2; | |
static const int case_shorter_interval_left_endpoint_upper_threshold = 3; | |
static const int shorter_interval_tie_lower_threshold = -35; | |
static const int shorter_interval_tie_upper_threshold = -35; | |
static const int max_trailing_zeros = 7; | |
}; | |
template <> | |
struct float_info<double> { | |
using carrier_uint = uint64_t; | |
static const int significand_bits = 52; | |
static const int exponent_bits = 11; | |
static const int min_exponent = -1022; | |
static const int max_exponent = 1023; | |
static const int exponent_bias = -1023; | |
static const int decimal_digits = 17; | |
static const int kappa = 2; | |
static const int big_divisor = 1000; | |
static const int small_divisor = 100; | |
static const int min_k = -292; | |
static const int max_k = 326; | |
static const int cache_bits = 128; | |
static const int divisibility_check_by_5_threshold = 86; | |
static const int case_fc_pm_half_lower_threshold = -2; | |
static const int case_fc_pm_half_upper_threshold = 9; | |
static const int case_fc_lower_threshold = -4; | |
static const int case_fc_upper_threshold = 9; | |
static const int case_shorter_interval_left_endpoint_lower_threshold = 2; | |
static const int case_shorter_interval_left_endpoint_upper_threshold = 3; | |
static const int shorter_interval_tie_lower_threshold = -77; | |
static const int shorter_interval_tie_upper_threshold = -77; | |
static const int max_trailing_zeros = 16; | |
}; | |
template <typename T> | |
struct decimal_fp { | |
using significand_type = typename float_info<T>::carrier_uint; | |
significand_type significand; | |
int exponent; | |
}; | |
template <typename T> | |
decimal_fp<T> to_decimal(T x) noexcept; | |
} // namespace dragonbox | |
template <typename T> | |
constexpr typename dragonbox::float_info<T>::carrier_uint exponent_mask() { | |
using uint = typename dragonbox::float_info<T>::carrier_uint; | |
return ((uint(1) << dragonbox::float_info<T>::exponent_bits) - 1) | |
<< dragonbox::float_info<T>::significand_bits; | |
} | |
enum class float_format : unsigned char { general, exp, fixed, hex }; | |
struct float_specs { | |
int precision; | |
float_format format : 8; | |
sign_t sign : 8; | |
bool upper : 1; | |
bool locale : 1; | |
bool binary32 : 1; | |
bool use_grisu : 1; | |
bool showpoint : 1; | |
}; | |
template <typename Char, typename It> | |
It write_exponent(int exp, It it) { | |
((-10000 < exp && exp < 10000) | |
? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
1300, | |
("exponent out of range"))); | |
if (exp < 0) { | |
*it++ = static_cast<Char>('-'); | |
exp = -exp; | |
} else { | |
*it++ = static_cast<Char>('+'); | |
} | |
if (exp >= 100) { | |
const char* top = data::digits[exp / 100]; | |
if (exp >= 1000) | |
*it++ = static_cast<Char>(top[0]); | |
*it++ = static_cast<Char>(top[1]); | |
exp %= 100; | |
} | |
const char* d = data::digits[exp]; | |
*it++ = static_cast<Char>(d[0]); | |
*it++ = static_cast<Char>(d[1]); | |
return it; | |
} | |
template <typename T> | |
int format_float(T value, int precision, float_specs specs, buffer<char>& buf); | |
template <typename T> | |
int snprintf_float(T value, | |
int precision, | |
float_specs specs, | |
buffer<char>& buf); | |
template <typename T> | |
T promote_float(T value) { | |
return value; | |
} | |
inline double promote_float(float value) { | |
return static_cast<double>(value); | |
} | |
template <typename Handler> | |
constexpr void handle_int_type_spec(char spec, Handler&& handler) { | |
switch (spec) { | |
case 0: | |
case 'd': | |
handler.on_dec(); | |
break; | |
case 'x': | |
case 'X': | |
handler.on_hex(); | |
break; | |
case 'b': | |
case 'B': | |
handler.on_bin(); | |
break; | |
case 'o': | |
handler.on_oct(); | |
break; | |
case 'L': | |
handler.on_num(); | |
break; | |
case 'c': | |
handler.on_chr(); | |
break; | |
default: | |
handler.on_error(); | |
} | |
} | |
template <typename ErrorHandler = error_handler, typename Char> | |
constexpr float_specs parse_float_type_spec( | |
const basic_format_specs<Char>& specs, ErrorHandler&& eh = {}) { | |
auto result = float_specs(); | |
result.showpoint = specs.alt; | |
switch (specs.type) { | |
case 0: | |
result.format = float_format::general; | |
result.showpoint |= specs.precision > 0; | |
break; | |
case 'G': | |
result.upper = true; | |
[[fallthrough]]; | |
case 'g': | |
result.format = float_format::general; | |
break; | |
case 'E': | |
result.upper = true; | |
[[fallthrough]]; | |
case 'e': | |
result.format = float_format::exp; | |
result.showpoint |= specs.precision != 0; | |
break; | |
case 'F': | |
result.upper = true; | |
[[fallthrough]]; | |
case 'f': | |
result.format = float_format::fixed; | |
result.showpoint |= specs.precision != 0; | |
break; | |
case 'A': | |
result.upper = true; | |
[[fallthrough]]; | |
case 'a': | |
result.format = float_format::hex; | |
break; | |
case 'L': | |
result.locale = true; | |
break; | |
default: | |
eh.on_error("invalid type specifier"); | |
break; | |
} | |
return result; | |
} | |
template <typename Char, typename Handler> | |
constexpr void handle_char_specs(const basic_format_specs<Char>* specs, | |
Handler&& handler) { | |
if (!specs) | |
return handler.on_char(); | |
if (specs->type && specs->type != 'c') | |
return handler.on_int(); | |
if (specs->align == align::numeric || specs->sign != sign::none || | |
specs->alt) | |
handler.on_error("invalid format specifier for char"); | |
handler.on_char(); | |
} | |
template <typename Char, typename Handler> | |
constexpr void handle_cstring_type_spec(Char spec, Handler&& handler) { | |
if (spec == 0 || spec == 's') | |
handler.on_string(); | |
else if (spec == 'p') | |
handler.on_pointer(); | |
else | |
handler.on_error("invalid type specifier"); | |
} | |
template <typename Char, typename ErrorHandler> | |
constexpr void check_string_type_spec(Char spec, ErrorHandler&& eh) { | |
if (spec != 0 && spec != 's') | |
eh.on_error("invalid type specifier"); | |
} | |
template <typename Char, typename ErrorHandler> | |
constexpr void check_pointer_type_spec(Char spec, ErrorHandler&& eh) { | |
if (spec != 0 && spec != 'p') | |
eh.on_error("invalid type specifier"); | |
} | |
template <typename ErrorHandler> | |
class int_type_checker : private ErrorHandler { | |
public: | |
constexpr explicit int_type_checker(ErrorHandler eh) : ErrorHandler(eh) { | |
} | |
constexpr void on_dec() { | |
} | |
constexpr void on_hex() { | |
} | |
constexpr void on_bin() { | |
} | |
constexpr void on_oct() { | |
} | |
constexpr void on_num() { | |
} | |
constexpr void on_chr() { | |
} | |
constexpr void on_error() { | |
ErrorHandler::on_error("invalid type specifier"); | |
} | |
}; | |
template <typename ErrorHandler> | |
class char_specs_checker : public ErrorHandler { | |
private: | |
char type_; | |
public: | |
constexpr char_specs_checker(char type, ErrorHandler eh) | |
: ErrorHandler(eh), type_(type) { | |
} | |
constexpr void on_int() { | |
handle_int_type_spec(type_, int_type_checker<ErrorHandler>(*this)); | |
} | |
constexpr void on_char() { | |
} | |
}; | |
template <typename ErrorHandler> | |
class cstring_type_checker : public ErrorHandler { | |
public: | |
constexpr explicit cstring_type_checker(ErrorHandler eh) | |
: ErrorHandler(eh) { | |
} | |
constexpr void on_string() { | |
} | |
constexpr void on_pointer() { | |
} | |
}; | |
template <typename OutputIt, typename Char> | |
__attribute__((noinline)) OutputIt fill(OutputIt it, | |
size_t n, | |
const fill_t<Char>& fill) { | |
auto fill_size = fill.size(); | |
if (fill_size == 1) | |
return std::fill_n(it, n, fill[0]); | |
for (size_t i = 0; i < n; ++i) | |
it = std::copy_n(fill.data(), fill_size, it); | |
return it; | |
} | |
template <align::type align = align::left, | |
typename OutputIt, | |
typename Char, | |
typename F> | |
inline OutputIt write_padded(OutputIt out, | |
const basic_format_specs<Char>& specs, | |
size_t size, | |
size_t width, | |
F&& f) { | |
static_assert(align == align::left || align == align::right, ""); | |
unsigned spec_width = to_unsigned(specs.width); | |
size_t padding = spec_width > width ? spec_width - width : 0; | |
auto* shifts = align == align::left ? data::left_padding_shifts | |
: data::right_padding_shifts; | |
size_t left_padding = padding >> shifts[specs.align]; | |
auto it = reserve(out, size + padding * specs.fill.size()); | |
it = fill(it, left_padding, specs.fill); | |
it = f(it); | |
it = fill(it, padding - left_padding, specs.fill); | |
return base_iterator(out, it); | |
} | |
template <align::type align = align::left, | |
typename OutputIt, | |
typename Char, | |
typename F> | |
inline OutputIt write_padded(OutputIt out, | |
const basic_format_specs<Char>& specs, | |
size_t size, | |
F&& f) { | |
return write_padded<align>(out, specs, size, size, f); | |
} | |
template <typename Char, typename OutputIt> | |
OutputIt write_bytes(OutputIt out, | |
string_view bytes, | |
const basic_format_specs<Char>& specs) { | |
using iterator = remove_reference_t<decltype(reserve(out, 0))>; | |
return write_padded(out, specs, bytes.size(), [bytes](iterator it) { | |
const char* data = bytes.data(); | |
return copy_str<Char>(data, data + bytes.size(), it); | |
}); | |
} | |
template <typename Char> | |
struct write_int_data { | |
size_t size; | |
size_t padding; | |
write_int_data(int num_digits, | |
string_view prefix, | |
const basic_format_specs<Char>& specs) | |
: size(prefix.size() + to_unsigned(num_digits)), padding(0) { | |
if (specs.align == align::numeric) { | |
auto width = to_unsigned(specs.width); | |
if (width > size) { | |
padding = width - size; | |
size = width; | |
} | |
} else if (specs.precision > num_digits) { | |
size = prefix.size() + to_unsigned(specs.precision); | |
padding = to_unsigned(specs.precision - num_digits); | |
} | |
} | |
}; | |
template <typename OutputIt, typename Char, typename F> | |
OutputIt write_int(OutputIt out, | |
int num_digits, | |
string_view prefix, | |
const basic_format_specs<Char>& specs, | |
F f) { | |
auto data = write_int_data<Char>(num_digits, prefix, specs); | |
using iterator = remove_reference_t<decltype(reserve(out, 0))>; | |
return write_padded<align::right>(out, specs, data.size, [=](iterator it) { | |
if (prefix.size() != 0) | |
it = copy_str<Char>(prefix.begin(), prefix.end(), it); | |
it = std::fill_n(it, data.padding, static_cast<Char>('0')); | |
return f(it); | |
}); | |
} | |
template <typename StrChar, typename Char, typename OutputIt> | |
OutputIt write(OutputIt out, | |
basic_string_view<StrChar> s, | |
const basic_format_specs<Char>& specs) { | |
auto data = s.data(); | |
auto size = s.size(); | |
if (specs.precision >= 0 && to_unsigned(specs.precision) < size) | |
size = code_point_index(s, to_unsigned(specs.precision)); | |
auto width = | |
specs.width != 0 | |
? count_code_points(basic_string_view<StrChar>(data, size)) | |
: 0; | |
using iterator = remove_reference_t<decltype(reserve(out, 0))>; | |
return write_padded(out, specs, size, width, [=](iterator it) { | |
return copy_str<Char>(data, data + size, it); | |
}); | |
} | |
template <typename OutputIt, typename Char, typename UInt> | |
struct int_writer { | |
OutputIt out; | |
locale_ref locale; | |
const basic_format_specs<Char>& specs; | |
UInt abs_value; | |
char prefix[4]; | |
unsigned prefix_size; | |
using iterator = | |
remove_reference_t<decltype(reserve(std::declval<OutputIt&>(), 0))>; | |
string_view get_prefix() const { | |
return string_view(prefix, prefix_size); | |
} | |
template <typename Int> | |
int_writer(OutputIt output, | |
locale_ref loc, | |
Int value, | |
const basic_format_specs<Char>& s) | |
: out(output), | |
locale(loc), | |
specs(s), | |
abs_value(static_cast<UInt>(value)), | |
prefix_size(0) { | |
static_assert(std::is_same<uint32_or_64_or_128_t<Int>, UInt>::value, | |
""); | |
if (is_negative(value)) { | |
prefix[0] = '-'; | |
++prefix_size; | |
abs_value = 0 - abs_value; | |
} else if (specs.sign != sign::none && specs.sign != sign::minus) { | |
prefix[0] = specs.sign == sign::plus ? '+' : ' '; | |
++prefix_size; | |
} | |
} | |
void on_dec() { | |
auto num_digits = count_digits(abs_value); | |
out = write_int( | |
out, | |
num_digits, | |
get_prefix(), | |
specs, | |
[this, num_digits](iterator it) { | |
return format_decimal<Char>(it, abs_value, num_digits).end; | |
}); | |
} | |
void on_hex() { | |
if (specs.alt) { | |
prefix[prefix_size++] = '0'; | |
prefix[prefix_size++] = specs.type; | |
} | |
int num_digits = count_digits<4>(abs_value); | |
out = write_int( | |
out, | |
num_digits, | |
get_prefix(), | |
specs, | |
[this, num_digits](iterator it) { | |
return format_uint<4, Char>( | |
it, abs_value, num_digits, specs.type != 'x'); | |
}); | |
} | |
void on_bin() { | |
if (specs.alt) { | |
prefix[prefix_size++] = '0'; | |
prefix[prefix_size++] = static_cast<char>(specs.type); | |
} | |
int num_digits = count_digits<1>(abs_value); | |
out = write_int(out, | |
num_digits, | |
get_prefix(), | |
specs, | |
[this, num_digits](iterator it) { | |
return format_uint<1, Char>( | |
it, abs_value, num_digits); | |
}); | |
} | |
void on_oct() { | |
int num_digits = count_digits<3>(abs_value); | |
if (specs.alt && specs.precision <= num_digits && abs_value != 0) { | |
prefix[prefix_size++] = '0'; | |
} | |
out = write_int(out, | |
num_digits, | |
get_prefix(), | |
specs, | |
[this, num_digits](iterator it) { | |
return format_uint<3, Char>( | |
it, abs_value, num_digits); | |
}); | |
} | |
enum { sep_size = 1 }; | |
void on_num() { | |
std::string groups = grouping<Char>(locale); | |
if (groups.empty()) | |
return on_dec(); | |
auto sep = thousands_sep<Char>(locale); | |
if (!sep) | |
return on_dec(); | |
int num_digits = count_digits(abs_value); | |
int size = num_digits, n = num_digits; | |
std::string::const_iterator group = groups.cbegin(); | |
while (group != groups.cend() && n > *group && *group > 0 && | |
*group != max_value<char>()) { | |
size += sep_size; | |
n -= *group; | |
++group; | |
} | |
if (group == groups.cend()) | |
size += sep_size * ((n - 1) / groups.back()); | |
char digits[40]; | |
format_decimal(digits, abs_value, num_digits); | |
basic_memory_buffer<Char> buffer; | |
size += static_cast<int>(prefix_size); | |
const auto usize = to_unsigned(size); | |
buffer.resize(usize); | |
basic_string_view<Char> s(&sep, sep_size); | |
int digit_index = 0; | |
group = groups.cbegin(); | |
auto p = buffer.data() + size - 1; | |
for (int i = num_digits - 1; i > 0; --i) { | |
*p-- = static_cast<Char>(digits[i]); | |
if (*group <= 0 || ++digit_index % *group != 0 || | |
*group == max_value<char>()) | |
continue; | |
if (group + 1 != groups.cend()) { | |
digit_index = 0; | |
++group; | |
} | |
std::uninitialized_copy( | |
s.data(), s.data() + s.size(), make_checked(p, s.size())); | |
p -= s.size(); | |
} | |
*p-- = static_cast<Char>(*digits); | |
if (prefix_size != 0) | |
*p = static_cast<Char>('-'); | |
auto data = buffer.data(); | |
out = write_padded<align::right>( | |
out, specs, usize, usize, [=](iterator it) { | |
return copy_str<Char>(data, data + size, it); | |
}); | |
} | |
void on_chr() { | |
*out++ = static_cast<Char>(abs_value); | |
} | |
[[noreturn]] void on_error() { | |
throw format_error("invalid type specifier"); | |
} | |
}; | |
template <typename Char, typename OutputIt> | |
OutputIt write_nonfinite(OutputIt out, | |
bool isinf, | |
const basic_format_specs<Char>& specs, | |
const float_specs& fspecs) { | |
auto str = isinf ? (fspecs.upper ? "INF" : "inf") | |
: (fspecs.upper ? "NAN" : "nan"); | |
constexpr size_t str_size = 3; | |
auto sign = fspecs.sign; | |
auto size = str_size + (sign ? 1 : 0); | |
using iterator = remove_reference_t<decltype(reserve(out, 0))>; | |
return write_padded(out, specs, size, [=](iterator it) { | |
if (sign) | |
*it++ = static_cast<Char>(data::signs[sign]); | |
return copy_str<Char>(str, str + str_size, it); | |
}); | |
} | |
struct big_decimal_fp { | |
const char* significand; | |
int significand_size; | |
int exponent; | |
}; | |
inline int get_significand_size(const big_decimal_fp& fp) { | |
return fp.significand_size; | |
} | |
template <typename T> | |
inline int get_significand_size(const dragonbox::decimal_fp<T>& fp) { | |
return count_digits(fp.significand); | |
} | |
template <typename Char, typename OutputIt> | |
inline OutputIt write_significand(OutputIt out, | |
const char* significand, | |
int& significand_size) { | |
return copy_str<Char>(significand, significand + significand_size, out); | |
} | |
template <typename Char, typename OutputIt, typename UInt> | |
inline OutputIt write_significand(OutputIt out, | |
UInt significand, | |
int significand_size) { | |
return format_decimal<Char>(out, significand, significand_size).end; | |
} | |
template <typename Char, | |
typename UInt, | |
enable_if_t<(std::is_integral<UInt>::value), int> = 0> | |
inline Char* write_significand(Char* out, | |
UInt significand, | |
int significand_size, | |
int integral_size, | |
Char decimal_point) { | |
if (!decimal_point) | |
return format_decimal(out, significand, significand_size).end; | |
auto end = format_decimal(out + 1, significand, significand_size).end; | |
if (integral_size == 1) | |
out[0] = out[1]; | |
else | |
std::copy_n(out + 1, integral_size, out); | |
out[integral_size] = decimal_point; | |
return end; | |
} | |
template <typename OutputIt, | |
typename UInt, | |
typename Char, | |
enable_if_t<(!std::is_pointer<remove_cvref_t<OutputIt>>::value), | |
int> = 0> | |
inline OutputIt write_significand(OutputIt out, | |
UInt significand, | |
int significand_size, | |
int integral_size, | |
Char decimal_point) { | |
Char buffer[digits10<UInt>() + 2]; | |
auto end = write_significand(buffer, | |
significand, | |
significand_size, | |
integral_size, | |
decimal_point); | |
return detail::copy_str<Char>(buffer, end, out); | |
} | |
template <typename OutputIt, typename Char> | |
inline OutputIt write_significand(OutputIt out, | |
const char* significand, | |
int significand_size, | |
int integral_size, | |
Char decimal_point) { | |
out = detail::copy_str<Char>(significand, significand + integral_size, out); | |
if (!decimal_point) | |
return out; | |
*out++ = decimal_point; | |
return detail::copy_str<Char>( | |
significand + integral_size, significand + significand_size, out); | |
} | |
template <typename OutputIt, typename DecimalFP, typename Char> | |
OutputIt write_float(OutputIt out, | |
const DecimalFP& fp, | |
const basic_format_specs<Char>& specs, | |
float_specs fspecs, | |
Char decimal_point) { | |
auto significand = fp.significand; | |
int significand_size = get_significand_size(fp); | |
static const Char zero = static_cast<Char>('0'); | |
auto sign = fspecs.sign; | |
size_t size = to_unsigned(significand_size) + (sign ? 1 : 0); | |
using iterator = remove_reference_t<decltype(reserve(out, 0))>; | |
int output_exp = fp.exponent + significand_size - 1; | |
auto use_exp_format = [=]() { | |
if (fspecs.format == float_format::exp) | |
return true; | |
if (fspecs.format != float_format::general) | |
return false; | |
const int exp_lower = -4, exp_upper = 16; | |
return output_exp < exp_lower || | |
output_exp >= | |
(fspecs.precision > 0 ? fspecs.precision : exp_upper); | |
}; | |
if (use_exp_format()) { | |
int num_zeros = 0; | |
if (fspecs.showpoint) { | |
num_zeros = (std::max)(fspecs.precision - significand_size, 0); | |
size += to_unsigned(num_zeros); | |
} else if (significand_size == 1) { | |
decimal_point = Char(); | |
} | |
auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp; | |
int exp_digits = 2; | |
if (abs_output_exp >= 100) | |
exp_digits = abs_output_exp >= 1000 ? 4 : 3; | |
size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits); | |
char exp_char = fspecs.upper ? 'E' : 'e'; | |
auto write = [=](iterator it) { | |
if (sign) | |
*it++ = static_cast<Char>(data::signs[sign]); | |
it = write_significand( | |
it, significand, significand_size, 1, decimal_point); | |
if (num_zeros > 0) | |
it = std::fill_n(it, num_zeros, zero); | |
*it++ = static_cast<Char>(exp_char); | |
return write_exponent<Char>(output_exp, it); | |
}; | |
return specs.width > 0 | |
? write_padded<align::right>(out, specs, size, write) | |
: base_iterator(out, write(reserve(out, size))); | |
} | |
int exp = fp.exponent + significand_size; | |
if (fp.exponent >= 0) { | |
size += to_unsigned(fp.exponent); | |
int num_zeros = fspecs.precision - exp; | |
if (fspecs.showpoint) { | |
if (num_zeros <= 0 && fspecs.format != float_format::fixed) | |
num_zeros = 1; | |
if (num_zeros > 0) | |
size += to_unsigned(num_zeros); | |
} | |
return write_padded<align::right>(out, specs, size, [&](iterator it) { | |
if (sign) | |
*it++ = static_cast<Char>(data::signs[sign]); | |
it = write_significand<Char>(it, significand, significand_size); | |
it = std::fill_n(it, fp.exponent, zero); | |
if (!fspecs.showpoint) | |
return it; | |
*it++ = decimal_point; | |
return num_zeros > 0 ? std::fill_n(it, num_zeros, zero) : it; | |
}); | |
} else if (exp > 0) { | |
int num_zeros = | |
fspecs.showpoint ? fspecs.precision - significand_size : 0; | |
size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0); | |
return write_padded<align::right>(out, specs, size, [&](iterator it) { | |
if (sign) | |
*it++ = static_cast<Char>(data::signs[sign]); | |
it = write_significand( | |
it, significand, significand_size, exp, decimal_point); | |
return num_zeros > 0 ? std::fill_n(it, num_zeros, zero) : it; | |
}); | |
} | |
int num_zeros = -exp; | |
if (significand_size == 0 && fspecs.precision >= 0 && | |
fspecs.precision < num_zeros) { | |
num_zeros = fspecs.precision; | |
} | |
size += 2 + to_unsigned(num_zeros); | |
return write_padded<align::right>(out, specs, size, [&](iterator it) { | |
if (sign) | |
*it++ = static_cast<Char>(data::signs[sign]); | |
*it++ = zero; | |
if (num_zeros == 0 && significand_size == 0 && !fspecs.showpoint) | |
return it; | |
*it++ = decimal_point; | |
it = std::fill_n(it, num_zeros, zero); | |
return write_significand<Char>(it, significand, significand_size); | |
}); | |
} | |
template <typename Char, | |
typename OutputIt, | |
typename T, | |
enable_if_t<(std::is_floating_point<T>::value), int> = 0> | |
OutputIt write(OutputIt out, | |
T value, | |
basic_format_specs<Char> specs, | |
locale_ref loc = {}) { | |
if (const_check(!is_supported_floating_point(value))) | |
return out; | |
float_specs fspecs = parse_float_type_spec(specs); | |
fspecs.sign = specs.sign; | |
if (std::signbit(value)) { | |
fspecs.sign = sign::minus; | |
value = -value; | |
} else if (fspecs.sign == sign::minus) { | |
fspecs.sign = sign::none; | |
} | |
if (!std::isfinite(value)) | |
return write_nonfinite(out, std::isinf(value), specs, fspecs); | |
if (specs.align == align::numeric && fspecs.sign) { | |
auto it = reserve(out, 1); | |
*it++ = static_cast<Char>(data::signs[fspecs.sign]); | |
out = base_iterator(out, it); | |
fspecs.sign = sign::none; | |
if (specs.width != 0) | |
--specs.width; | |
} | |
memory_buffer buffer; | |
if (fspecs.format == float_format::hex) { | |
if (fspecs.sign) | |
buffer.push_back(data::signs[fspecs.sign]); | |
snprintf_float(promote_float(value), specs.precision, fspecs, buffer); | |
return write_bytes(out, {buffer.data(), buffer.size()}, specs); | |
} | |
int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6; | |
if (fspecs.format == float_format::exp) { | |
if (precision == max_value<int>()) | |
throw format_error("number is too big"); | |
else | |
++precision; | |
} | |
if (const_check(std::is_same<T, float>())) | |
fspecs.binary32 = true; | |
fspecs.use_grisu = is_fast_float<T>(); | |
int exp = format_float(promote_float(value), precision, fspecs, buffer); | |
fspecs.precision = precision; | |
Char point = | |
fspecs.locale ? decimal_point<Char>(loc) : static_cast<Char>('.'); | |
auto fp = | |
big_decimal_fp{buffer.data(), static_cast<int>(buffer.size()), exp}; | |
return write_float(out, fp, specs, fspecs, point); | |
} | |
template <typename Char, | |
typename OutputIt, | |
typename T, | |
enable_if_t<(is_fast_float<T>::value), int> = 0> | |
OutputIt write(OutputIt out, T value) { | |
if (const_check(!is_supported_floating_point(value))) | |
return out; | |
using floaty = | |
conditional_t<std::is_same<T, long double>::value, double, T>; | |
using uint = typename dragonbox::float_info<floaty>::carrier_uint; | |
auto bits = bit_cast<uint>(value); | |
auto fspecs = float_specs(); | |
auto sign_bit = bits & (uint(1) << (num_bits<uint>() - 1)); | |
if (sign_bit != 0) { | |
fspecs.sign = sign::minus; | |
value = -value; | |
} | |
static const auto specs = basic_format_specs<Char>(); | |
uint mask = exponent_mask<floaty>(); | |
if ((bits & mask) == mask) | |
return write_nonfinite(out, std::isinf(value), specs, fspecs); | |
auto dec = dragonbox::to_decimal(static_cast<floaty>(value)); | |
return write_float(out, dec, specs, fspecs, static_cast<Char>('.')); | |
} | |
template <typename Char, | |
typename OutputIt, | |
typename T, | |
enable_if_t<(std::is_floating_point<T>::value && | |
!is_fast_float<T>::value), | |
int> = 0> | |
inline OutputIt write(OutputIt out, T value) { | |
return write(out, value, basic_format_specs<Char>()); | |
} | |
template <typename Char, typename OutputIt> | |
OutputIt write_char(OutputIt out, | |
Char value, | |
const basic_format_specs<Char>& specs) { | |
using iterator = remove_reference_t<decltype(reserve(out, 0))>; | |
return write_padded(out, specs, 1, [=](iterator it) { | |
*it++ = value; | |
return it; | |
}); | |
} | |
template <typename Char, typename OutputIt, typename UIntPtr> | |
OutputIt write_ptr(OutputIt out, | |
UIntPtr value, | |
const basic_format_specs<Char>* specs) { | |
int num_digits = count_digits<4>(value); | |
auto size = to_unsigned(num_digits) + size_t(2); | |
using iterator = remove_reference_t<decltype(reserve(out, 0))>; | |
auto write = [=](iterator it) { | |
*it++ = static_cast<Char>('0'); | |
*it++ = static_cast<Char>('x'); | |
return format_uint<4, Char>(it, value, num_digits); | |
}; | |
return specs ? write_padded<align::right>(out, *specs, size, write) | |
: base_iterator(out, write(reserve(out, size))); | |
} | |
template <typename T> | |
struct is_integral : std::is_integral<T> {}; | |
template <> | |
struct is_integral<int128_t> : std::true_type {}; | |
template <> | |
struct is_integral<uint128_t> : std::true_type {}; | |
template <typename Char, typename OutputIt> | |
OutputIt write(OutputIt out, monostate) { | |
((false) ? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
2007, | |
(""))); | |
return out; | |
} | |
template <typename Char, | |
typename OutputIt, | |
enable_if_t<(!std::is_same<Char, char>::value), int> = 0> | |
OutputIt write(OutputIt out, string_view value) { | |
auto it = reserve(out, value.size()); | |
it = copy_str<Char>(value.begin(), value.end(), it); | |
return base_iterator(out, it); | |
} | |
template <typename Char, typename OutputIt> | |
OutputIt write(OutputIt out, basic_string_view<Char> value) { | |
auto it = reserve(out, value.size()); | |
it = std::copy(value.begin(), value.end(), it); | |
return base_iterator(out, it); | |
} | |
template <typename Char> | |
buffer_appender<Char> write(buffer_appender<Char> out, | |
basic_string_view<Char> value) { | |
get_container(out).append(value.begin(), value.end()); | |
return out; | |
} | |
template <typename Char, | |
typename OutputIt, | |
typename T, | |
enable_if_t<(is_integral<T>::value && !std::is_same<T, bool>::value && | |
!std::is_same<T, Char>::value), | |
int> = 0 | |
> | |
OutputIt write(OutputIt out, T value) { | |
auto abs_value = static_cast<uint32_or_64_or_128_t<T>>(value); | |
bool negative = is_negative(value); | |
if (negative) | |
abs_value = ~abs_value + 1; | |
int num_digits = count_digits(abs_value); | |
auto size = (negative ? 1 : 0) + static_cast<size_t>(num_digits); | |
auto it = reserve(out, size); | |
if (auto ptr = to_pointer<Char>(it, size)) { | |
if (negative) | |
*ptr++ = static_cast<Char>('-'); | |
format_decimal<Char>(ptr, abs_value, num_digits); | |
return out; | |
} | |
if (negative) | |
*it++ = static_cast<Char>('-'); | |
it = format_decimal<Char>(it, abs_value, num_digits).end; | |
return base_iterator(out, it); | |
} | |
template <typename Char, typename OutputIt> | |
OutputIt write(OutputIt out, bool value) { | |
return write<Char>(out, string_view(value ? "true" : "false")); | |
} | |
template <typename Char, typename OutputIt> | |
OutputIt write(OutputIt out, Char value) { | |
auto it = reserve(out, 1); | |
*it++ = value; | |
return base_iterator(out, it); | |
} | |
template <typename Char, typename OutputIt> | |
OutputIt write(OutputIt out, const Char* value) { | |
if (!value) { | |
throw format_error("string pointer is null"); | |
} else { | |
auto length = std::char_traits<Char>::length(value); | |
out = write(out, basic_string_view<Char>(value, length)); | |
} | |
return out; | |
} | |
template <typename Char, typename OutputIt> | |
OutputIt write(OutputIt out, const void* value) { | |
return write_ptr<Char>(out, to_uintptr(value), nullptr); | |
} | |
template <typename Char, typename OutputIt, typename T> | |
auto write(OutputIt out, const T& value) -> typename std::enable_if< | |
mapped_type_constant<T, basic_format_context<OutputIt, Char>>::value == | |
type::custom_type, | |
OutputIt>::type { | |
using context_type = basic_format_context<OutputIt, Char>; | |
using formatter_type = | |
conditional_t<has_formatter<T, context_type>::value, | |
typename context_type::template formatter_type<T>, | |
fallback_formatter<T, Char>>; | |
context_type ctx(out, {}, {}); | |
return formatter_type().format(value, ctx); | |
} | |
template <typename OutputIt, typename Char> | |
struct default_arg_formatter { | |
using context = basic_format_context<OutputIt, Char>; | |
OutputIt out; | |
basic_format_args<context> args; | |
locale_ref loc; | |
template <typename T> | |
OutputIt operator()(T value) { | |
return write<Char>(out, value); | |
} | |
OutputIt operator()(typename basic_format_arg<context>::handle handle) { | |
basic_format_parse_context<Char> parse_ctx({}); | |
basic_format_context<OutputIt, Char> format_ctx(out, args, loc); | |
handle.format(parse_ctx, format_ctx); | |
return format_ctx.out(); | |
} | |
}; | |
template <typename OutputIt, | |
typename Char, | |
typename ErrorHandler = error_handler> | |
class arg_formatter_base { | |
public: | |
using iterator = OutputIt; | |
using char_type = Char; | |
using format_specs = basic_format_specs<Char>; | |
private: | |
iterator out_; | |
locale_ref locale_; | |
format_specs* specs_; | |
auto reserve(size_t n) -> decltype(detail::reserve(out_, n)) { | |
return detail::reserve(out_, n); | |
} | |
using reserve_iterator = remove_reference_t<decltype( | |
detail::reserve(std::declval<iterator&>(), 0))>; | |
template <typename T> | |
void write_int(T value, const format_specs& spec) { | |
using uint_type = uint32_or_64_or_128_t<T>; | |
int_writer<iterator, Char, uint_type> w(out_, locale_, value, spec); | |
handle_int_type_spec(spec.type, w); | |
out_ = w.out; | |
} | |
void write(char value) { | |
auto&& it = reserve(1); | |
*it++ = value; | |
} | |
template <typename Ch, | |
enable_if_t<(std::is_same<Ch, Char>::value), int> = 0> | |
void write(Ch value) { | |
out_ = detail::write<Char>(out_, value); | |
} | |
void write(string_view value) { | |
auto&& it = reserve(value.size()); | |
it = copy_str<Char>(value.begin(), value.end(), it); | |
} | |
void write(wstring_view value) { | |
static_assert(std::is_same<Char, wchar_t>::value, ""); | |
auto&& it = reserve(value.size()); | |
it = std::copy(value.begin(), value.end(), it); | |
} | |
template <typename Ch> | |
void write(const Ch* s, size_t size, const format_specs& specs) { | |
auto width = specs.width != 0 | |
? count_code_points(basic_string_view<Ch>(s, size)) | |
: 0; | |
out_ = write_padded(out_, specs, size, width, [=](reserve_iterator it) { | |
return copy_str<Char>(s, s + size, it); | |
}); | |
} | |
template <typename Ch> | |
void write(basic_string_view<Ch> s, const format_specs& specs = {}) { | |
out_ = detail::write(out_, s, specs); | |
} | |
void write_pointer(const void* p) { | |
out_ = write_ptr<char_type>(out_, to_uintptr(p), specs_); | |
} | |
struct char_spec_handler : ErrorHandler { | |
arg_formatter_base& formatter; | |
Char value; | |
char_spec_handler(arg_formatter_base& f, Char val) | |
: formatter(f), value(val) { | |
} | |
void on_int() { | |
formatter.write_int(static_cast<int>(value), *formatter.specs_); | |
} | |
void on_char() { | |
if (formatter.specs_) | |
formatter.out_ = | |
write_char(formatter.out_, value, *formatter.specs_); | |
else | |
formatter.write(value); | |
} | |
}; | |
struct cstring_spec_handler : error_handler { | |
arg_formatter_base& formatter; | |
const Char* value; | |
cstring_spec_handler(arg_formatter_base& f, const Char* val) | |
: formatter(f), value(val) { | |
} | |
void on_string() { | |
formatter.write(value); | |
} | |
void on_pointer() { | |
formatter.write_pointer(value); | |
} | |
}; | |
protected: | |
iterator out() { | |
return out_; | |
} | |
format_specs* specs() { | |
return specs_; | |
} | |
void write(bool value) { | |
if (specs_) | |
write(string_view(value ? "true" : "false"), *specs_); | |
else | |
out_ = detail::write<Char>(out_, value); | |
} | |
void write(const Char* value) { | |
if (!value) { | |
throw format_error("string pointer is null"); | |
} else { | |
auto length = std::char_traits<char_type>::length(value); | |
basic_string_view<char_type> sv(value, length); | |
specs_ ? write(sv, *specs_) : write(sv); | |
} | |
} | |
public: | |
arg_formatter_base(OutputIt out, format_specs* s, locale_ref loc) | |
: out_(out), locale_(loc), specs_(s) { | |
} | |
iterator operator()(monostate) { | |
((false) ? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
2242, | |
("invalid argument type"))); | |
return out_; | |
} | |
template <typename T, enable_if_t<(is_integral<T>::value), int> = 0> | |
inline __attribute__((always_inline)) iterator operator()(T value) { | |
if (specs_) | |
write_int(value, *specs_); | |
else | |
out_ = detail::write<Char>(out_, value); | |
return out_; | |
} | |
iterator operator()(Char value) { | |
handle_char_specs(specs_, | |
char_spec_handler(*this, static_cast<Char>(value))); | |
return out_; | |
} | |
iterator operator()(bool value) { | |
if (specs_ && specs_->type) | |
return (*this)(value ? 1 : 0); | |
write(value != 0); | |
return out_; | |
} | |
template <typename T, | |
enable_if_t<(std::is_floating_point<T>::value), int> = 0> | |
iterator operator()(T value) { | |
auto specs = specs_ ? *specs_ : format_specs(); | |
if (const_check(is_supported_floating_point(value))) | |
out_ = detail::write(out_, value, specs, locale_); | |
else | |
((false) ? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
2273, | |
("unsupported float argument type"))); | |
return out_; | |
} | |
iterator operator()(const Char* value) { | |
if (!specs_) | |
return write(value), out_; | |
handle_cstring_type_spec(specs_->type, | |
cstring_spec_handler(*this, value)); | |
return out_; | |
} | |
iterator operator()(basic_string_view<Char> value) { | |
if (specs_) { | |
check_string_type_spec(specs_->type, error_handler()); | |
write(value, *specs_); | |
} else { | |
write(value); | |
} | |
return out_; | |
} | |
iterator operator()(const void* value) { | |
if (specs_) | |
check_pointer_type_spec(specs_->type, error_handler()); | |
write_pointer(value); | |
return out_; | |
} | |
}; | |
template <typename OutputIt, typename Char> | |
class arg_formatter : public arg_formatter_base<OutputIt, Char> { | |
private: | |
using char_type = Char; | |
using base = arg_formatter_base<OutputIt, Char>; | |
using context_type = basic_format_context<OutputIt, Char>; | |
context_type& ctx_; | |
basic_format_parse_context<char_type>* parse_ctx_; | |
const Char* ptr_; | |
public: | |
using iterator = typename base::iterator; | |
using format_specs = typename base::format_specs; | |
// # 2323 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
explicit arg_formatter( | |
context_type& ctx, | |
basic_format_parse_context<char_type>* parse_ctx = nullptr, | |
format_specs* specs = nullptr, | |
const Char* ptr = nullptr) | |
: base(ctx.out(), specs, ctx.locale()), | |
ctx_(ctx), | |
parse_ctx_(parse_ctx), | |
ptr_(ptr) { | |
} | |
using base::operator(); | |
iterator operator()( | |
typename basic_format_arg<context_type>::handle handle) { | |
if (ptr_) | |
advance_to(*parse_ctx_, ptr_); | |
handle.format(*parse_ctx_, ctx_); | |
return ctx_.out(); | |
} | |
}; | |
template <typename Char> | |
constexpr bool is_name_start(Char c) { | |
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; | |
} | |
template <typename Char, typename ErrorHandler> | |
constexpr int parse_nonnegative_int(const Char*& begin, | |
const Char* end, | |
ErrorHandler&& eh) { | |
((begin != end && '0' <= *begin && *begin <= '9') | |
? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
2351, | |
(""))); | |
unsigned value = 0; | |
constexpr unsigned max_int = max_value<int>(); | |
unsigned big = max_int / 10; | |
do { | |
if (value > big) { | |
value = max_int + 1; | |
break; | |
} | |
value = value * 10 + unsigned(*begin - '0'); | |
++begin; | |
} while (begin != end && '0' <= *begin && *begin <= '9'); | |
if (value > max_int) | |
eh.on_error("number is too big"); | |
return static_cast<int>(value); | |
} | |
template <typename Context> | |
class custom_formatter { | |
private: | |
using char_type = typename Context::char_type; | |
basic_format_parse_context<char_type>& parse_ctx_; | |
Context& ctx_; | |
public: | |
explicit custom_formatter(basic_format_parse_context<char_type>& parse_ctx, | |
Context& ctx) | |
: parse_ctx_(parse_ctx), ctx_(ctx) { | |
} | |
void operator()(typename basic_format_arg<Context>::handle h) const { | |
h.format(parse_ctx_, ctx_); | |
} | |
template <typename T> | |
void operator()(T) const { | |
} | |
}; | |
template <typename T> | |
using is_integer = | |
bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value && | |
!std::is_same<T, char>::value && | |
!std::is_same<T, wchar_t>::value>; | |
template <typename ErrorHandler> | |
class width_checker { | |
public: | |
explicit constexpr width_checker(ErrorHandler& eh) : handler_(eh) { | |
} | |
template <typename T, enable_if_t<(is_integer<T>::value), int> = 0> | |
constexpr unsigned long long operator()(T value) { | |
if (is_negative(value)) | |
handler_.on_error("negative width"); | |
return static_cast<unsigned long long>(value); | |
} | |
template <typename T, enable_if_t<(!is_integer<T>::value), int> = 0> | |
constexpr unsigned long long operator()(T) { | |
handler_.on_error("width is not integer"); | |
return 0; | |
} | |
private: | |
ErrorHandler& handler_; | |
}; | |
template <typename ErrorHandler> | |
class precision_checker { | |
public: | |
explicit constexpr precision_checker(ErrorHandler& eh) : handler_(eh) { | |
} | |
template <typename T, enable_if_t<(is_integer<T>::value), int> = 0> | |
constexpr unsigned long long operator()(T value) { | |
if (is_negative(value)) | |
handler_.on_error("negative precision"); | |
return static_cast<unsigned long long>(value); | |
} | |
template <typename T, enable_if_t<(!is_integer<T>::value), int> = 0> | |
constexpr unsigned long long operator()(T) { | |
handler_.on_error("precision is not integer"); | |
return 0; | |
} | |
private: | |
ErrorHandler& handler_; | |
}; | |
template <typename Char> | |
class specs_setter { | |
public: | |
explicit constexpr specs_setter(basic_format_specs<Char>& specs) | |
: specs_(specs) { | |
} | |
constexpr specs_setter(const specs_setter& other) : specs_(other.specs_) { | |
} | |
constexpr void on_align(align_t align) { | |
specs_.align = align; | |
} | |
constexpr void on_fill(basic_string_view<Char> fill) { | |
specs_.fill = fill; | |
} | |
constexpr void on_plus() { | |
specs_.sign = sign::plus; | |
} | |
constexpr void on_minus() { | |
specs_.sign = sign::minus; | |
} | |
constexpr void on_space() { | |
specs_.sign = sign::space; | |
} | |
constexpr void on_hash() { | |
specs_.alt = true; | |
} | |
constexpr void on_zero() { | |
specs_.align = align::numeric; | |
specs_.fill[0] = Char('0'); | |
} | |
constexpr void on_width(int width) { | |
specs_.width = width; | |
} | |
constexpr void on_precision(int precision) { | |
specs_.precision = precision; | |
} | |
constexpr void end_precision() { | |
} | |
constexpr void on_type(Char type) { | |
specs_.type = static_cast<char>(type); | |
} | |
protected: | |
basic_format_specs<Char>& specs_; | |
}; | |
template <typename ErrorHandler> | |
class numeric_specs_checker { | |
public: | |
constexpr numeric_specs_checker(ErrorHandler& eh, detail::type arg_type) | |
: error_handler_(eh), arg_type_(arg_type) { | |
} | |
constexpr void require_numeric_argument() { | |
if (!is_arithmetic_type(arg_type_)) | |
error_handler_.on_error( | |
"format specifier requires numeric argument"); | |
} | |
constexpr void check_sign() { | |
require_numeric_argument(); | |
if (is_integral_type(arg_type_) && arg_type_ != type::int_type && | |
arg_type_ != type::long_long_type && arg_type_ != type::char_type) { | |
error_handler_.on_error( | |
"format specifier requires signed argument"); | |
} | |
} | |
constexpr void check_precision() { | |
if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type) | |
error_handler_.on_error( | |
"precision not allowed for this argument type"); | |
} | |
private: | |
ErrorHandler& error_handler_; | |
detail::type arg_type_; | |
}; | |
template <typename Handler> | |
class specs_checker : public Handler { | |
private: | |
numeric_specs_checker<Handler> checker_; | |
constexpr Handler& error_handler() { | |
return *this; | |
} | |
public: | |
constexpr specs_checker(const Handler& handler, detail::type arg_type) | |
: Handler(handler), checker_(error_handler(), arg_type) { | |
} | |
constexpr specs_checker(const specs_checker& other) | |
: Handler(other), checker_(error_handler(), other.arg_type_) { | |
} | |
constexpr void on_align(align_t align) { | |
if (align == align::numeric) | |
checker_.require_numeric_argument(); | |
Handler::on_align(align); | |
} | |
constexpr void on_plus() { | |
checker_.check_sign(); | |
Handler::on_plus(); | |
} | |
constexpr void on_minus() { | |
checker_.check_sign(); | |
Handler::on_minus(); | |
} | |
constexpr void on_space() { | |
checker_.check_sign(); | |
Handler::on_space(); | |
} | |
constexpr void on_hash() { | |
checker_.require_numeric_argument(); | |
Handler::on_hash(); | |
} | |
constexpr void on_zero() { | |
checker_.require_numeric_argument(); | |
Handler::on_zero(); | |
} | |
constexpr void end_precision() { | |
checker_.check_precision(); | |
} | |
}; | |
template <template <typename> class Handler, | |
typename FormatArg, | |
typename ErrorHandler> | |
constexpr int get_dynamic_spec(FormatArg arg, ErrorHandler eh) { | |
unsigned long long value = visit_format_arg(Handler<ErrorHandler>(eh), arg); | |
if (value > to_unsigned(max_value<int>())) | |
eh.on_error("number is too big"); | |
return static_cast<int>(value); | |
} | |
struct auto_id {}; | |
template <typename Context, typename ID> | |
constexpr typename Context::format_arg get_arg(Context& ctx, ID id) { | |
auto arg = ctx.arg(id); | |
if (!arg) | |
ctx.on_error("argument not found"); | |
return arg; | |
} | |
template <typename ParseContext, typename Context> | |
class specs_handler : public specs_setter<typename Context::char_type> { | |
public: | |
using char_type = typename Context::char_type; | |
constexpr specs_handler(basic_format_specs<char_type>& specs, | |
ParseContext& parse_ctx, | |
Context& ctx) | |
: specs_setter<char_type>(specs), | |
parse_context_(parse_ctx), | |
context_(ctx) { | |
} | |
template <typename Id> | |
constexpr void on_dynamic_width(Id arg_id) { | |
this->specs_.width = get_dynamic_spec<width_checker>( | |
get_arg(arg_id), context_.error_handler()); | |
} | |
template <typename Id> | |
constexpr void on_dynamic_precision(Id arg_id) { | |
this->specs_.precision = get_dynamic_spec<precision_checker>( | |
get_arg(arg_id), context_.error_handler()); | |
} | |
void on_error(const char* message) { | |
context_.on_error(message); | |
} | |
private: | |
using format_arg = typename Context::format_arg; | |
constexpr format_arg get_arg(auto_id) { | |
return detail::get_arg(context_, parse_context_.next_arg_id()); | |
} | |
constexpr format_arg get_arg(int arg_id) { | |
parse_context_.check_arg_id(arg_id); | |
return detail::get_arg(context_, arg_id); | |
} | |
constexpr format_arg get_arg(basic_string_view<char_type> arg_id) { | |
parse_context_.check_arg_id(arg_id); | |
return detail::get_arg(context_, arg_id); | |
} | |
ParseContext& parse_context_; | |
Context& context_; | |
}; | |
enum class arg_id_kind { none, index, name }; | |
template <typename Char> | |
struct arg_ref { | |
constexpr arg_ref() : kind(arg_id_kind::none), val() { | |
} | |
constexpr explicit arg_ref(int index) | |
: kind(arg_id_kind::index), val(index) { | |
} | |
constexpr explicit arg_ref(basic_string_view<Char> name) | |
: kind(arg_id_kind::name), val(name) { | |
} | |
constexpr arg_ref& operator=(int idx) { | |
kind = arg_id_kind::index; | |
val.index = idx; | |
return *this; | |
} | |
arg_id_kind kind; | |
union value { | |
constexpr value(int id = 0) : index{id} { | |
} | |
constexpr value(basic_string_view<Char> n) : name(n) { | |
} | |
int index; | |
basic_string_view<Char> name; | |
} val; | |
}; | |
template <typename Char> | |
struct dynamic_format_specs : basic_format_specs<Char> { | |
arg_ref<Char> width_ref; | |
arg_ref<Char> precision_ref; | |
}; | |
template <typename ParseContext> | |
class dynamic_specs_handler | |
: public specs_setter<typename ParseContext::char_type> { | |
public: | |
using char_type = typename ParseContext::char_type; | |
constexpr dynamic_specs_handler(dynamic_format_specs<char_type>& specs, | |
ParseContext& ctx) | |
: specs_setter<char_type>(specs), specs_(specs), context_(ctx) { | |
} | |
constexpr dynamic_specs_handler(const dynamic_specs_handler& other) | |
: specs_setter<char_type>(other), | |
specs_(other.specs_), | |
context_(other.context_) { | |
} | |
template <typename Id> | |
constexpr void on_dynamic_width(Id arg_id) { | |
specs_.width_ref = make_arg_ref(arg_id); | |
} | |
template <typename Id> | |
constexpr void on_dynamic_precision(Id arg_id) { | |
specs_.precision_ref = make_arg_ref(arg_id); | |
} | |
constexpr void on_error(const char* message) { | |
context_.on_error(message); | |
} | |
private: | |
using arg_ref_type = arg_ref<char_type>; | |
constexpr arg_ref_type make_arg_ref(int arg_id) { | |
context_.check_arg_id(arg_id); | |
return arg_ref_type(arg_id); | |
} | |
constexpr arg_ref_type make_arg_ref(auto_id) { | |
return arg_ref_type(context_.next_arg_id()); | |
} | |
constexpr arg_ref_type make_arg_ref(basic_string_view<char_type> arg_id) { | |
context_.check_arg_id(arg_id); | |
basic_string_view<char_type> format_str( | |
context_.begin(), | |
to_unsigned(context_.end() - context_.begin())); | |
return arg_ref_type(arg_id); | |
} | |
dynamic_format_specs<char_type>& specs_; | |
ParseContext& context_; | |
}; | |
template <typename Char, typename IDHandler> | |
constexpr const Char* parse_arg_id(const Char* begin, | |
const Char* end, | |
IDHandler&& handler) { | |
((begin != end) ? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
2702, | |
(""))); | |
Char c = *begin; | |
if (c == '}' || c == ':') { | |
handler(); | |
return begin; | |
} | |
if (c >= '0' && c <= '9') { | |
int index = 0; | |
if (c != '0') | |
index = parse_nonnegative_int(begin, end, handler); | |
else | |
++begin; | |
if (begin == end || (*begin != '}' && *begin != ':')) | |
handler.on_error("invalid format string"); | |
else | |
handler(index); | |
return begin; | |
} | |
if (!is_name_start(c)) { | |
handler.on_error("invalid format string"); | |
return begin; | |
} | |
auto it = begin; | |
do { | |
++it; | |
} while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9'))); | |
handler(basic_string_view<Char>(begin, to_unsigned(it - begin))); | |
return it; | |
} | |
template <typename SpecHandler, typename Char> | |
struct width_adapter { | |
explicit constexpr width_adapter(SpecHandler& h) : handler(h) { | |
} | |
constexpr void operator()() { | |
handler.on_dynamic_width(auto_id()); | |
} | |
constexpr void operator()(int id) { | |
handler.on_dynamic_width(id); | |
} | |
constexpr void operator()(basic_string_view<Char> id) { | |
handler.on_dynamic_width(id); | |
} | |
constexpr void on_error(const char* message) { | |
handler.on_error(message); | |
} | |
SpecHandler& handler; | |
}; | |
template <typename SpecHandler, typename Char> | |
struct precision_adapter { | |
explicit constexpr precision_adapter(SpecHandler& h) : handler(h) { | |
} | |
constexpr void operator()() { | |
handler.on_dynamic_precision(auto_id()); | |
} | |
constexpr void operator()(int id) { | |
handler.on_dynamic_precision(id); | |
} | |
constexpr void operator()(basic_string_view<Char> id) { | |
handler.on_dynamic_precision(id); | |
} | |
constexpr void on_error(const char* message) { | |
handler.on_error(message); | |
} | |
SpecHandler& handler; | |
}; | |
template <typename Char> | |
constexpr int code_point_length(const Char* begin) { | |
if (const_check(sizeof(Char) != 1)) | |
return 1; | |
constexpr char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0}; | |
int len = lengths[static_cast<unsigned char>(*begin) >> 3]; | |
return len + !len; | |
} | |
template <typename Char> | |
constexpr bool is_ascii_letter(Char c) { | |
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); | |
} | |
template <typename Char, enable_if_t<(std::is_integral<Char>::value), int> = 0> | |
constexpr Char to_ascii(Char value) { | |
return value; | |
} | |
template <typename Char, enable_if_t<(std::is_enum<Char>::value), int> = 0> | |
constexpr typename std::underlying_type<Char>::type to_ascii(Char value) { | |
return value; | |
} | |
template <typename Char, typename Handler> | |
constexpr const Char* parse_align(const Char* begin, | |
const Char* end, | |
Handler&& handler) { | |
((begin != end) ? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
2797, | |
(""))); | |
auto align = align::none; | |
auto p = begin + code_point_length(begin); | |
if (p >= end) | |
p = begin; | |
for (;;) { | |
switch (to_ascii(*p)) { | |
case '<': | |
align = align::left; | |
break; | |
case '>': | |
align = align::right; | |
break; | |
case '^': | |
align = align::center; | |
break; | |
} | |
if (align != align::none) { | |
if (p != begin) { | |
auto c = *begin; | |
if (c == '{') | |
return handler.on_error("invalid fill character '{'"), | |
begin; | |
handler.on_fill( | |
basic_string_view<Char>(begin, to_unsigned(p - begin))); | |
begin = p + 1; | |
} else | |
++begin; | |
handler.on_align(align); | |
break; | |
} else if (p == begin) { | |
break; | |
} | |
p = begin; | |
} | |
return begin; | |
} | |
template <typename Char, typename Handler> | |
constexpr const Char* parse_width(const Char* begin, | |
const Char* end, | |
Handler&& handler) { | |
((begin != end) ? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
2840, | |
(""))); | |
if ('0' <= *begin && *begin <= '9') { | |
handler.on_width(parse_nonnegative_int(begin, end, handler)); | |
} else if (*begin == '{') { | |
++begin; | |
if (begin != end) | |
begin = parse_arg_id( | |
begin, end, width_adapter<Handler, Char>(handler)); | |
if (begin == end || *begin != '}') | |
return handler.on_error("invalid format string"), begin; | |
++begin; | |
} | |
return begin; | |
} | |
template <typename Char, typename Handler> | |
constexpr const Char* parse_precision(const Char* begin, | |
const Char* end, | |
Handler&& handler) { | |
++begin; | |
auto c = begin != end ? *begin : Char(); | |
if ('0' <= c && c <= '9') { | |
handler.on_precision(parse_nonnegative_int(begin, end, handler)); | |
} else if (c == '{') { | |
++begin; | |
if (begin != end) { | |
begin = parse_arg_id( | |
begin, end, precision_adapter<Handler, Char>(handler)); | |
} | |
if (begin == end || *begin++ != '}') | |
return handler.on_error("invalid format string"), begin; | |
} else { | |
return handler.on_error("missing precision specifier"), begin; | |
} | |
handler.end_precision(); | |
return begin; | |
} | |
template <typename Char, typename SpecHandler> | |
constexpr const Char* parse_format_specs(const Char* begin, | |
const Char* end, | |
SpecHandler&& handler) { | |
if (begin == end) | |
return begin; | |
begin = parse_align(begin, end, handler); | |
if (begin == end) | |
return begin; | |
switch (to_ascii(*begin)) { | |
case '+': | |
handler.on_plus(); | |
++begin; | |
break; | |
case '-': | |
handler.on_minus(); | |
++begin; | |
break; | |
case ' ': | |
handler.on_space(); | |
++begin; | |
break; | |
} | |
if (begin == end) | |
return begin; | |
if (*begin == '#') { | |
handler.on_hash(); | |
if (++begin == end) | |
return begin; | |
} | |
if (*begin == '0') { | |
handler.on_zero(); | |
if (++begin == end) | |
return begin; | |
} | |
begin = parse_width(begin, end, handler); | |
if (begin == end) | |
return begin; | |
if (*begin == '.') { | |
begin = parse_precision(begin, end, handler); | |
} | |
if (begin != end && *begin != '}') | |
handler.on_type(*begin++); | |
return begin; | |
} | |
template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*> | |
constexpr bool find(Ptr first, Ptr last, T value, Ptr& out) { | |
for (out = first; out != last; ++out) { | |
if (*out == value) | |
return true; | |
} | |
return false; | |
} | |
template <> | |
inline bool find<false, char>(const char* first, | |
const char* last, | |
char value, | |
const char*& out) { | |
out = static_cast<const char*>( | |
std::memchr(first, value, detail::to_unsigned(last - first))); | |
return out != nullptr; | |
} | |
template <typename Handler, typename Char> | |
struct id_adapter { | |
Handler& handler; | |
int arg_id; | |
constexpr void operator()() { | |
arg_id = handler.on_arg_id(); | |
} | |
constexpr void operator()(int id) { | |
arg_id = handler.on_arg_id(id); | |
} | |
constexpr void operator()(basic_string_view<Char> id) { | |
arg_id = handler.on_arg_id(id); | |
} | |
constexpr void on_error(const char* message) { | |
handler.on_error(message); | |
} | |
}; | |
template <typename Char, typename Handler> | |
constexpr const Char* parse_replacement_field(const Char* begin, | |
const Char* end, | |
Handler&& handler) { | |
++begin; | |
if (begin == end) | |
return handler.on_error("invalid format string"), end; | |
if (*begin == '}') { | |
handler.on_replacement_field(handler.on_arg_id(), begin); | |
} else if (*begin == '{') { | |
handler.on_text(begin, begin + 1); | |
} else { | |
auto adapter = id_adapter<Handler, Char>{handler, 0}; | |
begin = parse_arg_id(begin, end, adapter); | |
Char c = begin != end ? *begin : Char(); | |
if (c == '}') { | |
handler.on_replacement_field(adapter.arg_id, begin); | |
} else if (c == ':') { | |
begin = handler.on_format_specs(adapter.arg_id, begin + 1, end); | |
if (begin == end || *begin != '}') | |
return handler.on_error("unknown format specifier"), end; | |
} else { | |
return handler.on_error("missing '}' in format string"), end; | |
} | |
} | |
return begin + 1; | |
} | |
template <bool IS_CONSTEXPR, typename Char, typename Handler> | |
constexpr inline __attribute__((always_inline)) void parse_format_string( | |
basic_string_view<Char> format_str, Handler&& handler) { | |
auto begin = format_str.data(); | |
auto end = begin + format_str.size(); | |
if (end - begin < 32) { | |
const Char* p = begin; | |
while (p != end) { | |
auto c = *p++; | |
if (c == '{') { | |
handler.on_text(begin, p - 1); | |
begin = p = parse_replacement_field(p - 1, end, handler); | |
} else if (c == '}') { | |
if (p == end || *p != '}') | |
return handler.on_error("unmatched '}' in format string"); | |
handler.on_text(begin, p); | |
begin = ++p; | |
} | |
} | |
handler.on_text(begin, end); | |
return; | |
} | |
struct writer { | |
constexpr void operator()(const Char* pbegin, const Char* pend) { | |
if (pbegin == pend) | |
return; | |
for (;;) { | |
const Char* p = nullptr; | |
if (!find<IS_CONSTEXPR>(pbegin, pend, '}', p)) | |
return handler_.on_text(pbegin, pend); | |
++p; | |
if (p == pend || *p != '}') | |
return handler_.on_error("unmatched '}' in format string"); | |
handler_.on_text(pbegin, p); | |
pbegin = p + 1; | |
} | |
} | |
Handler& handler_; | |
} write{handler}; | |
while (begin != end) { | |
const Char* p = begin; | |
if (*begin != '{' && !find<IS_CONSTEXPR>(begin + 1, end, '{', p)) | |
return write(begin, end); | |
write(begin, p); | |
begin = parse_replacement_field(p, end, handler); | |
} | |
} | |
template <typename T, typename ParseContext> | |
constexpr const typename ParseContext::char_type* parse_format_specs( | |
ParseContext& ctx) { | |
using char_type = typename ParseContext::char_type; | |
using context = buffer_context<char_type>; | |
using mapped_type = | |
conditional_t<detail::mapped_type_constant<T, context>::value != | |
type::custom_type, | |
decltype( | |
arg_mapper<context>().map(std::declval<T>())), | |
T>; | |
auto f = conditional_t<has_formatter<mapped_type, context>::value, | |
formatter<mapped_type, char_type>, | |
detail::fallback_formatter<T, char_type>>(); | |
return f.parse(ctx); | |
} | |
template <typename OutputIt, typename Char, typename Context> | |
struct format_handler : detail::error_handler { | |
basic_format_parse_context<Char> parse_context; | |
Context context; | |
format_handler(OutputIt out, | |
basic_string_view<Char> str, | |
basic_format_args<Context> format_args, | |
detail::locale_ref loc) | |
: parse_context(str), context(out, format_args, loc) { | |
} | |
void on_text(const Char* begin, const Char* end) { | |
auto size = to_unsigned(end - begin); | |
auto out = context.out(); | |
auto&& it = reserve(out, size); | |
it = std::copy_n(begin, size, it); | |
context.advance_to(out); | |
} | |
int on_arg_id() { | |
return parse_context.next_arg_id(); | |
} | |
int on_arg_id(int id) { | |
return parse_context.check_arg_id(id), id; | |
} | |
int on_arg_id(basic_string_view<Char> id) { | |
int arg_id = context.arg_id(id); | |
if (arg_id < 0) | |
on_error("argument not found"); | |
return arg_id; | |
} | |
inline __attribute__((always_inline)) void on_replacement_field( | |
int id, const Char*) { | |
auto arg = get_arg(context, id); | |
context.advance_to(visit_format_arg( | |
default_arg_formatter<OutputIt, Char>{ | |
context.out(), context.args(), context.locale()}, | |
arg)); | |
} | |
const Char* on_format_specs(int id, const Char* begin, const Char* end) { | |
auto arg = get_arg(context, id); | |
if (arg.type() == type::custom_type) { | |
advance_to(parse_context, begin); | |
visit_format_arg(custom_formatter<Context>(parse_context, context), | |
arg); | |
return parse_context.begin(); | |
} | |
auto specs = basic_format_specs<Char>(); | |
if (begin + 1 < end && begin[1] == '}' && is_ascii_letter(*begin)) { | |
specs.type = static_cast<char>(*begin++); | |
} else { | |
using parse_context_t = basic_format_parse_context<Char>; | |
specs_checker<specs_handler<parse_context_t, Context>> handler( | |
specs_handler<parse_context_t, Context>( | |
specs, parse_context, context), | |
arg.type()); | |
begin = parse_format_specs(begin, end, handler); | |
if (begin == end || *begin != '}') | |
on_error("missing '}' in format string"); | |
} | |
context.advance_to(visit_format_arg( | |
arg_formatter<OutputIt, Char>(context, &parse_context, &specs), | |
arg)); | |
return begin; | |
} | |
}; | |
template <typename Char, typename ErrorHandler = error_handler> | |
class compile_parse_context | |
: public basic_format_parse_context<Char, ErrorHandler> { | |
private: | |
int num_args_; | |
using base = basic_format_parse_context<Char, ErrorHandler>; | |
public: | |
explicit constexpr compile_parse_context(basic_string_view<Char> format_str, | |
int num_args = max_value<int>(), | |
ErrorHandler eh = {}) | |
: base(format_str, eh), num_args_(num_args) { | |
} | |
constexpr int next_arg_id() { | |
int id = base::next_arg_id(); | |
if (id >= num_args_) | |
this->on_error("argument not found"); | |
return id; | |
} | |
constexpr void check_arg_id(int id) { | |
base::check_arg_id(id); | |
if (id >= num_args_) | |
this->on_error("argument not found"); | |
} | |
using base::check_arg_id; | |
}; | |
template <typename Char, typename ErrorHandler, typename... Args> | |
class format_string_checker { | |
public: | |
explicit constexpr format_string_checker(basic_string_view<Char> format_str, | |
ErrorHandler eh) | |
: context_(format_str, num_args, eh), | |
parse_funcs_{&parse_format_specs<Args, parse_context_type>...} { | |
} | |
constexpr void on_text(const Char*, const Char*) { | |
} | |
constexpr int on_arg_id() { | |
return context_.next_arg_id(); | |
} | |
constexpr int on_arg_id(int id) { | |
return context_.check_arg_id(id), id; | |
} | |
constexpr int on_arg_id(basic_string_view<Char>) { | |
on_error("compile-time checks don't support named arguments"); | |
return 0; | |
} | |
constexpr void on_replacement_field(int, const Char*) { | |
} | |
constexpr const Char* on_format_specs(int id, | |
const Char* begin, | |
const Char*) { | |
advance_to(context_, begin); | |
return id < num_args ? parse_funcs_[id](context_) : begin; | |
} | |
constexpr void on_error(const char* message) { | |
context_.on_error(message); | |
} | |
private: | |
using parse_context_type = compile_parse_context<Char, ErrorHandler>; | |
enum { num_args = sizeof...(Args) }; | |
using parse_func = const Char* (*)(parse_context_type&); | |
parse_context_type context_; | |
parse_func parse_funcs_[num_args > 0 ? num_args : 1]; | |
}; | |
template <typename Char, size_t N> | |
constexpr basic_string_view<Char> compile_string_to_view(const Char (&s)[N]) { | |
return {s, | |
N - ((std::char_traits<Char>::to_int_type(s[N - 1]) == 0) ? 1 : 0)}; | |
} | |
template <typename Char> | |
constexpr basic_string_view<Char> compile_string_to_view( | |
const std_string_view<Char>& s) { | |
return {s.data(), s.size()}; | |
} | |
// # 3221 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
template <typename... Args, | |
typename S, | |
enable_if_t<(is_compile_string<S>::value), int>> | |
void check_format_string(S format_str) { | |
constexpr auto s = to_string_view(format_str); | |
using checker = format_string_checker<typename S::char_type, | |
error_handler, | |
remove_cvref_t<Args>...>; | |
constexpr bool invalid_format = | |
(parse_format_string<true>(s, checker(s, {})), true); | |
(void)invalid_format; | |
} | |
template <template <typename> class Handler, typename Context> | |
void handle_dynamic_spec(int& value, | |
arg_ref<typename Context::char_type> ref, | |
Context& ctx) { | |
switch (ref.kind) { | |
case arg_id_kind::none: | |
break; | |
case arg_id_kind::index: | |
value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.index), | |
ctx.error_handler()); | |
break; | |
case arg_id_kind::name: | |
value = detail::get_dynamic_spec<Handler>(ctx.arg(ref.val.name), | |
ctx.error_handler()); | |
break; | |
} | |
} | |
using format_func = void (*)(detail::buffer<char>&, int, string_view); | |
void format_error_code(buffer<char>& out, | |
int error_code, | |
string_view message) noexcept; | |
void report_error(format_func func, | |
int error_code, | |
string_view message) noexcept; | |
} // namespace detail | |
template <typename OutputIt, typename Char> | |
using arg_formatter [[deprecated]] = detail::arg_formatter<OutputIt, Char>; | |
class system_error : public std::runtime_error { | |
private: | |
void init(int err_code, string_view format_str, format_args args); | |
protected: | |
int error_code_; | |
system_error() : std::runtime_error(""), error_code_(0) { | |
} | |
public: | |
// # 3295 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
template <typename... Args> | |
system_error(int error_code, string_view message, const Args&... args) | |
: std::runtime_error("") { | |
init(error_code, message, make_format_args(args...)); | |
} | |
system_error(const system_error&) = default; | |
system_error& operator=(const system_error&) = default; | |
system_error(system_error&&) = default; | |
system_error& operator=(system_error&&) = default; | |
~system_error() noexcept override; | |
int error_code() const { | |
return error_code_; | |
} | |
}; | |
// # 3325 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
void format_system_error(detail::buffer<char>& out, | |
int error_code, | |
string_view message) noexcept; | |
void report_system_error(int error_code, string_view message) noexcept; | |
class format_int { | |
private: | |
enum { | |
buffer_size = std::numeric_limits<unsigned long long>::digits10 + 3 | |
}; | |
mutable char buffer_[buffer_size]; | |
char* str_; | |
template <typename UInt> | |
char* format_unsigned(UInt value) { | |
auto n = static_cast<detail::uint32_or_64_or_128_t<UInt>>(value); | |
return detail::format_decimal(buffer_, n, buffer_size - 1).begin; | |
} | |
template <typename Int> | |
char* format_signed(Int value) { | |
auto abs_value = static_cast<detail::uint32_or_64_or_128_t<Int>>(value); | |
bool negative = value < 0; | |
if (negative) | |
abs_value = 0 - abs_value; | |
auto begin = format_unsigned(abs_value); | |
if (negative) | |
*--begin = '-'; | |
return begin; | |
} | |
public: | |
explicit format_int(int value) : str_(format_signed(value)) { | |
} | |
explicit format_int(long value) : str_(format_signed(value)) { | |
} | |
explicit format_int(long long value) : str_(format_signed(value)) { | |
} | |
explicit format_int(unsigned value) : str_(format_unsigned(value)) { | |
} | |
explicit format_int(unsigned long value) : str_(format_unsigned(value)) { | |
} | |
explicit format_int(unsigned long long value) | |
: str_(format_unsigned(value)) { | |
} | |
size_t size() const { | |
return detail::to_unsigned(buffer_ - str_ + buffer_size - 1); | |
} | |
const char* data() const { | |
return str_; | |
} | |
const char* c_str() const { | |
buffer_[buffer_size - 1] = '\0'; | |
return str_; | |
} | |
std::string str() const { | |
return std::string(str_, size()); | |
} | |
}; | |
template <typename T, typename Char> | |
struct formatter<T, | |
Char, | |
enable_if_t<detail::type_constant<T, Char>::value != | |
detail::type::custom_type>> { | |
constexpr formatter() = default; | |
template <typename ParseContext> | |
constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | |
using handler_type = detail::dynamic_specs_handler<ParseContext>; | |
auto type = detail::type_constant<T, Char>::value; | |
detail::specs_checker<handler_type> handler(handler_type(specs_, ctx), | |
type); | |
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); | |
auto eh = ctx.error_handler(); | |
switch (type) { | |
case detail::type::none_type: | |
((false) ? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
3413, | |
("invalid argument type"))); | |
break; | |
case detail::type::int_type: | |
case detail::type::uint_type: | |
case detail::type::long_long_type: | |
case detail::type::ulong_long_type: | |
case detail::type::int128_type: | |
case detail::type::uint128_type: | |
case detail::type::bool_type: | |
handle_int_type_spec(specs_.type, | |
detail::int_type_checker<decltype(eh)>(eh)); | |
break; | |
case detail::type::char_type: | |
handle_char_specs( | |
&specs_, | |
detail::char_specs_checker<decltype(eh)>(specs_.type, eh)); | |
break; | |
case detail::type::float_type: | |
if (detail::const_check(1)) | |
detail::parse_float_type_spec(specs_, eh); | |
else | |
((false) ? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
3433, | |
("float support disabled"))); | |
break; | |
case detail::type::double_type: | |
if (detail::const_check(1)) | |
detail::parse_float_type_spec(specs_, eh); | |
else | |
((false) ? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
3439, | |
("double support disabled"))); | |
break; | |
case detail::type::long_double_type: | |
if (detail::const_check(1)) | |
detail::parse_float_type_spec(specs_, eh); | |
else | |
((false) ? (void)0 | |
: ::fmt::detail::assert_fail( | |
"tlm/deps/fmt.exploded/include/fmt/format.h", | |
3445, | |
("long double support disabled"))); | |
break; | |
case detail::type::cstring_type: | |
detail::handle_cstring_type_spec( | |
specs_.type, | |
detail::cstring_type_checker<decltype(eh)>(eh)); | |
break; | |
case detail::type::string_type: | |
detail::check_string_type_spec(specs_.type, eh); | |
break; | |
case detail::type::pointer_type: | |
detail::check_pointer_type_spec(specs_.type, eh); | |
break; | |
case detail::type::custom_type: | |
break; | |
} | |
return it; | |
} | |
template <typename FormatContext> | |
auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) { | |
detail::handle_dynamic_spec<detail::width_checker>( | |
specs_.width, specs_.width_ref, ctx); | |
detail::handle_dynamic_spec<detail::precision_checker>( | |
specs_.precision, specs_.precision_ref, ctx); | |
using af = detail::arg_formatter<typename FormatContext::iterator, | |
typename FormatContext::char_type>; | |
return visit_format_arg(af(ctx, nullptr, &specs_), | |
detail::make_arg<FormatContext>(val)); | |
} | |
private: | |
detail::dynamic_format_specs<Char> specs_; | |
}; | |
// # 3490 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
template <typename Char> | |
struct formatter<signed char, Char> : formatter<int, Char> { | |
template <typename FormatContext> | |
auto format(signed char const& val, FormatContext& ctx) | |
-> decltype(ctx.out()) { | |
return formatter<int, Char>::format(val, ctx); | |
} | |
}; | |
template <typename Char> | |
struct formatter<unsigned char, Char> : formatter<unsigned, Char> { | |
template <typename FormatContext> | |
auto format(unsigned char const& val, FormatContext& ctx) | |
-> decltype(ctx.out()) { | |
return formatter<unsigned, Char>::format(val, ctx); | |
} | |
}; | |
template <typename Char> | |
struct formatter<short, Char> : formatter<int, Char> { | |
template <typename FormatContext> | |
auto format(short const& val, FormatContext& ctx) -> decltype(ctx.out()) { | |
return formatter<int, Char>::format(val, ctx); | |
} | |
}; | |
template <typename Char> | |
struct formatter<unsigned short, Char> : formatter<unsigned, Char> { | |
template <typename FormatContext> | |
auto format(unsigned short const& val, FormatContext& ctx) | |
-> decltype(ctx.out()) { | |
return formatter<unsigned, Char>::format(val, ctx); | |
} | |
}; | |
template <typename Char> | |
struct formatter<long, Char> : formatter<long long, Char> { | |
template <typename FormatContext> | |
auto format(long const& val, FormatContext& ctx) -> decltype(ctx.out()) { | |
return formatter<long long, Char>::format(val, ctx); | |
} | |
}; | |
template <typename Char> | |
struct formatter<unsigned long, Char> : formatter<unsigned long long, Char> { | |
template <typename FormatContext> | |
auto format(unsigned long const& val, FormatContext& ctx) | |
-> decltype(ctx.out()) { | |
return formatter<unsigned long long, Char>::format(val, ctx); | |
} | |
}; | |
template <typename Char> | |
struct formatter<Char*, Char> : formatter<const Char*, Char> { | |
template <typename FormatContext> | |
auto format(Char* const& val, FormatContext& ctx) -> decltype(ctx.out()) { | |
return formatter<const Char*, Char>::format(val, ctx); | |
} | |
}; | |
template <typename Char> | |
struct formatter<std::basic_string<Char>, Char> | |
: formatter<basic_string_view<Char>, Char> { | |
template <typename FormatContext> | |
auto format(std::basic_string<Char> const& val, FormatContext& ctx) | |
-> decltype(ctx.out()) { | |
return formatter<basic_string_view<Char>, Char>::format(val, ctx); | |
} | |
}; | |
template <typename Char> | |
struct formatter<std::nullptr_t, Char> : formatter<const void*, Char> { | |
template <typename FormatContext> | |
auto format(std::nullptr_t const& val, FormatContext& ctx) | |
-> decltype(ctx.out()) { | |
return formatter<const void*, Char>::format(val, ctx); | |
} | |
}; | |
template <typename Char> | |
struct formatter<detail::std_string_view<Char>, Char> | |
: formatter<basic_string_view<Char>, Char> { | |
template <typename FormatContext> | |
auto format(detail::std_string_view<Char> const& val, FormatContext& ctx) | |
-> decltype(ctx.out()) { | |
return formatter<basic_string_view<Char>, Char>::format(val, ctx); | |
} | |
}; | |
template <typename Char> | |
struct formatter<void*, Char> : formatter<const void*, Char> { | |
template <typename FormatContext> | |
auto format(void* val, FormatContext& ctx) -> decltype(ctx.out()) { | |
return formatter<const void*, Char>::format(val, ctx); | |
} | |
}; | |
template <typename Char, size_t N> | |
struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> { | |
template <typename FormatContext> | |
auto format(const Char* val, FormatContext& ctx) -> decltype(ctx.out()) { | |
return formatter<basic_string_view<Char>, Char>::format(val, ctx); | |
} | |
}; | |
// # 3529 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
template <typename Char = char> | |
class dynamic_formatter { | |
private: | |
struct null_handler : detail::error_handler { | |
void on_align(align_t) { | |
} | |
void on_plus() { | |
} | |
void on_minus() { | |
} | |
void on_space() { | |
} | |
void on_hash() { | |
} | |
}; | |
public: | |
template <typename ParseContext> | |
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | |
format_str_ = ctx.begin(); | |
detail::dynamic_specs_handler<ParseContext> handler(specs_, ctx); | |
return parse_format_specs(ctx.begin(), ctx.end(), handler); | |
} | |
template <typename T, typename FormatContext> | |
auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) { | |
handle_specs(ctx); | |
detail::specs_checker<null_handler> checker( | |
null_handler(), | |
detail::mapped_type_constant<T, FormatContext>::value); | |
checker.on_align(specs_.align); | |
switch (specs_.sign) { | |
case sign::none: | |
break; | |
case sign::plus: | |
checker.on_plus(); | |
break; | |
case sign::minus: | |
checker.on_minus(); | |
break; | |
case sign::space: | |
checker.on_space(); | |
break; | |
} | |
if (specs_.alt) | |
checker.on_hash(); | |
if (specs_.precision >= 0) | |
checker.end_precision(); | |
using af = detail::arg_formatter<typename FormatContext::iterator, | |
typename FormatContext::char_type>; | |
visit_format_arg(af(ctx, nullptr, &specs_), | |
detail::make_arg<FormatContext>(val)); | |
return ctx.out(); | |
} | |
private: | |
template <typename Context> | |
void handle_specs(Context& ctx) { | |
detail::handle_dynamic_spec<detail::width_checker>( | |
specs_.width, specs_.width_ref, ctx); | |
detail::handle_dynamic_spec<detail::precision_checker>( | |
specs_.precision, specs_.precision_ref, ctx); | |
} | |
detail::dynamic_format_specs<Char> specs_; | |
const Char* format_str_; | |
}; | |
template <typename Char, typename ErrorHandler> | |
constexpr void advance_to(basic_format_parse_context<Char, ErrorHandler>& ctx, | |
const Char* p) { | |
ctx.advance_to(ctx.begin() + (p - &*ctx.begin())); | |
} | |
// # 3603 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
template <typename T> | |
inline const void* ptr(const T* p) { | |
return p; | |
} | |
template <typename T> | |
inline const void* ptr(const std::unique_ptr<T>& p) { | |
return p.get(); | |
} | |
template <typename T> | |
inline const void* ptr(const std::shared_ptr<T>& p) { | |
return p.get(); | |
} | |
class bytes { | |
private: | |
string_view data_; | |
friend struct formatter<bytes>; | |
public: | |
explicit bytes(string_view data) : data_(data) { | |
} | |
}; | |
template <> | |
struct formatter<bytes> { | |
private: | |
detail::dynamic_format_specs<char> specs_; | |
public: | |
template <typename ParseContext> | |
constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | |
using handler_type = detail::dynamic_specs_handler<ParseContext>; | |
detail::specs_checker<handler_type> handler(handler_type(specs_, ctx), | |
detail::type::string_type); | |
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); | |
detail::check_string_type_spec(specs_.type, ctx.error_handler()); | |
return it; | |
} | |
template <typename FormatContext> | |
auto format(bytes b, FormatContext& ctx) -> decltype(ctx.out()) { | |
detail::handle_dynamic_spec<detail::width_checker>( | |
specs_.width, specs_.width_ref, ctx); | |
detail::handle_dynamic_spec<detail::precision_checker>( | |
specs_.precision, specs_.precision_ref, ctx); | |
return detail::write_bytes(ctx.out(), b.data_, specs_); | |
} | |
}; | |
template <typename It, typename Sentinel, typename Char> | |
struct arg_join : detail::view { | |
It begin; | |
Sentinel end; | |
basic_string_view<Char> sep; | |
arg_join(It b, Sentinel e, basic_string_view<Char> s) | |
: begin(b), end(e), sep(s) { | |
} | |
}; | |
template <typename It, typename Sentinel, typename Char> | |
struct formatter<arg_join<It, Sentinel, Char>, Char> | |
: formatter<typename std::iterator_traits<It>::value_type, Char> { | |
template <typename FormatContext> | |
auto format(const arg_join<It, Sentinel, Char>& value, FormatContext& ctx) | |
-> decltype(ctx.out()) { | |
using base = | |
formatter<typename std::iterator_traits<It>::value_type, Char>; | |
auto it = value.begin; | |
auto out = ctx.out(); | |
if (it != value.end) { | |
out = base::format(*it++, ctx); | |
while (it != value.end) { | |
out = std::copy(value.sep.begin(), value.sep.end(), out); | |
ctx.advance_to(out); | |
out = base::format(*it++, ctx); | |
} | |
} | |
return out; | |
} | |
}; | |
template <typename It, typename Sentinel> | |
arg_join<It, Sentinel, char> join(It begin, Sentinel end, string_view sep) { | |
return {begin, end, sep}; | |
} | |
template <typename It, typename Sentinel> | |
arg_join<It, Sentinel, wchar_t> join(It begin, Sentinel end, wstring_view sep) { | |
return {begin, end, sep}; | |
} | |
// # 3706 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
template <typename Range> | |
arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>, char> join( | |
Range&& range, string_view sep) { | |
return join(std::begin(range), std::end(range), sep); | |
} | |
template <typename Range> | |
arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>, wchar_t> join( | |
Range&& range, wstring_view sep) { | |
return join(std::begin(range), std::end(range), sep); | |
} | |
// # 3729 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
template <typename T, enable_if_t<(!std::is_integral<T>::value), int> = 0> | |
inline std::string to_string(const T& value) { | |
std::string result; | |
detail::write<char>(std::back_inserter(result), value); | |
return result; | |
} | |
template <typename T, enable_if_t<(std::is_integral<T>::value), int> = 0> | |
inline std::string to_string(T value) { | |
constexpr int max_size = detail::digits10<T>() + 2; | |
char buffer[max_size > 5 ? static_cast<unsigned>(max_size) : 5]; | |
char* begin = buffer; | |
return std::string(begin, detail::write<char>(begin, value)); | |
} | |
template <typename T> | |
inline std::wstring to_wstring(const T& value) { | |
return format(L"{}", value); | |
} | |
template <typename Char, size_t SIZE> | |
std::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE>& buf) { | |
auto size = buf.size(); | |
detail::assume(size < std::basic_string<Char>().max_size()); | |
return std::basic_string<Char>(buf.data(), size); | |
} | |
template <typename Char> | |
void detail::vformat_to( | |
detail::buffer<Char>& buf, | |
basic_string_view<Char> format_str, | |
basic_format_args<buffer_context<type_identity_t<Char>>> args, | |
detail::locale_ref loc) { | |
using iterator = typename buffer_context<Char>::iterator; | |
auto out = buffer_appender<Char>(buf); | |
if (format_str.size() == 2 && equal2(format_str.data(), "{}")) { | |
auto arg = args.get(0); | |
if (!arg) | |
error_handler().on_error("argument not found"); | |
visit_format_arg(default_arg_formatter<iterator, Char>{out, args, loc}, | |
arg); | |
return; | |
} | |
format_handler<iterator, Char, buffer_context<Char>> h( | |
out, format_str, args, loc); | |
parse_format_string<false>(format_str, h); | |
} | |
extern template void detail::vformat_to(detail::buffer<char>&, | |
string_view, | |
basic_format_args<format_context>, | |
detail::locale_ref); | |
namespace detail { | |
extern template std::string grouping_impl<char>(locale_ref loc); | |
extern template std::string grouping_impl<wchar_t>(locale_ref loc); | |
extern template char thousands_sep_impl<char>(locale_ref loc); | |
extern template wchar_t thousands_sep_impl<wchar_t>(locale_ref loc); | |
extern template char decimal_point_impl(locale_ref loc); | |
extern template wchar_t decimal_point_impl(locale_ref loc); | |
extern template int format_float<double>(double value, | |
int precision, | |
float_specs specs, | |
buffer<char>& buf); | |
extern template int format_float<long double>(long double value, | |
int precision, | |
float_specs specs, | |
buffer<char>& buf); | |
int snprintf_float(float value, | |
int precision, | |
float_specs specs, | |
buffer<char>& buf) = delete; | |
extern template int snprintf_float<double>(double value, | |
int precision, | |
float_specs specs, | |
buffer<char>& buf); | |
extern template int snprintf_float<long double>(long double value, | |
int precision, | |
float_specs specs, | |
buffer<char>& buf); | |
} // namespace detail | |
template <typename S, | |
typename Char = char_t<S>, | |
enable_if_t<(detail::is_string<S>::value), int> = 0> | |
inline void vformat_to(detail::buffer<Char>& buf, | |
const S& format_str, | |
basic_format_args<basic_format_context< | |
detail::buffer_appender<type_identity_t<Char>>, | |
type_identity_t<Char>>> args) { | |
return detail::vformat_to(buf, to_string_view(format_str), args); | |
} | |
template <typename S, | |
typename... Args, | |
size_t SIZE = inline_buffer_size, | |
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>> | |
inline typename buffer_context<Char>::iterator format_to( | |
basic_memory_buffer<Char, SIZE>& buf, | |
const S& format_str, | |
Args&&... args) { | |
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); | |
detail::vformat_to(buf, to_string_view(format_str), vargs); | |
return detail::buffer_appender<Char>(buf); | |
} | |
template <typename OutputIt, typename Char = char> | |
using format_context_t = basic_format_context<OutputIt, Char>; | |
template <typename OutputIt, typename Char = char> | |
using format_args_t = basic_format_args<format_context_t<OutputIt, Char>>; | |
template <typename OutputIt, typename Char = typename OutputIt::value_type> | |
using format_to_n_context [[deprecated]] = buffer_context<Char>; | |
template <typename OutputIt, typename Char = typename OutputIt::value_type> | |
using format_to_n_args [[deprecated]] = basic_format_args<buffer_context<Char>>; | |
template <typename OutputIt, typename Char, typename... Args> | |
[[deprecated]] format_arg_store<buffer_context<Char>, Args...> | |
make_format_to_n_args(const Args&... args) { | |
return format_arg_store<buffer_context<Char>, Args...>(args...); | |
} | |
template <typename Char, enable_if_t<(!std::is_same<Char, char>::value), int>> | |
std::basic_string<Char> detail::vformat( | |
basic_string_view<Char> format_str, | |
basic_format_args<buffer_context<type_identity_t<Char>>> args) { | |
basic_memory_buffer<Char> buffer; | |
detail::vformat_to(buffer, format_str, args); | |
return to_string(buffer); | |
} | |
template <typename Char, | |
enable_if_t<(std::is_same<Char, wchar_t>::value), int> = 0> | |
void vprint(std::FILE* f, | |
basic_string_view<Char> format_str, | |
wformat_args args) { | |
wmemory_buffer buffer; | |
detail::vformat_to(buffer, format_str, args); | |
buffer.push_back(L'\0'); | |
if (std::fputws(buffer.data(), f) == -1) | |
throw system_error((*__errno_location()), "cannot write to file"); | |
} | |
template <typename Char, | |
enable_if_t<(std::is_same<Char, wchar_t>::value), int> = 0> | |
void vprint(basic_string_view<Char> format_str, wformat_args args) { | |
vprint(stdout, format_str, args); | |
} | |
namespace detail { | |
template <typename Char, Char... CHARS> | |
class udl_formatter { | |
public: | |
template <typename... Args> | |
std::basic_string<Char> operator()(Args&&... args) const { | |
static constexpr Char s[] = {CHARS..., '\0'}; | |
return format( | |
[] { | |
struct FMT_COMPILE_STRING : fmt::compile_string { | |
using char_type = fmt::remove_cvref_t<decltype(s[0])>; | |
[[maybe_unused]] constexpr | |
operator fmt::basic_string_view<char_type>() const { | |
return fmt::detail::compile_string_to_view< | |
char_type>(s); | |
} | |
}; | |
return FMT_COMPILE_STRING(); | |
}(), | |
std::forward<Args>(args)...); | |
} | |
}; | |
// # 3891 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
template <typename Char> | |
struct udl_arg { | |
const Char* str; | |
template <typename T> | |
named_arg<Char, T> operator=(T&& value) const { | |
return {str, std::forward<T>(value)}; | |
} | |
}; | |
} // namespace detail | |
inline namespace literals { | |
#pragma GCC diagnostic push | |
#pragma GCC diagnostic ignored "-Wpedantic" | |
template <typename Char, Char... CHARS> | |
constexpr detail::udl_formatter<Char, CHARS...> operator""_format() { | |
return {}; | |
} | |
#pragma GCC diagnostic pop | |
// # 3943 "tlm/deps/fmt.exploded/include/fmt/format.h" 3 4 | |
constexpr detail::udl_arg<char> operator"" _a(const char* s, size_t) { | |
return {s}; | |
} | |
constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) { | |
return {s}; | |
} | |
} // namespace literals | |
} // namespace v7 | |
} // namespace fmt | |
// # 27 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/fmt/fmt.h" | |
// 2 # 37 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/common.h" 2 # | |
// 81 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/common.h" | |
// # 81 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/common.h" | |
namespace spdlog { | |
class formatter; | |
namespace sinks { | |
class sink; | |
} | |
using filename_t = std::string; | |
using log_clock = std::chrono::system_clock; | |
using sink_ptr = std::shared_ptr<sinks::sink>; | |
using sinks_init_list = std::initializer_list<sink_ptr>; | |
using err_handler = std::function<void(const std::string& err_msg)>; | |
using string_view_t = fmt::basic_string_view<char>; | |
using wstring_view_t = fmt::basic_string_view<wchar_t>; | |
using memory_buf_t = fmt::basic_memory_buffer<char, 250>; | |
using wmemory_buf_t = fmt::basic_memory_buffer<wchar_t, 250>; | |
// # 117 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/common.h" | |
template <typename> | |
struct is_convertible_to_wstring_view : std::false_type {}; | |
using level_t = std::atomic<int>; | |
// # 141 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/common.h" | |
namespace level { | |
enum level_enum { | |
trace = 0, | |
debug = 1, | |
info = 2, | |
warn = 3, | |
err = 4, | |
critical = 5, | |
off = 6, | |
n_levels | |
}; | |
// # 169 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/common.h" | |
const string_view_t& to_string_view(spdlog::level::level_enum l) noexcept; | |
void set_string_view(spdlog::level::level_enum l, | |
const string_view_t& s) noexcept; | |
const char* to_short_c_str(spdlog::level::level_enum l) noexcept; | |
spdlog::level::level_enum from_str(const std::string& name) noexcept; | |
} // namespace level | |
enum class color_mode { always, automatic, never }; | |
enum class pattern_time_type { local, utc }; | |
class spdlog_ex : public std::exception { | |
public: | |
explicit spdlog_ex(std::string msg); | |
spdlog_ex(const std::string& msg, int last_errno); | |
const char* what() const noexcept override; | |
private: | |
std::string msg_; | |
}; | |
[[noreturn]] void throw_spdlog_ex(const std::string& msg, int last_errno); | |
[[noreturn]] void throw_spdlog_ex(std::string msg); | |
struct source_loc { | |
constexpr source_loc() = default; | |
constexpr source_loc(const char* filename_in, | |
int line_in, | |
const char* funcname_in) | |
: filename{filename_in}, line{line_in}, funcname{funcname_in} { | |
} | |
constexpr bool empty() const noexcept { | |
return line == 0; | |
} | |
const char* filename{nullptr}; | |
int line{0}; | |
const char* funcname{nullptr}; | |
}; | |
namespace details { | |
using std::make_unique; | |
// # 244 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/common.h" | |
} // namespace details | |
} // namespace spdlog | |
// # 18 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/logger.h" | |
// 2 # 1 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/log_msg.h" | |
// 1 | |
namespace spdlog { | |
namespace details { | |
struct log_msg { | |
log_msg() = default; | |
log_msg(log_clock::time_point log_time, | |
source_loc loc, | |
string_view_t logger_name, | |
level::level_enum lvl, | |
string_view_t msg); | |
log_msg(source_loc loc, | |
string_view_t logger_name, | |
level::level_enum lvl, | |
string_view_t msg); | |
log_msg(string_view_t logger_name, | |
level::level_enum lvl, | |
string_view_t msg); | |
log_msg(const log_msg& other) = default; | |
string_view_t logger_name; | |
level::level_enum level{level::off}; | |
log_clock::time_point time; | |
size_t thread_id{0}; | |
mutable size_t color_range_start{0}; | |
mutable size_t color_range_end{0}; | |
source_loc source; | |
string_view_t payload; | |
}; | |
} // namespace details | |
} // namespace spdlog | |
// # 19 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/logger.h" | |
// 2 # 1 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/backtracer.h" | |
// 1 | |
// # 1 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/log_msg_buffer.h" | |
// 1 | |
namespace spdlog { | |
namespace details { | |
class log_msg_buffer : public log_msg { | |
memory_buf_t buffer; | |
void update_string_views(); | |
public: | |
log_msg_buffer() = default; | |
explicit log_msg_buffer(const log_msg& orig_msg); | |
log_msg_buffer(const log_msg_buffer& other); | |
log_msg_buffer(log_msg_buffer&& other) noexcept; | |
log_msg_buffer& operator=(const log_msg_buffer& other); | |
log_msg_buffer& operator=(log_msg_buffer&& other) noexcept; | |
}; | |
} // namespace details | |
} // namespace spdlog | |
// # 7 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/backtracer.h" | |
// 2 # 1 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/circular_q.h" | |
// 1 | |
// # 9 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/circular_q.h" | |
// 2 | |
namespace spdlog { | |
namespace details { | |
template <typename T> | |
class circular_q { | |
size_t max_items_ = 0; | |
typename std::vector<T>::size_type head_ = 0; | |
typename std::vector<T>::size_type tail_ = 0; | |
size_t overrun_counter_ = 0; | |
std::vector<T> v_; | |
public: | |
using value_type = T; | |
circular_q() = default; | |
explicit circular_q(size_t max_items) | |
: max_items_(max_items + 1), v_(max_items_) { | |
} | |
circular_q(const circular_q&) = default; | |
circular_q& operator=(const circular_q&) = default; | |
circular_q(circular_q&& other) noexcept { | |
copy_moveable(std::move(other)); | |
} | |
circular_q& operator=(circular_q&& other) noexcept { | |
copy_moveable(std::move(other)); | |
return *this; | |
} | |
void push_back(T&& item) { | |
if (max_items_ > 0) { | |
v_[tail_] = std::move(item); | |
tail_ = (tail_ + 1) % max_items_; | |
if (tail_ == head_) { | |
head_ = (head_ + 1) % max_items_; | |
++overrun_counter_; | |
} | |
} | |
} | |
const T& front() const { | |
return v_[head_]; | |
} | |
T& front() { | |
return v_[head_]; | |
} | |
size_t size() const { | |
if (tail_ >= head_) { | |
return tail_ - head_; | |
} else { | |
return max_items_ - (head_ - tail_); | |
} | |
} | |
const T& at(size_t i) const { | |
// # 93 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/circular_q.h" | |
// 3 4 | |
(static_cast<bool>( | |
// # 93 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/circular_q.h" | |
i < size() | |
// # 93 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/circular_q.h" | |
// 3 4 | |
) | |
? void(0) | |
: __assert_fail( | |
// # 93 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/circular_q.h" | |
"i < size()" | |
// # 93 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/circular_q.h" | |
// 3 4 | |
, | |
"/mnt/Code/couchbase/docker/third_party/spdlog/" | |
"include/spdlog/details/circular_q.h", | |
93, | |
__extension__ __PRETTY_FUNCTION__)) | |
// # 93 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/circular_q.h" | |
; | |
return v_[(head_ + i) % max_items_]; | |
} | |
void pop_front() { | |
head_ = (head_ + 1) % max_items_; | |
} | |
bool empty() const { | |
return tail_ == head_; | |
} | |
bool full() const { | |
if (max_items_ > 0) { | |
return ((tail_ + 1) % max_items_) == head_; | |
} | |
return false; | |
} | |
size_t overrun_counter() const { | |
return overrun_counter_; | |
} | |
private: | |
void copy_moveable(circular_q&& other) noexcept { | |
max_items_ = other.max_items_; | |
head_ = other.head_; | |
tail_ = other.tail_; | |
overrun_counter_ = other.overrun_counter_; | |
v_ = std::move(other.v_); | |
other.max_items_ = 0; | |
other.head_ = other.tail_ = 0; | |
other.overrun_counter_ = 0; | |
} | |
}; | |
} // namespace details | |
} // namespace spdlog | |
// # 8 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/backtracer.h" | |
// 2 | |
// # 11 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/backtracer.h" | |
// 2 | |
// # 16 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/details/backtracer.h" | |
namespace spdlog { | |
namespace details { | |
class backtracer { | |
mutable std::mutex mutex_; | |
std::atomic<bool> enabled_{false}; | |
circular_q<log_msg_buffer> messages_; | |
public: | |
backtracer() = default; | |
backtracer(const backtracer& other); | |
backtracer(backtracer&& other) noexcept; | |
backtracer& operator=(backtracer other); | |
void enable(size_t size); | |
void disable(); | |
bool enabled() const; | |
void push_back(const log_msg& msg); | |
void foreach_pop(std::function<void(const details::log_msg&)> fun); | |
}; | |
} // namespace details | |
} // namespace spdlog | |
// # 20 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/logger.h" | |
// 2 # 40 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/logger.h" | |
namespace spdlog { | |
class logger { | |
public: | |
explicit logger(std::string name) : name_(std::move(name)), sinks_() { | |
} | |
template <typename It> | |
logger(std::string name, It begin, It end) | |
: name_(std::move(name)), sinks_(begin, end) { | |
} | |
logger(std::string name, sink_ptr single_sink) | |
: logger(std::move(name), {std::move(single_sink)}) { | |
} | |
logger(std::string name, sinks_init_list sinks) | |
: logger(std::move(name), sinks.begin(), sinks.end()) { | |
} | |
virtual ~logger() = default; | |
logger(const logger& other); | |
logger(logger&& other) noexcept; | |
logger& operator=(logger other) noexcept; | |
void swap(spdlog::logger& other) noexcept; | |
template < | |
typename FormatString, | |
typename std::enable_if<fmt::is_compile_string<FormatString>::value, | |
int>::type = 0, | |
typename... Args> | |
void log(source_loc loc, | |
level::level_enum lvl, | |
const FormatString& fmt, | |
Args&&... args) { | |
log_(loc, lvl, fmt, std::forward<Args>(args)...); | |
} | |
template <typename... Args> | |
void log(source_loc loc, | |
level::level_enum lvl, | |
string_view_t fmt, | |
Args&&... args) { | |
log_(loc, lvl, fmt, std::forward<Args>(args)...); | |
} | |
template <typename FormatString, typename... Args> | |
void log(level::level_enum lvl, const FormatString& fmt, Args&&... args) { | |
log(source_loc{}, lvl, fmt, std::forward<Args>(args)...); | |
} | |
template <typename FormatString, typename... Args> | |
void trace(const FormatString& fmt, Args&&... args) { | |
log(level::trace, fmt, std::forward<Args>(args)...); | |
} | |
template <typename FormatString, typename... Args> | |
void debug(const FormatString& fmt, Args&&... args) { | |
log(level::debug, fmt, std::forward<Args>(args)...); | |
} | |
template <typename FormatString, typename... Args> | |
void info(const FormatString& fmt, Args&&... args) { | |
log(level::info, fmt, std::forward<Args>(args)...); | |
} | |
template <typename FormatString, typename... Args> | |
void warn(const FormatString& fmt, Args&&... args) { | |
log(level::warn, fmt, std::forward<Args>(args)...); | |
} | |
template <typename FormatString, typename... Args> | |
void error(const FormatString& fmt, Args&&... args) { | |
log(level::err, fmt, std::forward<Args>(args)...); | |
} | |
template <typename FormatString, typename... Args> | |
void critical(const FormatString& fmt, Args&&... args) { | |
log(level::critical, fmt, std::forward<Args>(args)...); | |
} | |
template <typename T> | |
void log(level::level_enum lvl, const T& msg) { | |
log(source_loc{}, lvl, msg); | |
} | |
template <class T, | |
typename std::enable_if< | |
std::is_convertible<const T&, | |
spdlog::string_view_t>::value && | |
!fmt::is_compile_string<T>::value, | |
int>::type = 0> | |
void log(source_loc loc, level::level_enum lvl, const T& msg) { | |
log(loc, lvl, string_view_t{msg}); | |
} | |
void log(log_clock::time_point log_time, | |
source_loc loc, | |
level::level_enum lvl, | |
string_view_t msg) { | |
bool log_enabled = should_log(lvl); | |
bool traceback_enabled = tracer_.enabled(); | |
if (!log_enabled && !traceback_enabled) { | |
return; | |
} | |
details::log_msg log_msg(log_time, loc, name_, lvl, msg); | |
log_it_(log_msg, log_enabled, traceback_enabled); | |
} | |
void log(source_loc loc, level::level_enum lvl, string_view_t msg) { | |
bool log_enabled = should_log(lvl); | |
bool traceback_enabled = tracer_.enabled(); | |
if (!log_enabled && !traceback_enabled) { | |
return; | |
} | |
details::log_msg log_msg(loc, name_, lvl, msg); | |
log_it_(log_msg, log_enabled, traceback_enabled); | |
} | |
void log(level::level_enum lvl, string_view_t msg) { | |
log(source_loc{}, lvl, msg); | |
} | |
template <class T, | |
typename std::enable_if< | |
!std::is_convertible<const T&, | |
spdlog::string_view_t>::value && | |
!is_convertible_to_wstring_view<const T&>::value, | |
int>::type = 0> | |
void log(source_loc loc, level::level_enum lvl, const T& msg) { | |
log(loc, lvl, "{}", msg); | |
} | |
template <typename T> | |
void trace(const T& msg) { | |
log(level::trace, msg); | |
} | |
template <typename T> | |
void debug(const T& msg) { | |
log(level::debug, msg); | |
} | |
template <typename T> | |
void info(const T& msg) { | |
log(level::info, msg); | |
} | |
template <typename T> | |
void warn(const T& msg) { | |
log(level::warn, msg); | |
} | |
template <typename T> | |
void error(const T& msg) { | |
log(level::err, msg); | |
} | |
template <typename T> | |
void critical(const T& msg) { | |
log(level::critical, msg); | |
} | |
// # 274 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/logger.h" | |
bool should_log(level::level_enum msg_level) const { | |
return msg_level >= level_.load(std::memory_order_relaxed); | |
} | |
bool should_backtrace() const { | |
return tracer_.enabled(); | |
} | |
void set_level(level::level_enum log_level); | |
level::level_enum level() const; | |
const std::string& name() const; | |
void set_formatter(std::unique_ptr<formatter> f); | |
void set_pattern(std::string pattern, | |
pattern_time_type time_type = pattern_time_type::local); | |
void enable_backtrace(size_t n_messages); | |
void disable_backtrace(); | |
void dump_backtrace(); | |
void flush(); | |
void flush_on(level::level_enum log_level); | |
level::level_enum flush_level() const; | |
const std::vector<sink_ptr>& sinks() const; | |
std::vector<sink_ptr>& sinks(); | |
void set_error_handler(err_handler); | |
virtual std::shared_ptr<logger> clone(std::string logger_name); | |
protected: | |
std::string name_; | |
std::vector<sink_ptr> sinks_; | |
spdlog::level_t level_{level::info}; | |
spdlog::level_t flush_level_{level::off}; | |
err_handler custom_err_handler_{nullptr}; | |
details::backtracer tracer_; | |
template <typename FormatString, typename... Args> | |
void log_(source_loc loc, | |
level::level_enum lvl, | |
const FormatString& fmt, | |
Args&&... args) { | |
bool log_enabled = should_log(lvl); | |
bool traceback_enabled = tracer_.enabled(); | |
if (!log_enabled && !traceback_enabled) { | |
return; | |
} | |
try { | |
memory_buf_t buf; | |
fmt::format_to(buf, fmt, std::forward<Args>(args)...); | |
details::log_msg log_msg( | |
loc, name_, lvl, string_view_t(buf.data(), buf.size())); | |
log_it_(log_msg, log_enabled, traceback_enabled); | |
} catch (const std::exception& ex) { | |
err_handler_(ex.what()); | |
} catch (...) { | |
err_handler_("Unknown exception in logger"); | |
} | |
} | |
void log_it_(const details::log_msg& log_msg, | |
bool log_enabled, | |
bool traceback_enabled); | |
virtual void sink_it_(const details::log_msg& msg); | |
virtual void flush_(); | |
void dump_backtrace_(); | |
bool should_flush_(const details::log_msg& msg); | |
void err_handler_(const std::string& msg); | |
}; | |
void swap(logger& a, logger& b); | |
} // namespace spdlog | |
// # 15 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger.h" 2 | |
// # 1 | |
// "/mnt/Code/couchbase/docker/kv_engine/include/memcached/server_log_iface.h" 1 | |
// # 12 | |
// "/mnt/Code/couchbase/docker/kv_engine/include/memcached/server_log_iface.h" | |
namespace spdlog { | |
class logger; | |
} | |
struct ServerLogIface { | |
virtual ~ServerLogIface() = default; | |
virtual spdlog::logger* get_spdlogger() = 0; | |
virtual void register_spdlogger(std::shared_ptr<spdlog::logger> logger) = 0; | |
virtual void unregister_spdlogger(const std::string& name) = 0; | |
virtual void set_level(spdlog::level::level_enum severity) = 0; | |
}; | |
// # 17 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger.h" 2 | |
class EventuallyPersistentEngine; | |
const std::string globalBucketLoggerName = "globalBucketLogger"; | |
// # 87 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger.h" | |
class BucketLogger : public spdlog::logger { | |
public: | |
// # 97 | |
// "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger.h" | |
template <typename S, typename... Args> | |
void log(spdlog::level::level_enum lvl, const S& fmt, Args&&... args); | |
template <typename... Args> | |
void log(spdlog::level::level_enum lvl, const char* msg); | |
template <typename T> | |
void log(spdlog::level::level_enum lvl, const T& msg); | |
template <typename... Args> | |
void trace(const char* fmt, const Args&... args); | |
template <typename... Args> | |
void debug(const char* fmt, const Args&... args); | |
template <typename... Args> | |
void info(const char* fmt, const Args&... args); | |
template <typename... Args> | |
void warn(const char* fmt, const Args&... args); | |
template <typename... Args> | |
void error(const char* fmt, const Args&... args); | |
template <typename... Args> | |
void critical(const char* fmt, const Args&... args); | |
template <typename T> | |
void trace(const T& msg); | |
template <typename T> | |
void debug(const T& msg); | |
template <typename T> | |
void info(const T& msg); | |
template <typename T> | |
void warn(const T& msg); | |
template <typename T> | |
void error(const T& msg); | |
template <typename T> | |
void critical(const T& msg); | |
static void setLoggerAPI(ServerLogIface* api); | |
// # 159 | |
// "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger.h" | |
static std::shared_ptr<BucketLogger> createBucketLogger( | |
const std::string& name, const std::string& prefix = ""); | |
void setConnectionId(uint32_t id) { | |
this->connectionId = id; | |
} | |
std::string prefix; | |
void unregister(); | |
protected: | |
void sink_it_(const spdlog::details::log_msg& msg) override; | |
void flush_() override; | |
void logInner(spdlog::level::level_enum lvl, | |
fmt::string_view fmt, | |
fmt::format_args args); | |
std::string prefixStringWithBucketName( | |
const EventuallyPersistentEngine* engine, fmt::string_view fmt); | |
uint32_t connectionId{0}; | |
// # 214 | |
// "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger.h" | |
explicit BucketLogger(const std::string& name, std::string prefix = ""); | |
static ServerLogIface* getServerLogIface(); | |
private: | |
static std::atomic<ServerLogIface*> loggerAPI; | |
spdlog::logger* spdLogger; | |
static std::mutex initGuard; | |
}; | |
std::shared_ptr<BucketLogger>& getGlobalBucketLogger(); | |
// # 319 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger.h" | |
// # 1 | |
// "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger_impl.h" 1 | |
// # 11 | |
// "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger_impl.h" | |
// # 1 "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/fmt/ostr.h" | |
// 1 | |
// # 19 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/fmt/ostr.h" # 1 | |
// "tlm/deps/fmt.exploded/include/fmt/ostream.h" 1 3 4 # 13 | |
// "tlm/deps/fmt.exploded/include/fmt/ostream.h" 3 4 # 1 | |
// "tlm/deps/fmt.exploded/include/fmt/format.h" 1 3 4 # 14 | |
// "tlm/deps/fmt.exploded/include/fmt/ostream.h" 2 3 4 | |
// # 15 "tlm/deps/fmt.exploded/include/fmt/ostream.h" 3 4 | |
namespace fmt { | |
inline namespace v7 { | |
template <typename Char> | |
class basic_printf_parse_context; | |
template <typename OutputIt, typename Char> | |
class basic_printf_context; | |
namespace detail { | |
template <class Char> | |
class formatbuf : public std::basic_streambuf<Char> { | |
private: | |
using int_type = typename std::basic_streambuf<Char>::int_type; | |
using traits_type = typename std::basic_streambuf<Char>::traits_type; | |
buffer<Char>& buffer_; | |
public: | |
formatbuf(buffer<Char>& buf) : buffer_(buf) { | |
} | |
protected: | |
int_type overflow(int_type ch = traits_type::eof()) override { | |
if (!traits_type::eq_int_type(ch, traits_type::eof())) | |
buffer_.push_back(static_cast<Char>(ch)); | |
return ch; | |
} | |
std::streamsize xsputn(const Char* s, std::streamsize count) override { | |
buffer_.append(s, s + count); | |
return count; | |
} | |
}; | |
struct converter { | |
template <typename T, enable_if_t<(is_integral<T>::value), int> = 0> | |
converter(T); | |
}; | |
template <typename Char> | |
struct test_stream : std::basic_ostream<Char> { | |
private: | |
void_t<> operator<<(converter); | |
}; | |
template <typename Char, typename Traits> | |
void_t<> operator<<(std::basic_ostream<Char, Traits>&, Char); | |
template <typename Char, typename Traits> | |
void_t<> operator<<(std::basic_ostream<Char, Traits>&, char); | |
template <typename Traits> | |
void_t<> operator<<(std::basic_ostream<char, Traits>&, char); | |
template <typename Traits> | |
void_t<> operator<<(std::basic_ostream<char, Traits>&, signed char); | |
template <typename Traits> | |
void_t<> operator<<(std::basic_ostream<char, Traits>&, unsigned char); | |
template <typename T, typename Char> | |
class is_streamable { | |
private: | |
template <typename U> | |
static bool_constant<!std::is_same< | |
decltype(std::declval<test_stream<Char>&>() << std::declval<U>()), | |
void_t<>>::value> | |
test(int); | |
template <typename> | |
static std::false_type test(...); | |
using result = decltype(test<T>(0)); | |
public: | |
static const bool value = result::value; | |
}; | |
template <typename Char> | |
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) { | |
const Char* buf_data = buf.data(); | |
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type; | |
unsigned_streamsize size = buf.size(); | |
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>()); | |
do { | |
unsigned_streamsize n = size <= max_size ? size : max_size; | |
os.write(buf_data, static_cast<std::streamsize>(n)); | |
buf_data += n; | |
size -= n; | |
} while (size != 0); | |
} | |
template <typename Char, typename T> | |
void format_value(buffer<Char>& buf, | |
const T& value, | |
locale_ref loc = locale_ref()) { | |
formatbuf<Char> format_buf(buf); | |
std::basic_ostream<Char> output(&format_buf); | |
if (loc) | |
output.imbue(loc.get<std::locale>()); | |
output << value; | |
output.exceptions(std::ios_base::failbit | std::ios_base::badbit); | |
buf.try_resize(buf.size()); | |
} | |
template <typename T, typename Char> | |
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>> | |
: private formatter<basic_string_view<Char>, Char> { | |
constexpr auto parse(basic_format_parse_context<Char>& ctx) | |
-> decltype(ctx.begin()) { | |
return formatter<basic_string_view<Char>, Char>::parse(ctx); | |
} | |
template < | |
typename ParseCtx, | |
enable_if_t<(std::is_same<ParseCtx, | |
basic_printf_parse_context<Char>>::value), | |
int> = 0> | |
auto parse(ParseCtx& ctx) -> decltype(ctx.begin()) { | |
return ctx.begin(); | |
} | |
template <typename OutputIt> | |
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) | |
-> OutputIt { | |
basic_memory_buffer<Char> buffer; | |
format_value(buffer, value, ctx.locale()); | |
basic_string_view<Char> str(buffer.data(), buffer.size()); | |
return formatter<basic_string_view<Char>, Char>::format(str, ctx); | |
} | |
template <typename OutputIt> | |
auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx) | |
-> OutputIt { | |
basic_memory_buffer<Char> buffer; | |
format_value(buffer, value, ctx.locale()); | |
return std::copy(buffer.begin(), buffer.end(), ctx.out()); | |
} | |
}; | |
} // namespace detail | |
template <typename Char> | |
void vprint(std::basic_ostream<Char>& os, | |
basic_string_view<Char> format_str, | |
basic_format_args<buffer_context<type_identity_t<Char>>> args) { | |
basic_memory_buffer<Char> buffer; | |
detail::vformat_to(buffer, format_str, args); | |
detail::write_buffer(os, buffer); | |
} | |
// # 169 "tlm/deps/fmt.exploded/include/fmt/ostream.h" 3 4 | |
template <typename S, | |
typename... Args, | |
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>> | |
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) { | |
vprint(os, | |
to_string_view(format_str), | |
fmt::make_args_checked<Args...>(format_str, args...)); | |
} | |
} // namespace v7 | |
} // namespace fmt | |
// # 20 | |
// "/mnt/Code/couchbase/docker/third_party/spdlog/include/spdlog/fmt/ostr.h" 2 | |
// # 14 | |
// "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger_impl.h" 2 | |
// # 19 | |
// "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger_impl.h" | |
template <typename S, typename... Args> | |
void BucketLogger::log(spdlog::level::level_enum lvl, | |
const S& fmt, | |
Args&&... args) { | |
if (!should_log(lvl)) { | |
return; | |
} | |
logInner(lvl, fmt, fmt::make_args_checked<Args...>(fmt, args...)); | |
} | |
template <typename... Args> | |
void BucketLogger::log(spdlog::level::level_enum lvl, const char* msg) { | |
if (!should_log(lvl)) { | |
return; | |
} | |
logInner(lvl, msg, {}); | |
} | |
template <typename T> | |
void BucketLogger::log(spdlog::level::level_enum lvl, const T& msg) { | |
if (!should_log(lvl)) { | |
return; | |
} | |
logInner(lvl, "{}", fmt::make_args_checked<T>("{}", msg)); | |
} | |
template <typename... Args> | |
void BucketLogger::trace(const char* fmt, const Args&... args) { | |
log(spdlog::level::trace, fmt, args...); | |
} | |
template <typename... Args> | |
void BucketLogger::debug(const char* fmt, const Args&... args) { | |
log(spdlog::level::debug, fmt, args...); | |
} | |
template <typename... Args> | |
void BucketLogger::info(const char* fmt, const Args&... args) { | |
log(spdlog::level::info, fmt, args...); | |
} | |
template <typename... Args> | |
void BucketLogger::warn(const char* fmt, const Args&... args) { | |
log(spdlog::level::warn, fmt, args...); | |
} | |
template <typename... Args> | |
void BucketLogger::error(const char* fmt, const Args&... args) { | |
log(spdlog::level::err, fmt, args...); | |
} | |
template <typename... Args> | |
void BucketLogger::critical(const char* fmt, const Args&... args) { | |
log(spdlog::level::critical, fmt, args...); | |
} | |
template <typename T> | |
void BucketLogger::trace(const T& msg) { | |
log(spdlog::level::trace, msg); | |
} | |
template <typename T> | |
void BucketLogger::debug(const T& msg) { | |
log(spdlog::level::debug, msg); | |
} | |
template <typename T> | |
void BucketLogger::info(const T& msg) { | |
log(spdlog::level::info, msg); | |
} | |
template <typename T> | |
void BucketLogger::warn(const T& msg) { | |
log(spdlog::level::warn, msg); | |
} | |
template <typename T> | |
void BucketLogger::error(const T& msg) { | |
log(spdlog::level::err, msg); | |
} | |
template <typename T> | |
void BucketLogger::critical(const T& msg) { | |
log(spdlog::level::critical, msg); | |
} | |
// # 320 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/bucket_logger.h" 2 | |
// # 15 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/dcp/producer.cc" 2 | |
// # 1 "tlm/deps/folly.exploded/include/folly/AtomicHashMap.h" 1 3 4 | |
// # 82 "tlm/deps/folly.exploded/include/folly/AtomicHashMap.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/AtomicHashArray.h" 1 3 4 | |
// # 32 "tlm/deps/folly.exploded/include/folly/AtomicHashArray.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/ThreadCachedInt.h" 1 3 4 | |
// # 23 "tlm/deps/folly.exploded/include/folly/ThreadCachedInt.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Likely.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/Likely.h" 3 4 | |
// # 28 "tlm/deps/folly.exploded/include/folly/ThreadCachedInt.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/ThreadLocal.h" 1 3 4 | |
// # 41 "tlm/deps/folly.exploded/include/folly/ThreadLocal.h" 3 4 | |
// # 45 "tlm/deps/folly.exploded/include/folly/ThreadLocal.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/ScopeGuard.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/ScopeGuard.h" 3 4 | |
// # 21 "tlm/deps/folly.exploded/include/folly/ScopeGuard.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Preprocessor.h" 1 3 4 | |
// # 19 "tlm/deps/folly.exploded/include/folly/Preprocessor.h" 3 4 | |
// # 28 "tlm/deps/folly.exploded/include/folly/ScopeGuard.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/lang/Exception.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/lang/Exception.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/CppAttributes.h" 1 3 4 | |
// # 23 "tlm/deps/folly.exploded/include/folly/CppAttributes.h" 3 4 | |
// # 25 "tlm/deps/folly.exploded/include/folly/lang/Exception.h" 2 3 4 | |
namespace folly { | |
template <typename Ex> | |
[[noreturn]] __attribute__((__noinline__)) __attribute__((__cold__)) void | |
throw_exception(Ex&& ex) { | |
throw static_cast<Ex&&>(ex); | |
} | |
template <typename Ex> | |
[[noreturn]] __attribute__((__noinline__)) __attribute__((__cold__)) void | |
terminate_with(Ex&& ex) noexcept { | |
throw_exception(static_cast<Ex&&>(ex)); | |
} | |
namespace detail { | |
template <typename T> | |
inline __attribute__((__always_inline__)) | |
__attribute__((__visibility__("hidden"))) T&& | |
to_exception_arg_(T&& t) { | |
return static_cast<T&&>(t); | |
} | |
template <std::size_t N> | |
inline __attribute__((__always_inline__)) | |
__attribute__((__visibility__("hidden"))) char const* | |
to_exception_arg_(char const (&array)[N]) { | |
return static_cast<char const*>(array); | |
} | |
template <typename Ex, typename... Args> | |
[[noreturn]] __attribute__((__noinline__)) __attribute__((__cold__)) void | |
throw_exception_(Args&&... args) { | |
throw_exception(Ex(static_cast<Args&&>(args)...)); | |
} | |
template <typename Ex, typename... Args> | |
[[noreturn]] __attribute__((__noinline__)) __attribute__((__cold__)) void | |
terminate_with_(Args&&... args) noexcept { | |
throw_exception(Ex(static_cast<Args&&>(args)...)); | |
} | |
} // namespace detail | |
// # 80 "tlm/deps/folly.exploded/include/folly/lang/Exception.h" 3 4 | |
template <typename Ex, typename... Args> | |
[[noreturn]] inline __attribute__((__always_inline__)) | |
__attribute__((__visibility__("hidden"))) void | |
throw_exception(Args&&... args) { | |
detail::throw_exception_<Ex>( | |
detail::to_exception_arg_(static_cast<Args&&>(args))...); | |
} | |
template <typename Ex, typename... Args> | |
[[noreturn]] inline __attribute__((__always_inline__)) | |
__attribute__((__visibility__("hidden"))) void | |
terminate_with(Args&&... args) noexcept { | |
detail::terminate_with_<Ex>( | |
detail::to_exception_arg_(static_cast<Args&&>(args))...); | |
} | |
// # 117 "tlm/deps/folly.exploded/include/folly/lang/Exception.h" 3 4 | |
template <typename F, typename... A> | |
__attribute__((__noinline__)) __attribute__((__cold__)) auto invoke_cold( | |
F&& f, A&&... a) | |
-> decltype(static_cast<F&&>(f)(static_cast<A&&>(a)...)) { | |
return static_cast<F&&>(f)(static_cast<A&&>(a)...); | |
} | |
// # 147 "tlm/deps/folly.exploded/include/folly/lang/Exception.h" 3 4 | |
template <typename F, typename... A> | |
[[noreturn]] __attribute__((__noinline__)) __attribute__((__cold__)) void | |
invoke_noreturn_cold(F&& f, A&&... a) { | |
static_cast<F&&>(f)(static_cast<A&&>(a)...); | |
std::terminate(); | |
} | |
// # 183 "tlm/deps/folly.exploded/include/folly/lang/Exception.h" 3 4 | |
template <typename E, typename Try, typename Catch, typename... CatchA> | |
inline __attribute__((__always_inline__)) | |
__attribute__((__visibility__("hidden"))) auto | |
catch_exception(Try&& t, Catch&& c, CatchA&&... a) -> typename std::common_type< | |
decltype(static_cast<Try&&>(t)()), | |
decltype(static_cast<Catch&&>(c)(std::declval<E>(), | |
static_cast<CatchA&&>(a)...))>::type { | |
try { | |
return static_cast<Try&&>(t)(); | |
} catch (E e) { | |
return invoke_cold( | |
static_cast<Catch&&>(c), e, static_cast<CatchA&&>(a)...); | |
} | |
} | |
// # 223 "tlm/deps/folly.exploded/include/folly/lang/Exception.h" 3 4 | |
template <typename Try, typename Catch, typename... CatchA> | |
inline __attribute__((__always_inline__)) | |
__attribute__((__visibility__("hidden"))) auto | |
catch_exception(Try&& t, Catch&& c, CatchA&&... a) -> typename std::common_type< | |
decltype(static_cast<Try&&>(t)()), | |
decltype(static_cast<Catch&&>(c)(static_cast<CatchA&&>(a)...))>::type { | |
try { | |
return static_cast<Try&&>(t)(); | |
} catch (...) { | |
return invoke_cold(static_cast<Catch&&>(c), | |
static_cast<CatchA&&>(a)...); | |
} | |
} | |
[[noreturn]] inline __attribute__((__always_inline__)) | |
__attribute__((__visibility__("hidden"))) void | |
rethrow_current_exception() { | |
throw; | |
} | |
} // namespace folly | |
// # 30 "tlm/deps/folly.exploded/include/folly/ScopeGuard.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/lang/UncaughtExceptions.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/lang/UncaughtExceptions.h" 3 4 | |
namespace __cxxabiv1 { | |
struct __cxa_eh_globals; | |
extern "C" __cxa_eh_globals* __cxa_get_globals() noexcept; | |
} // namespace __cxxabiv1 | |
namespace folly { | |
inline int uncaught_exceptions() noexcept { | |
return *(reinterpret_cast<unsigned int*>( | |
static_cast<char*>( | |
static_cast<void*>(__cxxabiv1::__cxa_get_globals())) + | |
sizeof(void*))); | |
// # 65 "tlm/deps/folly.exploded/include/folly/lang/UncaughtExceptions.h" 3 | |
// 4 | |
} | |
} // namespace folly | |
// # 31 "tlm/deps/folly.exploded/include/folly/ScopeGuard.h" 2 3 4 | |
namespace folly { | |
namespace detail { | |
class ScopeGuardImplBase { | |
public: | |
void dismiss() noexcept { | |
dismissed_ = true; | |
} | |
protected: | |
ScopeGuardImplBase() noexcept : dismissed_(false) { | |
} | |
static void warnAboutToCrash() noexcept; | |
static ScopeGuardImplBase makeEmptyScopeGuard() noexcept { | |
return ScopeGuardImplBase{}; | |
} | |
template <typename T> | |
static const T& asConst(const T& t) noexcept { | |
return t; | |
} | |
bool dismissed_; | |
}; | |
template <typename FunctionType, bool InvokeNoexcept> | |
class ScopeGuardImpl : public ScopeGuardImplBase { | |
public: | |
explicit ScopeGuardImpl(FunctionType& fn) noexcept( | |
std::is_nothrow_copy_constructible<FunctionType>::value) | |
: ScopeGuardImpl( | |
asConst(fn), | |
makeFailsafe( | |
std::is_nothrow_copy_constructible<FunctionType>{}, | |
&fn)) { | |
} | |
explicit ScopeGuardImpl(const FunctionType& fn) noexcept( | |
std::is_nothrow_copy_constructible<FunctionType>::value) | |
: ScopeGuardImpl( | |
fn, | |
makeFailsafe( | |
std::is_nothrow_copy_constructible<FunctionType>{}, | |
&fn)) { | |
} | |
explicit ScopeGuardImpl(FunctionType&& fn) noexcept( | |
std::is_nothrow_move_constructible<FunctionType>::value) | |
: ScopeGuardImpl( | |
std::move_if_noexcept(fn), | |
makeFailsafe( | |
std::is_nothrow_move_constructible<FunctionType>{}, | |
&fn)) { | |
} | |
ScopeGuardImpl(ScopeGuardImpl&& other) noexcept( | |
std::is_nothrow_move_constructible<FunctionType>::value) | |
: function_(std::move_if_noexcept(other.function_)) { | |
dismissed_ = std::exchange(other.dismissed_, true); | |
} | |
~ScopeGuardImpl() noexcept(InvokeNoexcept) { | |
if (!dismissed_) { | |
execute(); | |
} | |
} | |
private: | |
static ScopeGuardImplBase makeFailsafe(std::true_type, | |
const void*) noexcept { | |
return makeEmptyScopeGuard(); | |
} | |
template <typename Fn> | |
static auto makeFailsafe(std::false_type, Fn* fn) noexcept | |
-> ScopeGuardImpl<decltype(std::ref(*fn)), InvokeNoexcept> { | |
return ScopeGuardImpl<decltype(std::ref(*fn)), InvokeNoexcept>{ | |
std::ref(*fn)}; | |
} | |
template <typename Fn> | |
explicit ScopeGuardImpl(Fn&& fn, ScopeGuardImplBase&& failsafe) | |
: ScopeGuardImplBase{}, function_(std::forward<Fn>(fn)) { | |
failsafe.dismiss(); | |
} | |
void* operator new(std::size_t) = delete; | |
void execute() noexcept(InvokeNoexcept) { | |
if (InvokeNoexcept) { | |
using R = decltype(function_()); | |
auto catcher = []() -> R { warnAboutToCrash(), std::terminate(); }; | |
catch_exception(function_, catcher); | |
} else { | |
function_(); | |
} | |
} | |
FunctionType function_; | |
}; | |
template <typename F, bool INE> | |
using ScopeGuardImplDecay = ScopeGuardImpl<typename std::decay<F>::type, INE>; | |
} // namespace detail | |
// # 181 "tlm/deps/folly.exploded/include/folly/ScopeGuard.h" 3 4 | |
template <typename F> | |
[[nodiscard]] detail::ScopeGuardImplDecay<F, true> makeGuard(F&& f) noexcept( | |
noexcept(detail::ScopeGuardImplDecay<F, true>(static_cast<F&&>(f)))) { | |
return detail::ScopeGuardImplDecay<F, true>(static_cast<F&&>(f)); | |
} | |
namespace detail { | |
// # 204 "tlm/deps/folly.exploded/include/folly/ScopeGuard.h" 3 4 | |
template <typename FunctionType, bool ExecuteOnException> | |
class ScopeGuardForNewException { | |
public: | |
explicit ScopeGuardForNewException(const FunctionType& fn) : guard_(fn) { | |
} | |
explicit ScopeGuardForNewException(FunctionType&& fn) | |
: guard_(std::move(fn)) { | |
} | |
ScopeGuardForNewException(ScopeGuardForNewException&& other) = default; | |
~ScopeGuardForNewException() noexcept(ExecuteOnException) { | |
if (ExecuteOnException != (exceptionCounter_ < uncaught_exceptions())) { | |
guard_.dismiss(); | |
} | |
} | |
private: | |
void* operator new(std::size_t) = delete; | |
void operator delete(void*) = delete; | |
ScopeGuardImpl<FunctionType, ExecuteOnException> guard_; | |
int exceptionCounter_{uncaught_exceptions()}; | |
}; | |
enum class ScopeGuardOnFail {}; | |
template <typename FunctionType> | |
ScopeGuardForNewException<typename std::decay<FunctionType>::type, true> | |
operator+(detail::ScopeGuardOnFail, FunctionType&& fn) { | |
return ScopeGuardForNewException<typename std::decay<FunctionType>::type, | |
true>(std::forward<FunctionType>(fn)); | |
} | |
enum class ScopeGuardOnSuccess {}; | |
template <typename FunctionType> | |
ScopeGuardForNewException<typename std::decay<FunctionType>::type, false> | |
operator+(ScopeGuardOnSuccess, FunctionType&& fn) { | |
return ScopeGuardForNewException<typename std::decay<FunctionType>::type, | |
false>(std::forward<FunctionType>(fn)); | |
} | |
enum class ScopeGuardOnExit {}; | |
template <typename FunctionType> | |
ScopeGuardImpl<typename std::decay<FunctionType>::type, true> operator+( | |
detail::ScopeGuardOnExit, FunctionType&& fn) { | |
return ScopeGuardImpl<typename std::decay<FunctionType>::type, true>( | |
std::forward<FunctionType>(fn)); | |
} | |
} // namespace detail | |
} // namespace folly | |
// # 51 "tlm/deps/folly.exploded/include/folly/ThreadLocal.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 1 3 4 | |
// # 19 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 4 | |
// # 29 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" 3 4 | |
// # 23 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" 2 3 | |
// 4 # 31 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" 3 | |
// 4 # 1 "tlm/deps/folly.exploded/include/folly/Indestructible.h" 1 3 4 # 17 | |
// "tlm/deps/folly.exploded/include/folly/Indestructible.h" 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/Indestructible.h" 2 3 4 | |
namespace folly { | |
// # 60 "tlm/deps/folly.exploded/include/folly/Indestructible.h" 3 4 | |
template <typename T> | |
class Indestructible final { | |
public: | |
template <typename S = T, typename = decltype(S())> | |
constexpr Indestructible() noexcept(noexcept(T())) { | |
} | |
// # 81 "tlm/deps/folly.exploded/include/folly/Indestructible.h" 3 4 | |
template <typename U = T, | |
std::enable_if_t<std::is_constructible<T, U&&>::value>* = nullptr, | |
std::enable_if_t<!std::is_same<Indestructible<T>, | |
remove_cvref_t<U>>::value>* = | |
nullptr, | |
std::enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr> | |
explicit constexpr Indestructible(U&& u) noexcept( | |
noexcept(T(std::declval<U>()))) | |
: storage_(std::forward<U>(u)) { | |
} | |
template <typename U = T, | |
std::enable_if_t<std::is_constructible<T, U&&>::value>* = nullptr, | |
std::enable_if_t<!std::is_same<Indestructible<T>, | |
remove_cvref_t<U>>::value>* = | |
nullptr, | |
std::enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr> | |
constexpr Indestructible(U&& u) noexcept(noexcept(T(std::declval<U>()))) | |
: storage_(std::forward<U>(u)) { | |
} | |
template <typename... Args, typename = decltype(T(std::declval<Args>()...))> | |
explicit constexpr Indestructible(Args&&... args) noexcept( | |
noexcept(T(std::declval<Args>()...))) | |
: storage_(std::forward<Args>(args)...) { | |
} | |
template <typename U, | |
typename... Args, | |
typename = decltype(T(std::declval<std::initializer_list<U>&>(), | |
std::declval<Args>()...))> | |
explicit constexpr Indestructible( | |
std::initializer_list<U> il, | |
Args... args) noexcept(noexcept(T(std:: | |
declval<std::initializer_list< | |
U>&>(), | |
std::declval<Args>()...))) | |
: storage_(il, std::forward<Args>(args)...) { | |
} | |
~Indestructible() = default; | |
Indestructible(Indestructible const&) = delete; | |
Indestructible& operator=(Indestructible const&) = delete; | |
Indestructible(Indestructible&& other) noexcept( | |
noexcept(T(std::declval<T>()))) | |
: storage_(std::move(other.storage_.value)) { | |
other.erased_ = true; | |
} | |
Indestructible& operator=(Indestructible&& other) noexcept( | |
noexcept(T(std::declval<T>()))) { | |
storage_.value = std::move(other.storage_.value); | |
other.erased_ = true; | |
} | |
T* get() noexcept { | |
check(); | |
return &storage_.value; | |
} | |
T const* get() const noexcept { | |
check(); | |
return &storage_.value; | |
} | |
T& operator*() noexcept { | |
return *get(); | |
} | |
T const& operator*() const noexcept { | |
return *get(); | |
} | |
T* operator->() noexcept { | |
return get(); | |
} | |
T const* operator->() const noexcept { | |
return get(); | |
} | |
private: | |
void check() const noexcept { | |
(static_cast<bool>(!erased_) | |
? void(0) | |
: __assert_fail("!erased_", | |
"tlm/deps/folly.exploded/include/folly/" | |
"Indestructible.h", | |
157, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
union Storage { | |
T value; | |
template <typename S = T, typename = decltype(S())> | |
constexpr Storage() noexcept(noexcept(T())) : value() { | |
} | |
template <typename... Args, | |
typename = decltype(T(std::declval<Args>()...))> | |
explicit constexpr Storage(Args&&... args) noexcept( | |
noexcept(T(std::declval<Args>()...))) | |
: value(std::forward<Args>(args)...) { | |
} | |
~Storage() { | |
} | |
}; | |
Storage storage_{}; | |
bool erased_{false}; | |
}; | |
} // namespace folly | |
// # 32 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" 2 3 | |
// 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Memory.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/Memory.h" 2 3 4 | |
// # 21 "tlm/deps/folly.exploded/include/folly/Memory.h" 2 3 4 | |
// # 23 "tlm/deps/folly.exploded/include/folly/Memory.h" 2 3 4 | |
// # 33 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 3 4 | |
// # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/control/expr_iif.hpp" | |
// 1 3 4 # 15 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/control/expr_iif.hpp" 3 4 | |
// # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/config/config.hpp" 1 | |
// 3 4 # 16 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/control/expr_iif.hpp" 2 3 | |
// 4 # 23 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 2 3 4 # 1 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/facilities/is_empty_variadic.hpp" | |
// 1 3 4 # 19 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/facilities/is_empty_variadic.hpp" | |
// 3 4 # 1 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/punctuation/is_begin_parens.hpp" | |
// 1 3 4 # 19 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/punctuation/is_begin_parens.hpp" | |
// 3 4 # 1 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/punctuation/detail/is_begin_parens.hpp" | |
// 1 3 4 # 20 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/punctuation/is_begin_parens.hpp" | |
// 2 3 4 # 20 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/facilities/is_empty_variadic.hpp" | |
// 2 3 4 # 1 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/facilities/detail/is_empty.hpp" | |
// 1 3 4 # 21 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/facilities/is_empty_variadic.hpp" | |
// 2 3 4 # 24 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 2 3 4 | |
// # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/list/for_each.hpp" 1 | |
// 3 4 # 18 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/list/for_each.hpp" 3 4 # | |
// 1 "tlm/deps/boost.exploded/include/boost/preprocessor/list/for_each_i.hpp" 1 | |
// 3 4 # 17 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/list/for_each_i.hpp" 3 4 | |
// # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/arithmetic/inc.hpp" 1 | |
// 3 4 # 18 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/list/for_each_i.hpp" 2 3 | |
// 4 | |
// # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/list/adt.hpp" 1 3 4 | |
// # 18 "tlm/deps/boost.exploded/include/boost/preprocessor/list/adt.hpp" 3 4 | |
// # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/detail/is_binary.hpp" | |
// 1 3 4 # 16 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/detail/is_binary.hpp" 3 4 | |
// # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/detail/check.hpp" 1 3 | |
// 4 # 15 "tlm/deps/boost.exploded/include/boost/preprocessor/detail/check.hpp" | |
// 3 4 # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/cat.hpp" 1 3 4 # | |
// 16 "tlm/deps/boost.exploded/include/boost/preprocessor/detail/check.hpp" 2 3 | |
// 4 # 17 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/detail/is_binary.hpp" 2 3 | |
// 4 # 19 "tlm/deps/boost.exploded/include/boost/preprocessor/list/adt.hpp" 2 3 | |
// 4 # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/logical/compl.hpp" | |
// 1 3 4 # 20 "tlm/deps/boost.exploded/include/boost/preprocessor/list/adt.hpp" | |
// 2 3 4 # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/eat.hpp" | |
// 1 3 4 # 21 "tlm/deps/boost.exploded/include/boost/preprocessor/list/adt.hpp" | |
// 2 3 4 # 20 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/list/for_each_i.hpp" 2 3 | |
// 4 # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/repetition/for.hpp" | |
// 1 3 4 # 18 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/repetition/for.hpp" 3 4 | |
// # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/debug/error.hpp" 1 3 | |
// 4 # 19 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/repetition/for.hpp" 2 3 4 | |
// # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/facilities/empty.hpp" | |
// 1 3 4 # 20 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/repetition/for.hpp" 2 3 4 | |
// # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/logical/bool.hpp" 1 3 | |
// 4 # 21 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/repetition/for.hpp" 2 3 4 | |
// # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/detail/auto_rec.hpp" | |
// 1 3 4 # 21 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/detail/auto_rec.hpp" 3 4 | |
// # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/control/iif.hpp" 1 3 | |
// 4 # 22 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/detail/auto_rec.hpp" 2 3 | |
// 4 # 22 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/repetition/for.hpp" 2 3 4 | |
// # 44 "tlm/deps/boost.exploded/include/boost/preprocessor/repetition/for.hpp" | |
// 3 4 # 1 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/repetition/detail/for.hpp" | |
// 1 3 4 # 45 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/repetition/for.hpp" 2 3 4 | |
// # 21 "tlm/deps/boost.exploded/include/boost/preprocessor/list/for_each_i.hpp" | |
// 2 3 4 # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/elem.hpp" | |
// 1 3 4 # 20 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/elem.hpp" 3 4 # 1 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/facilities/expand.hpp" 1 | |
// 3 4 # 21 "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/elem.hpp" | |
// 2 3 4 # 1 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/facilities/overload.hpp" | |
// 1 3 4 # 17 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/facilities/overload.hpp" | |
// 3 4 # 1 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/variadic/size.hpp" 1 3 4 | |
// # 18 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/facilities/overload.hpp" | |
// 2 3 4 # 22 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/elem.hpp" 2 3 4 # 1 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/rem.hpp" 1 3 4 # 20 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/rem.hpp" 3 4 # 1 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/detail/is_single_return.hpp" | |
// 1 3 4 # 21 "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/rem.hpp" | |
// 2 3 4 # 23 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/elem.hpp" 2 3 4 # 1 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/variadic/elem.hpp" 1 3 4 | |
// # 24 "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/elem.hpp" 2 3 | |
// 4 # 22 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/list/for_each_i.hpp" 2 3 | |
// 4 # 19 "tlm/deps/boost.exploded/include/boost/preprocessor/list/for_each.hpp" | |
// 2 3 4 # 25 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 2 3 4 | |
// # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/logical/not.hpp" 1 3 | |
// 4 # 26 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 2 3 4 # 1 | |
// "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/to_list.hpp" 1 3 4 | |
// # 21 "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/to_list.hpp" 3 | |
// 4 # 1 "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/size.hpp" 1 3 | |
// 4 # 22 "tlm/deps/boost.exploded/include/boost/preprocessor/tuple/to_list.hpp" | |
// 2 3 4 # 27 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/lang/CustomizationPoint.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/lang/CustomizationPoint.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/lang/StaticConst.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/lang/StaticConst.h" 3 4 | |
namespace folly { | |
template <typename T> | |
struct StaticConst { | |
static constexpr T value{}; | |
}; | |
template <typename T> | |
constexpr T StaticConst<T>::value; | |
} // namespace folly | |
// # 23 "tlm/deps/folly.exploded/include/folly/lang/CustomizationPoint.h" 2 3 4 | |
// # 50 "tlm/deps/folly.exploded/include/folly/lang/CustomizationPoint.h" 3 4 | |
namespace folly { | |
// # 71 "tlm/deps/folly.exploded/include/folly/lang/CustomizationPoint.h" 3 4 | |
template <const auto& Tag> | |
using cpo_t = std::decay_t<decltype(Tag)>; | |
} // namespace folly | |
// # 34 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 2 3 4 | |
// # 52 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 3 4 | |
namespace folly { | |
using std::invoke; | |
} | |
// # 82 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 3 4 | |
namespace folly { | |
using std::invoke_result; | |
using std::invoke_result_t; | |
using std::is_invocable; | |
using std::is_invocable_r; | |
using std::is_invocable_r_v; | |
using std::is_invocable_v; | |
using std::is_nothrow_invocable; | |
using std::is_nothrow_invocable_r; | |
using std::is_nothrow_invocable_r_v; | |
using std::is_nothrow_invocable_v; | |
} // namespace folly | |
// # 204 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 3 4 | |
namespace folly { | |
namespace detail { | |
struct invoke_private_overload; | |
template <bool, typename Invoke> | |
struct invoke_traits_base_ {}; | |
template <typename Invoke> | |
struct invoke_traits_base_<false, Invoke> {}; | |
template <typename Invoke> | |
struct invoke_traits_base_<true, Invoke> { | |
inline static constexpr Invoke invoke{}; | |
}; | |
template <typename Invoke> | |
using invoke_traits_base = | |
invoke_traits_base_<is_constexpr_default_constructible_v<Invoke>, | |
Invoke>; | |
} // namespace detail | |
// # 252 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 3 4 | |
template <typename Invoke> | |
struct invoke_traits : detail::invoke_traits_base<Invoke> { | |
public: | |
using invoke_type = Invoke; | |
template <typename... Args> | |
struct invoke_result : folly::invoke_result<Invoke, Args...> {}; | |
template <typename... Args> | |
using invoke_result_t = folly::invoke_result_t<Invoke, Args...>; | |
template <typename... Args> | |
struct is_invocable : folly::is_invocable<Invoke, Args...> {}; | |
template <typename... Args> | |
inline static constexpr bool is_invocable_v = is_invocable<Args...>::value; | |
template <typename R, typename... Args> | |
struct is_invocable_r : folly::is_invocable_r<R, Invoke, Args...> {}; | |
template <typename R, typename... Args> | |
inline static constexpr bool is_invocable_r_v = | |
is_invocable_r<R, Args...>::value; | |
template <typename... Args> | |
struct is_nothrow_invocable : folly::is_nothrow_invocable<Invoke, Args...> { | |
}; | |
template <typename... Args> | |
inline static constexpr bool is_nothrow_invocable_v = | |
is_nothrow_invocable<Args...>::value; | |
template <typename R, typename... Args> | |
struct is_nothrow_invocable_r | |
: folly::is_nothrow_invocable_r<R, Invoke, Args...> {}; | |
template <typename R, typename... Args> | |
inline static constexpr bool is_nothrow_invocable_r_v = | |
is_nothrow_invocable_r<R, Args...>::value; | |
}; | |
} // namespace folly | |
// # 484 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 3 4 | |
namespace folly { | |
namespace detail_tag_invoke_fn { | |
void tag_invoke(); | |
struct tag_invoke_fn { | |
template <typename Tag, typename... Args> | |
constexpr auto operator()(Tag tag, Args&&... args) const | |
noexcept(noexcept(tag_invoke(static_cast<Tag&&>(tag), | |
static_cast<Args&&>(args)...))) | |
-> decltype(tag_invoke(static_cast<Tag&&>(tag), | |
static_cast<Args&&>(args)...)) { | |
return tag_invoke(static_cast<Tag&&>(tag), | |
static_cast<Args&&>(args)...); | |
} | |
}; | |
// # 509 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 3 4 | |
template <typename Tag, typename... Args> | |
using tag_invoke_result_t = | |
decltype(tag_invoke(static_cast<Tag && (*)() noexcept>(nullptr)(), | |
static_cast<Args && (*)() noexcept>(nullptr)()...)); | |
template <typename Tag, typename... Args> | |
auto try_tag_invoke(int) noexcept( | |
noexcept(tag_invoke(static_cast<Tag && (*)() noexcept>(nullptr)(), | |
static_cast<Args && (*)() noexcept>(nullptr)()...))) | |
-> decltype(static_cast<void>(tag_invoke( | |
static_cast<Tag && (*)() noexcept>(nullptr)(), | |
static_cast<Args && (*)() noexcept>(nullptr)()...)), | |
std::true_type{}); | |
template <typename Tag, typename... Args> | |
std::false_type try_tag_invoke(...) noexcept(false); | |
template <template <typename...> class T, typename... Args> | |
struct defer { | |
using type = T<Args...>; | |
}; | |
struct empty {}; | |
} // namespace detail_tag_invoke_fn | |
// # 564 "tlm/deps/folly.exploded/include/folly/functional/Invoke.h" 3 4 | |
namespace folly_cpo__ { | |
inline constexpr detail_tag_invoke_fn::tag_invoke_fn tag_invoke{}; | |
} | |
using namespace folly_cpo__; | |
template <typename Tag, typename... Args> | |
inline constexpr bool is_tag_invocable_v = | |
decltype(detail_tag_invoke_fn::try_tag_invoke<Tag, Args...>(0))::value; | |
template <typename Tag, typename... Args> | |
struct is_tag_invocable : bool_constant<is_tag_invocable_v<Tag, Args...>> {}; | |
template <typename Tag, typename... Args> | |
inline constexpr bool is_nothrow_tag_invocable_v = | |
noexcept(detail_tag_invoke_fn::try_tag_invoke<Tag, Args...>(0)); | |
template <typename Tag, typename... Args> | |
struct is_nothrow_tag_invocable | |
: bool_constant<is_nothrow_tag_invocable_v<Tag, Args...>> {}; | |
template <typename R, typename Tag, typename... Args> | |
using is_tag_invocable_r = | |
folly::is_invocable_r<R, decltype(folly::tag_invoke), Tag, Args...>; | |
template <typename R, typename Tag, typename... Args> | |
inline constexpr bool is_tag_invocable_r_v = | |
is_tag_invocable_r<R, decltype(folly::tag_invoke), Tag, Args...>::value; | |
template <typename R, typename Tag, typename... Args> | |
using is_nothrow_tag_invocable_r = folly:: | |
is_nothrow_invocable_r<R, decltype(folly::tag_invoke), Tag, Args...>; | |
template <typename R, typename Tag, typename... Args> | |
inline constexpr bool is_nothrow_tag_invocable_r_v = | |
is_nothrow_tag_invocable_r<R, Tag, Args...>::value; | |
using detail_tag_invoke_fn::tag_invoke_result_t; | |
template <typename Tag, typename... Args> | |
struct tag_invoke_result | |
: conditional_t< | |
is_tag_invocable_v<Tag, Args...>, | |
detail_tag_invoke_fn::defer<tag_invoke_result_t, Tag, Args...>, | |
detail_tag_invoke_fn::empty> {}; | |
} // namespace folly | |
// # 34 "tlm/deps/folly.exploded/include/folly/Memory.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/lang/Align.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/lang/Align.h" 3 4 | |
namespace folly { | |
// # 37 "tlm/deps/folly.exploded/include/folly/lang/Align.h" 3 4 | |
constexpr bool has_extended_alignment = | |
kIsLinux && sizeof(void*) >= sizeof(std::uint64_t); | |
namespace detail { | |
template <typename... Ts> | |
struct max_align_t_ { | |
static constexpr std::size_t value() { | |
std::size_t const values[] = {0u, alignof(Ts)...}; | |
std::size_t r = 0u; | |
for (auto const v : values) { | |
r = r < v ? v : r; | |
} | |
return r; | |
} | |
}; | |
using max_align_v_ = max_align_t_<long double, | |
double, | |
float, | |
long long int, | |
long int, | |
int, | |
short int, | |
bool, | |
char, | |
char16_t, | |
char32_t, | |
wchar_t, | |
void*, | |
std::max_align_t>; | |
} // namespace detail | |
// # 105 "tlm/deps/folly.exploded/include/folly/lang/Align.h" 3 4 | |
constexpr std::size_t max_align_v = detail::max_align_v_::value(); | |
struct alignas(max_align_v) max_align_t {}; | |
// # 122 "tlm/deps/folly.exploded/include/folly/lang/Align.h" 3 4 | |
constexpr std::size_t hardware_destructive_interference_size = | |
(kIsArchArm || kIsArchS390X) ? 64 : 128; | |
static_assert(hardware_destructive_interference_size >= max_align_v, "math?"); | |
// # 133 "tlm/deps/folly.exploded/include/folly/lang/Align.h" 3 4 | |
constexpr std::size_t hardware_constructive_interference_size = 64; | |
static_assert(hardware_constructive_interference_size >= max_align_v, "math?"); | |
constexpr std::size_t cacheline_align_v = | |
has_extended_alignment ? hardware_constructive_interference_size | |
: max_align_v; | |
struct alignas(cacheline_align_v) cacheline_align_t {}; | |
} // namespace folly | |
// # 35 "tlm/deps/folly.exploded/include/folly/Memory.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/memory/Malloc.h" 1 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/memory/Malloc.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/Malloc.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/Malloc.h" 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/portability/Malloc.h" 2 3 4 | |
// # 39 "tlm/deps/folly.exploded/include/folly/portability/Malloc.h" 3 4 | |
// # 40 "tlm/deps/folly.exploded/include/folly/portability/Malloc.h" 2 3 4 | |
// # 25 "tlm/deps/folly.exploded/include/folly/memory/Malloc.h" 2 3 4 | |
// # 43 "tlm/deps/folly.exploded/include/folly/memory/Malloc.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/memory/detail/MallocImpl.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/memory/detail/MallocImpl.h" 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/memory/detail/MallocImpl.h" 2 3 4 | |
extern "C" { | |
void* mallocx(size_t, int) __attribute__((__nothrow__, __weak__)); | |
void* rallocx(void*, size_t, int) __attribute__((__nothrow__, __weak__)); | |
size_t xallocx(void*, size_t, size_t, int) | |
__attribute__((__nothrow__, __weak__)); | |
size_t sallocx(const void*, int) __attribute__((__nothrow__, __weak__)); | |
void dallocx(void*, int) __attribute__((__nothrow__, __weak__)); | |
void sdallocx(void*, size_t, int) __attribute__((__nothrow__, __weak__)); | |
size_t nallocx(size_t, int) __attribute__((__nothrow__, __weak__)); | |
int mallctl(const char*, void*, size_t*, void*, size_t) | |
__attribute__((__nothrow__, __weak__)); | |
int mallctlnametomib(const char*, size_t*, size_t*) | |
__attribute__((__nothrow__, __weak__)); | |
int mallctlbymib(const size_t*, size_t, void*, size_t*, void*, size_t) | |
__attribute__((__nothrow__, __weak__)); | |
bool MallocExtension_Internal_GetNumericProperty(const char*, size_t, size_t*) | |
__attribute__((__weak__)); | |
// # 97 "tlm/deps/folly.exploded/include/folly/memory/detail/MallocImpl.h" 3 4 | |
} | |
// # 44 "tlm/deps/folly.exploded/include/folly/memory/Malloc.h" 2 3 4 | |
// # 46 "tlm/deps/folly.exploded/include/folly/memory/Malloc.h" 2 3 4 | |
// # 49 "tlm/deps/folly.exploded/include/folly/memory/Malloc.h" 2 3 4 | |
// # 50 "tlm/deps/folly.exploded/include/folly/memory/Malloc.h" 2 3 4 | |
namespace folly { | |
// # 79 "tlm/deps/folly.exploded/include/folly/memory/Malloc.h" 3 4 | |
__attribute__((__noinline__)) inline bool usingJEMalloc() noexcept { | |
// # 88 "tlm/deps/folly.exploded/include/folly/memory/Malloc.h" 3 4 | |
static const bool result = []() noexcept { | |
if (mallocx == nullptr || rallocx == nullptr || xallocx == nullptr || | |
sallocx == nullptr || dallocx == nullptr || sdallocx == nullptr || | |
nallocx == nullptr || mallctl == nullptr || | |
mallctlnametomib == nullptr || mallctlbymib == nullptr) { | |
return false; | |
} | |
volatile uint64_t* counter; | |
size_t counterLen = sizeof(uint64_t*); | |
if (mallctl("thread.allocatedp", | |
static_cast<void*>(&counter), | |
&counterLen, | |
nullptr, | |
0) != 0) { | |
return false; | |
} | |
if (counterLen != sizeof(uint64_t*)) { | |
return false; | |
} | |
uint64_t origAllocated = *counter; | |
static void* volatile ptr = malloc(1); | |
if (!ptr) { | |
return false; | |
} | |
free(ptr); | |
return (origAllocated != *counter); | |
}(); | |
return result; | |
} | |
inline bool getTCMallocNumericProperty(const char* name, size_t* out) noexcept { | |
return MallocExtension_Internal_GetNumericProperty(name, strlen(name), out); | |
} | |
// # 148 "tlm/deps/folly.exploded/include/folly/memory/Malloc.h" 3 4 | |
__attribute__((__noinline__)) inline bool usingTCMalloc() noexcept { | |
static const bool result = []() noexcept { | |
if (MallocExtension_Internal_GetNumericProperty == nullptr || | |
sdallocx == nullptr || nallocx == nullptr) { | |
return false; | |
} | |
static const char kAllocBytes[] = "generic.current_allocated_bytes"; | |
size_t before_bytes = 0; | |
getTCMallocNumericProperty(kAllocBytes, &before_bytes); | |
static void* volatile ptr = malloc(1); | |
if (!ptr) { | |
return false; | |
} | |
size_t after_bytes = 0; | |
getTCMallocNumericProperty(kAllocBytes, &after_bytes); | |
free(ptr); | |
return (before_bytes != after_bytes); | |
}(); | |
return result; | |
} | |
__attribute__((__noinline__)) inline bool canSdallocx() noexcept { | |
static bool rv = usingJEMalloc() || usingTCMalloc(); | |
return rv; | |
} | |
__attribute__((__noinline__)) inline bool canNallocx() noexcept { | |
static bool rv = usingJEMalloc() || usingTCMalloc(); | |
return rv; | |
} | |
inline size_t goodMallocSize(size_t minSize) noexcept { | |
if (minSize == 0) { | |
return 0; | |
} | |
if (!canNallocx()) { | |
return minSize; | |
} | |
auto rv = nallocx(minSize, 0); | |
return rv ? rv : minSize; | |
} | |
static const size_t jemallocMinInPlaceExpandable = 4096; | |
inline void* checkedMalloc(size_t size) { | |
void* p = malloc(size); | |
if (!p) { | |
throw_exception<std::bad_alloc>(); | |
} | |
return p; | |
} | |
inline void* checkedCalloc(size_t n, size_t size) { | |
void* p = calloc(n, size); | |
if (!p) { | |
throw_exception<std::bad_alloc>(); | |
} | |
return p; | |
} | |
inline void* checkedRealloc(void* ptr, size_t size) { | |
void* p = realloc(ptr, size); | |
if (!p) { | |
throw_exception<std::bad_alloc>(); | |
} | |
return p; | |
} | |
inline void sizedFree(void* ptr, size_t size) { | |
if (canSdallocx()) { | |
sdallocx(ptr, size, 0); | |
} else { | |
free(ptr); | |
} | |
} | |
// # 259 "tlm/deps/folly.exploded/include/folly/memory/Malloc.h" 3 4 | |
__attribute__((__returns_nonnull__, __malloc__)) | |
__attribute__((__noinline__)) inline void* | |
smartRealloc(void* p, | |
const size_t currentSize, | |
const size_t currentCapacity, | |
const size_t newCapacity) { | |
(static_cast<bool>(p) | |
? void(0) | |
: __assert_fail( | |
"p", | |
"tlm/deps/folly.exploded/include/folly/memory/Malloc.h", | |
264, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(currentSize <= currentCapacity && | |
currentCapacity < newCapacity) | |
? void(0) | |
: __assert_fail( | |
"currentSize <= currentCapacity && currentCapacity < " | |
"newCapacity", | |
"tlm/deps/folly.exploded/include/folly/memory/Malloc.h", | |
265, | |
__extension__ __PRETTY_FUNCTION__)); | |
auto const slack = currentCapacity - currentSize; | |
if (slack * 2 > currentSize) { | |
auto const result = checkedMalloc(newCapacity); | |
std::memcpy(result, p, currentSize); | |
free(p); | |
return result; | |
} | |
return checkedRealloc(p, newCapacity); | |
} | |
} // namespace folly | |
// # 37 "tlm/deps/folly.exploded/include/folly/Memory.h" 2 3 4 | |
namespace folly { | |
inline void* allocateBytes(size_t n) { | |
return ::operator new(n); | |
} | |
inline void deallocateBytes(void* p, size_t n) { | |
return ::operator delete(p, n); | |
} | |
// # 64 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
inline void* aligned_malloc(size_t size, size_t align) { | |
void* ptr = nullptr; | |
int rc = posix_memalign(&ptr, align, size); | |
return rc == 0 ? ((*__errno_location()) = 0, ptr) | |
: ((*__errno_location()) = rc, nullptr); | |
} | |
inline void aligned_free(void* aligned_ptr) { | |
free(aligned_ptr); | |
} | |
// # 97 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
namespace detail { | |
template <typename Alloc, size_t kAlign, bool kAllocate> | |
void rawOverAlignedImpl(Alloc const& alloc, size_t n, void*& raw) { | |
static_assert((kAlign & (kAlign - 1)) == 0, "Align must be a power of 2"); | |
using AllocTraits = std::allocator_traits<Alloc>; | |
using T = typename AllocTraits::value_type; | |
constexpr bool kCanBypass = std::is_same<Alloc, std::allocator<T>>::value; | |
constexpr size_t kBaseAlign = constexpr_min(kAlign, alignof(max_align_t)); | |
using BaseType = std::aligned_storage_t<kBaseAlign, kBaseAlign>; | |
using BaseAllocTraits = | |
typename AllocTraits::template rebind_traits<BaseType>; | |
using BaseAlloc = typename BaseAllocTraits::allocator_type; | |
static_assert( | |
sizeof(BaseType) == kBaseAlign && alignof(BaseType) == kBaseAlign, | |
""); | |
if (kCanBypass && kAlign == kBaseAlign) { | |
if (kAllocate) { | |
raw = ::operator new(n * sizeof(T)); | |
} else { | |
::operator delete(raw, n * sizeof(T)); | |
} | |
return; | |
} | |
if (kCanBypass && kAlign > kBaseAlign) { | |
if (kAllocate) { | |
raw = aligned_malloc(n * sizeof(T), kAlign); | |
} else { | |
aligned_free(raw); | |
} | |
return; | |
} | |
BaseAlloc a(alloc); | |
size_t quanta = (n * sizeof(T) + kBaseAlign - 1) / sizeof(BaseType); | |
if (kAlign <= kBaseAlign) { | |
if (kAllocate) { | |
raw = static_cast<void*>( | |
std::addressof(*BaseAllocTraits::allocate(a, quanta))); | |
} else { | |
BaseAllocTraits::deallocate( | |
a, | |
std::pointer_traits<typename BaseAllocTraits::pointer>:: | |
pointer_to(*static_cast<BaseType*>(raw)), | |
quanta); | |
} | |
return; | |
} | |
// # 173 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
if (kAllocate) { | |
char* base = reinterpret_cast<char*>( | |
std::addressof(*BaseAllocTraits::allocate( | |
a, quanta + kAlign / sizeof(BaseType)))); | |
size_t byteDelta = | |
kAlign - (reinterpret_cast<uintptr_t>(base) & (kAlign - 1)); | |
raw = static_cast<void*>(base + byteDelta); | |
static_cast<size_t*>(raw)[-1] = byteDelta; | |
} else { | |
size_t byteDelta = static_cast<size_t*>(raw)[-1]; | |
char* base = static_cast<char*>(raw) - byteDelta; | |
BaseAllocTraits::deallocate( | |
a, | |
std::pointer_traits<typename BaseAllocTraits::pointer>:: | |
pointer_to(*reinterpret_cast<BaseType*>(base)), | |
quanta + kAlign / sizeof(BaseType)); | |
} | |
} | |
} // namespace detail | |
template <typename Alloc, | |
size_t kAlign = | |
alignof(typename std::allocator_traits<Alloc>::value_type)> | |
typename std::allocator_traits<Alloc>::pointer allocateOverAligned( | |
Alloc const& alloc, size_t n) { | |
void* raw = nullptr; | |
detail::rawOverAlignedImpl<Alloc, kAlign, true>(alloc, n, raw); | |
return std::pointer_traits<typename std::allocator_traits<Alloc>::pointer>:: | |
pointer_to(*static_cast< | |
typename std::allocator_traits<Alloc>::value_type*>( | |
raw)); | |
} | |
template <typename Alloc, | |
size_t kAlign = | |
alignof(typename std::allocator_traits<Alloc>::value_type)> | |
void deallocateOverAligned(Alloc const& alloc, | |
typename std::allocator_traits<Alloc>::pointer ptr, | |
size_t n) { | |
void* raw = static_cast<void*>(std::addressof(*ptr)); | |
detail::rawOverAlignedImpl<Alloc, kAlign, false>(alloc, n, raw); | |
} | |
template <typename Alloc, | |
size_t kAlign = | |
alignof(typename std::allocator_traits<Alloc>::value_type)> | |
size_t allocationBytesForOverAligned(size_t n) { | |
static_assert((kAlign & (kAlign - 1)) == 0, "Align must be a power of 2"); | |
using AllocTraits = std::allocator_traits<Alloc>; | |
using T = typename AllocTraits::value_type; | |
constexpr size_t kBaseAlign = constexpr_min(kAlign, alignof(max_align_t)); | |
if (kAlign > kBaseAlign && std::is_same<Alloc, std::allocator<T>>::value) { | |
return n * sizeof(T); | |
} else { | |
size_t quanta = (n * sizeof(T) + kBaseAlign - 1) / kBaseAlign; | |
if (kAlign > kBaseAlign) { | |
quanta += kAlign / kBaseAlign; | |
} | |
return quanta * kBaseAlign; | |
} | |
} | |
// # 255 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
using std::make_unique; | |
// # 299 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
template <typename T, void (*f)(T*)> | |
struct static_function_deleter { | |
void operator()(T* t) const { | |
f(t); | |
} | |
}; | |
// # 324 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
template <typename T, typename D> | |
std::shared_ptr<T> to_shared_ptr(std::unique_ptr<T, D>&& ptr) { | |
return std::shared_ptr<T>(std::move(ptr)); | |
} | |
// # 347 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
template <typename T> | |
std::weak_ptr<T> to_weak_ptr(const std::shared_ptr<T>& ptr) { | |
return std::weak_ptr<T>(ptr); | |
} | |
// # 359 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
template <typename T> | |
std::unique_ptr<remove_cvref_t<T>> copy_to_unique_ptr(T&& t) { | |
return make_unique<remove_cvref_t<T>>(static_cast<T&&>(t)); | |
} | |
// # 371 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
template <typename T> | |
std::shared_ptr<remove_cvref_t<T>> copy_to_shared_ptr(T&& t) { | |
return std::make_shared<remove_cvref_t<T>>(static_cast<T&&>(t)); | |
} | |
template <typename T> | |
class SysAllocator { | |
private: | |
using Self = SysAllocator<T>; | |
public: | |
using value_type = T; | |
constexpr SysAllocator() = default; | |
constexpr SysAllocator(SysAllocator const&) = default; | |
template <typename U, std::enable_if_t<!std::is_same<U, T>::value, int> = 0> | |
constexpr SysAllocator(SysAllocator<U> const&) noexcept { | |
} | |
T* allocate(size_t count) { | |
auto const p = std::malloc(sizeof(T) * count); | |
if (!p) { | |
throw_exception<std::bad_alloc>(); | |
} | |
return static_cast<T*>(p); | |
} | |
void deallocate(T* p, size_t count) { | |
sizedFree(p, count * sizeof(T)); | |
} | |
friend bool operator==(Self const&, Self const&) noexcept { | |
return true; | |
} | |
friend bool operator!=(Self const&, Self const&) noexcept { | |
return false; | |
} | |
}; | |
class DefaultAlign { | |
private: | |
using Self = DefaultAlign; | |
std::size_t align_; | |
public: | |
explicit DefaultAlign(std::size_t align) noexcept : align_(align) { | |
(static_cast<bool>(!(align_ < sizeof(void*)) && | |
bool("bad align: too small")) | |
? void(0) | |
: __assert_fail( | |
"!(align_ < sizeof(void*)) && bool(\"bad align: too " | |
"small\")", | |
"tlm/deps/folly.exploded/include/folly/Memory.h", | |
423, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(!(align_ & (align_ - 1)) && | |
bool("bad align: not power-of-two")) | |
? void(0) | |
: __assert_fail( | |
"!(align_ & (align_ - 1)) && bool(\"bad align: not " | |
"power-of-two\")", | |
"tlm/deps/folly.exploded/include/folly/Memory.h", | |
424, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
std::size_t operator()() const noexcept { | |
return align_; | |
} | |
friend bool operator==(Self const& a, Self const& b) noexcept { | |
return a.align_ == b.align_; | |
} | |
friend bool operator!=(Self const& a, Self const& b) noexcept { | |
return a.align_ != b.align_; | |
} | |
}; | |
template <std::size_t Align> | |
class FixedAlign { | |
private: | |
static_assert(!(Align < sizeof(void*)), "bad align: too small"); | |
static_assert(!(Align & (Align - 1)), "bad align: not power-of-two"); | |
using Self = FixedAlign<Align>; | |
public: | |
constexpr std::size_t operator()() const noexcept { | |
return Align; | |
} | |
friend bool operator==(Self const&, Self const&) noexcept { | |
return true; | |
} | |
friend bool operator!=(Self const&, Self const&) noexcept { | |
return false; | |
} | |
}; | |
// # 474 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
template <typename T, typename Align = DefaultAlign> | |
class AlignedSysAllocator : private Align { | |
private: | |
using Self = AlignedSysAllocator<T, Align>; | |
template <typename, typename> | |
friend class AlignedSysAllocator; | |
constexpr Align const& align() const { | |
return *this; | |
} | |
public: | |
static_assert(std::is_nothrow_copy_constructible<Align>::value, ""); | |
static_assert(is_nothrow_invocable_r_v<std::size_t, Align>, ""); | |
using value_type = T; | |
using propagate_on_container_copy_assignment = std::true_type; | |
using propagate_on_container_move_assignment = std::true_type; | |
using propagate_on_container_swap = std::true_type; | |
using Align::Align; | |
template < | |
typename S = Align, | |
std::enable_if_t<std::is_default_constructible<S>::value, int> = 0> | |
constexpr AlignedSysAllocator() noexcept(noexcept(Align())) : Align() { | |
} | |
constexpr AlignedSysAllocator(AlignedSysAllocator const&) = default; | |
template <typename U, std::enable_if_t<!std::is_same<U, T>::value, int> = 0> | |
constexpr AlignedSysAllocator( | |
AlignedSysAllocator<U, Align> const& other) noexcept | |
: Align(other.align()) { | |
} | |
T* allocate(size_t count) { | |
auto const a = align()() < alignof(T) ? alignof(T) : align()(); | |
auto const p = aligned_malloc(sizeof(T) * count, a); | |
if (!p) { | |
if ((__builtin_expect(((*__errno_location()) != 12), 0))) { | |
std::terminate(); | |
} | |
throw_exception<std::bad_alloc>(); | |
} | |
return static_cast<T*>(p); | |
} | |
void deallocate(T* p, size_t) { | |
aligned_free(p); | |
} | |
friend bool operator==(Self const& a, Self const& b) noexcept { | |
return a.align() == b.align(); | |
} | |
friend bool operator!=(Self const& a, Self const& b) noexcept { | |
return a.align() != b.align(); | |
} | |
}; | |
// # 545 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
template <typename T, class Inner, bool FallbackToStdAlloc = false> | |
class CxxAllocatorAdaptor : private std::allocator<T> { | |
private: | |
using Self = CxxAllocatorAdaptor<T, Inner, FallbackToStdAlloc>; | |
template <typename U, typename UInner, bool UFallback> | |
friend class CxxAllocatorAdaptor; | |
Inner* inner_ = nullptr; | |
public: | |
using value_type = T; | |
using propagate_on_container_copy_assignment = std::true_type; | |
using propagate_on_container_move_assignment = std::true_type; | |
using propagate_on_container_swap = std::true_type; | |
template <bool X = FallbackToStdAlloc, std::enable_if_t<X, int> = 0> | |
constexpr explicit CxxAllocatorAdaptor() { | |
} | |
constexpr explicit CxxAllocatorAdaptor(Inner& ref) : inner_(&ref) { | |
} | |
constexpr CxxAllocatorAdaptor(CxxAllocatorAdaptor const&) = default; | |
template <typename U, std::enable_if_t<!std::is_same<U, T>::value, int> = 0> | |
constexpr CxxAllocatorAdaptor( | |
CxxAllocatorAdaptor<U, Inner, FallbackToStdAlloc> const& other) | |
: inner_(other.inner_) { | |
} | |
T* allocate(std::size_t n) { | |
if (FallbackToStdAlloc && inner_ == nullptr) { | |
return std::allocator<T>::allocate(n); | |
} | |
return static_cast<T*>(inner_->allocate(sizeof(T) * n)); | |
} | |
void deallocate(T* p, std::size_t n) { | |
if (inner_ != nullptr) { | |
inner_->deallocate(p, sizeof(T) * n); | |
} else { | |
(static_cast<bool>(FallbackToStdAlloc) | |
? void(0) | |
: __assert_fail( | |
"FallbackToStdAlloc", | |
"tlm/deps/folly.exploded/include/folly/Memory.h", | |
585, | |
__extension__ __PRETTY_FUNCTION__)); | |
std::allocator<T>::deallocate(p, n); | |
} | |
} | |
friend bool operator==(Self const& a, Self const& b) noexcept { | |
return a.inner_ == b.inner_; | |
} | |
friend bool operator!=(Self const& a, Self const& b) noexcept { | |
return a.inner_ != b.inner_; | |
} | |
template <typename U> | |
struct rebind { | |
using other = CxxAllocatorAdaptor<U, Inner, FallbackToStdAlloc>; | |
}; | |
}; | |
// # 611 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
template <typename Alloc> | |
class allocator_delete : private std::remove_reference<Alloc>::type { | |
private: | |
using allocator_type = typename std::remove_reference<Alloc>::type; | |
using allocator_traits = std::allocator_traits<allocator_type>; | |
using value_type = typename allocator_traits::value_type; | |
using pointer = typename allocator_traits::pointer; | |
public: | |
allocator_delete() = default; | |
allocator_delete(allocator_delete const&) = default; | |
allocator_delete(allocator_delete&&) = default; | |
allocator_delete& operator=(allocator_delete const&) = default; | |
allocator_delete& operator=(allocator_delete&&) = default; | |
explicit allocator_delete(const allocator_type& alloc) | |
: allocator_type(alloc) { | |
} | |
explicit allocator_delete(allocator_type&& alloc) | |
: allocator_type(std::move(alloc)) { | |
} | |
template <typename U> | |
allocator_delete(const allocator_delete<U>& other) | |
: allocator_type(other.get_allocator()) { | |
} | |
allocator_type const& get_allocator() const { | |
return *this; | |
} | |
void operator()(pointer p) const { | |
auto alloc = get_allocator(); | |
allocator_traits::destroy(alloc, p); | |
allocator_traits::deallocate(alloc, p, 1); | |
} | |
}; | |
template <typename T, typename Alloc, typename... Args> | |
std::unique_ptr<T, allocator_delete<Alloc>> allocate_unique(Alloc const& alloc, | |
Args&&... args) { | |
using traits = std::allocator_traits<Alloc>; | |
struct DeferCondDeallocate { | |
bool& cond; | |
Alloc& copy; | |
T* p; | |
~DeferCondDeallocate() { | |
if ((__builtin_expect((!cond), 0))) { | |
traits::deallocate(copy, p, 1); | |
} | |
} | |
}; | |
auto copy = alloc; | |
auto const p = traits::allocate(copy, 1); | |
{ | |
bool constructed = false; | |
DeferCondDeallocate handler{constructed, copy, p}; | |
traits::construct(copy, p, static_cast<Args&&>(args)...); | |
constructed = true; | |
} | |
return {p, allocator_delete<Alloc>(std::move(copy))}; | |
} | |
struct SysBufferDeleter { | |
void operator()(void* ptr) { | |
std::free(ptr); | |
} | |
}; | |
using SysBufferUniquePtr = std::unique_ptr<void, SysBufferDeleter>; | |
inline SysBufferUniquePtr allocate_sys_buffer(std::size_t size) { | |
auto p = std::malloc(size); | |
if (!p) { | |
throw_exception<std::bad_alloc>(); | |
} | |
return {p, {}}; | |
} | |
// # 701 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
template <typename Alloc> | |
struct AllocatorHasTrivialDeallocate : std::false_type {}; | |
template <typename T, class Alloc> | |
struct AllocatorHasTrivialDeallocate<CxxAllocatorAdaptor<T, Alloc>> | |
: AllocatorHasTrivialDeallocate<Alloc> {}; | |
namespace detail { | |
struct AllocatorConstruct_ { | |
template <typename O, typename... Args> | |
[[maybe_unused]] inline __attribute__((__always_inline__)) constexpr auto | |
operator()(O&& o, Args&&... args) const noexcept(noexcept( | |
static_cast<O&&>(o).construct(static_cast<Args&&>(args)...))) | |
-> decltype(static_cast<O&&>(o).construct( | |
static_cast<Args&&>(args)...)) { | |
return static_cast<O&&>(o).construct(static_cast<Args&&>(args)...); | |
} | |
}; | |
struct AllocatorDestroy_ { | |
template <typename O, typename... Args> | |
[[maybe_unused]] inline __attribute__((__always_inline__)) constexpr auto | |
operator()(O&& o, Args&&... args) const noexcept( | |
noexcept(static_cast<O&&>(o).destroy(static_cast<Args&&>(args)...))) | |
-> decltype( | |
static_cast<O&&>(o).destroy(static_cast<Args&&>(args)...)) { | |
return static_cast<O&&>(o).destroy(static_cast<Args&&>(args)...); | |
} | |
}; | |
template <typename Void, typename Alloc, typename... Args> | |
struct AllocatorCustomizesConstruct_ | |
: folly::is_invocable<AllocatorConstruct_, Alloc, Args...> {}; | |
template <typename Alloc, typename... Args> | |
struct AllocatorCustomizesConstruct_< | |
void_t<typename Alloc::folly_has_default_object_construct>, | |
Alloc, | |
Args...> | |
: Negation<typename Alloc::folly_has_default_object_construct> {}; | |
template <typename Void, typename Alloc, typename... Args> | |
struct AllocatorCustomizesDestroy_ | |
: folly::is_invocable<AllocatorDestroy_, Alloc, Args...> {}; | |
template <typename Alloc, typename... Args> | |
struct AllocatorCustomizesDestroy_< | |
void_t<typename Alloc::folly_has_default_object_destroy>, | |
Alloc, | |
Args...> : Negation<typename Alloc::folly_has_default_object_destroy> { | |
}; | |
} // namespace detail | |
// # 751 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
template <typename Alloc, typename T, typename... Args> | |
struct AllocatorHasDefaultObjectConstruct | |
: Negation< | |
detail::AllocatorCustomizesConstruct_<void, Alloc, T*, Args...>> { | |
}; | |
template <typename Value, typename T, typename... Args> | |
struct AllocatorHasDefaultObjectConstruct<std::allocator<Value>, T, Args...> | |
: std::true_type {}; | |
// # 775 "tlm/deps/folly.exploded/include/folly/Memory.h" 3 4 | |
template <typename Alloc, typename T> | |
struct AllocatorHasDefaultObjectDestroy | |
: Negation<detail::AllocatorCustomizesDestroy_<void, Alloc, T*>> {}; | |
template <typename Value, typename T> | |
struct AllocatorHasDefaultObjectDestroy<std::allocator<Value>, T> | |
: std::true_type {}; | |
} // namespace folly | |
// # 34 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" 2 3 | |
// 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/hash/Hash.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/hash/Hash.h" 3 4 | |
// # 21 "tlm/deps/folly.exploded/include/folly/hash/Hash.h" 2 3 4 | |
// # 31 "tlm/deps/folly.exploded/include/folly/hash/Hash.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/functional/ApplyTuple.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/functional/ApplyTuple.h" 3 4 | |
// # 27 "tlm/deps/folly.exploded/include/folly/functional/ApplyTuple.h" 3 4 | |
namespace folly { | |
template <typename Tuple> | |
using index_sequence_for_tuple = | |
std::make_index_sequence<std::tuple_size<Tuple>::value>; | |
namespace detail { | |
namespace apply_tuple { | |
namespace adl { | |
using std::get; | |
struct ApplyInvoke { | |
template <typename T> | |
using seq = index_sequence_for_tuple<std::remove_reference_t<T>>; | |
template <typename F, typename T, std::size_t... I> | |
static constexpr auto | |
invoke_(F&& f, T&& t, std::index_sequence<I...>) noexcept( | |
is_nothrow_invocable<F&&, | |
decltype(get<I>(std::declval<T>()))...>::value) | |
-> invoke_result_t<F&&, decltype(get<I>(std::declval<T>()))...> { | |
return invoke(static_cast<F&&>(f), get<I>(static_cast<T&&>(t))...); | |
} | |
}; | |
template <typename Tuple, | |
std::size_t... Indices, | |
typename ReturnTuple = | |
std::tuple<decltype(get<Indices>(std::declval<Tuple>()))...>> | |
auto forward_tuple(Tuple&& tuple, std::index_sequence<Indices...>) | |
-> ReturnTuple { | |
return ReturnTuple{get<Indices>(std::forward<Tuple>(tuple))...}; | |
} | |
} // namespace adl | |
} // namespace apply_tuple | |
} // namespace detail | |
struct ApplyInvoke : private detail::apply_tuple::adl::ApplyInvoke { | |
public: | |
template <typename F, typename T> | |
constexpr auto operator()(F&& f, T&& t) const noexcept(noexcept( | |
invoke_(static_cast<F&&>(f), static_cast<T&&>(t), seq<T>{}))) | |
-> decltype(invoke_(static_cast<F&&>(f), | |
static_cast<T&&>(t), | |
seq<T>{})) { | |
return invoke_(static_cast<F&&>(f), static_cast<T&&>(t), seq<T>{}); | |
} | |
}; | |
// # 89 "tlm/deps/folly.exploded/include/folly/functional/ApplyTuple.h" 3 4 | |
using std::apply; | |
// # 117 "tlm/deps/folly.exploded/include/folly/functional/ApplyTuple.h" 3 4 | |
template <typename Tuple> | |
auto forward_tuple(Tuple&& tuple) noexcept | |
-> decltype(detail::apply_tuple::adl::forward_tuple( | |
std::declval<Tuple>(), | |
std::declval<index_sequence_for_tuple< | |
std::remove_reference_t<Tuple>>>())) { | |
return detail::apply_tuple::adl::forward_tuple( | |
std::forward<Tuple>(tuple), | |
index_sequence_for_tuple<std::remove_reference_t<Tuple>>{}); | |
} | |
template <typename F, typename Tuple> | |
struct apply_result : invoke_result<ApplyInvoke, F, Tuple> {}; | |
template <typename F, typename Tuple> | |
using apply_result_t = invoke_result_t<ApplyInvoke, F, Tuple>; | |
template <typename F, typename Tuple> | |
struct is_applicable : is_invocable<ApplyInvoke, F, Tuple> {}; | |
template <typename F, typename Tuple> | |
inline constexpr bool is_applicable_v = is_applicable<F, Tuple>::value; | |
template <typename R, typename F, typename Tuple> | |
struct is_applicable_r : is_invocable_r<R, ApplyInvoke, F, Tuple> {}; | |
template <typename R, typename F, typename Tuple> | |
inline constexpr bool is_applicable_r_v = is_applicable_r<R, F, Tuple>::value; | |
template <typename F, typename Tuple> | |
struct is_nothrow_applicable : is_nothrow_invocable<ApplyInvoke, F, Tuple> {}; | |
template <typename F, typename Tuple> | |
inline constexpr bool is_nothrow_applicable_v = | |
is_nothrow_applicable<F, Tuple>::value; | |
template <typename R, typename F, typename Tuple> | |
struct is_nothrow_applicable_r | |
: is_nothrow_invocable_r<R, ApplyInvoke, F, Tuple> {}; | |
template <typename R, typename F, typename Tuple> | |
inline constexpr bool is_nothrow_applicable_r_v = | |
is_nothrow_applicable_r<R, F, Tuple>::value; | |
namespace detail { | |
namespace apply_tuple { | |
template <class F> | |
class Uncurry { | |
public: | |
explicit Uncurry(F&& func) : func_(std::move(func)) { | |
} | |
explicit Uncurry(const F& func) : func_(func) { | |
} | |
template <class Tuple> | |
auto operator()(Tuple&& tuple) const | |
-> decltype(apply(std::declval<F>(), std::forward<Tuple>(tuple))) { | |
return apply(func_, std::forward<Tuple>(tuple)); | |
} | |
private: | |
F func_; | |
}; | |
} // namespace apply_tuple | |
} // namespace detail | |
// # 197 "tlm/deps/folly.exploded/include/folly/functional/ApplyTuple.h" 3 4 | |
template <class F> | |
auto uncurry(F&& f) | |
-> detail::apply_tuple::Uncurry<typename std::decay<F>::type> { | |
return detail::apply_tuple::Uncurry<typename std::decay<F>::type>( | |
std::forward<F>(f)); | |
} | |
using std::make_from_tuple; | |
// # 231 "tlm/deps/folly.exploded/include/folly/functional/ApplyTuple.h" 3 4 | |
} // namespace folly | |
// # 32 "tlm/deps/folly.exploded/include/folly/hash/Hash.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV1.h" 1 3 4 | |
// # 45 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV1.h" 3 4 | |
namespace folly { | |
namespace hash { | |
class SpookyHashV1 { | |
public: | |
static void Hash128(const void* message, | |
size_t length, | |
uint64_t* hash1, | |
uint64_t* hash2); | |
static uint64_t Hash64(const void* message, size_t length, uint64_t seed) { | |
uint64_t hash1 = seed; | |
Hash128(message, length, &hash1, &seed); | |
return hash1; | |
} | |
static uint32_t Hash32(const void* message, size_t length, uint32_t seed) { | |
uint64_t hash1 = seed, hash2 = seed; | |
Hash128(message, length, &hash1, &hash2); | |
return (uint32_t)hash1; | |
} | |
void Init(uint64_t seed1, uint64_t seed2); | |
void Update(const void* message, size_t length); | |
// # 116 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV1.h" 3 4 | |
void Final(uint64_t* hash1, uint64_t* hash2); | |
static inline uint64_t Rot64(uint64_t x, int k) { | |
return (x << k) | (x >> (64 - k)); | |
} | |
// # 141 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV1.h" 3 4 | |
static inline void Mix(const uint64_t* data, | |
uint64_t& s0, | |
uint64_t& s1, | |
uint64_t& s2, | |
uint64_t& s3, | |
uint64_t& s4, | |
uint64_t& s5, | |
uint64_t& s6, | |
uint64_t& s7, | |
uint64_t& s8, | |
uint64_t& s9, | |
uint64_t& s10, | |
uint64_t& s11) { | |
s0 += data[0]; | |
s2 ^= s10; | |
s11 ^= s0; | |
s0 = Rot64(s0, 11); | |
s11 += s1; | |
s1 += data[1]; | |
s3 ^= s11; | |
s0 ^= s1; | |
s1 = Rot64(s1, 32); | |
s0 += s2; | |
s2 += data[2]; | |
s4 ^= s0; | |
s1 ^= s2; | |
s2 = Rot64(s2, 43); | |
s1 += s3; | |
s3 += data[3]; | |
s5 ^= s1; | |
s2 ^= s3; | |
s3 = Rot64(s3, 31); | |
s2 += s4; | |
s4 += data[4]; | |
s6 ^= s2; | |
s3 ^= s4; | |
s4 = Rot64(s4, 17); | |
s3 += s5; | |
s5 += data[5]; | |
s7 ^= s3; | |
s4 ^= s5; | |
s5 = Rot64(s5, 28); | |
s4 += s6; | |
s6 += data[6]; | |
s8 ^= s4; | |
s5 ^= s6; | |
s6 = Rot64(s6, 39); | |
s5 += s7; | |
s7 += data[7]; | |
s9 ^= s5; | |
s6 ^= s7; | |
s7 = Rot64(s7, 57); | |
s6 += s8; | |
s8 += data[8]; | |
s10 ^= s6; | |
s7 ^= s8; | |
s8 = Rot64(s8, 55); | |
s7 += s9; | |
s9 += data[9]; | |
s11 ^= s7; | |
s8 ^= s9; | |
s9 = Rot64(s9, 54); | |
s8 += s10; | |
s10 += data[10]; | |
s0 ^= s8; | |
s9 ^= s10; | |
s10 = Rot64(s10, 22); | |
s9 += s11; | |
s11 += data[11]; | |
s1 ^= s9; | |
s10 ^= s11; | |
s11 = Rot64(s11, 46); | |
s10 += s0; | |
} | |
// # 177 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV1.h" 3 4 | |
static inline void EndPartial(uint64_t& h0, | |
uint64_t& h1, | |
uint64_t& h2, | |
uint64_t& h3, | |
uint64_t& h4, | |
uint64_t& h5, | |
uint64_t& h6, | |
uint64_t& h7, | |
uint64_t& h8, | |
uint64_t& h9, | |
uint64_t& h10, | |
uint64_t& h11) { | |
h11 += h1; | |
h2 ^= h11; | |
h1 = Rot64(h1, 44); | |
h0 += h2; | |
h3 ^= h0; | |
h2 = Rot64(h2, 15); | |
h1 += h3; | |
h4 ^= h1; | |
h3 = Rot64(h3, 34); | |
h2 += h4; | |
h5 ^= h2; | |
h4 = Rot64(h4, 21); | |
h3 += h5; | |
h6 ^= h3; | |
h5 = Rot64(h5, 38); | |
h4 += h6; | |
h7 ^= h4; | |
h6 = Rot64(h6, 33); | |
h5 += h7; | |
h8 ^= h5; | |
h7 = Rot64(h7, 10); | |
h6 += h8; | |
h9 ^= h6; | |
h8 = Rot64(h8, 13); | |
h7 += h9; | |
h10 ^= h7; | |
h9 = Rot64(h9, 38); | |
h8 += h10; | |
h11 ^= h8; | |
h10 = Rot64(h10, 53); | |
h9 += h11; | |
h0 ^= h9; | |
h11 = Rot64(h11, 42); | |
h10 += h0; | |
h1 ^= h10; | |
h0 = Rot64(h0, 54); | |
} | |
static inline void End(uint64_t& h0, | |
uint64_t& h1, | |
uint64_t& h2, | |
uint64_t& h3, | |
uint64_t& h4, | |
uint64_t& h5, | |
uint64_t& h6, | |
uint64_t& h7, | |
uint64_t& h8, | |
uint64_t& h9, | |
uint64_t& h10, | |
uint64_t& h11) { | |
EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); | |
EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); | |
EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); | |
} | |
// # 221 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV1.h" 3 4 | |
static inline void ShortMix(uint64_t& h0, | |
uint64_t& h1, | |
uint64_t& h2, | |
uint64_t& h3) { | |
h2 = Rot64(h2, 50); | |
h2 += h3; | |
h0 ^= h2; | |
h3 = Rot64(h3, 52); | |
h3 += h0; | |
h1 ^= h3; | |
h0 = Rot64(h0, 30); | |
h0 += h1; | |
h2 ^= h0; | |
h1 = Rot64(h1, 41); | |
h1 += h2; | |
h3 ^= h1; | |
h2 = Rot64(h2, 54); | |
h2 += h3; | |
h0 ^= h2; | |
h3 = Rot64(h3, 48); | |
h3 += h0; | |
h1 ^= h3; | |
h0 = Rot64(h0, 38); | |
h0 += h1; | |
h2 ^= h0; | |
h1 = Rot64(h1, 37); | |
h1 += h2; | |
h3 ^= h1; | |
h2 = Rot64(h2, 62); | |
h2 += h3; | |
h0 ^= h2; | |
h3 = Rot64(h3, 34); | |
h3 += h0; | |
h1 ^= h3; | |
h0 = Rot64(h0, 5); | |
h0 += h1; | |
h2 ^= h0; | |
h1 = Rot64(h1, 36); | |
h1 += h2; | |
h3 ^= h1; | |
} | |
// # 250 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV1.h" 3 4 | |
static inline void ShortEnd(uint64_t& h0, | |
uint64_t& h1, | |
uint64_t& h2, | |
uint64_t& h3) { | |
h3 ^= h2; | |
h2 = Rot64(h2, 15); | |
h3 += h2; | |
h0 ^= h3; | |
h3 = Rot64(h3, 52); | |
h0 += h3; | |
h1 ^= h0; | |
h0 = Rot64(h0, 26); | |
h1 += h0; | |
h2 ^= h1; | |
h1 = Rot64(h1, 51); | |
h2 += h1; | |
h3 ^= h2; | |
h2 = Rot64(h2, 28); | |
h3 += h2; | |
h0 ^= h3; | |
h3 = Rot64(h3, 9); | |
h0 += h3; | |
h1 ^= h0; | |
h0 = Rot64(h0, 47); | |
h1 += h0; | |
h2 ^= h1; | |
h1 = Rot64(h1, 54); | |
h2 += h1; | |
h3 ^= h2; | |
h2 = Rot64(h2, 32); | |
h3 += h2; | |
h0 ^= h3; | |
h3 = Rot64(h3, 25); | |
h0 += h3; | |
h1 ^= h0; | |
h0 = Rot64(h0, 63); | |
h1 += h0; | |
} | |
private: | |
static void Short(const void* message, | |
size_t length, | |
uint64_t* hash1, | |
uint64_t* hash2); | |
static const size_t sc_numVars = 12; | |
static const size_t sc_blockSize = sc_numVars * 8; | |
static const size_t sc_bufSize = 2 * sc_blockSize; | |
// # 296 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV1.h" 3 4 | |
static const uint64_t sc_const = 0xdeadbeefdeadbeefULL; | |
uint64_t m_data[2 * sc_numVars]; | |
uint64_t m_state[sc_numVars]; | |
size_t m_length; | |
uint8_t m_remainder; | |
}; | |
} // namespace hash | |
} // namespace folly | |
// # 33 "tlm/deps/folly.exploded/include/folly/hash/Hash.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV2.h" 1 3 4 | |
// # 46 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV2.h" 3 4 | |
namespace folly { | |
namespace hash { | |
class SpookyHashV2 { | |
public: | |
static void Hash128(const void* message, | |
size_t length, | |
uint64_t* hash1, | |
uint64_t* hash2); | |
static uint64_t Hash64(const void* message, size_t length, uint64_t seed) { | |
uint64_t hash1 = seed; | |
Hash128(message, length, &hash1, &seed); | |
return hash1; | |
} | |
static uint32_t Hash32(const void* message, size_t length, uint32_t seed) { | |
uint64_t hash1 = seed, hash2 = seed; | |
Hash128(message, length, &hash1, &hash2); | |
return (uint32_t)hash1; | |
} | |
void Init(uint64_t seed1, uint64_t seed2); | |
void Update(const void* message, size_t length); | |
// # 117 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV2.h" 3 4 | |
void Final(uint64_t* hash1, uint64_t* hash2) const; | |
static inline uint64_t Rot64(uint64_t x, int k) { | |
return (x << k) | (x >> (64 - k)); | |
} | |
// # 142 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV2.h" 3 4 | |
static inline void Mix(const uint64_t* data, | |
uint64_t& s0, | |
uint64_t& s1, | |
uint64_t& s2, | |
uint64_t& s3, | |
uint64_t& s4, | |
uint64_t& s5, | |
uint64_t& s6, | |
uint64_t& s7, | |
uint64_t& s8, | |
uint64_t& s9, | |
uint64_t& s10, | |
uint64_t& s11) { | |
s0 += data[0]; | |
s2 ^= s10; | |
s11 ^= s0; | |
s0 = Rot64(s0, 11); | |
s11 += s1; | |
s1 += data[1]; | |
s3 ^= s11; | |
s0 ^= s1; | |
s1 = Rot64(s1, 32); | |
s0 += s2; | |
s2 += data[2]; | |
s4 ^= s0; | |
s1 ^= s2; | |
s2 = Rot64(s2, 43); | |
s1 += s3; | |
s3 += data[3]; | |
s5 ^= s1; | |
s2 ^= s3; | |
s3 = Rot64(s3, 31); | |
s2 += s4; | |
s4 += data[4]; | |
s6 ^= s2; | |
s3 ^= s4; | |
s4 = Rot64(s4, 17); | |
s3 += s5; | |
s5 += data[5]; | |
s7 ^= s3; | |
s4 ^= s5; | |
s5 = Rot64(s5, 28); | |
s4 += s6; | |
s6 += data[6]; | |
s8 ^= s4; | |
s5 ^= s6; | |
s6 = Rot64(s6, 39); | |
s5 += s7; | |
s7 += data[7]; | |
s9 ^= s5; | |
s6 ^= s7; | |
s7 = Rot64(s7, 57); | |
s6 += s8; | |
s8 += data[8]; | |
s10 ^= s6; | |
s7 ^= s8; | |
s8 = Rot64(s8, 55); | |
s7 += s9; | |
s9 += data[9]; | |
s11 ^= s7; | |
s8 ^= s9; | |
s9 = Rot64(s9, 54); | |
s8 += s10; | |
s10 += data[10]; | |
s0 ^= s8; | |
s9 ^= s10; | |
s10 = Rot64(s10, 22); | |
s9 += s11; | |
s11 += data[11]; | |
s1 ^= s9; | |
s10 ^= s11; | |
s11 = Rot64(s11, 46); | |
s10 += s0; | |
} | |
// # 178 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV2.h" 3 4 | |
static inline void EndPartial(uint64_t& h0, | |
uint64_t& h1, | |
uint64_t& h2, | |
uint64_t& h3, | |
uint64_t& h4, | |
uint64_t& h5, | |
uint64_t& h6, | |
uint64_t& h7, | |
uint64_t& h8, | |
uint64_t& h9, | |
uint64_t& h10, | |
uint64_t& h11) { | |
h11 += h1; | |
h2 ^= h11; | |
h1 = Rot64(h1, 44); | |
h0 += h2; | |
h3 ^= h0; | |
h2 = Rot64(h2, 15); | |
h1 += h3; | |
h4 ^= h1; | |
h3 = Rot64(h3, 34); | |
h2 += h4; | |
h5 ^= h2; | |
h4 = Rot64(h4, 21); | |
h3 += h5; | |
h6 ^= h3; | |
h5 = Rot64(h5, 38); | |
h4 += h6; | |
h7 ^= h4; | |
h6 = Rot64(h6, 33); | |
h5 += h7; | |
h8 ^= h5; | |
h7 = Rot64(h7, 10); | |
h6 += h8; | |
h9 ^= h6; | |
h8 = Rot64(h8, 13); | |
h7 += h9; | |
h10 ^= h7; | |
h9 = Rot64(h9, 38); | |
h8 += h10; | |
h11 ^= h8; | |
h10 = Rot64(h10, 53); | |
h9 += h11; | |
h0 ^= h9; | |
h11 = Rot64(h11, 42); | |
h10 += h0; | |
h1 ^= h10; | |
h0 = Rot64(h0, 54); | |
} | |
static inline void End(const uint64_t* data, | |
uint64_t& h0, | |
uint64_t& h1, | |
uint64_t& h2, | |
uint64_t& h3, | |
uint64_t& h4, | |
uint64_t& h5, | |
uint64_t& h6, | |
uint64_t& h7, | |
uint64_t& h8, | |
uint64_t& h9, | |
uint64_t& h10, | |
uint64_t& h11) { | |
h0 += data[0]; | |
h1 += data[1]; | |
h2 += data[2]; | |
h3 += data[3]; | |
h4 += data[4]; | |
h5 += data[5]; | |
h6 += data[6]; | |
h7 += data[7]; | |
h8 += data[8]; | |
h9 += data[9]; | |
h10 += data[10]; | |
h11 += data[11]; | |
EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); | |
EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); | |
EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); | |
} | |
// # 226 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV2.h" 3 4 | |
static inline void ShortMix(uint64_t& h0, | |
uint64_t& h1, | |
uint64_t& h2, | |
uint64_t& h3) { | |
h2 = Rot64(h2, 50); | |
h2 += h3; | |
h0 ^= h2; | |
h3 = Rot64(h3, 52); | |
h3 += h0; | |
h1 ^= h3; | |
h0 = Rot64(h0, 30); | |
h0 += h1; | |
h2 ^= h0; | |
h1 = Rot64(h1, 41); | |
h1 += h2; | |
h3 ^= h1; | |
h2 = Rot64(h2, 54); | |
h2 += h3; | |
h0 ^= h2; | |
h3 = Rot64(h3, 48); | |
h3 += h0; | |
h1 ^= h3; | |
h0 = Rot64(h0, 38); | |
h0 += h1; | |
h2 ^= h0; | |
h1 = Rot64(h1, 37); | |
h1 += h2; | |
h3 ^= h1; | |
h2 = Rot64(h2, 62); | |
h2 += h3; | |
h0 ^= h2; | |
h3 = Rot64(h3, 34); | |
h3 += h0; | |
h1 ^= h3; | |
h0 = Rot64(h0, 5); | |
h0 += h1; | |
h2 ^= h0; | |
h1 = Rot64(h1, 36); | |
h1 += h2; | |
h3 ^= h1; | |
} | |
// # 255 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV2.h" 3 4 | |
static inline void ShortEnd(uint64_t& h0, | |
uint64_t& h1, | |
uint64_t& h2, | |
uint64_t& h3) { | |
h3 ^= h2; | |
h2 = Rot64(h2, 15); | |
h3 += h2; | |
h0 ^= h3; | |
h3 = Rot64(h3, 52); | |
h0 += h3; | |
h1 ^= h0; | |
h0 = Rot64(h0, 26); | |
h1 += h0; | |
h2 ^= h1; | |
h1 = Rot64(h1, 51); | |
h2 += h1; | |
h3 ^= h2; | |
h2 = Rot64(h2, 28); | |
h3 += h2; | |
h0 ^= h3; | |
h3 = Rot64(h3, 9); | |
h0 += h3; | |
h1 ^= h0; | |
h0 = Rot64(h0, 47); | |
h1 += h0; | |
h2 ^= h1; | |
h1 = Rot64(h1, 54); | |
h2 += h1; | |
h3 ^= h2; | |
h2 = Rot64(h2, 32); | |
h3 += h2; | |
h0 ^= h3; | |
h3 = Rot64(h3, 25); | |
h0 += h3; | |
h1 ^= h0; | |
h0 = Rot64(h0, 63); | |
h1 += h0; | |
} | |
private: | |
static void Short(const void* message, | |
size_t length, | |
uint64_t* hash1, | |
uint64_t* hash2); | |
static constexpr size_t sc_numVars = 12; | |
static constexpr size_t sc_blockSize = sc_numVars * 8; | |
static constexpr size_t sc_bufSize = 2 * sc_blockSize; | |
// # 301 "tlm/deps/folly.exploded/include/folly/hash/SpookyHashV2.h" 3 4 | |
static constexpr uint64_t sc_const = 0xdeadbeefdeadbeefULL; | |
uint64_t m_data[2 * sc_numVars]; | |
uint64_t m_state[sc_numVars]; | |
size_t m_length; | |
uint8_t m_remainder; | |
}; | |
} // namespace hash | |
} // namespace folly | |
// # 34 "tlm/deps/folly.exploded/include/folly/hash/Hash.h" 2 3 4 | |
namespace folly { | |
namespace hash { | |
inline uint64_t hash_128_to_64(const uint64_t upper, | |
const uint64_t lower) noexcept { | |
const uint64_t kMul = 0x9ddfea08eb382d69ULL; | |
uint64_t a = (lower ^ upper) * kMul; | |
a ^= (a >> 47); | |
uint64_t b = (upper ^ a) * kMul; | |
b ^= (b >> 47); | |
b *= kMul; | |
return b; | |
} | |
inline uint64_t twang_mix64(uint64_t key) noexcept { | |
key = (~key) + (key << 21); | |
key = key ^ (key >> 24); | |
key = key + (key << 3) + (key << 8); | |
key = key ^ (key >> 14); | |
key = key + (key << 2) + (key << 4); | |
key = key ^ (key >> 28); | |
key = key + (key << 31); | |
return key; | |
} | |
inline uint64_t twang_unmix64(uint64_t key) noexcept { | |
key *= 4611686016279904257U; | |
key ^= (key >> 28) ^ (key >> 56); | |
key *= 14933078535860113213U; | |
key ^= (key >> 14) ^ (key >> 28) ^ (key >> 42) ^ (key >> 56); | |
key *= 15244667743933553977U; | |
key ^= (key >> 24) ^ (key >> 48); | |
key = (key + 1) * 9223367638806167551U; | |
return key; | |
} | |
inline uint32_t twang_32from64(uint64_t key) noexcept { | |
key = (~key) + (key << 18); | |
key = key ^ (key >> 31); | |
key = key * 21; | |
key = key ^ (key >> 11); | |
key = key + (key << 6); | |
key = key ^ (key >> 22); | |
return (uint32_t)key; | |
} | |
inline uint32_t jenkins_rev_mix32(uint32_t key) noexcept { | |
key += (key << 12); | |
key ^= (key >> 22); | |
key += (key << 4); | |
key ^= (key >> 9); | |
key += (key << 10); | |
key ^= (key >> 2); | |
key += (key << 7); | |
key += (key << 12); | |
return key; | |
} | |
// # 135 "tlm/deps/folly.exploded/include/folly/hash/Hash.h" 3 4 | |
inline uint32_t jenkins_rev_unmix32(uint32_t key) noexcept { | |
key *= 2364026753U; | |
key ^= (key >> 2) ^ (key >> 4) ^ (key >> 6) ^ (key >> 8) ^ (key >> 10) ^ | |
(key >> 12) ^ (key >> 14) ^ (key >> 16) ^ (key >> 18) ^ (key >> 20) ^ | |
(key >> 22) ^ (key >> 24) ^ (key >> 26) ^ (key >> 28) ^ (key >> 30); | |
key *= 3222273025U; | |
key ^= (key >> 9) ^ (key >> 18) ^ (key >> 27); | |
key *= 4042322161U; | |
key ^= (key >> 22); | |
key *= 16773121U; | |
return key; | |
} | |
const uint32_t FNV_32_HASH_START = 2166136261UL; | |
const uint64_t FNV_64_HASH_START = 14695981039346656037ULL; | |
const uint64_t FNVA_64_HASH_START = 14695981039346656037ULL; | |
inline uint32_t fnv32(const char* buf, | |
uint32_t hash = FNV_32_HASH_START) noexcept { | |
const signed char* s = reinterpret_cast<const signed char*>(buf); | |
for (; *s; ++s) { | |
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + | |
(hash << 24); | |
hash ^= *s; | |
} | |
return hash; | |
} | |
inline uint32_t fnv32_buf(const void* buf, | |
size_t n, | |
uint32_t hash = FNV_32_HASH_START) noexcept { | |
const signed char* char_buf = reinterpret_cast<const signed char*>(buf); | |
for (size_t i = 0; i < n; ++i) { | |
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + | |
(hash << 24); | |
hash ^= char_buf[i]; | |
} | |
return hash; | |
} | |
inline uint32_t fnv32(const std::string& str, | |
uint32_t hash = FNV_32_HASH_START) noexcept { | |
return fnv32_buf(str.data(), str.size(), hash); | |
} | |
inline uint64_t fnv64(const char* buf, | |
uint64_t hash = FNV_64_HASH_START) noexcept { | |
const signed char* s = reinterpret_cast<const signed char*>(buf); | |
for (; *s; ++s) { | |
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + | |
(hash << 8) + (hash << 40); | |
hash ^= *s; | |
} | |
return hash; | |
} | |
inline uint64_t fnv64_buf(const void* buf, | |
size_t n, | |
uint64_t hash = FNV_64_HASH_START) noexcept { | |
const signed char* char_buf = reinterpret_cast<const signed char*>(buf); | |
for (size_t i = 0; i < n; ++i) { | |
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + | |
(hash << 8) + (hash << 40); | |
hash ^= char_buf[i]; | |
} | |
return hash; | |
} | |
inline uint64_t fnv64(const std::string& str, | |
uint64_t hash = FNV_64_HASH_START) noexcept { | |
return fnv64_buf(str.data(), str.size(), hash); | |
} | |
inline uint64_t fnva64_buf(const void* buf, | |
size_t n, | |
uint64_t hash = FNVA_64_HASH_START) noexcept { | |
const uint8_t* char_buf = reinterpret_cast<const uint8_t*>(buf); | |
for (size_t i = 0; i < n; ++i) { | |
hash ^= char_buf[i]; | |
hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + | |
(hash << 8) + (hash << 40); | |
} | |
return hash; | |
} | |
inline uint64_t fnva64(const std::string& str, | |
uint64_t hash = FNVA_64_HASH_START) noexcept { | |
return fnva64_buf(str.data(), str.size(), hash); | |
} | |
inline uint32_t hsieh_hash32_buf(const void* buf, size_t len) noexcept { | |
const unsigned char* s = reinterpret_cast<const unsigned char*>(buf); | |
uint32_t hash = static_cast<uint32_t>(len); | |
uint32_t tmp; | |
size_t rem; | |
if (len <= 0 || buf == nullptr) { | |
return 0; | |
} | |
rem = len & 3; | |
len >>= 2; | |
for (; len > 0; len--) { | |
hash += folly::loadUnaligned<uint16_t>(s); | |
tmp = (folly::loadUnaligned<uint16_t>(s + 2) << 11) ^ hash; | |
hash = (hash << 16) ^ tmp; | |
s += 2 * sizeof(uint16_t); | |
hash += hash >> 11; | |
} | |
switch (rem) { | |
case 3: | |
hash += folly::loadUnaligned<uint16_t>(s); | |
hash ^= hash << 16; | |
hash ^= s[sizeof(uint16_t)] << 18; | |
hash += hash >> 11; | |
break; | |
case 2: | |
hash += folly::loadUnaligned<uint16_t>(s); | |
hash ^= hash << 11; | |
hash += hash >> 17; | |
break; | |
case 1: | |
hash += *s; | |
hash ^= hash << 10; | |
hash += hash >> 1; | |
} | |
hash ^= hash << 3; | |
hash += hash >> 5; | |
hash ^= hash << 4; | |
hash += hash >> 17; | |
hash ^= hash << 25; | |
hash += hash >> 6; | |
return hash; | |
} | |
inline uint32_t hsieh_hash32(const char* s) noexcept { | |
return hsieh_hash32_buf(s, std::strlen(s)); | |
} | |
inline uint32_t hsieh_hash32_str(const std::string& str) noexcept { | |
return hsieh_hash32_buf(str.data(), str.size()); | |
} | |
} // namespace hash | |
namespace detail { | |
template <typename I> | |
struct integral_hasher { | |
using folly_is_avalanching = | |
bool_constant<(sizeof(I) >= 8 || sizeof(size_t) == 4)>; | |
size_t operator()(I const& i) const noexcept { | |
static_assert(sizeof(I) <= 16, "Input type is too wide"); | |
if (sizeof(I) <= 4) { | |
auto const i32 = static_cast<int32_t>(i); | |
auto const u32 = static_cast<uint32_t>(i32); | |
return static_cast<size_t>(hash::jenkins_rev_mix32(u32)); | |
} else if (sizeof(I) <= 8) { | |
auto const u64 = static_cast<uint64_t>(i); | |
return static_cast<size_t>(hash::twang_mix64(u64)); | |
} else { | |
auto const u = to_unsigned(i); | |
auto const hi = static_cast<uint64_t>(u >> sizeof(I) * 4); | |
auto const lo = static_cast<uint64_t>(u); | |
return hash::hash_128_to_64(hi, lo); | |
} | |
} | |
}; | |
template <typename F> | |
struct float_hasher { | |
using folly_is_avalanching = std::true_type; | |
size_t operator()(F const& f) const noexcept { | |
static_assert(sizeof(F) <= 8, "Input type is too wide"); | |
if (f == F{}) { | |
return 0; | |
} | |
uint64_t u64 = 0; | |
memcpy(&u64, &f, sizeof(F)); | |
return static_cast<size_t>(hash::twang_mix64(u64)); | |
} | |
}; | |
} // namespace detail | |
template <class Key, class Enable = void> | |
struct hasher; | |
struct Hash { | |
template <class T> | |
size_t operator()(const T& v) const noexcept(noexcept(hasher<T>()(v))) { | |
return hasher<T>()(v); | |
} | |
template <class T, class... Ts> | |
size_t operator()(const T& t, const Ts&... ts) const { | |
return hash::hash_128_to_64((*this)(t), (*this)(ts...)); | |
} | |
size_t operator()() const noexcept { | |
return 0; | |
} | |
}; | |
// # 429 "tlm/deps/folly.exploded/include/folly/hash/Hash.h" 3 4 | |
template <typename Hasher, typename Key> | |
struct IsAvalanchingHasher; | |
namespace detail { | |
template <typename Hasher, typename Void = void> | |
struct IsAvalanchingHasherFromMemberType : std::false_type {}; | |
template <typename Hasher> | |
struct IsAvalanchingHasherFromMemberType< | |
Hasher, | |
void_t<typename Hasher::folly_is_avalanching>> | |
: bool_constant<Hasher::folly_is_avalanching::value> {}; | |
} // namespace detail | |
template <typename Hasher, typename Key> | |
struct IsAvalanchingHasher : detail::IsAvalanchingHasherFromMemberType<Hasher> { | |
}; | |
template <typename H, typename K> | |
struct IsAvalanchingHasher<transparent<H>, K> : IsAvalanchingHasher<H, K> {}; | |
template <typename K> | |
struct IsAvalanchingHasher<Hash, K> : IsAvalanchingHasher<hasher<K>, K> {}; | |
template <> | |
struct hasher<bool> { | |
using folly_is_avalanching = std::true_type; | |
size_t operator()(bool key) const noexcept { | |
return key ? std::numeric_limits<size_t>::max() : 0; | |
} | |
}; | |
template <typename K> | |
struct IsAvalanchingHasher<hasher<bool>, K> : std::true_type {}; | |
template <> | |
struct hasher<unsigned long long> | |
: detail::integral_hasher<unsigned long long> {}; | |
template <> | |
struct hasher<signed long long> : detail::integral_hasher<signed long long> {}; | |
template <> | |
struct hasher<unsigned long> : detail::integral_hasher<unsigned long> {}; | |
template <> | |
struct hasher<signed long> : detail::integral_hasher<signed long> {}; | |
template <> | |
struct hasher<unsigned int> : detail::integral_hasher<unsigned int> {}; | |
template <> | |
struct hasher<signed int> : detail::integral_hasher<signed int> {}; | |
template <> | |
struct hasher<unsigned short> : detail::integral_hasher<unsigned short> {}; | |
template <> | |
struct hasher<signed short> : detail::integral_hasher<signed short> {}; | |
template <> | |
struct hasher<unsigned char> : detail::integral_hasher<unsigned char> {}; | |
template <> | |
struct hasher<signed char> : detail::integral_hasher<signed char> {}; | |
template <> | |
struct hasher<char> : detail::integral_hasher<char> {}; | |
template <> | |
struct hasher<signed __int128> : detail::integral_hasher<signed __int128> {}; | |
template <> | |
struct hasher<unsigned __int128> : detail::integral_hasher<unsigned __int128> { | |
}; | |
template <> | |
struct hasher<float> : detail::float_hasher<float> {}; | |
template <> | |
struct hasher<double> : detail::float_hasher<double> {}; | |
template <> | |
struct hasher<std::string> { | |
using folly_is_avalanching = std::true_type; | |
size_t operator()(const std::string& key) const { | |
return static_cast<size_t>( | |
hash::SpookyHashV2::Hash64(key.data(), key.size(), 0)); | |
} | |
}; | |
template <typename K> | |
struct IsAvalanchingHasher<hasher<std::string>, K> : std::true_type {}; | |
template <typename T> | |
struct hasher<T, std::enable_if_t<std::is_enum<T>::value>> { | |
size_t operator()(T key) const noexcept { | |
return Hash()(to_underlying(key)); | |
} | |
}; | |
template <typename T, typename K> | |
struct IsAvalanchingHasher<hasher<T, std::enable_if_t<std::is_enum<T>::value>>, | |
K> | |
: IsAvalanchingHasher<hasher<std::underlying_type_t<T>>, K> {}; | |
template <typename T1, typename T2> | |
struct hasher<std::pair<T1, T2>> { | |
using folly_is_avalanching = std::true_type; | |
size_t operator()(const std::pair<T1, T2>& key) const { | |
return Hash()(key.first, key.second); | |
} | |
}; | |
template <typename... Ts> | |
struct hasher<std::tuple<Ts...>> { | |
size_t operator()(const std::tuple<Ts...>& key) const { | |
return apply(Hash(), key); | |
} | |
}; | |
template <typename T> | |
struct hasher<T*> { | |
using folly_is_avalanching = hasher<std::uintptr_t>::folly_is_avalanching; | |
size_t operator()(T* key) const { | |
return Hash()(bit_cast<std::uintptr_t>(key)); | |
} | |
}; | |
template <typename T> | |
struct hasher<std::unique_ptr<T>> { | |
using folly_is_avalanching = typename hasher<T*>::folly_is_avalanching; | |
size_t operator()(const std::unique_ptr<T>& key) const { | |
return Hash()(key.get()); | |
} | |
}; | |
template <typename T> | |
struct hasher<std::shared_ptr<T>> { | |
using folly_is_avalanching = typename hasher<T*>::folly_is_avalanching; | |
size_t operator()(const std::shared_ptr<T>& key) const { | |
return Hash()(key.get()); | |
} | |
}; | |
template <typename T, typename K> | |
struct IsAvalanchingHasher<hasher<std::tuple<T>>, K> | |
: IsAvalanchingHasher<hasher<T>, K> {}; | |
template <typename T1, typename T2, typename... Ts, typename K> | |
struct IsAvalanchingHasher<hasher<std::tuple<T1, T2, Ts...>>, K> | |
: std::true_type {}; | |
namespace hash { | |
class StdHasher { | |
public: | |
template <typename T> | |
size_t operator()(const T& t) const noexcept(noexcept(std::hash<T>()(t))) { | |
return std::hash<T>()(t); | |
} | |
}; | |
// # 616 "tlm/deps/folly.exploded/include/folly/hash/Hash.h" 3 4 | |
template <class Hash, class Value> | |
uint64_t commutative_hash_combine_value_generic(uint64_t seed, | |
Hash const& hasher, | |
Value const& value) { | |
auto const x = hasher(value); | |
auto const y = IsAvalanchingHasher<Hash, Value>::value ? x : twang_mix64(x); | |
return 3860031 + (seed + y) * 2779 + (seed * y * 2); | |
} | |
template < | |
class Iter, | |
class Hash = std::hash<typename std::iterator_traits<Iter>::value_type>> | |
uint64_t hash_range(Iter begin, | |
Iter end, | |
uint64_t hash = 0, | |
Hash hasher = Hash()) { | |
for (; begin != end; ++begin) { | |
hash = hash_128_to_64(hash, hasher(*begin)); | |
} | |
return hash; | |
} | |
template <class Hash, class Iter> | |
uint64_t commutative_hash_combine_range_generic(uint64_t seed, | |
Hash const& hasher, | |
Iter first, | |
Iter last) { | |
while (first != last) { | |
seed = commutative_hash_combine_value_generic(seed, hasher, *first++); | |
} | |
return seed; | |
} | |
template <class Iter> | |
uint64_t commutative_hash_combine_range(Iter first, Iter last) { | |
return commutative_hash_combine_range_generic(0, Hash{}, first, last); | |
} | |
namespace detail { | |
using c_array_size_t = size_t[]; | |
} | |
template <class Hasher> | |
inline size_t hash_combine_generic(const Hasher&) noexcept { | |
return 0; | |
} | |
template <class Hasher, typename T, typename... Ts> | |
size_t hash_combine_generic( | |
const Hasher& h, | |
const T& t, | |
const Ts&... ts) noexcept(noexcept(detail::c_array_size_t{h(t), | |
h(ts)...})) { | |
size_t seed = h(t); | |
if (sizeof...(ts) == 0) { | |
return seed; | |
} | |
size_t remainder = hash_combine_generic(h, ts...); | |
if (sizeof(size_t) == sizeof(uint32_t)) { | |
return twang_32from64((uint64_t(seed) << 32) | remainder); | |
} else { | |
return static_cast<size_t>(hash_128_to_64(seed, remainder)); | |
} | |
} | |
template <typename Hash, typename... Value> | |
uint64_t commutative_hash_combine_generic(uint64_t seed, | |
Hash const& hasher, | |
Value const&... value) { | |
uint64_t _[] = {0, | |
seed = commutative_hash_combine_value_generic( | |
seed, hasher, value)...}; | |
(void)_; | |
return seed; | |
} | |
template <typename T, typename... Ts> | |
size_t hash_combine(const T& t, const Ts&... ts) noexcept( | |
noexcept(hash_combine_generic(StdHasher{}, t, ts...))) { | |
return hash_combine_generic(StdHasher{}, t, ts...); | |
} | |
template <typename... Value> | |
uint64_t commutative_hash_combine(Value const&... value) { | |
return commutative_hash_combine_generic(0, Hash{}, value...); | |
} | |
} // namespace hash | |
template <size_t index, typename... Ts> | |
struct TupleHasher { | |
size_t operator()(std::tuple<Ts...> const& key) const { | |
return hash::hash_combine(TupleHasher<index - 1, Ts...>()(key), | |
std::get<index>(key)); | |
} | |
}; | |
template <typename... Ts> | |
struct TupleHasher<0, Ts...> { | |
size_t operator()(std::tuple<Ts...> const& key) const { | |
return hash::hash_combine(std::get<0>(key)); | |
} | |
}; | |
} // namespace folly | |
namespace std { | |
// # 747 "tlm/deps/folly.exploded/include/folly/hash/Hash.h" 3 4 | |
template <typename T1, typename T2> | |
struct hash<std::pair<T1, T2>> { | |
using folly_is_avalanching = std::true_type; | |
size_t operator()(const std::pair<T1, T2>& x) const { | |
return folly::hash::hash_combine(x.first, x.second); | |
} | |
}; | |
template <typename... Ts> | |
struct hash<std::tuple<Ts...>> { | |
private: | |
using FirstT = | |
std::decay_t<std::tuple_element_t<0, std::tuple<Ts..., bool>>>; | |
public: | |
using folly_is_avalanching = folly::bool_constant<( | |
sizeof...(Ts) != 1 || | |
folly::IsAvalanchingHasher<std::hash<FirstT>, FirstT>::value)>; | |
size_t operator()(std::tuple<Ts...> const& key) const { | |
folly::TupleHasher<sizeof...(Ts) - 1, Ts...> hasher; | |
return hasher(key); | |
} | |
}; | |
} // namespace std | |
namespace folly { | |
// # 787 "tlm/deps/folly.exploded/include/folly/hash/Hash.h" 3 4 | |
template <typename... Args, typename K> | |
struct IsAvalanchingHasher<std::hash<std::basic_string<Args...>>, K> | |
: std::true_type {}; | |
} // namespace folly | |
// # 36 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" 2 3 | |
// 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/system/ThreadId.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/system/ThreadId.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/PThread.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/PThread.h" 3 4 | |
// # 22 "tlm/deps/folly.exploded/include/folly/system/ThreadId.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/SysSyscall.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/SysSyscall.h" 3 4 | |
// # 21 "tlm/deps/folly.exploded/include/folly/portability/SysSyscall.h" 2 3 4 | |
// # 23 "tlm/deps/folly.exploded/include/folly/system/ThreadId.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/Unistd.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/Unistd.h" 3 4 | |
// # 24 "tlm/deps/folly.exploded/include/folly/system/ThreadId.h" 2 3 4 | |
namespace folly { | |
// # 42 "tlm/deps/folly.exploded/include/folly/system/ThreadId.h" 3 4 | |
inline uint64_t getCurrentThreadID() { | |
return uint64_t(pthread_self()); | |
} | |
// # 80 "tlm/deps/folly.exploded/include/folly/system/ThreadId.h" 3 4 | |
inline uint64_t getOSThreadID() { | |
// # 92 "tlm/deps/folly.exploded/include/folly/system/ThreadId.h" 3 4 | |
return uint64_t(syscall(186)); | |
} | |
} // namespace folly | |
// # 39 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" 2 3 | |
// 4 | |
namespace folly { | |
// # 66 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" 3 4 | |
struct CacheLocality { | |
size_t numCpus; | |
std::vector<size_t> numCachesByLevel; | |
// # 86 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" | |
// 3 4 | |
std::vector<size_t> localityIndexByCpu; | |
// # 102 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" | |
// 3 4 | |
template <template <typename> class Atom = std::atomic> | |
static const CacheLocality& system(); | |
// # 113 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" | |
// 3 4 | |
static CacheLocality readFromSysfsTree( | |
const std::function<std::string(std::string)>& mapping); | |
static CacheLocality readFromSysfs(); | |
static CacheLocality readFromProcCpuinfoLines( | |
std::vector<std::string> const& lines); | |
static CacheLocality readFromProcCpuinfo(); | |
static CacheLocality uniform(size_t numCpus); | |
}; | |
struct Getcpu { | |
typedef int (*Func)(unsigned* cpu, unsigned* node, void* unused); | |
static Func resolveVdsoFunc(); | |
}; | |
template <template <typename> class Atom> | |
struct SequentialThreadId { | |
static unsigned get() { | |
auto rv = currentId; | |
if ((__builtin_expect((rv == 0), 0))) { | |
rv = currentId = ++prevId; | |
} | |
return rv; | |
} | |
private: | |
static Atom<unsigned> prevId; | |
static __thread unsigned currentId; | |
}; | |
template <template <typename> class Atom> | |
Atom<unsigned> SequentialThreadId<Atom>::prevId(0); | |
template <template <typename> class Atom> | |
__thread unsigned SequentialThreadId<Atom>::currentId(0); | |
extern template struct SequentialThreadId<std::atomic>; | |
struct HashingThreadId { | |
static unsigned get() { | |
return hash::twang_32from64(getCurrentThreadID()); | |
} | |
}; | |
template <typename ThreadId> | |
struct FallbackGetcpu { | |
static int getcpu(unsigned* cpu, unsigned* node, void*) { | |
auto id = ThreadId::get(); | |
if (cpu) { | |
*cpu = id; | |
} | |
if (node) { | |
*node = id; | |
} | |
return 0; | |
} | |
}; | |
typedef FallbackGetcpu<SequentialThreadId<std::atomic>> FallbackGetcpuType; | |
// # 245 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" 3 4 | |
template <template <typename> class Atom = std::atomic> | |
struct AccessSpreader { | |
static size_t current(size_t numStripes) { | |
(static_cast<bool>(numStripes > 0) | |
? void(0) | |
: __assert_fail("numStripes > 0", | |
"tlm/deps/folly.exploded/include/folly/" | |
"concurrency/CacheLocality.h", | |
252, | |
__extension__ __PRETTY_FUNCTION__)); | |
unsigned cpu; | |
getcpuFunc(&cpu, nullptr, nullptr); | |
return widthAndCpuToStripe[std::min(size_t(kMaxCpus), numStripes)] | |
[cpu % kMaxCpus]; | |
} | |
// # 267 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" | |
// 3 4 | |
static size_t cachedCurrent(size_t numStripes) { | |
return widthAndCpuToStripe[std::min(size_t(kMaxCpus), numStripes)] | |
[cpuCache.cpu()]; | |
} | |
// # 280 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" | |
// 3 4 | |
static constexpr size_t maxStripeValue() { | |
return kMaxCpus; | |
} | |
private: | |
enum { | |
kMaxCpus = kIsMobile ? 16 : 256, | |
}; | |
typedef uint8_t CompactStripe; | |
static_assert((kMaxCpus & (kMaxCpus - 1)) == 0, | |
"kMaxCpus should be a power of two so modulo is fast"); | |
static_assert(kMaxCpus - 1 <= std::numeric_limits<CompactStripe>::max(), | |
"stripeByCpu element type isn't wide enough"); | |
static Getcpu::Func getcpuFunc; | |
static CompactStripe widthAndCpuToStripe[kMaxCpus + 1][kMaxCpus]; | |
class CpuCache { | |
public: | |
unsigned cpu() { | |
if ((__builtin_expect((cachedCpuUses_-- == 0), 0))) { | |
unsigned cpu; | |
AccessSpreader::getcpuFunc(&cpu, nullptr, nullptr); | |
cachedCpu_ = cpu % kMaxCpus; | |
cachedCpuUses_ = kMaxCachedCpuUses - 1; | |
} | |
return cachedCpu_; | |
} | |
private: | |
static constexpr unsigned kMaxCachedCpuUses = 32; | |
unsigned cachedCpu_{0}; | |
unsigned cachedCpuUses_{0}; | |
}; | |
static __thread CpuCache cpuCache; | |
static bool initialized; | |
static Getcpu::Func pickGetcpuFunc() { | |
auto best = Getcpu::resolveVdsoFunc(); | |
return best ? best : &FallbackGetcpuType::getcpu; | |
} | |
static int degenerateGetcpu(unsigned* cpu, unsigned* node, void*) { | |
if (cpu != nullptr) { | |
*cpu = 0; | |
} | |
if (node != nullptr) { | |
*node = 0; | |
} | |
return 0; | |
} | |
// # 371 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" | |
// 3 4 | |
static bool initialize() { | |
getcpuFunc = pickGetcpuFunc(); | |
auto& cacheLocality = CacheLocality::system<Atom>(); | |
auto n = cacheLocality.numCpus; | |
for (size_t width = 0; width <= kMaxCpus; ++width) { | |
auto& row = widthAndCpuToStripe[width]; | |
auto numStripes = std::max(size_t{1}, width); | |
for (size_t cpu = 0; cpu < kMaxCpus && cpu < n; ++cpu) { | |
auto index = cacheLocality.localityIndexByCpu[cpu]; | |
(static_cast<bool>(index < n) | |
? void(0) | |
: __assert_fail("index < n", | |
"tlm/deps/folly.exploded/include/" | |
"folly/concurrency/CacheLocality.h", | |
381, | |
__extension__ __PRETTY_FUNCTION__)); | |
row[cpu] = static_cast<CompactStripe>((index * numStripes) / n); | |
(static_cast<bool>(row[cpu] < numStripes) | |
? void(0) | |
: __assert_fail("row[cpu] < numStripes", | |
"tlm/deps/folly.exploded/include/" | |
"folly/concurrency/CacheLocality.h", | |
385, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
size_t filled = n; | |
while (filled < kMaxCpus) { | |
size_t len = std::min(filled, kMaxCpus - filled); | |
std::memcpy(&row[filled], &row[0], len); | |
filled += len; | |
} | |
for (size_t cpu = n; cpu < kMaxCpus; ++cpu) { | |
(static_cast<bool>(row[cpu] == row[cpu - n]) | |
? void(0) | |
: __assert_fail("row[cpu] == row[cpu - n]", | |
"tlm/deps/folly.exploded/include/" | |
"folly/concurrency/CacheLocality.h", | |
394, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
} | |
return true; | |
} | |
}; | |
template <template <typename> class Atom> | |
Getcpu::Func AccessSpreader<Atom>::getcpuFunc = | |
AccessSpreader<Atom>::degenerateGetcpu; | |
template <template <typename> class Atom> | |
typename AccessSpreader<Atom>::CompactStripe | |
AccessSpreader<Atom>::widthAndCpuToStripe[kMaxCpus + 1][kMaxCpus] = {}; | |
template <template <typename> class Atom> | |
__thread typename AccessSpreader<Atom>::CpuCache AccessSpreader<Atom>::cpuCache; | |
template <template <typename> class Atom> | |
bool AccessSpreader<Atom>::initialized = AccessSpreader<Atom>::initialize(); | |
extern template struct AccessSpreader<std::atomic>; | |
class SimpleAllocator { | |
std::mutex m_; | |
uint8_t* mem_{nullptr}; | |
uint8_t* end_{nullptr}; | |
void* freelist_{nullptr}; | |
size_t allocSize_; | |
size_t sz_; | |
std::vector<void*> blocks_; | |
public: | |
SimpleAllocator(size_t allocSize, size_t sz); | |
~SimpleAllocator(); | |
void* allocateHard(); | |
void* allocate() { | |
std::lock_guard<std::mutex> g(m_); | |
if (freelist_) { | |
auto mem = freelist_; | |
freelist_ = *static_cast<void**>(freelist_); | |
return mem; | |
} | |
if (intptr_t(mem_) % 128 == 0) { | |
mem_ += std::min(sz_, max_align_v); | |
} | |
if (mem_ && (mem_ + sz_ <= end_)) { | |
auto mem = mem_; | |
mem_ += sz_; | |
(static_cast<bool>(intptr_t(mem) % 128 != 0) | |
? void(0) | |
: __assert_fail("intptr_t(mem) % 128 != 0", | |
"tlm/deps/folly.exploded/include/folly/" | |
"concurrency/CacheLocality.h", | |
461, | |
__extension__ __PRETTY_FUNCTION__)); | |
return mem; | |
} | |
return allocateHard(); | |
} | |
void deallocate(void* mem) { | |
std::lock_guard<std::mutex> g(m_); | |
*static_cast<void**>(mem) = freelist_; | |
freelist_ = mem; | |
} | |
}; | |
// # 488 "tlm/deps/folly.exploded/include/folly/concurrency/CacheLocality.h" 3 4 | |
template <size_t Stripes> | |
class CoreRawAllocator { | |
public: | |
class Allocator { | |
static constexpr size_t AllocSize{4096}; | |
uint8_t sizeClass(size_t size) { | |
if (size <= 8) { | |
return 0; | |
} else if (size <= 16) { | |
return 1; | |
} else if (size <= 32) { | |
return 2; | |
} else if (size <= 64) { | |
return 3; | |
} else { | |
return 4; | |
} | |
} | |
std::array<SimpleAllocator, 4> allocators_{{{AllocSize, 8}, | |
{AllocSize, 16}, | |
{AllocSize, 32}, | |
{AllocSize, 64}}}; | |
public: | |
void* allocate(size_t size) { | |
auto cl = sizeClass(size); | |
if (cl == 4) { | |
size = size + (hardware_destructive_interference_size - 1); | |
size &= ~size_t(hardware_destructive_interference_size - 1); | |
void* mem = aligned_malloc( | |
size, hardware_destructive_interference_size); | |
if (!mem) { | |
throw_exception<std::bad_alloc>(); | |
} | |
return mem; | |
} | |
return allocators_[cl].allocate(); | |
} | |
void deallocate(void* mem, size_t = 0) { | |
if (!mem) { | |
return; | |
} | |
if (intptr_t(mem) % 128 != 0) { | |
auto addr = reinterpret_cast<void*>(intptr_t(mem) & | |
~intptr_t(AllocSize - 1)); | |
auto allocator = *static_cast<SimpleAllocator**>(addr); | |
allocator->deallocate(mem); | |
} else { | |
aligned_free(mem); | |
} | |
} | |
}; | |
Allocator* get(size_t stripe) { | |
(static_cast<bool>(stripe < Stripes) | |
? void(0) | |
: __assert_fail("stripe < Stripes", | |
"tlm/deps/folly.exploded/include/folly/" | |
"concurrency/CacheLocality.h", | |
545, | |
__extension__ __PRETTY_FUNCTION__)); | |
return &allocators_[stripe]; | |
} | |
private: | |
Allocator allocators_[Stripes]; | |
}; | |
template <typename T, size_t Stripes> | |
CxxAllocatorAdaptor<T, typename CoreRawAllocator<Stripes>::Allocator> | |
getCoreAllocator(size_t stripe) { | |
static Indestructible<CoreRawAllocator<Stripes>> allocator; | |
return CxxAllocatorAdaptor<T, | |
typename CoreRawAllocator<Stripes>::Allocator>( | |
*allocator->get(stripe)); | |
} | |
} // namespace folly | |
// # 30 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/detail/Futex.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/detail/Futex.h" 3 4 | |
// # 21 "tlm/deps/folly.exploded/include/folly/detail/Futex.h" 2 3 4 | |
namespace folly { | |
namespace detail { | |
enum class FutexResult { | |
VALUE_CHANGED, | |
AWOKEN, | |
INTERRUPTED, | |
TIMEDOUT, | |
}; | |
// # 50 "tlm/deps/folly.exploded/include/folly/detail/Futex.h" 3 4 | |
template <template <typename> class Atom = std::atomic> | |
using Futex = Atom<std::uint32_t>; | |
template <typename Futex> | |
FutexResult futexWait(const Futex* futex, | |
uint32_t expected, | |
uint32_t waitMask = -1); | |
// # 72 "tlm/deps/folly.exploded/include/folly/detail/Futex.h" 3 4 | |
template <typename Futex, class Clock, class Duration> | |
FutexResult futexWaitUntil( | |
const Futex* futex, | |
uint32_t expected, | |
std::chrono::time_point<Clock, Duration> const& deadline, | |
uint32_t waitMask = -1); | |
// # 88 "tlm/deps/folly.exploded/include/folly/detail/Futex.h" 3 4 | |
template <typename Futex> | |
int futexWake(const Futex* futex, | |
int count = std::numeric_limits<int>::max(), | |
uint32_t wakeMask = -1); | |
template <typename T> | |
struct EmulatedFutexAtomic : public std::atomic<T> { | |
EmulatedFutexAtomic() noexcept = default; | |
constexpr EmulatedFutexAtomic(T init) noexcept : std::atomic<T>(init) { | |
} | |
EmulatedFutexAtomic(EmulatedFutexAtomic&& rhs) = delete; | |
}; | |
} // namespace detail | |
} // namespace folly | |
// # 1 "tlm/deps/folly.exploded/include/folly/detail/Futex-inl.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/detail/Futex-inl.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/synchronization/ParkingLot.h" 1 3 | |
// 4 # 17 "tlm/deps/folly.exploded/include/folly/synchronization/ParkingLot.h" 3 | |
// 4 | |
// # 21 "tlm/deps/folly.exploded/include/folly/synchronization/ParkingLot.h" 2 3 | |
// 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Hash.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/Hash.h" 3 4 | |
// # 24 "tlm/deps/folly.exploded/include/folly/synchronization/ParkingLot.h" 2 3 | |
// 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Unit.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/Unit.h" 3 4 | |
namespace folly { | |
// # 36 "tlm/deps/folly.exploded/include/folly/Unit.h" 3 4 | |
struct Unit { | |
constexpr bool operator==(const Unit&) const { | |
return true; | |
} | |
constexpr bool operator!=(const Unit&) const { | |
return false; | |
} | |
}; | |
constexpr Unit unit{}; | |
template <typename T> | |
struct lift_unit { | |
using type = T; | |
}; | |
template <> | |
struct lift_unit<void> { | |
using type = Unit; | |
}; | |
template <typename T> | |
using lift_unit_t = typename lift_unit<T>::type; | |
template <typename T> | |
struct drop_unit { | |
using type = T; | |
}; | |
template <> | |
struct drop_unit<Unit> { | |
using type = void; | |
}; | |
template <typename T> | |
using drop_unit_t = typename drop_unit<T>::type; | |
} // namespace folly | |
// # 27 "tlm/deps/folly.exploded/include/folly/synchronization/ParkingLot.h" 2 3 | |
// 4 # 1 "tlm/deps/folly.exploded/include/folly/lang/SafeAssert.h" 1 3 4 # 17 | |
// "tlm/deps/folly.exploded/include/folly/lang/SafeAssert.h" 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/lang/SafeAssert.h" 2 3 4 | |
// # 56 "tlm/deps/folly.exploded/include/folly/lang/SafeAssert.h" 3 4 | |
namespace folly { | |
namespace detail { | |
[[noreturn]] void assertionFailure(const char* expr, | |
const char* msg, | |
const char* file, | |
unsigned int line, | |
const char* function, | |
int error); | |
} | |
} // namespace folly | |
// # 28 "tlm/deps/folly.exploded/include/folly/synchronization/ParkingLot.h" 2 3 | |
// 4 | |
namespace folly { | |
namespace parking_lot_detail { | |
struct WaitNodeBase { | |
const uint64_t key_; | |
const uint64_t lotid_; | |
WaitNodeBase* next_{nullptr}; | |
WaitNodeBase* prev_{nullptr}; | |
bool signaled_; | |
std::mutex mutex_; | |
std::condition_variable cond_; | |
WaitNodeBase(uint64_t key, uint64_t lotid) | |
: key_(key), lotid_(lotid), signaled_(false) { | |
} | |
template <typename Clock, typename Duration> | |
std::cv_status wait(std::chrono::time_point<Clock, Duration> deadline) { | |
std::cv_status status = std::cv_status::no_timeout; | |
std::unique_lock<std::mutex> nodeLock(mutex_); | |
while (!signaled_ && status != std::cv_status::timeout) { | |
if (deadline != std::chrono::time_point<Clock, Duration>::max()) { | |
status = cond_.wait_until(nodeLock, deadline); | |
} else { | |
cond_.wait(nodeLock); | |
} | |
} | |
return status; | |
} | |
void wake() { | |
std::lock_guard<std::mutex> nodeLock(mutex_); | |
signaled_ = true; | |
cond_.notify_one(); | |
} | |
bool signaled() { | |
return signaled_; | |
} | |
}; | |
extern std::atomic<uint64_t> idallocator; | |
struct Bucket { | |
std::mutex mutex_; | |
WaitNodeBase* head_; | |
WaitNodeBase* tail_; | |
std::atomic<uint64_t> count_; | |
static Bucket& bucketFor(uint64_t key); | |
void push_back(WaitNodeBase* node) { | |
if (tail_) { | |
((!::folly::kIsDebug || (head_)) | |
? static_cast<void>(0) | |
: ::folly::detail::assertionFailure( | |
"(head_)", | |
(("")), | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/ParkingLot.h", | |
89, | |
__PRETTY_FUNCTION__, | |
0)); | |
node->prev_ = tail_; | |
tail_->next_ = node; | |
tail_ = node; | |
} else { | |
tail_ = node; | |
head_ = node; | |
} | |
} | |
void erase(WaitNodeBase* node) { | |
((!::folly::kIsDebug || (count_.load(std::memory_order_relaxed) >= 1)) | |
? static_cast<void>(0) | |
: ::folly::detail::assertionFailure( | |
"(count_.load(std::memory_order_relaxed) >= 1)", | |
(("")), | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/ParkingLot.h", | |
100, | |
__PRETTY_FUNCTION__, | |
0)); | |
if (head_ == node && tail_ == node) { | |
((!::folly::kIsDebug || (node->prev_ == nullptr)) | |
? static_cast<void>(0) | |
: ::folly::detail::assertionFailure( | |
"(node->prev_ == nullptr)", | |
(("")), | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/ParkingLot.h", | |
102, | |
__PRETTY_FUNCTION__, | |
0)); | |
((!::folly::kIsDebug || (node->next_ == nullptr)) | |
? static_cast<void>(0) | |
: ::folly::detail::assertionFailure( | |
"(node->next_ == nullptr)", | |
(("")), | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/ParkingLot.h", | |
103, | |
__PRETTY_FUNCTION__, | |
0)); | |
head_ = nullptr; | |
tail_ = nullptr; | |
} else if (head_ == node) { | |
((!::folly::kIsDebug || (node->prev_ == nullptr)) | |
? static_cast<void>(0) | |
: ::folly::detail::assertionFailure( | |
"(node->prev_ == nullptr)", | |
(("")), | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/ParkingLot.h", | |
107, | |
__PRETTY_FUNCTION__, | |
0)); | |
((!::folly::kIsDebug || (node->next_)) | |
? static_cast<void>(0) | |
: ::folly::detail::assertionFailure( | |
"(node->next_)", | |
(("")), | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/ParkingLot.h", | |
108, | |
__PRETTY_FUNCTION__, | |
0)); | |
head_ = node->next_; | |
head_->prev_ = nullptr; | |
} else if (tail_ == node) { | |
((!::folly::kIsDebug || (node->next_ == nullptr)) | |
? static_cast<void>(0) | |
: ::folly::detail::assertionFailure( | |
"(node->next_ == nullptr)", | |
(("")), | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/ParkingLot.h", | |
112, | |
__PRETTY_FUNCTION__, | |
0)); | |
((!::folly::kIsDebug || (node->prev_)) | |
? static_cast<void>(0) | |
: ::folly::detail::assertionFailure( | |
"(node->prev_)", | |
(("")), | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/ParkingLot.h", | |
113, | |
__PRETTY_FUNCTION__, | |
0)); | |
tail_ = node->prev_; | |
tail_->next_ = nullptr; | |
} else { | |
((!::folly::kIsDebug || (node->next_)) | |
? static_cast<void>(0) | |
: ::folly::detail::assertionFailure( | |
"(node->next_)", | |
(("")), | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/ParkingLot.h", | |
117, | |
__PRETTY_FUNCTION__, | |
0)); | |
((!::folly::kIsDebug || (node->prev_)) | |
? static_cast<void>(0) | |
: ::folly::detail::assertionFailure( | |
"(node->prev_)", | |
(("")), | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/ParkingLot.h", | |
118, | |
__PRETTY_FUNCTION__, | |
0)); | |
node->next_->prev_ = node->prev_; | |
node->prev_->next_ = node->next_; | |
} | |
count_.fetch_sub(1, std::memory_order_relaxed); | |
} | |
}; | |
} // namespace parking_lot_detail | |
enum class UnparkControl { | |
RetainContinue, | |
RemoveContinue, | |
RetainBreak, | |
RemoveBreak, | |
}; | |
enum class ParkResult { | |
Skip, | |
Unpark, | |
Timeout, | |
}; | |
// # 161 "tlm/deps/folly.exploded/include/folly/synchronization/ParkingLot.h" 3 | |
// 4 | |
template <typename Data = Unit> | |
class ParkingLot { | |
const uint64_t lotid_; | |
ParkingLot(const ParkingLot&) = delete; | |
struct WaitNode : public parking_lot_detail::WaitNodeBase { | |
const Data data_; | |
template <typename D> | |
WaitNode(uint64_t key, uint64_t lotid, D&& data) | |
: WaitNodeBase(key, lotid), data_(std::forward<D>(data)) { | |
} | |
}; | |
public: | |
ParkingLot() : lotid_(parking_lot_detail::idallocator++) { | |
} | |
// # 188 | |
// "tlm/deps/folly.exploded/include/folly/synchronization/ParkingLot.h" 3 4 | |
template <typename Key, typename D, typename ToPark, typename PreWait> | |
ParkResult park(const Key key, | |
D&& data, | |
ToPark&& toPark, | |
PreWait&& preWait) { | |
return park_until(key, | |
std::forward<D>(data), | |
std::forward<ToPark>(toPark), | |
std::forward<PreWait>(preWait), | |
std::chrono::steady_clock::time_point::max()); | |
} | |
template <typename Key, | |
typename D, | |
typename ToPark, | |
typename PreWait, | |
typename Clock, | |
typename Duration> | |
ParkResult park_until(const Key key, | |
D&& data, | |
ToPark&& toPark, | |
PreWait&& preWait, | |
std::chrono::time_point<Clock, Duration> deadline); | |
template <typename Key, | |
typename D, | |
typename ToPark, | |
typename PreWait, | |
typename Rep, | |
typename Period> | |
ParkResult park_for(const Key key, | |
D&& data, | |
ToPark&& toPark, | |
PreWait&& preWait, | |
std::chrono::duration<Rep, Period>& timeout) { | |
return park_until(key, | |
std::forward<D>(data), | |
std::forward<ToPark>(toPark), | |
std::forward<PreWait>(preWait), | |
timeout + std::chrono::steady_clock::now()); | |
} | |
// # 244 | |
// "tlm/deps/folly.exploded/include/folly/synchronization/ParkingLot.h" 3 4 | |
template <typename Key, typename Unparker> | |
void unpark(const Key key, Unparker&& func); | |
}; | |
template <typename Data> | |
template <typename Key, | |
typename D, | |
typename ToPark, | |
typename PreWait, | |
typename Clock, | |
typename Duration> | |
ParkResult ParkingLot<Data>::park_until( | |
const Key bits, | |
D&& data, | |
ToPark&& toPark, | |
PreWait&& preWait, | |
std::chrono::time_point<Clock, Duration> deadline) { | |
auto key = hash::twang_mix64(uint64_t(bits)); | |
auto& bucket = parking_lot_detail::Bucket::bucketFor(key); | |
WaitNode node(key, lotid_, std::forward<D>(data)); | |
{ | |
bucket.count_.fetch_add(1, std::memory_order_seq_cst); | |
std::unique_lock<std::mutex> bucketLock(bucket.mutex_); | |
if (!std::forward<ToPark>(toPark)()) { | |
bucketLock.unlock(); | |
bucket.count_.fetch_sub(1, std::memory_order_relaxed); | |
return ParkResult::Skip; | |
} | |
bucket.push_back(&node); | |
} | |
std::forward<PreWait>(preWait)(); | |
auto status = node.wait(deadline); | |
if (status == std::cv_status::timeout) { | |
std::lock_guard<std::mutex> bucketLock(bucket.mutex_); | |
if (!node.signaled()) { | |
bucket.erase(&node); | |
return ParkResult::Timeout; | |
} | |
} | |
return ParkResult::Unpark; | |
} | |
template <typename Data> | |
template <typename Key, typename Func> | |
void ParkingLot<Data>::unpark(const Key bits, Func&& func) { | |
auto key = hash::twang_mix64(uint64_t(bits)); | |
auto& bucket = parking_lot_detail::Bucket::bucketFor(key); | |
if (bucket.count_.load(std::memory_order_seq_cst) == 0) { | |
return; | |
} | |
std::lock_guard<std::mutex> bucketLock(bucket.mutex_); | |
for (auto iter = bucket.head_; iter != nullptr;) { | |
auto node = static_cast<WaitNode*>(iter); | |
iter = iter->next_; | |
if (node->key_ == key && node->lotid_ == lotid_) { | |
auto result = std::forward<Func>(func)(node->data_); | |
if (result == UnparkControl::RemoveBreak || | |
result == UnparkControl::RemoveContinue) { | |
bucket.erase(node); | |
node->wake(); | |
} | |
if (result == UnparkControl::RemoveBreak || | |
result == UnparkControl::RetainBreak) { | |
return; | |
} | |
} | |
} | |
} | |
} // namespace folly | |
// # 21 "tlm/deps/folly.exploded/include/folly/detail/Futex-inl.h" 2 3 4 | |
namespace folly { | |
namespace detail { | |
template <typename TargetClock, typename Clock, typename Duration> | |
typename TargetClock::time_point time_point_conv( | |
std::chrono::time_point<Clock, Duration> const& time) { | |
using std::chrono::duration_cast; | |
using TimePoint = std::chrono::time_point<Clock, Duration>; | |
using TargetDuration = typename TargetClock::duration; | |
using TargetTimePoint = typename TargetClock::time_point; | |
if (time == TimePoint::max()) { | |
return TargetTimePoint::max(); | |
} else if (std::is_same<Clock, TargetClock>::value) { | |
auto const delta = time.time_since_epoch(); | |
return TargetTimePoint(duration_cast<TargetDuration>(delta)); | |
} else { | |
auto const delta = time - Clock::now(); | |
return TargetClock::now() + duration_cast<TargetDuration>(delta); | |
} | |
} | |
// # 56 "tlm/deps/folly.exploded/include/folly/detail/Futex-inl.h" 3 4 | |
int futexWakeImpl(const Futex<std::atomic>* futex, | |
int count, | |
uint32_t wakeMask); | |
FutexResult futexWaitImpl( | |
const Futex<std::atomic>* futex, | |
uint32_t expected, | |
std::chrono::system_clock::time_point const* absSystemTime, | |
std::chrono::steady_clock::time_point const* absSteadyTime, | |
uint32_t waitMask); | |
int futexWakeImpl(const Futex<EmulatedFutexAtomic>* futex, | |
int count, | |
uint32_t wakeMask); | |
FutexResult futexWaitImpl( | |
const Futex<EmulatedFutexAtomic>* futex, | |
uint32_t expected, | |
std::chrono::system_clock::time_point const* absSystemTime, | |
std::chrono::steady_clock::time_point const* absSteadyTime, | |
uint32_t waitMask); | |
template <typename Futex, typename Deadline> | |
typename std::enable_if<Deadline::clock::is_steady, FutexResult>::type | |
futexWaitImpl(Futex* futex, | |
uint32_t expected, | |
Deadline const& deadline, | |
uint32_t waitMask) { | |
return futexWaitImpl(futex, expected, nullptr, &deadline, waitMask); | |
} | |
template <typename Futex, typename Deadline> | |
typename std::enable_if<!Deadline::clock::is_steady, FutexResult>::type | |
futexWaitImpl(Futex* futex, | |
uint32_t expected, | |
Deadline const& deadline, | |
uint32_t waitMask) { | |
return futexWaitImpl(futex, expected, &deadline, nullptr, waitMask); | |
} | |
template <typename Futex> | |
FutexResult futexWait(const Futex* futex, | |
uint32_t expected, | |
uint32_t waitMask) { | |
auto rv = futexWaitImpl(futex, expected, nullptr, nullptr, waitMask); | |
(static_cast<bool>(rv != FutexResult::TIMEDOUT) | |
? void(0) | |
: __assert_fail("rv != FutexResult::TIMEDOUT", | |
"tlm/deps/folly.exploded/include/folly/detail/" | |
"Futex-inl.h", | |
102, | |
__extension__ __PRETTY_FUNCTION__)); | |
return rv; | |
} | |
template <typename Futex> | |
int futexWake(const Futex* futex, int count, uint32_t wakeMask) { | |
return futexWakeImpl(futex, count, wakeMask); | |
} | |
template <typename Futex, class Clock, class Duration> | |
FutexResult futexWaitUntil( | |
const Futex* futex, | |
uint32_t expected, | |
std::chrono::time_point<Clock, Duration> const& deadline, | |
uint32_t waitMask) { | |
using Target = typename std::conditional<Clock::is_steady, | |
std::chrono::steady_clock, | |
std::chrono::system_clock>::type; | |
auto const converted = time_point_conv<Target>(deadline); | |
return converted == Target::time_point::max() | |
? futexWaitImpl(futex, expected, nullptr, nullptr, waitMask) | |
: futexWaitImpl(futex, expected, converted, waitMask); | |
} | |
} // namespace detail | |
} // namespace folly | |
// # 110 "tlm/deps/folly.exploded/include/folly/detail/Futex.h" 2 3 4 | |
// # 31 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/Asm.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/Asm.h" 3 4 | |
// # 27 "tlm/deps/folly.exploded/include/folly/portability/Asm.h" 3 4 | |
namespace folly { | |
inline void asm_volatile_memory() { | |
asm volatile("" : : : "memory"); | |
} | |
inline void asm_volatile_pause() { | |
asm volatile("pause"); | |
} | |
} // namespace folly | |
// # 32 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/SysResource.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/SysResource.h" 3 4 | |
// # 21 "tlm/deps/folly.exploded/include/folly/portability/SysResource.h" 2 3 4 | |
// # 33 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/synchronization/AtomicRef.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/synchronization/AtomicRef.h" 3 4 | |
namespace folly { | |
namespace detail { | |
template <typename T> | |
struct atomic_ref_base { | |
static_assert(sizeof(T) == sizeof(std::atomic<T>), "size mismatch"); | |
static_assert(alignof(T) == alignof(std::atomic<T>), "alignment mismatch"); | |
static_assert(is_trivially_copyable_v<T>, "value not trivially-copyable"); | |
explicit atomic_ref_base(T& ref) : ref_(ref) { | |
} | |
atomic_ref_base(atomic_ref_base const&) = default; | |
void store(T desired, | |
std::memory_order order = std::memory_order_seq_cst) const | |
noexcept { | |
return atomic().store(desired, order); | |
} | |
T load(std::memory_order order = std::memory_order_seq_cst) const noexcept { | |
return atomic().load(order); | |
} | |
bool compare_exchange_weak(T& expected, | |
T desired, | |
std::memory_order success, | |
std::memory_order failure) const noexcept { | |
return atomic().compare_exchange_weak( | |
expected, desired, success, failure); | |
} | |
bool compare_exchange_weak( | |
T& expected, | |
T desired, | |
std::memory_order order = std::memory_order_seq_cst) const | |
noexcept { | |
return atomic().compare_exchange_weak(expected, desired, order); | |
} | |
bool compare_exchange_strong(T& expected, | |
T desired, | |
std::memory_order success, | |
std::memory_order failure) const noexcept { | |
return atomic().compare_exchange_strong( | |
expected, desired, success, failure); | |
} | |
bool compare_exchange_strong( | |
T& expected, | |
T desired, | |
std::memory_order order = std::memory_order_seq_cst) const | |
noexcept { | |
return atomic().compare_exchange_strong(expected, desired, order); | |
} | |
std::atomic<T>& atomic() const noexcept { | |
return reinterpret_cast<std::atomic<T>&>(ref_); | |
} | |
T& ref_; | |
}; | |
template <typename T> | |
struct atomic_ref_integral_base : atomic_ref_base<T> { | |
using atomic_ref_base<T>::atomic_ref_base; | |
using atomic_ref_base<T>::atomic; | |
T fetch_add(T arg, | |
std::memory_order order = std::memory_order_seq_cst) const | |
noexcept { | |
return atomic().fetch_add(arg, order); | |
} | |
T fetch_sub(T arg, | |
std::memory_order order = std::memory_order_seq_cst) const | |
noexcept { | |
return atomic().fetch_sub(arg, order); | |
} | |
}; | |
template <typename T> | |
using atomic_ref_select = conditional_t<std::is_integral<T>::value, | |
atomic_ref_integral_base<T>, | |
atomic_ref_base<T>>; | |
} // namespace detail | |
// # 119 "tlm/deps/folly.exploded/include/folly/synchronization/AtomicRef.h" 3 4 | |
template <typename T> | |
class atomic_ref : public detail::atomic_ref_select<T> { | |
private: | |
using base = detail::atomic_ref_select<T>; | |
public: | |
using base::base; | |
}; | |
template <typename T> | |
atomic_ref(T&)->atomic_ref<T>; | |
struct make_atomic_ref_t { | |
template <typename T, | |
std::enable_if_t<is_trivially_copyable_v<T> && | |
sizeof(T) == sizeof(std::atomic<T>) && | |
alignof(T) == alignof(std::atomic<T>), | |
int> = 0> | |
atomic_ref<T> operator()(T& ref) const { | |
return atomic_ref<T>{ref}; | |
} | |
}; | |
inline constexpr make_atomic_ref_t make_atomic_ref; | |
} // namespace folly | |
// # 34 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/synchronization/SanitizeThread.h" | |
// 1 3 4 # 17 | |
// "tlm/deps/folly.exploded/include/folly/synchronization/SanitizeThread.h" 3 4 | |
namespace folly { | |
enum class annotate_rwlock_level : long { | |
rdlock = 0, | |
wrlock = 1, | |
}; | |
namespace detail { | |
void annotate_rwlock_create_impl(void const volatile* const addr, | |
char const* const f, | |
int const l); | |
void annotate_rwlock_create_static_impl(void const volatile* const addr, | |
char const* const f, | |
int const l); | |
void annotate_rwlock_destroy_impl(void const volatile* const addr, | |
char const* const f, | |
int const l); | |
void annotate_rwlock_acquired_impl(void const volatile* const addr, | |
annotate_rwlock_level const w, | |
char const* const f, | |
int const l); | |
void annotate_rwlock_released_impl(void const volatile* const addr, | |
annotate_rwlock_level const w, | |
char const* const f, | |
int const l); | |
void annotate_benign_race_sized_impl(const volatile void* addr, | |
long size, | |
const char* desc, | |
const char* f, | |
int l); | |
void annotate_ignore_reads_begin_impl(const char* f, int l); | |
void annotate_ignore_reads_end_impl(const char* f, int l); | |
void annotate_ignore_writes_begin_impl(const char* f, int l); | |
void annotate_ignore_writes_end_impl(const char* f, int l); | |
void annotate_ignore_sync_begin_impl(const char* f, int l); | |
void annotate_ignore_sync_end_impl(const char* f, int l); | |
} // namespace detail | |
inline __attribute__((__always_inline__)) static void annotate_rwlock_create( | |
void const volatile* const addr, char const* const f, int const l) { | |
if (kIsSanitizeThread) { | |
detail::annotate_rwlock_create_impl(addr, f, l); | |
} | |
} | |
inline __attribute__((__always_inline__)) static void | |
annotate_rwlock_create_static(void const volatile* const addr, | |
char const* const f, | |
int const l) { | |
if (kIsSanitizeThread) { | |
detail::annotate_rwlock_create_static_impl(addr, f, l); | |
} | |
} | |
inline __attribute__((__always_inline__)) static void annotate_rwlock_destroy( | |
void const volatile* const addr, char const* const f, int const l) { | |
if (kIsSanitizeThread) { | |
detail::annotate_rwlock_destroy_impl(addr, f, l); | |
} | |
} | |
inline __attribute__((__always_inline__)) static void annotate_rwlock_acquired( | |
void const volatile* const addr, | |
annotate_rwlock_level const w, | |
char const* const f, | |
int const l) { | |
if (kIsSanitizeThread) { | |
detail::annotate_rwlock_acquired_impl(addr, w, f, l); | |
} | |
} | |
inline __attribute__((__always_inline__)) static void | |
annotate_rwlock_try_acquired(void const volatile* const addr, | |
annotate_rwlock_level const w, | |
bool const result, | |
char const* const f, | |
int const l) { | |
if (result) { | |
annotate_rwlock_acquired(addr, w, f, l); | |
} | |
} | |
inline __attribute__((__always_inline__)) static void annotate_rwlock_released( | |
void const volatile* const addr, | |
annotate_rwlock_level const w, | |
char const* const f, | |
int const l) { | |
if (kIsSanitizeThread) { | |
detail::annotate_rwlock_released_impl(addr, w, f, l); | |
} | |
} | |
inline __attribute__((__always_inline__)) static void | |
annotate_benign_race_sized(void const volatile* const addr, | |
long const size, | |
char const* const desc, | |
char const* const f, | |
int const l) { | |
if (kIsSanitizeThread) { | |
detail::annotate_benign_race_sized_impl(addr, size, desc, f, l); | |
} | |
} | |
inline __attribute__((__always_inline__)) static void | |
annotate_ignore_reads_begin(const char* f, int l) { | |
if (kIsSanitizeThread) { | |
detail::annotate_ignore_reads_begin_impl(f, l); | |
} | |
} | |
inline __attribute__((__always_inline__)) static void annotate_ignore_reads_end( | |
const char* f, int l) { | |
if (kIsSanitizeThread) { | |
detail::annotate_ignore_reads_end_impl(f, l); | |
} | |
} | |
inline __attribute__((__always_inline__)) static void | |
annotate_ignore_writes_begin(const char* f, int l) { | |
if (kIsSanitizeThread) { | |
detail::annotate_ignore_writes_begin_impl(f, l); | |
} | |
} | |
inline __attribute__((__always_inline__)) static void | |
annotate_ignore_writes_end(const char* f, int l) { | |
if (kIsSanitizeThread) { | |
detail::annotate_ignore_writes_end_impl(f, l); | |
} | |
} | |
inline __attribute__((__always_inline__)) static void | |
annotate_ignore_sync_begin(const char* f, int l) { | |
if (kIsSanitizeThread) { | |
detail::annotate_ignore_sync_begin_impl(f, l); | |
} | |
} | |
inline __attribute__((__always_inline__)) static void annotate_ignore_sync_end( | |
const char* f, int l) { | |
if (kIsSanitizeThread) { | |
detail::annotate_ignore_sync_end_impl(f, l); | |
} | |
} | |
class annotate_ignore_thread_sanitizer_guard { | |
public: | |
annotate_ignore_thread_sanitizer_guard(const char* file, int line) | |
: file_(file), line_(line) { | |
annotate_ignore_reads_begin(file_, line_); | |
annotate_ignore_writes_begin(file_, line_); | |
annotate_ignore_sync_begin(file_, line_); | |
} | |
annotate_ignore_thread_sanitizer_guard( | |
const annotate_ignore_thread_sanitizer_guard&) = delete; | |
annotate_ignore_thread_sanitizer_guard& operator=( | |
const annotate_ignore_thread_sanitizer_guard&) = delete; | |
~annotate_ignore_thread_sanitizer_guard() { | |
annotate_ignore_reads_end(file_, line_); | |
annotate_ignore_writes_end(file_, line_); | |
annotate_ignore_sync_end(file_, line_); | |
} | |
private: | |
const char* file_; | |
int line_; | |
}; | |
} // namespace folly | |
// # 35 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 2 3 4 | |
// # 249 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 4 | |
namespace folly { | |
struct SharedMutexToken { | |
enum class Type : uint16_t { | |
INVALID = 0, | |
INLINE_SHARED, | |
DEFERRED_SHARED, | |
}; | |
Type type_; | |
uint16_t slot_; | |
}; | |
namespace shared_mutex_detail { | |
std::unique_lock<std::mutex> annotationGuard(void* ptr); | |
constexpr uint32_t kMaxDeferredReadersAllocated = 256 * 2; | |
__attribute__((__noinline__)) uint32_t getMaxDeferredReadersSlow( | |
std::atomic<uint32_t>& cache); | |
__attribute__((__visibility__("default"))) inline | |
__attribute__((__always_inline__)) uint32_t | |
getMaxDeferredReaders() { | |
static std::atomic<uint32_t> cache{0}; | |
auto const value = cache.load(std::memory_order_acquire); | |
return (__builtin_expect((!!value), 1)) ? value | |
: getMaxDeferredReadersSlow(cache); | |
} | |
} // namespace shared_mutex_detail | |
template <bool ReaderPriority, | |
typename Tag_ = void, | |
template <typename> class Atom = std::atomic, | |
bool BlockImmediately = false, | |
bool AnnotateForThreadSanitizer = | |
kIsSanitizeThread && !ReaderPriority> | |
class SharedMutexImpl { | |
public: | |
static constexpr bool kReaderPriority = ReaderPriority; | |
typedef Tag_ Tag; | |
typedef SharedMutexToken Token; | |
class [[nodiscard]] ReadHolder; | |
class [[nodiscard]] UpgradeHolder; | |
class [[nodiscard]] WriteHolder; | |
constexpr SharedMutexImpl() noexcept : state_(0) { | |
} | |
SharedMutexImpl(const SharedMutexImpl&) = delete; | |
SharedMutexImpl(SharedMutexImpl&&) = delete; | |
SharedMutexImpl& operator=(const SharedMutexImpl&) = delete; | |
SharedMutexImpl& operator=(SharedMutexImpl&&) = delete; | |
// # 312 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 4 | |
~SharedMutexImpl() { | |
auto state = state_.load(std::memory_order_relaxed); | |
if ((__builtin_expect(((state & kHasS) != 0), 0))) { | |
cleanupTokenlessSharedDeferred(state); | |
} | |
if (folly::kIsDebug) { | |
(static_cast<bool>((state & ~(kWaitingAny | kMayDefer | | |
kAnnotationCreated)) == 0) | |
? void(0) | |
: __assert_fail("(state & ~(kWaitingAny | kMayDefer | " | |
"kAnnotationCreated)) == 0", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
326, | |
__extension__ __PRETTY_FUNCTION__)); | |
if ((state & kMayDefer) != 0) { | |
const uint32_t maxDeferredReaders = | |
shared_mutex_detail::getMaxDeferredReaders(); | |
for (uint32_t slot = 0; slot < maxDeferredReaders; ++slot) { | |
auto slotValue = deferredReader(slot)->load( | |
std::memory_order_relaxed); | |
(static_cast<bool>(!slotValueIsThis(slotValue)) | |
? void(0) | |
: __assert_fail( | |
"!slotValueIsThis(slotValue)", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
333, | |
__extension__ __PRETTY_FUNCTION__)); | |
(void)slotValue; | |
} | |
} | |
} | |
annotateDestroy(); | |
} | |
bool eligible_for_lock_elision() const { | |
auto state = state_.load(std::memory_order_relaxed); | |
return (state & (kHasS | kMayDefer | kHasE | kHasU)) == 0; | |
} | |
bool eligible_for_lock_upgrade_elision() const { | |
auto state = state_.load(std::memory_order_relaxed); | |
return (state & (kHasE | kHasU)) == 0; | |
} | |
bool eligible_for_lock_shared_elision() const { | |
auto state = state_.load(std::memory_order_relaxed); | |
return (state & kHasE) == 0; | |
} | |
void lock() { | |
WaitForever ctx; | |
(void)lockExclusiveImpl(kHasSolo, ctx); | |
annotateAcquired(annotate_rwlock_level::wrlock); | |
} | |
bool try_lock() { | |
WaitNever ctx; | |
auto result = lockExclusiveImpl(kHasSolo, ctx); | |
annotateTryAcquired(result, annotate_rwlock_level::wrlock); | |
return result; | |
} | |
template <class Rep, class Period> | |
bool try_lock_for(const std::chrono::duration<Rep, Period>& duration) { | |
WaitForDuration<Rep, Period> ctx(duration); | |
auto result = lockExclusiveImpl(kHasSolo, ctx); | |
annotateTryAcquired(result, annotate_rwlock_level::wrlock); | |
return result; | |
} | |
template <class Clock, class Duration> | |
bool try_lock_until( | |
const std::chrono::time_point<Clock, Duration>& absDeadline) { | |
WaitUntilDeadline<Clock, Duration> ctx{absDeadline}; | |
auto result = lockExclusiveImpl(kHasSolo, ctx); | |
annotateTryAcquired(result, annotate_rwlock_level::wrlock); | |
return result; | |
} | |
void unlock() { | |
annotateReleased(annotate_rwlock_level::wrlock); | |
auto state = (state_ &= ~(kWaitingNotS | kPrevDefer | kHasE)); | |
(static_cast<bool>((state & ~(kWaitingAny | kAnnotationCreated)) == 0) | |
? void(0) | |
: __assert_fail( | |
"(state & ~(kWaitingAny | kAnnotationCreated)) == 0", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
405, | |
__extension__ __PRETTY_FUNCTION__)); | |
wakeRegisteredWaiters(state, kWaitingE | kWaitingU | kWaitingS); | |
} | |
void lock_shared() { | |
WaitForever ctx; | |
(void)lockSharedImpl(nullptr, ctx); | |
annotateAcquired(annotate_rwlock_level::rdlock); | |
} | |
void lock_shared(Token& token) { | |
WaitForever ctx; | |
(void)lockSharedImpl(&token, ctx); | |
annotateAcquired(annotate_rwlock_level::rdlock); | |
} | |
bool try_lock_shared() { | |
WaitNever ctx; | |
auto result = lockSharedImpl(nullptr, ctx); | |
annotateTryAcquired(result, annotate_rwlock_level::rdlock); | |
return result; | |
} | |
bool try_lock_shared(Token& token) { | |
WaitNever ctx; | |
auto result = lockSharedImpl(&token, ctx); | |
annotateTryAcquired(result, annotate_rwlock_level::rdlock); | |
return result; | |
} | |
template <class Rep, class Period> | |
bool try_lock_shared_for( | |
const std::chrono::duration<Rep, Period>& duration) { | |
WaitForDuration<Rep, Period> ctx(duration); | |
auto result = lockSharedImpl(nullptr, ctx); | |
annotateTryAcquired(result, annotate_rwlock_level::rdlock); | |
return result; | |
} | |
template <class Rep, class Period> | |
bool try_lock_shared_for(const std::chrono::duration<Rep, Period>& duration, | |
Token& token) { | |
WaitForDuration<Rep, Period> ctx(duration); | |
auto result = lockSharedImpl(&token, ctx); | |
annotateTryAcquired(result, annotate_rwlock_level::rdlock); | |
return result; | |
} | |
template <class Clock, class Duration> | |
bool try_lock_shared_until( | |
const std::chrono::time_point<Clock, Duration>& absDeadline) { | |
WaitUntilDeadline<Clock, Duration> ctx{absDeadline}; | |
auto result = lockSharedImpl(nullptr, ctx); | |
annotateTryAcquired(result, annotate_rwlock_level::rdlock); | |
return result; | |
} | |
template <class Clock, class Duration> | |
bool try_lock_shared_until( | |
const std::chrono::time_point<Clock, Duration>& absDeadline, | |
Token& token) { | |
WaitUntilDeadline<Clock, Duration> ctx{absDeadline}; | |
auto result = lockSharedImpl(&token, ctx); | |
annotateTryAcquired(result, annotate_rwlock_level::rdlock); | |
return result; | |
} | |
void unlock_shared() { | |
annotateReleased(annotate_rwlock_level::rdlock); | |
auto state = state_.load(std::memory_order_acquire); | |
(static_cast<bool>((state & (kPrevDefer | kHasE | kBegunE)) != | |
kPrevDefer) | |
? void(0) | |
: __assert_fail("(state & (kPrevDefer | kHasE | kBegunE)) != " | |
"kPrevDefer", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
480, | |
__extension__ __PRETTY_FUNCTION__)); | |
if ((state & (kMayDefer | kPrevDefer)) == 0 || | |
!tryUnlockTokenlessSharedDeferred()) { | |
unlockSharedInline(); | |
} | |
} | |
void unlock_shared(Token& token) { | |
annotateReleased(annotate_rwlock_level::rdlock); | |
(static_cast<bool>(token.type_ == Token::Type::INLINE_SHARED || | |
token.type_ == Token::Type::DEFERRED_SHARED) | |
? void(0) | |
: __assert_fail("token.type_ == Token::Type::INLINE_SHARED || " | |
"token.type_ == Token::Type::DEFERRED_SHARED", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
496, | |
__extension__ __PRETTY_FUNCTION__)) | |
; | |
if (token.type_ != Token::Type::DEFERRED_SHARED || | |
!tryUnlockSharedDeferred(token.slot_)) { | |
unlockSharedInline(); | |
} | |
if (folly::kIsDebug) { | |
token.type_ = Token::Type::INVALID; | |
} | |
} | |
void unlock_and_lock_shared() { | |
annotateReleased(annotate_rwlock_level::wrlock); | |
annotateAcquired(annotate_rwlock_level::rdlock); | |
auto state = state_.load(std::memory_order_acquire); | |
do { | |
(static_cast<bool>((state & ~(kWaitingAny | kPrevDefer | | |
kAnnotationCreated)) == kHasE) | |
? void(0) | |
: __assert_fail("(state & ~(kWaitingAny | kPrevDefer | " | |
"kAnnotationCreated)) == kHasE", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
520, | |
__extension__ __PRETTY_FUNCTION__)); | |
} while (!state_.compare_exchange_strong( | |
state, | |
(state & ~(kWaitingAny | kPrevDefer | kHasE)) + kIncrHasS)); | |
if ((state & (kWaitingE | kWaitingU | kWaitingS)) != 0) { | |
futexWakeAll(kWaitingE | kWaitingU | kWaitingS); | |
} | |
} | |
void unlock_and_lock_shared(Token& token) { | |
unlock_and_lock_shared(); | |
token.type_ = Token::Type::INLINE_SHARED; | |
} | |
void lock_upgrade() { | |
WaitForever ctx; | |
(void)lockUpgradeImpl(ctx); | |
annotateAcquired(annotate_rwlock_level::rdlock); | |
} | |
bool try_lock_upgrade() { | |
WaitNever ctx; | |
auto result = lockUpgradeImpl(ctx); | |
annotateTryAcquired(result, annotate_rwlock_level::rdlock); | |
return result; | |
} | |
template <class Rep, class Period> | |
bool try_lock_upgrade_for( | |
const std::chrono::duration<Rep, Period>& duration) { | |
WaitForDuration<Rep, Period> ctx(duration); | |
auto result = lockUpgradeImpl(ctx); | |
annotateTryAcquired(result, annotate_rwlock_level::rdlock); | |
return result; | |
} | |
template <class Clock, class Duration> | |
bool try_lock_upgrade_until( | |
const std::chrono::time_point<Clock, Duration>& absDeadline) { | |
WaitUntilDeadline<Clock, Duration> ctx{absDeadline}; | |
auto result = lockUpgradeImpl(ctx); | |
annotateTryAcquired(result, annotate_rwlock_level::rdlock); | |
return result; | |
} | |
void unlock_upgrade() { | |
annotateReleased(annotate_rwlock_level::rdlock); | |
auto state = (state_ -= kHasU); | |
(static_cast<bool>((state & (kWaitingNotS | kHasSolo)) == 0) | |
? void(0) | |
: __assert_fail("(state & (kWaitingNotS | kHasSolo)) == 0", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
569, | |
__extension__ __PRETTY_FUNCTION__)); | |
wakeRegisteredWaiters(state, kWaitingE | kWaitingU); | |
} | |
void unlock_upgrade_and_lock() { | |
WaitForever ctx; | |
(void)lockExclusiveImpl(0, ctx); | |
annotateReleased(annotate_rwlock_level::rdlock); | |
annotateAcquired(annotate_rwlock_level::wrlock); | |
} | |
void unlock_upgrade_and_lock_shared() { | |
auto state = (state_ -= kHasU - kIncrHasS); | |
(static_cast<bool>((state & (kWaitingNotS | kHasSolo)) == 0) | |
? void(0) | |
: __assert_fail("(state & (kWaitingNotS | kHasSolo)) == 0", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
585, | |
__extension__ __PRETTY_FUNCTION__)); | |
wakeRegisteredWaiters(state, kWaitingE | kWaitingU); | |
} | |
void unlock_upgrade_and_lock_shared(Token& token) { | |
unlock_upgrade_and_lock_shared(); | |
token.type_ = Token::Type::INLINE_SHARED; | |
} | |
void unlock_and_lock_upgrade() { | |
annotateReleased(annotate_rwlock_level::wrlock); | |
annotateAcquired(annotate_rwlock_level::rdlock); | |
auto state = state_.load(std::memory_order_acquire); | |
while (true) { | |
(static_cast<bool>((state & ~(kWaitingAny | kPrevDefer | | |
kAnnotationCreated)) == kHasE) | |
? void(0) | |
: __assert_fail("(state & ~(kWaitingAny | kPrevDefer | " | |
"kAnnotationCreated)) == kHasE", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
602, | |
__extension__ __PRETTY_FUNCTION__)); | |
auto after = | |
(state & ~(kWaitingNotS | kWaitingS | kPrevDefer | kHasE)) + | |
kHasU; | |
if (state_.compare_exchange_strong(state, after)) { | |
if ((state & kWaitingS) != 0) { | |
futexWakeAll(kWaitingS); | |
} | |
return; | |
} | |
} | |
} | |
private: | |
typedef typename folly::detail::Futex<Atom> Futex; | |
struct WaitForever { | |
bool canBlock() { | |
return true; | |
} | |
bool canTimeOut() { | |
return false; | |
} | |
bool shouldTimeOut() { | |
return false; | |
} | |
bool doWait(Futex& futex, uint32_t expected, uint32_t waitMask) { | |
detail::futexWait(&futex, expected, waitMask); | |
return true; | |
} | |
}; | |
struct WaitNever { | |
bool canBlock() { | |
return false; | |
} | |
bool canTimeOut() { | |
return true; | |
} | |
bool shouldTimeOut() { | |
return true; | |
} | |
bool doWait(Futex&, uint32_t, uint32_t) { | |
return false; | |
} | |
}; | |
template <class Rep, class Period> | |
struct WaitForDuration { | |
std::chrono::duration<Rep, Period> duration_; | |
bool deadlineComputed_; | |
std::chrono::steady_clock::time_point deadline_; | |
explicit WaitForDuration( | |
const std::chrono::duration<Rep, Period>& duration) | |
: duration_(duration), deadlineComputed_(false) { | |
} | |
std::chrono::steady_clock::time_point deadline() { | |
if (!deadlineComputed_) { | |
deadline_ = std::chrono::steady_clock::now() + duration_; | |
deadlineComputed_ = true; | |
} | |
return deadline_; | |
} | |
bool canBlock() { | |
return duration_.count() > 0; | |
} | |
bool canTimeOut() { | |
return true; | |
} | |
bool shouldTimeOut() { | |
return std::chrono::steady_clock::now() > deadline(); | |
} | |
bool doWait(Futex& futex, uint32_t expected, uint32_t waitMask) { | |
auto result = detail::futexWaitUntil( | |
&futex, expected, deadline(), waitMask); | |
return result != folly::detail::FutexResult::TIMEDOUT; | |
} | |
}; | |
template <class Clock, class Duration> | |
struct WaitUntilDeadline { | |
std::chrono::time_point<Clock, Duration> absDeadline_; | |
bool canBlock() { | |
return true; | |
} | |
bool canTimeOut() { | |
return true; | |
} | |
bool shouldTimeOut() { | |
return Clock::now() > absDeadline_; | |
} | |
bool doWait(Futex& futex, uint32_t expected, uint32_t waitMask) { | |
auto result = detail::futexWaitUntil( | |
&futex, expected, absDeadline_, waitMask); | |
return result != folly::detail::FutexResult::TIMEDOUT; | |
} | |
}; | |
void annotateLazyCreate() { | |
if (AnnotateForThreadSanitizer && | |
(state_.load() & kAnnotationCreated) == 0) { | |
auto guard = shared_mutex_detail::annotationGuard(this); | |
if ((state_.load() & kAnnotationCreated) == 0) { | |
state_.fetch_or(kAnnotationCreated); | |
annotate_benign_race_sized( | |
&state_, | |
sizeof(state_), | |
"init TSAN", | |
"tlm/deps/folly.exploded/include/folly/SharedMutex.h", | |
724); | |
annotate_rwlock_create( | |
this, | |
"tlm/deps/folly.exploded/include/folly/SharedMutex.h", | |
725); | |
} | |
} | |
} | |
void annotateDestroy() { | |
if (AnnotateForThreadSanitizer) { | |
annotateLazyCreate(); | |
annotate_rwlock_destroy( | |
this, | |
"tlm/deps/folly.exploded/include/folly/SharedMutex.h", | |
733); | |
} | |
} | |
void annotateAcquired(annotate_rwlock_level w) { | |
if (AnnotateForThreadSanitizer) { | |
annotateLazyCreate(); | |
annotate_rwlock_acquired( | |
this, | |
w, | |
"tlm/deps/folly.exploded/include/folly/SharedMutex.h", | |
740); | |
} | |
} | |
void annotateTryAcquired(bool result, annotate_rwlock_level w) { | |
if (AnnotateForThreadSanitizer) { | |
annotateLazyCreate(); | |
annotate_rwlock_try_acquired( | |
this, | |
w, | |
result, | |
"tlm/deps/folly.exploded/include/folly/SharedMutex.h", | |
747); | |
} | |
} | |
void annotateReleased(annotate_rwlock_level w) { | |
if (AnnotateForThreadSanitizer) { | |
(static_cast<bool>((state_.load() & kAnnotationCreated) != 0) | |
? void(0) | |
: __assert_fail( | |
"(state_.load() & kAnnotationCreated) != 0", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
753, | |
__extension__ __PRETTY_FUNCTION__)); | |
annotate_rwlock_released( | |
this, | |
w, | |
"tlm/deps/folly.exploded/include/folly/SharedMutex.h", | |
754); | |
} | |
} | |
Futex state_{}; | |
// # 769 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 4 | |
static constexpr uint32_t kIncrHasS = 1 << 11; | |
static constexpr uint32_t kHasS = ~(kIncrHasS - 1); | |
static constexpr uint32_t kAnnotationCreated = 1 << 10; | |
static constexpr uint32_t kMayDefer = 1 << 9; | |
static constexpr uint32_t kPrevDefer = 1 << 8; | |
static constexpr uint32_t kHasE = 1 << 7; | |
static constexpr uint32_t kBegunE = 1 << 6; | |
// # 809 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 4 | |
static constexpr uint32_t kHasU = 1 << 5; | |
static constexpr uint32_t kHasSolo = kHasE | kBegunE | kHasU; | |
static constexpr uint32_t kWaitingNotS = 1 << 4; | |
// # 834 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 4 | |
static constexpr uint32_t kWaitingESingle = 1 << 2; | |
static constexpr uint32_t kWaitingEMultiple = 1 << 3; | |
static constexpr uint32_t kWaitingE = kWaitingESingle | kWaitingEMultiple; | |
static constexpr uint32_t kWaitingU = 1 << 1; | |
static constexpr uint32_t kWaitingS = 1 << 0; | |
static constexpr uint32_t kWaitingAny = | |
kWaitingNotS | kWaitingE | kWaitingU | kWaitingS; | |
static constexpr uint32_t kNumSharedToStartDeferring = 2; | |
static constexpr uint32_t kMaxSpinCount = !BlockImmediately ? 1000 : 2; | |
static constexpr uint32_t kMaxSoftYieldCount = !BlockImmediately ? 1000 : 0; | |
// # 899 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 4 | |
public: | |
static constexpr uint32_t kDeferredSearchDistance = 2; | |
static constexpr uint32_t kDeferredSeparationFactor = 4; | |
private: | |
static_assert(!(kDeferredSearchDistance & (kDeferredSearchDistance - 1)), | |
"kDeferredSearchDistance must be a power of 2"); | |
static constexpr uint32_t kTokenStackTLSCapacity = 2; | |
// # 924 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 4 | |
static constexpr uintptr_t kTokenless = 0x1; | |
static __thread uint32_t tls_lastTokenlessSlot; | |
static __thread uint32_t tls_lastDeferredReaderSlot; | |
public: | |
typedef Atom<uintptr_t> DeferredReaderSlot; | |
private: | |
alignas(hardware_destructive_interference_size) static DeferredReaderSlot | |
deferredReaders[shared_mutex_detail::kMaxDeferredReadersAllocated * | |
kDeferredSeparationFactor]; | |
template <class WaitContext> | |
bool lockExclusiveImpl(uint32_t preconditionGoalMask, WaitContext& ctx) { | |
uint32_t state = state_.load(std::memory_order_acquire); | |
if ((__builtin_expect(((state & (preconditionGoalMask | kMayDefer | | |
kHasS)) == 0 && | |
state_.compare_exchange_strong( | |
state, (state | kHasE) & ~kHasU)), | |
1)) | |
) { | |
return true; | |
} else { | |
return lockExclusiveImpl(state, preconditionGoalMask, ctx); | |
} | |
} | |
template <class WaitContext> | |
bool lockExclusiveImpl(uint32_t& state, | |
uint32_t preconditionGoalMask, | |
WaitContext& ctx) { | |
while (true) { | |
if ((__builtin_expect(((state & preconditionGoalMask) != 0), 0)) && | |
!waitForZeroBits(state, preconditionGoalMask, kWaitingE, ctx) && | |
ctx.canTimeOut()) { | |
return false; | |
} | |
uint32_t after = (state & kMayDefer) == 0 ? 0 : kPrevDefer; | |
if (!kReaderPriority || (state & (kMayDefer | kHasS)) == 0) { | |
after |= (state | kHasE) & ~(kHasU | kMayDefer); | |
} else { | |
after |= (state | kBegunE) & ~(kHasU | kMayDefer); | |
} | |
if (state_.compare_exchange_strong(state, after)) { | |
auto before = state; | |
state = after; | |
// # 996 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 | |
// 4 | |
if ((__builtin_expect(((before & kMayDefer) != 0), 0))) { | |
applyDeferredReaders(state, ctx); | |
} | |
while (true) { | |
(static_cast<bool>((state & (kHasE | kBegunE)) != 0 && | |
(state & kHasU) == 0) | |
? void(0) | |
: __assert_fail( | |
"(state & (kHasE | kBegunE)) != 0 && " | |
"(state & kHasU) == 0", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
1000, | |
__extension__ __PRETTY_FUNCTION__)); | |
if ((__builtin_expect(((state & kHasS) != 0), 0)) && | |
!waitForZeroBits(state, kHasS, kWaitingNotS, ctx) && | |
ctx.canTimeOut()) { | |
state = (state_ &= ~(kPrevDefer | kHasE | kBegunE | | |
kWaitingNotS)); | |
wakeRegisteredWaiters( | |
state, kWaitingE | kWaitingU | kWaitingS); | |
return false; | |
} | |
if (kReaderPriority && (state & kHasE) == 0) { | |
(static_cast<bool>((state & kBegunE) != 0) | |
? void(0) | |
: __assert_fail( | |
"(state & kBegunE) != 0", | |
"tlm/deps/folly.exploded/include/" | |
"folly/SharedMutex.h", | |
1014, | |
__extension__ __PRETTY_FUNCTION__)); | |
if (!state_.compare_exchange_strong( | |
state, (state & ~kBegunE) | kHasE)) { | |
continue; | |
} | |
} | |
return true; | |
} | |
} | |
} | |
} | |
template <class WaitContext> | |
bool waitForZeroBits(uint32_t& state, | |
uint32_t goal, | |
uint32_t waitMask, | |
WaitContext& ctx) { | |
uint32_t spinCount = 0; | |
while (true) { | |
state = state_.load(std::memory_order_acquire); | |
if ((state & goal) == 0) { | |
return true; | |
} | |
asm_volatile_pause(); | |
++spinCount; | |
if ((__builtin_expect((spinCount >= kMaxSpinCount), 0))) { | |
return ctx.canBlock() && | |
yieldWaitForZeroBits(state, goal, waitMask, ctx); | |
} | |
} | |
} | |
template <class WaitContext> | |
bool yieldWaitForZeroBits(uint32_t& state, | |
uint32_t goal, | |
uint32_t waitMask, | |
WaitContext& ctx) { | |
struct rusage usage; | |
std::memset(&usage, 0, sizeof(usage)); | |
long before = -1; | |
for (uint32_t yieldCount = 0; yieldCount < kMaxSoftYieldCount; | |
++yieldCount) { | |
for (int softState = 0; softState < 3; ++softState) { | |
if (softState < 2) { | |
std::this_thread::yield(); | |
} else { | |
getrusage(RUSAGE_THREAD, &usage); | |
} | |
if (((state = state_.load(std::memory_order_acquire)) & goal) == | |
0) { | |
return true; | |
} | |
if (ctx.shouldTimeOut()) { | |
return false; | |
} | |
} | |
if (before >= 0 && usage.ru_nivcsw >= before + 2) { | |
break; | |
} | |
before = usage.ru_nivcsw; | |
} | |
return futexWaitForZeroBits(state, goal, waitMask, ctx); | |
} | |
template <class WaitContext> | |
bool futexWaitForZeroBits(uint32_t& state, | |
uint32_t goal, | |
uint32_t waitMask, | |
WaitContext& ctx) { | |
(static_cast<bool>(waitMask == kWaitingNotS || waitMask == kWaitingE || | |
waitMask == kWaitingU || waitMask == kWaitingS) | |
? void(0) | |
: __assert_fail( | |
"waitMask == kWaitingNotS || waitMask == kWaitingE " | |
"|| waitMask == kWaitingU || waitMask == kWaitingS", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
1095, | |
__extension__ __PRETTY_FUNCTION__)) | |
; | |
while (true) { | |
state = state_.load(std::memory_order_acquire); | |
if ((state & goal) == 0) { | |
return true; | |
} | |
auto after = state; | |
if (waitMask == kWaitingE) { | |
if ((state & kWaitingESingle) != 0) { | |
after |= kWaitingEMultiple; | |
} else { | |
after |= kWaitingESingle; | |
} | |
} else { | |
after |= waitMask; | |
} | |
if (after != state && | |
!state_.compare_exchange_strong(state, after)) { | |
continue; | |
} | |
if (!ctx.doWait(state_, after, waitMask)) { | |
return false; | |
} | |
} | |
} | |
void wakeRegisteredWaiters(uint32_t& state, uint32_t wakeMask) { | |
if ((__builtin_expect(((state & wakeMask) != 0), 0))) { | |
wakeRegisteredWaitersImpl(state, wakeMask); | |
} | |
} | |
void wakeRegisteredWaitersImpl(uint32_t& state, uint32_t wakeMask) { | |
// # 1153 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 4 | |
if ((wakeMask & kWaitingE) == kWaitingE && | |
(state & wakeMask) == kWaitingE && | |
detail::futexWake(&state_, 1, kWaitingE) > 0) { | |
return; | |
} | |
if ((state & wakeMask) != 0) { | |
auto prev = state_.fetch_and(~wakeMask); | |
if ((prev & wakeMask) != 0) { | |
futexWakeAll(wakeMask); | |
} | |
state = prev & ~wakeMask; | |
} | |
} | |
void futexWakeAll(uint32_t wakeMask) { | |
detail::futexWake(&state_, std::numeric_limits<int>::max(), wakeMask); | |
} | |
DeferredReaderSlot* deferredReader(uint32_t slot) { | |
return &deferredReaders[slot * kDeferredSeparationFactor]; | |
} | |
uintptr_t tokenfulSlotValue() { | |
return reinterpret_cast<uintptr_t>(this); | |
} | |
uintptr_t tokenlessSlotValue() { | |
return tokenfulSlotValue() | kTokenless; | |
} | |
bool slotValueIsThis(uintptr_t slotValue) { | |
return (slotValue & ~kTokenless) == tokenfulSlotValue(); | |
} | |
template <class WaitContext> | |
void applyDeferredReaders(uint32_t& state, WaitContext& ctx) { | |
uint32_t slot = 0; | |
uint32_t spinCount = 0; | |
const uint32_t maxDeferredReaders = | |
shared_mutex_detail::getMaxDeferredReaders(); | |
while (true) { | |
while (!slotValueIsThis( | |
deferredReader(slot)->load(std::memory_order_acquire))) { | |
if (++slot == maxDeferredReaders) { | |
return; | |
} | |
} | |
asm_volatile_pause(); | |
if ((__builtin_expect((++spinCount >= kMaxSpinCount), 0))) { | |
applyDeferredReaders(state, ctx, slot); | |
return; | |
} | |
} | |
} | |
template <class WaitContext> | |
void applyDeferredReaders(uint32_t& state, | |
WaitContext& ctx, | |
uint32_t slot) { | |
struct rusage usage; | |
std::memset(&usage, 0, sizeof(usage)); | |
long before = -1; | |
const uint32_t maxDeferredReaders = | |
shared_mutex_detail::getMaxDeferredReaders(); | |
for (uint32_t yieldCount = 0; yieldCount < kMaxSoftYieldCount; | |
++yieldCount) { | |
for (int softState = 0; softState < 3; ++softState) { | |
if (softState < 2) { | |
std::this_thread::yield(); | |
} else { | |
getrusage(RUSAGE_THREAD, &usage); | |
} | |
while (!slotValueIsThis(deferredReader(slot)->load( | |
std::memory_order_acquire))) { | |
if (++slot == maxDeferredReaders) { | |
return; | |
} | |
} | |
if (ctx.shouldTimeOut()) { | |
break; | |
} | |
} | |
if (before >= 0 && usage.ru_nivcsw >= before + 2) { | |
break; | |
} | |
before = usage.ru_nivcsw; | |
} | |
uint32_t movedSlotCount = 0; | |
for (; slot < maxDeferredReaders; ++slot) { | |
auto slotPtr = deferredReader(slot); | |
auto slotValue = slotPtr->load(std::memory_order_acquire); | |
if (slotValueIsThis(slotValue) && | |
slotPtr->compare_exchange_strong(slotValue, 0)) { | |
++movedSlotCount; | |
} | |
} | |
if (movedSlotCount > 0) { | |
state = (state_ += movedSlotCount * kIncrHasS); | |
} | |
(static_cast<bool>((state & (kHasE | kBegunE)) != 0) | |
? void(0) | |
: __assert_fail("(state & (kHasE | kBegunE)) != 0", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
1267, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(state < state + kIncrHasS) | |
? void(0) | |
: __assert_fail("state < state + kIncrHasS", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
1272, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
// # 1288 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 4 | |
template <class WaitContext> | |
bool lockSharedImpl(Token* token, WaitContext& ctx) { | |
uint32_t state = state_.load(std::memory_order_relaxed); | |
if ((state & (kHasS | kMayDefer | kHasE)) == 0 && | |
state_.compare_exchange_strong(state, state + kIncrHasS)) { | |
if (token != nullptr) { | |
token->type_ = Token::Type::INLINE_SHARED; | |
} | |
return true; | |
} | |
return lockSharedImpl(state, token, ctx); | |
} | |
template <class WaitContext> | |
bool lockSharedImpl(uint32_t& state, Token* token, WaitContext& ctx); | |
void cleanupTokenlessSharedDeferred(uint32_t& state) { | |
const uint32_t maxDeferredReaders = | |
shared_mutex_detail::getMaxDeferredReaders(); | |
for (uint32_t i = 0; i < maxDeferredReaders; ++i) { | |
auto slotPtr = deferredReader(i); | |
auto slotValue = slotPtr->load(std::memory_order_relaxed); | |
if (slotValue == tokenlessSlotValue()) { | |
slotPtr->store(0, std::memory_order_relaxed); | |
state += kIncrHasS; | |
if ((state & kHasS) == 0) { | |
break; | |
} | |
} | |
} | |
} | |
bool tryUnlockTokenlessSharedDeferred(); | |
bool tryUnlockSharedDeferred(uint32_t slot) { | |
(static_cast<bool>(slot < shared_mutex_detail::getMaxDeferredReaders()) | |
? void(0) | |
: __assert_fail("slot < " | |
"shared_mutex_detail::getMaxDeferredReaders()", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
1325, | |
__extension__ __PRETTY_FUNCTION__)); | |
auto slotValue = tokenfulSlotValue(); | |
return deferredReader(slot)->compare_exchange_strong(slotValue, 0); | |
} | |
uint32_t unlockSharedInline() { | |
uint32_t state = (state_ -= kIncrHasS); | |
(static_cast<bool>((state & (kHasE | kBegunE | kMayDefer)) != 0 || | |
state < state + kIncrHasS) | |
? void(0) | |
: __assert_fail("(state & (kHasE | kBegunE | kMayDefer)) != 0 " | |
"|| state < state + kIncrHasS", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
1332, | |
__extension__ __PRETTY_FUNCTION__)) | |
; | |
if ((state & kHasS) == 0) { | |
wakeRegisteredWaiters(state, kWaitingNotS); | |
} | |
return state; | |
} | |
template <class WaitContext> | |
bool lockUpgradeImpl(WaitContext& ctx) { | |
uint32_t state; | |
do { | |
if (!waitForZeroBits(state, kHasSolo, kWaitingU, ctx)) { | |
return false; | |
} | |
} while (!state_.compare_exchange_strong(state, state | kHasU)); | |
return true; | |
} | |
public: | |
class [[nodiscard]] ReadHolder { | |
ReadHolder() : lock_(nullptr) { | |
} | |
public: | |
explicit ReadHolder(const SharedMutexImpl* lock) | |
: lock_(const_cast<SharedMutexImpl*>(lock)) { | |
if (lock_) { | |
lock_->lock_shared(token_); | |
} | |
} | |
explicit ReadHolder(const SharedMutexImpl& lock) | |
: lock_(const_cast<SharedMutexImpl*>(&lock)) { | |
lock_->lock_shared(token_); | |
} | |
ReadHolder(ReadHolder && rhs) noexcept | |
: lock_(rhs.lock_), token_(rhs.token_) { | |
rhs.lock_ = nullptr; | |
} | |
explicit ReadHolder(UpgradeHolder && upgraded) : lock_(upgraded.lock_) { | |
(static_cast<bool>(upgraded.lock_ != nullptr) | |
? void(0) | |
: __assert_fail("upgraded.lock_ != nullptr", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
1378, | |
__extension__ __PRETTY_FUNCTION__)); | |
upgraded.lock_ = nullptr; | |
lock_->unlock_upgrade_and_lock_shared(token_); | |
} | |
explicit ReadHolder(WriteHolder && writer) : lock_(writer.lock_) { | |
(static_cast<bool>(writer.lock_ != nullptr) | |
? void(0) | |
: __assert_fail("writer.lock_ != nullptr", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
1385, | |
__extension__ __PRETTY_FUNCTION__)); | |
writer.lock_ = nullptr; | |
lock_->unlock_and_lock_shared(token_); | |
} | |
ReadHolder& operator=(ReadHolder&& rhs) noexcept { | |
std::swap(lock_, rhs.lock_); | |
std::swap(token_, rhs.token_); | |
return *this; | |
} | |
ReadHolder(const ReadHolder& rhs) = delete; | |
ReadHolder& operator=(const ReadHolder& rhs) = delete; | |
~ReadHolder() { | |
unlock(); | |
} | |
void unlock() { | |
if (lock_) { | |
lock_->unlock_shared(token_); | |
lock_ = nullptr; | |
} | |
} | |
private: | |
friend class UpgradeHolder; | |
friend class WriteHolder; | |
SharedMutexImpl* lock_; | |
SharedMutexToken token_; | |
}; | |
class [[nodiscard]] UpgradeHolder { | |
UpgradeHolder() : lock_(nullptr) { | |
} | |
public: | |
explicit UpgradeHolder(SharedMutexImpl * lock) : lock_(lock) { | |
if (lock_) { | |
lock_->lock_upgrade(); | |
} | |
} | |
explicit UpgradeHolder(SharedMutexImpl & lock) : lock_(&lock) { | |
lock_->lock_upgrade(); | |
} | |
explicit UpgradeHolder(WriteHolder && writer) : lock_(writer.lock_) { | |
(static_cast<bool>(writer.lock_ != nullptr) | |
? void(0) | |
: __assert_fail("writer.lock_ != nullptr", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
1433, | |
__extension__ __PRETTY_FUNCTION__)); | |
writer.lock_ = nullptr; | |
lock_->unlock_and_lock_upgrade(); | |
} | |
UpgradeHolder(UpgradeHolder && rhs) noexcept : lock_(rhs.lock_) { | |
rhs.lock_ = nullptr; | |
} | |
UpgradeHolder& operator=(UpgradeHolder&& rhs) noexcept { | |
std::swap(lock_, rhs.lock_); | |
return *this; | |
} | |
UpgradeHolder(const UpgradeHolder& rhs) = delete; | |
UpgradeHolder& operator=(const UpgradeHolder& rhs) = delete; | |
~UpgradeHolder() { | |
unlock(); | |
} | |
void unlock() { | |
if (lock_) { | |
lock_->unlock_upgrade(); | |
lock_ = nullptr; | |
} | |
} | |
private: | |
friend class WriteHolder; | |
friend class ReadHolder; | |
SharedMutexImpl* lock_; | |
}; | |
class [[nodiscard]] WriteHolder { | |
WriteHolder() : lock_(nullptr) { | |
} | |
public: | |
explicit WriteHolder(SharedMutexImpl * lock) : lock_(lock) { | |
if (lock_) { | |
lock_->lock(); | |
} | |
} | |
explicit WriteHolder(SharedMutexImpl & lock) : lock_(&lock) { | |
lock_->lock(); | |
} | |
explicit WriteHolder(UpgradeHolder && upgrade) : lock_(upgrade.lock_) { | |
(static_cast<bool>(upgrade.lock_ != nullptr) | |
? void(0) | |
: __assert_fail("upgrade.lock_ != nullptr", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
1483, | |
__extension__ __PRETTY_FUNCTION__)); | |
upgrade.lock_ = nullptr; | |
lock_->unlock_upgrade_and_lock(); | |
} | |
// # 1512 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 4 | |
WriteHolder(WriteHolder && rhs) noexcept : lock_(rhs.lock_) { | |
rhs.lock_ = nullptr; | |
} | |
WriteHolder& operator=(WriteHolder&& rhs) noexcept { | |
std::swap(lock_, rhs.lock_); | |
return *this; | |
} | |
WriteHolder(const WriteHolder& rhs) = delete; | |
WriteHolder& operator=(const WriteHolder& rhs) = delete; | |
~WriteHolder() { | |
unlock(); | |
} | |
void unlock() { | |
if (lock_) { | |
lock_->unlock(); | |
lock_ = nullptr; | |
} | |
} | |
private: | |
friend class ReadHolder; | |
friend class UpgradeHolder; | |
SharedMutexImpl* lock_; | |
}; | |
friend void acquireRead(SharedMutexImpl& lock) { | |
lock.lock_shared(); | |
} | |
friend void acquireReadWrite(SharedMutexImpl& lock) { | |
lock.lock(); | |
} | |
friend void releaseRead(SharedMutexImpl& lock) { | |
lock.unlock_shared(); | |
} | |
friend void releaseReadWrite(SharedMutexImpl& lock) { | |
lock.unlock(); | |
} | |
friend bool acquireRead(SharedMutexImpl& lock, unsigned int ms) { | |
return lock.try_lock_shared_for(std::chrono::milliseconds(ms)); | |
} | |
friend bool acquireReadWrite(SharedMutexImpl& lock, unsigned int ms) { | |
return lock.try_lock_for(std::chrono::milliseconds(ms)); | |
} | |
}; | |
typedef SharedMutexImpl<true> SharedMutexReadPriority; | |
typedef SharedMutexImpl<false> SharedMutexWritePriority; | |
typedef SharedMutexWritePriority SharedMutex; | |
typedef SharedMutexImpl<false, void, std::atomic, false, false> | |
SharedMutexSuppressTSAN; | |
extern template class SharedMutexImpl<true>; | |
extern template class SharedMutexImpl<false>; | |
template <bool ReaderPriority, | |
typename Tag_, | |
template <typename> | |
class Atom, | |
bool BlockImmediately, | |
bool AnnotateForThreadSanitizer> | |
alignas(hardware_destructive_interference_size) | |
typename SharedMutexImpl<ReaderPriority, | |
Tag_, | |
Atom, | |
BlockImmediately, | |
AnnotateForThreadSanitizer>::DeferredReaderSlot | |
SharedMutexImpl<ReaderPriority, | |
Tag_, | |
Atom, | |
BlockImmediately, | |
AnnotateForThreadSanitizer>::deferredReaders | |
[shared_mutex_detail::kMaxDeferredReadersAllocated * | |
kDeferredSeparationFactor] = {}; | |
template <bool ReaderPriority, | |
typename Tag_, | |
template <typename> | |
class Atom, | |
bool BlockImmediately, | |
bool AnnotateForThreadSanitizer> | |
__thread uint32_t | |
SharedMutexImpl<ReaderPriority, | |
Tag_, | |
Atom, | |
BlockImmediately, | |
AnnotateForThreadSanitizer>::tls_lastTokenlessSlot = 0; | |
template <bool ReaderPriority, | |
typename Tag_, | |
template <typename> | |
class Atom, | |
bool BlockImmediately, | |
bool AnnotateForThreadSanitizer> | |
__thread uint32_t SharedMutexImpl< | |
ReaderPriority, | |
Tag_, | |
Atom, | |
BlockImmediately, | |
AnnotateForThreadSanitizer>::tls_lastDeferredReaderSlot = 0; | |
template <bool ReaderPriority, | |
typename Tag_, | |
template <typename> | |
class Atom, | |
bool BlockImmediately, | |
bool AnnotateForThreadSanitizer> | |
bool SharedMutexImpl< | |
ReaderPriority, | |
Tag_, | |
Atom, | |
BlockImmediately, | |
AnnotateForThreadSanitizer>::tryUnlockTokenlessSharedDeferred() { | |
auto bestSlot = make_atomic_ref(tls_lastTokenlessSlot) | |
.load(std::memory_order_relaxed); | |
uint32_t i = 0; | |
do { | |
auto slotPtr = deferredReader(bestSlot ^ i); | |
auto slotValue = slotPtr->load(std::memory_order_relaxed); | |
if (slotValue == tokenlessSlotValue() && | |
slotPtr->compare_exchange_strong(slotValue, 0)) { | |
make_atomic_ref(tls_lastTokenlessSlot) | |
.store(bestSlot ^ i, std::memory_order_relaxed); | |
return true; | |
} | |
++i; | |
} while (i < shared_mutex_detail::getMaxDeferredReaders()); | |
return false; | |
} | |
template <bool ReaderPriority, | |
typename Tag_, | |
template <typename> | |
class Atom, | |
bool BlockImmediately, | |
bool AnnotateForThreadSanitizer> | |
template <class WaitContext> | |
bool SharedMutexImpl< | |
ReaderPriority, | |
Tag_, | |
Atom, | |
BlockImmediately, | |
AnnotateForThreadSanitizer>::lockSharedImpl(uint32_t& state, | |
Token* token, | |
WaitContext& ctx) { | |
const uint32_t maxDeferredReaders = | |
shared_mutex_detail::getMaxDeferredReaders(); | |
while (true) { | |
if ((__builtin_expect(((state & kHasE) != 0), 0)) && | |
!waitForZeroBits(state, kHasE, kWaitingS, ctx) && | |
ctx.canTimeOut()) { | |
return false; | |
} | |
uint32_t slot = make_atomic_ref(tls_lastDeferredReaderSlot) | |
.load(std::memory_order_relaxed); | |
uintptr_t slotValue = 1; | |
bool canAlreadyDefer = (state & kMayDefer) != 0; | |
bool aboveDeferThreshold = | |
(state & kHasS) >= (kNumSharedToStartDeferring - 1) * kIncrHasS; | |
bool drainInProgress = ReaderPriority && (state & kBegunE) != 0; | |
if (canAlreadyDefer || (aboveDeferThreshold && !drainInProgress)) { | |
slotValue = deferredReader(slot)->load(std::memory_order_relaxed); | |
if (slotValue != 0) { | |
uint32_t bestSlot = | |
(uint32_t)folly::AccessSpreader<Atom>::current( | |
maxDeferredReaders); | |
for (uint32_t i = 0; i < kDeferredSearchDistance; ++i) { | |
slot = bestSlot ^ i; | |
(static_cast<bool>(slot < maxDeferredReaders) | |
? void(0) | |
: __assert_fail( | |
"slot < maxDeferredReaders", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
1694, | |
__extension__ __PRETTY_FUNCTION__)); | |
slotValue = deferredReader(slot)->load( | |
std::memory_order_relaxed); | |
if (slotValue == 0) { | |
make_atomic_ref(tls_lastDeferredReaderSlot) | |
.store(slot, std::memory_order_relaxed); | |
break; | |
} | |
} | |
} | |
} | |
if (slotValue != 0) { | |
if (state_.compare_exchange_strong(state, state + kIncrHasS)) { | |
if (token != nullptr) { | |
token->type_ = Token::Type::INLINE_SHARED; | |
} | |
return true; | |
} | |
continue; | |
} | |
if ((state & kMayDefer) == 0) { | |
if (!state_.compare_exchange_strong(state, state | kMayDefer)) { | |
if ((state & (kHasE | kMayDefer)) != kMayDefer) { | |
continue; | |
} | |
} | |
} | |
bool gotSlot = deferredReader(slot)->compare_exchange_strong( | |
slotValue, | |
token == nullptr ? tokenlessSlotValue() : tokenfulSlotValue()); | |
// # 1743 "tlm/deps/folly.exploded/include/folly/SharedMutex.h" 3 4 | |
state = state_.load(std::memory_order_acquire); | |
if (!gotSlot) { | |
continue; | |
} | |
if (token == nullptr) { | |
make_atomic_ref(tls_lastTokenlessSlot) | |
.store(slot, std::memory_order_relaxed); | |
} | |
if ((state & kMayDefer) != 0) { | |
(static_cast<bool>((state & kHasE) == 0) | |
? void(0) | |
: __assert_fail("(state & kHasE) == 0", | |
"tlm/deps/folly.exploded/include/folly/" | |
"SharedMutex.h", | |
1755, | |
__extension__ __PRETTY_FUNCTION__)); | |
if (token != nullptr) { | |
token->type_ = Token::Type::DEFERRED_SHARED; | |
token->slot_ = (uint16_t)slot; | |
} | |
return true; | |
} | |
if (token == nullptr) { | |
if (!tryUnlockTokenlessSharedDeferred()) { | |
unlockSharedInline(); | |
} | |
} else { | |
if (!tryUnlockSharedDeferred(slot)) { | |
unlockSharedInline(); | |
} | |
} | |
} | |
} | |
} // namespace folly | |
// # 52 "tlm/deps/folly.exploded/include/folly/ThreadLocal.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 2 3 4 | |
// # 28 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 3 4 | |
// # 1 "tlm/deps/glog.exploded/include/glog/logging.h" 1 3 4 | |
// # 44 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
// # 45 "tlm/deps/glog.exploded/include/glog/logging.h" 2 3 4 | |
// # 89 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
namespace google { | |
typedef int32_t int32; | |
typedef uint32_t uint32; | |
typedef int64_t int64; | |
typedef uint64_t uint64; | |
// # 110 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
} // namespace google | |
// # 334 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
namespace fLB { | |
extern bool FLAGS_logtostderr; | |
} | |
using fLB::FLAGS_logtostderr; | |
namespace fLB { | |
extern bool FLAGS_alsologtostderr; | |
} | |
using fLB::FLAGS_alsologtostderr; | |
namespace fLB { | |
extern bool FLAGS_colorlogtostderr; | |
} | |
using fLB::FLAGS_colorlogtostderr; | |
namespace fLI { | |
extern google::int32 FLAGS_stderrthreshold; | |
} | |
using fLI::FLAGS_stderrthreshold; | |
namespace fLB { | |
extern bool FLAGS_log_prefix; | |
} | |
using fLB::FLAGS_log_prefix; | |
namespace fLI { | |
extern google::int32 FLAGS_logbuflevel; | |
} | |
using fLI::FLAGS_logbuflevel; | |
namespace fLI { | |
extern google::int32 FLAGS_logbufsecs; | |
} | |
using fLI::FLAGS_logbufsecs; | |
namespace fLI { | |
extern google::int32 FLAGS_minloglevel; | |
} | |
using fLI::FLAGS_minloglevel; | |
namespace fLS { | |
extern std::string& FLAGS_log_dir; | |
} | |
using fLS::FLAGS_log_dir; | |
namespace fLI { | |
extern google::int32 FLAGS_logfile_mode; | |
} | |
using fLI::FLAGS_logfile_mode; | |
namespace fLS { | |
extern std::string& FLAGS_log_link; | |
} | |
using fLS::FLAGS_log_link; | |
namespace fLI { | |
extern google::int32 FLAGS_v; | |
} | |
using fLI::FLAGS_v; | |
namespace fLI { | |
extern google::int32 FLAGS_max_log_size; | |
} | |
using fLI::FLAGS_max_log_size; | |
namespace fLB { | |
extern bool FLAGS_stop_logging_if_full_disk; | |
} | |
using fLB::FLAGS_stop_logging_if_full_disk; | |
// # 509 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
namespace google { | |
// # 1 "tlm/deps/glog.exploded/include/glog/log_severity.h" 1 3 4 | |
// # 45 "tlm/deps/glog.exploded/include/glog/log_severity.h" 3 4 | |
typedef int LogSeverity; | |
const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3, | |
NUM_SEVERITIES = 4; | |
// # 64 "tlm/deps/glog.exploded/include/glog/log_severity.h" 3 4 | |
extern const char* const LogSeverityNames[NUM_SEVERITIES]; | |
// # 88 "tlm/deps/glog.exploded/include/glog/log_severity.h" 3 4 | |
enum { DEBUG_MODE = 1 }; | |
// # 513 "tlm/deps/glog.exploded/include/glog/logging.h" 2 3 4 | |
// # 1 "tlm/deps/glog.exploded/include/glog/vlog_is_on.h" 1 3 4 | |
// # 104 "tlm/deps/glog.exploded/include/glog/vlog_is_on.h" 3 4 | |
extern int SetVLOGLevel(const char* module_pattern, int log_level); | |
extern google::int32 kLogSiteUninitialized; | |
// # 123 "tlm/deps/glog.exploded/include/glog/vlog_is_on.h" 3 4 | |
extern bool InitVLOG3__(google::int32** site_flag, | |
google::int32* site_default, | |
const char* fname, | |
google::int32 verbose_level); | |
// # 514 "tlm/deps/glog.exploded/include/glog/logging.h" 2 3 4 | |
void InitGoogleLogging(const char* argv0); | |
void ShutdownGoogleLogging(); | |
void InstallFailureFunction(void (*fail_func)()); | |
class LogSink; | |
// # 592 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
struct CheckOpString { | |
CheckOpString(std::string* str) : str_(str) { | |
} | |
operator bool() const { | |
return (__builtin_expect(str_ != __null, 0)); | |
} | |
std::string* str_; | |
}; | |
template <class T> | |
inline const T& GetReferenceableValue(const T& t) { | |
return t; | |
} | |
inline char GetReferenceableValue(char t) { | |
return t; | |
} | |
inline unsigned char GetReferenceableValue(unsigned char t) { | |
return t; | |
} | |
inline signed char GetReferenceableValue(signed char t) { | |
return t; | |
} | |
inline short GetReferenceableValue(short t) { | |
return t; | |
} | |
inline unsigned short GetReferenceableValue(unsigned short t) { | |
return t; | |
} | |
inline int GetReferenceableValue(int t) { | |
return t; | |
} | |
inline unsigned int GetReferenceableValue(unsigned int t) { | |
return t; | |
} | |
inline long GetReferenceableValue(long t) { | |
return t; | |
} | |
inline unsigned long GetReferenceableValue(unsigned long t) { | |
return t; | |
} | |
inline long long GetReferenceableValue(long long t) { | |
return t; | |
} | |
inline unsigned long long GetReferenceableValue(unsigned long long t) { | |
return t; | |
} | |
struct DummyClassToDefineOperator {}; | |
} // namespace google | |
inline std::ostream& operator<<(std::ostream& out, | |
const google::DummyClassToDefineOperator&) { | |
return out; | |
} | |
namespace google { | |
template <typename T> | |
inline void MakeCheckOpValueString(std::ostream* os, const T& v) { | |
(*os) << v; | |
} | |
template <> | |
void MakeCheckOpValueString(std::ostream* os, const char& v); | |
template <> | |
void MakeCheckOpValueString(std::ostream* os, const signed char& v); | |
template <> | |
void MakeCheckOpValueString(std::ostream* os, const unsigned char& v); | |
template <typename T1, typename T2> | |
std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) | |
__attribute__((noinline)); | |
namespace base { | |
namespace internal { | |
LogSeverity NormalizeSeverity(LogSeverity s); | |
} | |
class CheckOpMessageBuilder { | |
public: | |
explicit CheckOpMessageBuilder(const char* exprtext); | |
~CheckOpMessageBuilder(); | |
std::ostream* ForVar1() { | |
return stream_; | |
} | |
std::ostream* ForVar2(); | |
std::string* NewString(); | |
private: | |
std::ostringstream* stream_; | |
}; | |
} // namespace base | |
template <typename T1, typename T2> | |
std::string* MakeCheckOpString(const T1& v1, | |
const T2& v2, | |
const char* exprtext) { | |
base::CheckOpMessageBuilder comb(exprtext); | |
MakeCheckOpValueString(comb.ForVar1(), v1); | |
MakeCheckOpValueString(comb.ForVar2(), v2); | |
return comb.NewString(); | |
} | |
// # 719 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
template <typename T1, typename T2> | |
inline std::string* Check_EQImpl(const T1& v1, | |
const T2& v2, | |
const char* exprtext) { | |
if ((__builtin_expect(!!(v1 == v2), 1))) | |
return __null; | |
else | |
return MakeCheckOpString(v1, v2, exprtext); | |
} | |
inline std::string* Check_EQImpl(int v1, int v2, const char* exprtext) { | |
return Check_EQImpl<int, int>(v1, v2, exprtext); | |
} | |
template <typename T1, typename T2> | |
inline std::string* Check_NEImpl(const T1& v1, | |
const T2& v2, | |
const char* exprtext) { | |
if ((__builtin_expect(!!(v1 != v2), 1))) | |
return __null; | |
else | |
return MakeCheckOpString(v1, v2, exprtext); | |
} | |
inline std::string* Check_NEImpl(int v1, int v2, const char* exprtext) { | |
return Check_NEImpl<int, int>(v1, v2, exprtext); | |
} | |
template <typename T1, typename T2> | |
inline std::string* Check_LEImpl(const T1& v1, | |
const T2& v2, | |
const char* exprtext) { | |
if ((__builtin_expect(!!(v1 <= v2), 1))) | |
return __null; | |
else | |
return MakeCheckOpString(v1, v2, exprtext); | |
} | |
inline std::string* Check_LEImpl(int v1, int v2, const char* exprtext) { | |
return Check_LEImpl<int, int>(v1, v2, exprtext); | |
} | |
template <typename T1, typename T2> | |
inline std::string* Check_LTImpl(const T1& v1, | |
const T2& v2, | |
const char* exprtext) { | |
if ((__builtin_expect(!!(v1 < v2), 1))) | |
return __null; | |
else | |
return MakeCheckOpString(v1, v2, exprtext); | |
} | |
inline std::string* Check_LTImpl(int v1, int v2, const char* exprtext) { | |
return Check_LTImpl<int, int>(v1, v2, exprtext); | |
} | |
template <typename T1, typename T2> | |
inline std::string* Check_GEImpl(const T1& v1, | |
const T2& v2, | |
const char* exprtext) { | |
if ((__builtin_expect(!!(v1 >= v2), 1))) | |
return __null; | |
else | |
return MakeCheckOpString(v1, v2, exprtext); | |
} | |
inline std::string* Check_GEImpl(int v1, int v2, const char* exprtext) { | |
return Check_GEImpl<int, int>(v1, v2, exprtext); | |
} | |
template <typename T1, typename T2> | |
inline std::string* Check_GTImpl(const T1& v1, | |
const T2& v2, | |
const char* exprtext) { | |
if ((__builtin_expect(!!(v1 > v2), 1))) | |
return __null; | |
else | |
return MakeCheckOpString(v1, v2, exprtext); | |
} | |
inline std::string* Check_GTImpl(int v1, int v2, const char* exprtext) { | |
return Check_GTImpl<int, int>(v1, v2, exprtext); | |
} | |
// # 743 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
typedef std::string _Check_string; | |
// # 808 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
std::string* CheckstrcmptrueImpl(const char* s1, | |
const char* s2, | |
const char* names); | |
std::string* CheckstrcmpfalseImpl(const char* s1, | |
const char* s2, | |
const char* names); | |
std::string* CheckstrcasecmptrueImpl(const char* s1, | |
const char* s2, | |
const char* names); | |
std::string* CheckstrcasecmpfalseImpl(const char* s1, | |
const char* s2, | |
const char* names); | |
// # 930 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
namespace glog_internal_namespace_ { | |
template <bool> | |
struct CompileAssert {}; | |
struct CrashReason; | |
bool IsFailureSignalHandlerInstalled(); | |
} // namespace glog_internal_namespace_ | |
// # 957 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
enum PRIVATE_Counter { COUNTER }; | |
// # 968 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
const LogSeverity GLOG_0 = GLOG_ERROR; | |
// # 1109 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
namespace base_logging { | |
class LogStreamBuf : public std::streambuf { | |
public: | |
LogStreamBuf(char* buf, int len) { | |
setp(buf, buf + len - 2); | |
} | |
virtual int_type overflow(int_type ch) { | |
return ch; | |
} | |
size_t pcount() const { | |
return pptr() - pbase(); | |
} | |
char* pbase() const { | |
return std::streambuf::pbase(); | |
} | |
}; | |
} // namespace base_logging | |
// # 1142 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
class LogMessage { | |
public: | |
enum { | |
kNoLogPrefix = -1 | |
}; | |
class LogStream : public std::ostream { | |
public: | |
LogStream(char* buf, int len, int ctr) | |
: std::ostream(__null), | |
streambuf_(buf, len), | |
ctr_(ctr), | |
self_(this) { | |
rdbuf(&streambuf_); | |
} | |
int ctr() const { | |
return ctr_; | |
} | |
void set_ctr(int ctr) { | |
ctr_ = ctr; | |
} | |
LogStream* self() const { | |
return self_; | |
} | |
size_t pcount() const { | |
return streambuf_.pcount(); | |
} | |
char* pbase() const { | |
return streambuf_.pbase(); | |
} | |
char* str() const { | |
return pbase(); | |
} | |
private: | |
LogStream(const LogStream&); | |
LogStream& operator=(const LogStream&); | |
base_logging::LogStreamBuf streambuf_; | |
int ctr_; | |
LogStream* self_; | |
}; | |
public: | |
typedef void (LogMessage::*SendMethod)(); | |
LogMessage(const char* file, | |
int line, | |
LogSeverity severity, | |
int ctr, | |
SendMethod send_method); | |
// # 1203 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
LogMessage(const char* file, int line); | |
LogMessage(const char* file, int line, LogSeverity severity); | |
LogMessage(const char* file, | |
int line, | |
LogSeverity severity, | |
LogSink* sink, | |
bool also_send_to_log); | |
LogMessage(const char* file, | |
int line, | |
LogSeverity severity, | |
std::vector<std::string>* outvec); | |
LogMessage(const char* file, | |
int line, | |
LogSeverity severity, | |
std::string* message); | |
LogMessage(const char* file, int line, const CheckOpString& result); | |
~LogMessage(); | |
void Flush(); | |
static const size_t kMaxLogMessageLen; | |
void SendToLog(); | |
void SendToSyslogAndLog(); | |
static void __attribute__((noreturn)) Fail(); | |
std::ostream& stream(); | |
int preserved_errno() const; | |
static int64 num_messages(int severity); | |
struct LogMessageData; | |
private: | |
void SendToSinkAndLog(); | |
void SendToSink(); | |
void WriteToStringAndLog(); | |
void SaveOrSendToLog(); | |
void Init(const char* file, | |
int line, | |
LogSeverity severity, | |
void (LogMessage::*send_method)()); | |
void RecordCrashReason(glog_internal_namespace_::CrashReason* reason); | |
static int64 num_messages_[NUM_SEVERITIES]; | |
LogMessageData* allocated_; | |
LogMessageData* data_; | |
friend class LogDestination; | |
LogMessage(const LogMessage&); | |
void operator=(const LogMessage&); | |
}; | |
class LogMessageFatal : public LogMessage { | |
public: | |
LogMessageFatal(const char* file, int line); | |
LogMessageFatal(const char* file, int line, const CheckOpString& result); | |
__attribute__((noreturn)) ~LogMessageFatal(); | |
}; | |
inline void LogAtLevel(int const severity, std::string const& msg) { | |
LogMessage("tlm/deps/glog.exploded/include/glog/logging.h", 1304, severity) | |
.stream() | |
<< msg; | |
} | |
// # 1332 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
template <typename T> | |
T CheckNotNull(const char* file, int line, const char* names, T&& t) { | |
if (t == nullptr) { | |
LogMessageFatal(file, line, new std::string(names)); | |
} | |
return std::forward<T>(t); | |
} | |
// # 1355 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
std::ostream& operator<<(std::ostream& os, const PRIVATE_Counter&); | |
class ErrnoLogMessage : public LogMessage { | |
public: | |
ErrnoLogMessage(const char* file, | |
int line, | |
LogSeverity severity, | |
int ctr, | |
void (LogMessage::*send_method)()); | |
~ErrnoLogMessage(); | |
private: | |
ErrnoLogMessage(const ErrnoLogMessage&); | |
void operator=(const ErrnoLogMessage&); | |
}; | |
class LogMessageVoidify { | |
public: | |
LogMessageVoidify() { | |
} | |
void operator&(std::ostream&) { | |
} | |
}; | |
void FlushLogFiles(LogSeverity min_severity); | |
void FlushLogFilesUnsafe(LogSeverity min_severity); | |
void SetLogDestination(LogSeverity severity, const char* base_filename); | |
void SetLogSymlink(LogSeverity severity, const char* symlink_basename); | |
class LogSink { | |
public: | |
virtual ~LogSink(); | |
virtual void send(LogSeverity severity, | |
const char* full_filename, | |
const char* base_filename, | |
int line, | |
const struct ::tm* tm_time, | |
const char* message, | |
size_t message_len) = 0; | |
// # 1444 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
virtual void WaitTillSent(); | |
static std::string ToString(LogSeverity severity, | |
const char* file, | |
int line, | |
const struct ::tm* tm_time, | |
const char* message, | |
size_t message_len); | |
}; | |
void AddLogSink(LogSink* destination); | |
void RemoveLogSink(LogSink* destination); | |
void SetLogFilenameExtension(const char* filename_extension); | |
void SetStderrLogging(LogSeverity min_severity); | |
void LogToStderr(); | |
void SetEmailLogging(LogSeverity min_severity, const char* addresses); | |
bool SendEmail(const char* dest, const char* subject, const char* body); | |
const std::vector<std::string>& GetLoggingDirectories(); | |
void TestOnly_ClearLoggingDirectoriesList(); | |
void GetExistingTempDirectories(std::vector<std::string>* list); | |
void ReprintFatalMessage(); | |
// # 1517 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
void TruncateLogFile(const char* path, int64 limit, int64 keep); | |
void TruncateStdoutStderr(); | |
const char* GetLogSeverityName(LogSeverity severity); | |
// # 1540 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
namespace base { | |
class Logger { | |
public: | |
virtual ~Logger(); | |
// # 1554 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
virtual void Write(bool force_flush, | |
time_t timestamp, | |
const char* message, | |
int message_len) = 0; | |
virtual void Flush() = 0; | |
virtual uint32 LogSize() = 0; | |
}; | |
extern Logger* GetLogger(LogSeverity level); | |
extern void SetLogger(LogSeverity level, Logger* logger); | |
} // namespace base | |
// # 1591 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
int posix_strerror_r(int err, char* buf, size_t len); | |
std::string StrError(int err); | |
class NullStream : public LogMessage::LogStream { | |
public: | |
NullStream() : LogMessage::LogStream(message_buffer_, 1, 0) { | |
} | |
NullStream(const char*, int, const CheckOpString&) | |
: LogMessage::LogStream(message_buffer_, 1, 0) { | |
} | |
NullStream& stream() { | |
return *this; | |
} | |
private: | |
char message_buffer_[2]; | |
}; | |
template <class T> | |
inline NullStream& operator<<(NullStream& str, const T&) { | |
return str; | |
} | |
class NullStreamFatal : public NullStream { | |
public: | |
NullStreamFatal() { | |
} | |
NullStreamFatal(const char* file, int line, const CheckOpString& result) | |
: NullStream(file, line, result) { | |
} | |
__attribute__((noreturn)) ~NullStreamFatal() throw() { | |
_exit(1); | |
} | |
}; | |
// # 1651 "tlm/deps/glog.exploded/include/glog/logging.h" 3 4 | |
void InstallFailureSignalHandler(); | |
void InstallFailureWriter(void (*writer)(const char* data, int size)); | |
} // namespace google | |
// # 29 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Exception.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/Exception.h" 3 4 | |
// # 22 "tlm/deps/folly.exploded/include/folly/Exception.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Conv.h" 1 3 4 | |
// # 100 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
// # 104 "tlm/deps/folly.exploded/include/folly/Conv.h" 2 3 4 | |
// # 105 "tlm/deps/folly.exploded/include/folly/Conv.h" 2 3 4 | |
// # 106 "tlm/deps/folly.exploded/include/folly/Conv.h" 2 3 4 | |
// # 114 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
// # 1 | |
// "tlm/deps/double-conversion.exploded/include/double-conversion/double-conversion.h" | |
// 1 3 4 # 31 | |
// "tlm/deps/double-conversion.exploded/include/double-conversion/double-conversion.h" | |
// 3 4 # 1 | |
// "tlm/deps/double-conversion.exploded/include/double-conversion/utils.h" 1 3 4 | |
// # 31 "tlm/deps/double-conversion.exploded/include/double-conversion/utils.h" | |
// 3 4 # 32 | |
// "tlm/deps/double-conversion.exploded/include/double-conversion/utils.h" 2 3 4 | |
// # 35 "tlm/deps/double-conversion.exploded/include/double-conversion/utils.h" | |
// 2 3 4 # 119 | |
// "tlm/deps/double-conversion.exploded/include/double-conversion/utils.h" 3 4 | |
typedef uint16_t uc16; | |
// # 157 "tlm/deps/double-conversion.exploded/include/double-conversion/utils.h" | |
// 3 4 | |
namespace double_conversion { | |
static const int kCharSize = sizeof(char); | |
template <typename T> | |
static T Max(T a, T b) { | |
return a < b ? b : a; | |
} | |
template <typename T> | |
static T Min(T a, T b) { | |
return a < b ? a : b; | |
} | |
inline int StrLength(const char* string) { | |
size_t length = strlen(string); | |
(static_cast<bool>(length == static_cast<size_t>(static_cast<int>(length))) | |
? void(0) | |
: __assert_fail("length == " | |
"static_cast<size_t>(static_cast<int>(length))", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
177, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
return static_cast<int>(length); | |
} | |
template <typename T> | |
class Vector { | |
public: | |
Vector() : start_(__null), length_(0) { | |
} | |
Vector(T* data, int len) : start_(data), length_(len) { | |
(static_cast<bool>(len == 0 || (len > 0 && data != __null)) | |
? void(0) | |
: __assert_fail("len == 0 || (len > 0 && data != __null)", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
187, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
} | |
Vector<T> SubVector(int from, int to) { | |
(static_cast<bool>(to <= length_) | |
? void(0) | |
: __assert_fail("to <= length_", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
193, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
(static_cast<bool>(from < to) | |
? void(0) | |
: __assert_fail("from < to", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
194, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
(static_cast<bool>(0 <= from) | |
? void(0) | |
: __assert_fail("0 <= from", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
195, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
return Vector<T>(start() + from, to - from); | |
} | |
int length() const { | |
return length_; | |
} | |
bool is_empty() const { | |
return length_ == 0; | |
} | |
T* start() const { | |
return start_; | |
} | |
T& operator[](int index) const { | |
(static_cast<bool>(0 <= index && index < length_) | |
? void(0) | |
: __assert_fail("0 <= index && index < length_", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
210, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
return start_[index]; | |
} | |
T& first() { | |
return start_[0]; | |
} | |
T& last() { | |
return start_[length_ - 1]; | |
} | |
private: | |
T* start_; | |
int length_; | |
}; | |
class StringBuilder { | |
public: | |
StringBuilder(char* buffer, int buffer_size) | |
: buffer_(buffer, buffer_size), position_(0) { | |
} | |
~StringBuilder() { | |
if (!is_finalized()) | |
Finalize(); | |
} | |
int size() const { | |
return buffer_.length(); | |
} | |
int position() const { | |
(static_cast<bool>(!is_finalized()) | |
? void(0) | |
: __assert_fail("!is_finalized()", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
238, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
return position_; | |
} | |
void Reset() { | |
position_ = 0; | |
} | |
void AddCharacter(char c) { | |
(static_cast<bool>(c != '\0') | |
? void(0) | |
: __assert_fail("c != '\\0'", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
249, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
(static_cast<bool>(!is_finalized() && position_ < buffer_.length()) | |
? void(0) | |
: __assert_fail( | |
"!is_finalized() && position_ < buffer_.length()", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
250, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
buffer_[position_++] = c; | |
} | |
void AddString(const char* s) { | |
AddSubstring(s, StrLength(s)); | |
} | |
void AddSubstring(const char* s, int n) { | |
(static_cast<bool>(!is_finalized() && position_ + n < buffer_.length()) | |
? void(0) | |
: __assert_fail("!is_finalized() && position_ + n < " | |
"buffer_.length()", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
263, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
(static_cast<bool>(static_cast<size_t>(n) <= strlen(s)) | |
? void(0) | |
: __assert_fail("static_cast<size_t>(n) <= strlen(s)", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
264, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
memmove(&buffer_[position_], s, n * kCharSize); | |
position_ += n; | |
} | |
void AddPadding(char c, int count) { | |
for (int i = 0; i < count; i++) { | |
AddCharacter(c); | |
} | |
} | |
char* Finalize() { | |
(static_cast<bool>(!is_finalized() && position_ < buffer_.length()) | |
? void(0) | |
: __assert_fail( | |
"!is_finalized() && position_ < buffer_.length()", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
280, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
buffer_[position_] = '\0'; | |
(static_cast<bool>(strlen(buffer_.start()) == | |
static_cast<size_t>(position_)) | |
? void(0) | |
: __assert_fail("strlen(buffer_.start()) == " | |
"static_cast<size_t>(position_)", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
284, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
position_ = -1; | |
(static_cast<bool>(is_finalized()) | |
? void(0) | |
: __assert_fail("is_finalized()", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/utils.h", | |
286, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
return buffer_.start(); | |
} | |
private: | |
Vector<char> buffer_; | |
int position_; | |
bool is_finalized() const { | |
return position_ < 0; | |
} | |
StringBuilder(); | |
StringBuilder(const StringBuilder&); | |
void operator=(const StringBuilder&); | |
}; | |
// # 323 "tlm/deps/double-conversion.exploded/include/double-conversion/utils.h" | |
// 3 4 | |
template <class Dest, class Source> | |
inline Dest BitCast(const Source& source) { | |
__attribute__((unused)) typedef char | |
VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]; | |
Dest dest; | |
memmove(&dest, &source, sizeof(dest)); | |
return dest; | |
} | |
template <class Dest, class Source> | |
inline Dest BitCast(Source* source) { | |
return BitCast<Dest>(reinterpret_cast<uintptr_t>(source)); | |
} | |
} // namespace double_conversion | |
// # 32 | |
// "tlm/deps/double-conversion.exploded/include/double-conversion/double-conversion.h" | |
// 2 3 4 | |
namespace double_conversion { | |
class DoubleToStringConverter { | |
public: | |
static const int kMaxFixedDigitsBeforePoint = 60; | |
static const int kMaxFixedDigitsAfterPoint = 60; | |
static const int kMaxExponentialDigits = 120; | |
static const int kMinPrecisionDigits = 1; | |
static const int kMaxPrecisionDigits = 120; | |
enum Flags { | |
NO_FLAGS = 0, | |
EMIT_POSITIVE_EXPONENT_SIGN = 1, | |
EMIT_TRAILING_DECIMAL_POINT = 2, | |
EMIT_TRAILING_ZERO_AFTER_POINT = 4, | |
UNIQUE_ZERO = 8 | |
}; | |
// # 107 | |
// "tlm/deps/double-conversion.exploded/include/double-conversion/double-conversion.h" | |
// 3 4 | |
DoubleToStringConverter(int flags, | |
const char* infinity_symbol, | |
const char* nan_symbol, | |
char exponent_character, | |
int decimal_in_shortest_low, | |
int decimal_in_shortest_high, | |
int max_leading_padding_zeroes_in_precision_mode, | |
int max_trailing_padding_zeroes_in_precision_mode) | |
: flags_(flags), | |
infinity_symbol_(infinity_symbol), | |
nan_symbol_(nan_symbol), | |
exponent_character_(exponent_character), | |
decimal_in_shortest_low_(decimal_in_shortest_low), | |
decimal_in_shortest_high_(decimal_in_shortest_high), | |
max_leading_padding_zeroes_in_precision_mode_( | |
max_leading_padding_zeroes_in_precision_mode), | |
max_trailing_padding_zeroes_in_precision_mode_( | |
max_trailing_padding_zeroes_in_precision_mode) { | |
(static_cast<bool>(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) || | |
!((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0)) | |
? void(0) | |
: __assert_fail( | |
"((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) || " | |
"!((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0)", | |
"tlm/deps/double-conversion.exploded/include/" | |
"double-conversion/double-conversion.h", | |
127, | |
__extension__ __PRETTY_FUNCTION__)); | |
; | |
} | |
static const DoubleToStringConverter& EcmaScriptConverter(); | |
// # 157 | |
// "tlm/deps/double-conversion.exploded/include/double-conversion/double-conversion.h" | |
// 3 4 | |
bool ToShortest(double value, StringBuilder* result_builder) const { | |
return ToShortestIeeeNumber(value, result_builder, SHORTEST); | |
} | |
bool ToShortestSingle(float value, StringBuilder* result_builder) const { | |
return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE); | |
} | |
// # 200 | |
// "tlm/deps/double-conversion.exploded/include/double-conversion/double-conversion.h" | |
// 3 4 | |
bool ToFixed(double value, | |
int requested_digits, | |
StringBuilder* result_builder) const; | |
// # 232 | |
// "tlm/deps/double-conversion.exploded/include/double-conversion/double-conversion.h" | |
// 3 4 | |
bool ToExponential(double value, | |
int requested_digits, | |
StringBuilder* result_builder) const; | |
// # 270 | |
// "tlm/deps/double-conversion.exploded/include/double-conversion/double-conversion.h" | |
// 3 4 | |
bool ToPrecision(double value, | |
int precision, | |
StringBuilder* result_builder) const; | |
enum DtoaMode { | |
SHORTEST, | |
SHORTEST_SINGLE, | |
FIXED, | |
PRECISION | |
}; | |
static const int kBase10MaximalLength = 17; | |
// # 335 | |
// "tlm/deps/double-conversion.exploded/include/double-conversion/double-conversion.h" | |
// 3 4 | |
static void DoubleToAscii(double v, | |
DtoaMode mode, | |
int requested_digits, | |
char* buffer, | |
int buffer_length, | |
bool* sign, | |
int* length, | |
int* point); | |
private: | |
bool ToShortestIeeeNumber(double value, | |
StringBuilder* result_builder, | |
DtoaMode mode) const; | |
bool HandleSpecialValues(double value, StringBuilder* result_builder) const; | |
void CreateExponentialRepresentation(const char* decimal_digits, | |
int length, | |
int exponent, | |
StringBuilder* result_builder) const; | |
void CreateDecimalRepresentation(const char* decimal_digits, | |
int length, | |
int decimal_point, | |
int digits_after_point, | |
StringBuilder* result_builder) const; | |
const int flags_; | |
const char* const infinity_symbol_; | |
const char* const nan_symbol_; | |
const char exponent_character_; | |
const int decimal_in_shortest_low_; | |
const int decimal_in_shortest_high_; | |
const int max_leading_padding_zeroes_in_precision_mode_; | |
const int max_trailing_padding_zeroes_in_precision_mode_; | |
DoubleToStringConverter(); | |
DoubleToStringConverter(const DoubleToStringConverter&); | |
void operator=(const DoubleToStringConverter&); | |
}; | |
class StringToDoubleConverter { | |
public: | |
enum Flags { | |
NO_FLAGS = 0, | |
ALLOW_HEX = 1, | |
ALLOW_OCTALS = 2, | |
ALLOW_TRAILING_JUNK = 4, | |
ALLOW_LEADING_SPACES = 8, | |
ALLOW_TRAILING_SPACES = 16, | |
ALLOW_SPACES_AFTER_SIGN = 32 | |
}; | |
// # 487 | |
// "tlm/deps/double-conversion.exploded/include/double-conversion/double-conversion.h" | |
// 3 4 | |
StringToDoubleConverter(int flags, | |
double empty_string_value, | |
double junk_string_value, | |
const char* infinity_symbol, | |
const char* nan_symbol) | |
: flags_(flags), | |
empty_string_value_(empty_string_value), | |
junk_string_value_(junk_string_value), | |
infinity_symbol_(infinity_symbol), | |
nan_symbol_(nan_symbol) { | |
} | |
double StringToDouble(const char* buffer, | |
int length, | |
int* processed_characters_count) const; | |
double StringToDouble(const uc16* buffer, | |
int length, | |
int* processed_characters_count) const; | |
float StringToFloat(const char* buffer, | |
int length, | |
int* processed_characters_count) const; | |
float StringToFloat(const uc16* buffer, | |
int length, | |
int* processed_characters_count) const; | |
private: | |
const int flags_; | |
const double empty_string_value_; | |
const double junk_string_value_; | |
const char* const infinity_symbol_; | |
const char* const nan_symbol_; | |
template <class Iterator> | |
double StringToIeee(Iterator start_pointer, | |
int length, | |
bool read_as_double, | |
int* processed_characters_count) const; | |
StringToDoubleConverter(); | |
StringToDoubleConverter(const StringToDoubleConverter&); | |
void operator=(const StringToDoubleConverter&); | |
}; | |
} // namespace double_conversion | |
// # 115 "tlm/deps/folly.exploded/include/folly/Conv.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Demangle.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/Demangle.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/FBString.h" 1 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
// # 39 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
// # 40 "tlm/deps/folly.exploded/include/folly/FBString.h" 2 3 4 | |
// # 41 "tlm/deps/folly.exploded/include/folly/FBString.h" 2 3 4 | |
// # 50 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
// # 50 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
#pragma GCC diagnostic push | |
// # 50 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
// # 52 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
#pragma GCC diagnostic ignored "-Wshadow" | |
// # 52 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
namespace folly { | |
// # 68 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
namespace fbstring_detail { | |
template <class InIt, class OutIt> | |
inline std::pair<InIt, OutIt> copy_n( | |
InIt b, | |
typename std::iterator_traits<InIt>::difference_type n, | |
OutIt d) { | |
for (; n != 0; --n, ++b, ++d) { | |
*d = *b; | |
} | |
return std::make_pair(b, d); | |
} | |
template <class Pod, class T> | |
inline void podFill(Pod* b, Pod* e, T c) { | |
(static_cast<bool>(b && e && b <= e) | |
? void(0) | |
: __assert_fail("b && e && b <= e", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
83, | |
__extension__ __PRETTY_FUNCTION__)); | |
constexpr auto kUseMemset = sizeof(T) == 1; | |
if (kUseMemset) { | |
memset(b, c, size_t(e - b)); | |
} else { | |
auto const ee = b + ((e - b) & ~7u); | |
for (; b != ee; b += 8) { | |
b[0] = c; | |
b[1] = c; | |
b[2] = c; | |
b[3] = c; | |
b[4] = c; | |
b[5] = c; | |
b[6] = c; | |
b[7] = c; | |
} | |
for (; b != e; ++b) { | |
*b = c; | |
} | |
} | |
} | |
// # 114 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
template <class Pod> | |
inline void podCopy(const Pod* b, const Pod* e, Pod* d) { | |
(static_cast<bool>(b != nullptr) | |
? void(0) | |
: __assert_fail("b != nullptr", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
116, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(e != nullptr) | |
? void(0) | |
: __assert_fail("e != nullptr", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
117, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(d != nullptr) | |
? void(0) | |
: __assert_fail("d != nullptr", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
118, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(e >= b) | |
? void(0) | |
: __assert_fail("e >= b", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
119, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(d >= e || d + (e - b) <= b) | |
? void(0) | |
: __assert_fail("d >= e || d + (e - b) <= b", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
120, | |
__extension__ __PRETTY_FUNCTION__)); | |
memcpy(d, b, (e - b) * sizeof(Pod)); | |
} | |
template <class Pod> | |
inline void podMove(const Pod* b, const Pod* e, Pod* d) { | |
(static_cast<bool>(e >= b) | |
? void(0) | |
: __assert_fail("e >= b", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
130, | |
__extension__ __PRETTY_FUNCTION__)); | |
memmove(d, b, (e - b) * sizeof(*b)); | |
} | |
} // namespace fbstring_detail | |
enum class AcquireMallocatedString {}; | |
// # 244 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
template <class Char> | |
class fbstring_core { | |
public: | |
fbstring_core() noexcept { | |
reset(); | |
} | |
fbstring_core(const fbstring_core& rhs) { | |
(static_cast<bool>(&rhs != this) | |
? void(0) | |
: __assert_fail( | |
"&rhs != this", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
252, | |
__extension__ __PRETTY_FUNCTION__)); | |
switch (rhs.category()) { | |
case Category::isSmall: | |
copySmall(rhs); | |
break; | |
case Category::isMedium: | |
copyMedium(rhs); | |
break; | |
case Category::isLarge: | |
copyLarge(rhs); | |
break; | |
default: | |
folly::assume_unreachable(); | |
} | |
(static_cast<bool>(size() == rhs.size()) | |
? void(0) | |
: __assert_fail( | |
"size() == rhs.size()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
266, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(memcmp(data(), rhs.data(), size() * sizeof(Char)) == | |
0) | |
? void(0) | |
: __assert_fail( | |
"memcmp(data(), rhs.data(), size() * sizeof(Char)) " | |
"== 0", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
267, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
fbstring_core& operator=(const fbstring_core& rhs) = delete; | |
fbstring_core(fbstring_core&& goner) noexcept { | |
ml_ = goner.ml_; | |
goner.reset(); | |
} | |
fbstring_core(const Char* const data, | |
const size_t size, | |
bool disableSSO = false) { | |
if (!disableSSO && size <= maxSmallSize) { | |
initSmall(data, size); | |
} else if (size <= maxMediumSize) { | |
initMedium(data, size); | |
} else { | |
initLarge(data, size); | |
} | |
(static_cast<bool>(this->size() == size) | |
? void(0) | |
: __assert_fail( | |
"this->size() == size", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
290, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(size == 0 || | |
memcmp(this->data(), data, size * sizeof(Char)) == 0) | |
? void(0) | |
: __assert_fail( | |
"size == 0 || memcmp(this->data(), data, size * " | |
"sizeof(Char)) == 0", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
291, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
~fbstring_core() noexcept { | |
if (category() == Category::isSmall) { | |
return; | |
} | |
destroyMediumLarge(); | |
} | |
// # 308 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
fbstring_core(Char* const data, | |
const size_t size, | |
const size_t allocatedSize, | |
AcquireMallocatedString) { | |
if (size > 0) { | |
(static_cast<bool>(allocatedSize >= size + 1) | |
? void(0) | |
: __assert_fail("allocatedSize >= size + 1", | |
"tlm/deps/folly.exploded/include/folly/" | |
"FBString.h", | |
314, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(data[size] == '\0') | |
? void(0) | |
: __assert_fail("data[size] == '\\0'", | |
"tlm/deps/folly.exploded/include/folly/" | |
"FBString.h", | |
315, | |
__extension__ __PRETTY_FUNCTION__)); | |
ml_.data_ = data; | |
ml_.size_ = size; | |
ml_.setCapacity(allocatedSize - 1, Category::isMedium); | |
} else { | |
free(data); | |
reset(); | |
} | |
} | |
void swap(fbstring_core& rhs) { | |
auto const t = ml_; | |
ml_ = rhs.ml_; | |
rhs.ml_ = t; | |
} | |
const Char* data() const { | |
return c_str(); | |
} | |
Char* data() { | |
return c_str(); | |
} | |
Char* mutableData() { | |
switch (category()) { | |
case Category::isSmall: | |
return small_; | |
case Category::isMedium: | |
return ml_.data_; | |
case Category::isLarge: | |
return mutableDataLarge(); | |
} | |
folly::assume_unreachable(); | |
} | |
const Char* c_str() const { | |
const Char* ptr = ml_.data_; | |
ptr = (category() == Category::isSmall) ? small_ : ptr; | |
return ptr; | |
} | |
void shrink(const size_t delta) { | |
if (category() == Category::isSmall) { | |
shrinkSmall(delta); | |
} else if (category() == Category::isMedium || | |
RefCounted::refs(ml_.data_) == 1) { | |
shrinkMedium(delta); | |
} else { | |
shrinkLarge(delta); | |
} | |
} | |
__attribute__((__noinline__)) void reserve(size_t minCapacity, | |
bool disableSSO = false) { | |
switch (category()) { | |
case Category::isSmall: | |
reserveSmall(minCapacity, disableSSO); | |
break; | |
case Category::isMedium: | |
reserveMedium(minCapacity); | |
break; | |
case Category::isLarge: | |
reserveLarge(minCapacity); | |
break; | |
default: | |
folly::assume_unreachable(); | |
} | |
(static_cast<bool>(capacity() >= minCapacity) | |
? void(0) | |
: __assert_fail( | |
"capacity() >= minCapacity", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
392, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
Char* expandNoinit(const size_t delta, | |
bool expGrowth = false, | |
bool disableSSO = false); | |
void push_back(Char c) { | |
*expandNoinit(1, true) = c; | |
} | |
size_t size() const { | |
size_t ret = ml_.size_; | |
if (kIsLittleEndian) { | |
typedef typename std::make_unsigned<Char>::type UChar; | |
auto maybeSmallSize = | |
size_t(maxSmallSize) - | |
size_t(static_cast<UChar>(small_[maxSmallSize])); | |
ret = (static_cast<ssize_t>(maybeSmallSize) >= 0) ? maybeSmallSize | |
: ret; | |
} else { | |
ret = (category() == Category::isSmall) ? smallSize() : ret; | |
} | |
return ret; | |
} | |
size_t capacity() const { | |
switch (category()) { | |
case Category::isSmall: | |
return maxSmallSize; | |
case Category::isLarge: | |
if (RefCounted::refs(ml_.data_) > 1) { | |
return ml_.size_; | |
} | |
break; | |
case Category::isMedium: | |
default: | |
break; | |
} | |
return ml_.capacity(); | |
} | |
bool isShared() const { | |
return category() == Category::isLarge && | |
RefCounted::refs(ml_.data_) > 1; | |
} | |
private: | |
Char* c_str() { | |
Char* ptr = ml_.data_; | |
ptr = (category() == Category::isSmall) ? small_ : ptr; | |
return ptr; | |
} | |
void reset() { | |
setSmallSize(0); | |
} | |
__attribute__((__noinline__)) void destroyMediumLarge() noexcept { | |
auto const c = category(); | |
(static_cast<bool>(c != Category::isSmall) | |
? void(0) | |
: __assert_fail( | |
"c != Category::isSmall", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
457, | |
__extension__ __PRETTY_FUNCTION__)); | |
if (c == Category::isMedium) { | |
free(ml_.data_); | |
} else { | |
RefCounted::decrementRefs(ml_.data_); | |
} | |
} | |
struct RefCounted { | |
std::atomic<size_t> refCount_; | |
Char data_[1]; | |
constexpr static size_t getDataOffset() { | |
return __builtin_offsetof(RefCounted, data_); | |
} | |
static RefCounted* fromData(Char* p) { | |
return static_cast<RefCounted*>(static_cast<void*>( | |
static_cast<unsigned char*>(static_cast<void*>(p)) - | |
getDataOffset())); | |
} | |
static size_t refs(Char* p) { | |
return fromData(p)->refCount_.load(std::memory_order_acquire); | |
} | |
static void incrementRefs(Char* p) { | |
fromData(p)->refCount_.fetch_add(1, std::memory_order_acq_rel); | |
} | |
static void decrementRefs(Char* p) { | |
auto const dis = fromData(p); | |
size_t oldcnt = | |
dis->refCount_.fetch_sub(1, std::memory_order_acq_rel); | |
(static_cast<bool>(oldcnt > 0) | |
? void(0) | |
: __assert_fail("oldcnt > 0", | |
"tlm/deps/folly.exploded/include/folly/" | |
"FBString.h", | |
490, | |
__extension__ __PRETTY_FUNCTION__)); | |
if (oldcnt == 1) { | |
free(dis); | |
} | |
} | |
static RefCounted* create(size_t* size) { | |
const size_t allocSize = goodMallocSize(getDataOffset() + | |
(*size + 1) * sizeof(Char)); | |
auto result = static_cast<RefCounted*>(checkedMalloc(allocSize)); | |
result->refCount_.store(1, std::memory_order_release); | |
*size = (allocSize - getDataOffset()) / sizeof(Char) - 1; | |
return result; | |
} | |
static RefCounted* create(const Char* data, size_t* size) { | |
const size_t effectiveSize = *size; | |
auto result = create(size); | |
if ((__builtin_expect((effectiveSize > 0), 1))) { | |
fbstring_detail::podCopy( | |
data, data + effectiveSize, result->data_); | |
} | |
return result; | |
} | |
static RefCounted* reallocate(Char* const data, | |
const size_t currentSize, | |
const size_t currentCapacity, | |
size_t* newCapacity) { | |
(static_cast<bool>(*newCapacity > 0 && *newCapacity > currentSize) | |
? void(0) | |
: __assert_fail( | |
"*newCapacity > 0 && *newCapacity > currentSize", | |
"tlm/deps/folly.exploded/include/folly/" | |
"FBString.h", | |
519, | |
__extension__ __PRETTY_FUNCTION__)); | |
const size_t allocNewCapacity = goodMallocSize( | |
getDataOffset() + (*newCapacity + 1) * sizeof(Char)); | |
auto const dis = fromData(data); | |
(static_cast<bool>(dis->refCount_.load(std::memory_order_acquire) == | |
1) | |
? void(0) | |
: __assert_fail("dis->refCount_.load(std::memory_order_" | |
"acquire) == 1", | |
"tlm/deps/folly.exploded/include/folly/" | |
"FBString.h", | |
523, | |
__extension__ __PRETTY_FUNCTION__)); | |
auto result = static_cast<RefCounted*>(smartRealloc( | |
dis, | |
getDataOffset() + (currentSize + 1) * sizeof(Char), | |
getDataOffset() + (currentCapacity + 1) * sizeof(Char), | |
allocNewCapacity)); | |
(static_cast<bool>( | |
result->refCount_.load(std::memory_order_acquire) == 1) | |
? void(0) | |
: __assert_fail("result->refCount_.load(std::memory_order_" | |
"acquire) == 1", | |
"tlm/deps/folly.exploded/include/folly/" | |
"FBString.h", | |
529, | |
__extension__ __PRETTY_FUNCTION__)); | |
*newCapacity = | |
(allocNewCapacity - getDataOffset()) / sizeof(Char) - 1; | |
return result; | |
} | |
}; | |
typedef uint8_t category_type; | |
enum class Category : category_type { | |
isSmall = 0, | |
isMedium = kIsLittleEndian ? 0x80 : 0x2, | |
isLarge = kIsLittleEndian ? 0x40 : 0x1, | |
}; | |
Category category() const { | |
return static_cast<Category>(bytes_[lastChar] & categoryExtractMask); | |
} | |
struct MediumLarge { | |
Char* data_; | |
size_t size_; | |
size_t capacity_; | |
size_t capacity() const { | |
return kIsLittleEndian ? capacity_ & capacityExtractMask | |
: capacity_ >> 2; | |
} | |
void setCapacity(size_t cap, Category cat) { | |
capacity_ = kIsLittleEndian ? cap | (static_cast<size_t>(cat) | |
<< kCategoryShift) | |
: (cap << 2) | static_cast<size_t>(cat); | |
} | |
}; | |
union { | |
uint8_t bytes_[sizeof(MediumLarge)]; | |
Char small_[sizeof(MediumLarge) / sizeof(Char)]; | |
MediumLarge ml_; | |
}; | |
constexpr static size_t lastChar = sizeof(MediumLarge) - 1; | |
constexpr static size_t maxSmallSize = lastChar / sizeof(Char); | |
constexpr static size_t maxMediumSize = 254 / sizeof(Char); | |
constexpr static uint8_t categoryExtractMask = kIsLittleEndian ? 0xC0 : 0x3; | |
constexpr static size_t kCategoryShift = (sizeof(size_t) - 1) * 8; | |
constexpr static size_t capacityExtractMask = | |
kIsLittleEndian ? ~(size_t(categoryExtractMask) << kCategoryShift) | |
: 0x0; | |
static_assert(!(sizeof(MediumLarge) % sizeof(Char)), | |
"Corrupt memory layout for fbstring."); | |
size_t smallSize() const { | |
(static_cast<bool>(category() == Category::isSmall) | |
? void(0) | |
: __assert_fail( | |
"category() == Category::isSmall", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
584, | |
__extension__ __PRETTY_FUNCTION__)); | |
constexpr auto shift = kIsLittleEndian ? 0 : 2; | |
auto smallShifted = static_cast<size_t>(small_[maxSmallSize]) >> shift; | |
(static_cast<bool>(static_cast<size_t>(maxSmallSize) >= smallShifted) | |
? void(0) | |
: __assert_fail( | |
"static_cast<size_t>(maxSmallSize) >= smallShifted", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
587, | |
__extension__ __PRETTY_FUNCTION__)); | |
return static_cast<size_t>(maxSmallSize) - smallShifted; | |
} | |
void setSmallSize(size_t s) { | |
(static_cast<bool>(s <= maxSmallSize) | |
? void(0) | |
: __assert_fail( | |
"s <= maxSmallSize", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
595, | |
__extension__ __PRETTY_FUNCTION__)); | |
constexpr auto shift = kIsLittleEndian ? 0 : 2; | |
small_[maxSmallSize] = char((maxSmallSize - s) << shift); | |
small_[s] = '\0'; | |
(static_cast<bool>(category() == Category::isSmall && size() == s) | |
? void(0) | |
: __assert_fail( | |
"category() == Category::isSmall && size() == s", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
599, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
void copySmall(const fbstring_core&); | |
void copyMedium(const fbstring_core&); | |
void copyLarge(const fbstring_core&); | |
void initSmall(const Char* data, size_t size); | |
void initMedium(const Char* data, size_t size); | |
void initLarge(const Char* data, size_t size); | |
void reserveSmall(size_t minCapacity, bool disableSSO); | |
void reserveMedium(size_t minCapacity); | |
void reserveLarge(size_t minCapacity); | |
void shrinkSmall(size_t delta); | |
void shrinkMedium(size_t delta); | |
void shrinkLarge(size_t delta); | |
void unshare(size_t minCapacity = 0); | |
Char* mutableDataLarge(); | |
}; | |
template <class Char> | |
inline void fbstring_core<Char>::copySmall(const fbstring_core& rhs) { | |
static_assert(__builtin_offsetof(MediumLarge, data_) == 0, | |
"fbstring layout failure"); | |
static_assert(__builtin_offsetof(MediumLarge, size_) == sizeof(ml_.data_), | |
"fbstring layout failure"); | |
static_assert( | |
__builtin_offsetof(MediumLarge, capacity_) == 2 * sizeof(ml_.data_), | |
"fbstring layout failure"); | |
ml_ = rhs.ml_; | |
(static_cast<bool>(category() == Category::isSmall && | |
this->size() == rhs.size()) | |
? void(0) | |
: __assert_fail("category() == Category::isSmall && this->size() " | |
"== rhs.size()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
637, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
template <class Char> | |
__attribute__((__noinline__)) inline void fbstring_core<Char>::copyMedium( | |
const fbstring_core& rhs) { | |
auto const allocSize = goodMallocSize((1 + rhs.ml_.size_) * sizeof(Char)); | |
ml_.data_ = static_cast<Char*>(checkedMalloc(allocSize)); | |
fbstring_detail::podCopy( | |
rhs.ml_.data_, rhs.ml_.data_ + rhs.ml_.size_ + 1, ml_.data_); | |
ml_.size_ = rhs.ml_.size_; | |
ml_.setCapacity(allocSize / sizeof(Char) - 1, Category::isMedium); | |
(static_cast<bool>(category() == Category::isMedium) | |
? void(0) | |
: __assert_fail("category() == Category::isMedium", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
652, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
template <class Char> | |
__attribute__((__noinline__)) inline void fbstring_core<Char>::copyLarge( | |
const fbstring_core& rhs) { | |
ml_ = rhs.ml_; | |
RefCounted::incrementRefs(ml_.data_); | |
(static_cast<bool>(category() == Category::isLarge && size() == rhs.size()) | |
? void(0) | |
: __assert_fail("category() == Category::isLarge && size() == " | |
"rhs.size()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
661, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
template <class Char> | |
inline void fbstring_core<Char>::initSmall(const Char* const data, | |
const size_t size) { | |
static_assert(sizeof(*this) == sizeof(Char*) + 2 * sizeof(size_t), | |
"fbstring has unexpected size"); | |
static_assert(sizeof(Char*) == sizeof(size_t), | |
"fbstring size assumption violation"); | |
static_assert((sizeof(size_t) & (sizeof(size_t) - 1)) == 0, | |
"fbstring size assumption violation"); | |
if ((reinterpret_cast<size_t>(data) & (sizeof(size_t) - 1)) == 0) { | |
const size_t byteSize = size * sizeof(Char); | |
constexpr size_t wordWidth = sizeof(size_t); | |
switch ((byteSize + wordWidth - 1) / wordWidth) { | |
case 3: | |
ml_.capacity_ = reinterpret_cast<const size_t*>(data)[2]; | |
[[fallthrough]]; | |
case 2: | |
ml_.size_ = reinterpret_cast<const size_t*>(data)[1]; | |
[[fallthrough]]; | |
case 1: | |
ml_.data_ = *reinterpret_cast<Char**>(const_cast<Char*>(data)); | |
[[fallthrough]]; | |
case 0: | |
break; | |
} | |
} else | |
{ | |
if (size != 0) { | |
fbstring_detail::podCopy(data, data + size, small_); | |
} | |
} | |
setSmallSize(size); | |
} | |
template <class Char> | |
__attribute__((__noinline__)) inline void fbstring_core<Char>::initMedium( | |
const Char* const data, const size_t size) { | |
auto const allocSize = goodMallocSize((1 + size) * sizeof(Char)); | |
ml_.data_ = static_cast<Char*>(checkedMalloc(allocSize)); | |
if ((__builtin_expect((size > 0), 1))) { | |
fbstring_detail::podCopy(data, data + size, ml_.data_); | |
} | |
ml_.size_ = size; | |
ml_.setCapacity(allocSize / sizeof(Char) - 1, Category::isMedium); | |
ml_.data_[size] = '\0'; | |
} | |
template <class Char> | |
__attribute__((__noinline__)) inline void fbstring_core<Char>::initLarge( | |
const Char* const data, const size_t size) { | |
size_t effectiveCapacity = size; | |
auto const newRC = RefCounted::create(data, &effectiveCapacity); | |
ml_.data_ = newRC->data_; | |
ml_.size_ = size; | |
ml_.setCapacity(effectiveCapacity, Category::isLarge); | |
ml_.data_[size] = '\0'; | |
} | |
template <class Char> | |
__attribute__((__noinline__)) inline void fbstring_core<Char>::unshare( | |
size_t minCapacity) { | |
(static_cast<bool>(category() == Category::isLarge) | |
? void(0) | |
: __assert_fail("category() == Category::isLarge", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
743, | |
__extension__ __PRETTY_FUNCTION__)); | |
size_t effectiveCapacity = std::max(minCapacity, ml_.capacity()); | |
auto const newRC = RefCounted::create(&effectiveCapacity); | |
(static_cast<bool>(effectiveCapacity >= ml_.capacity()) | |
? void(0) | |
: __assert_fail("effectiveCapacity >= ml_.capacity()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
748, | |
__extension__ __PRETTY_FUNCTION__)); | |
fbstring_detail::podCopy( | |
ml_.data_, ml_.data_ + ml_.size_ + 1, newRC->data_); | |
RefCounted::decrementRefs(ml_.data_); | |
ml_.data_ = newRC->data_; | |
ml_.setCapacity(effectiveCapacity, Category::isLarge); | |
} | |
template <class Char> | |
inline Char* fbstring_core<Char>::mutableDataLarge() { | |
(static_cast<bool>(category() == Category::isLarge) | |
? void(0) | |
: __assert_fail("category() == Category::isLarge", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
759, | |
__extension__ __PRETTY_FUNCTION__)); | |
if (RefCounted::refs(ml_.data_) > 1) { | |
unshare(); | |
} | |
return ml_.data_; | |
} | |
template <class Char> | |
__attribute__((__noinline__)) inline void fbstring_core<Char>::reserveLarge( | |
size_t minCapacity) { | |
(static_cast<bool>(category() == Category::isLarge) | |
? void(0) | |
: __assert_fail("category() == Category::isLarge", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
769, | |
__extension__ __PRETTY_FUNCTION__)); | |
if (RefCounted::refs(ml_.data_) > 1) { | |
unshare(minCapacity); | |
} else { | |
if (minCapacity > ml_.capacity()) { | |
auto const newRC = RefCounted::reallocate( | |
ml_.data_, ml_.size_, ml_.capacity(), &minCapacity); | |
ml_.data_ = newRC->data_; | |
ml_.setCapacity(minCapacity, Category::isLarge); | |
} | |
(static_cast<bool>(capacity() >= minCapacity) | |
? void(0) | |
: __assert_fail( | |
"capacity() >= minCapacity", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
786, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
} | |
template <class Char> | |
__attribute__((__noinline__)) inline void fbstring_core<Char>::reserveMedium( | |
const size_t minCapacity) { | |
(static_cast<bool>(category() == Category::isMedium) | |
? void(0) | |
: __assert_fail("category() == Category::isMedium", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
793, | |
__extension__ __PRETTY_FUNCTION__)); | |
if (minCapacity <= ml_.capacity()) { | |
return; | |
} | |
if (minCapacity <= maxMediumSize) { | |
size_t capacityBytes = goodMallocSize((1 + minCapacity) * sizeof(Char)); | |
ml_.data_ = static_cast<Char*>( | |
smartRealloc(ml_.data_, | |
(ml_.size_ + 1) * sizeof(Char), | |
(ml_.capacity() + 1) * sizeof(Char), | |
capacityBytes)); | |
ml_.setCapacity(capacityBytes / sizeof(Char) - 1, Category::isMedium); | |
} else { | |
fbstring_core nascent; | |
nascent.reserve(minCapacity); | |
nascent.ml_.size_ = ml_.size_; | |
fbstring_detail::podCopy( | |
ml_.data_, ml_.data_ + ml_.size_ + 1, nascent.ml_.data_); | |
nascent.swap(*this); | |
(static_cast<bool>(capacity() >= minCapacity) | |
? void(0) | |
: __assert_fail( | |
"capacity() >= minCapacity", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
819, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
} | |
template <class Char> | |
__attribute__((__noinline__)) inline void fbstring_core<Char>::reserveSmall( | |
size_t minCapacity, const bool disableSSO) { | |
(static_cast<bool>(category() == Category::isSmall) | |
? void(0) | |
: __assert_fail("category() == Category::isSmall", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
827, | |
__extension__ __PRETTY_FUNCTION__)); | |
if (!disableSSO && minCapacity <= maxSmallSize) { | |
} else if (minCapacity <= maxMediumSize) { | |
auto const allocSizeBytes = | |
goodMallocSize((1 + minCapacity) * sizeof(Char)); | |
auto const pData = static_cast<Char*>(checkedMalloc(allocSizeBytes)); | |
auto const size = smallSize(); | |
fbstring_detail::podCopy(small_, small_ + size + 1, pData); | |
ml_.data_ = pData; | |
ml_.size_ = size; | |
ml_.setCapacity(allocSizeBytes / sizeof(Char) - 1, Category::isMedium); | |
} else { | |
auto const newRC = RefCounted::create(&minCapacity); | |
auto const size = smallSize(); | |
fbstring_detail::podCopy(small_, small_ + size + 1, newRC->data_); | |
ml_.data_ = newRC->data_; | |
ml_.size_ = size; | |
ml_.setCapacity(minCapacity, Category::isLarge); | |
(static_cast<bool>(capacity() >= minCapacity) | |
? void(0) | |
: __assert_fail( | |
"capacity() >= minCapacity", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
852, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
} | |
template <class Char> | |
inline Char* fbstring_core<Char>::expandNoinit(const size_t delta, | |
bool expGrowth, | |
bool disableSSO) { | |
(static_cast<bool>(capacity() >= size()) | |
? void(0) | |
: __assert_fail("capacity() >= size()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
862, | |
__extension__ __PRETTY_FUNCTION__)); | |
size_t sz, newSz; | |
if (category() == Category::isSmall) { | |
sz = smallSize(); | |
newSz = sz + delta; | |
if (!disableSSO && (__builtin_expect((newSz <= maxSmallSize), 1))) { | |
setSmallSize(newSz); | |
return small_ + sz; | |
} | |
reserveSmall(expGrowth ? std::max(newSz, 2 * maxSmallSize) : newSz, | |
disableSSO); | |
} else { | |
sz = ml_.size_; | |
newSz = sz + delta; | |
if ((__builtin_expect((newSz > capacity()), 0))) { | |
reserve(expGrowth ? std::max(newSz, 1 + capacity() * 3 / 2) | |
: newSz); | |
} | |
} | |
(static_cast<bool>(capacity() >= newSz) | |
? void(0) | |
: __assert_fail("capacity() >= newSz", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
881, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(category() == Category::isMedium || | |
category() == Category::isLarge) | |
? void(0) | |
: __assert_fail("category() == Category::isMedium || category() " | |
"== Category::isLarge", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
883, | |
__extension__ __PRETTY_FUNCTION__)); | |
ml_.size_ = newSz; | |
ml_.data_[newSz] = '\0'; | |
(static_cast<bool>(size() == newSz) | |
? void(0) | |
: __assert_fail("size() == newSz", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
886, | |
__extension__ __PRETTY_FUNCTION__)); | |
return ml_.data_ + sz; | |
} | |
template <class Char> | |
inline void fbstring_core<Char>::shrinkSmall(const size_t delta) { | |
(static_cast<bool>(delta <= smallSize()) | |
? void(0) | |
: __assert_fail("delta <= smallSize()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
893, | |
__extension__ __PRETTY_FUNCTION__)); | |
setSmallSize(smallSize() - delta); | |
} | |
template <class Char> | |
inline void fbstring_core<Char>::shrinkMedium(const size_t delta) { | |
(static_cast<bool>(ml_.size_ >= delta) | |
? void(0) | |
: __assert_fail("ml_.size_ >= delta", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
901, | |
__extension__ __PRETTY_FUNCTION__)); | |
ml_.size_ -= delta; | |
ml_.data_[ml_.size_] = '\0'; | |
} | |
template <class Char> | |
inline void fbstring_core<Char>::shrinkLarge(const size_t delta) { | |
(static_cast<bool>(ml_.size_ >= delta) | |
? void(0) | |
: __assert_fail("ml_.size_ >= delta", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
908, | |
__extension__ __PRETTY_FUNCTION__)); | |
if (delta) { | |
fbstring_core(ml_.data_, ml_.size_ - delta).swap(*this); | |
} | |
} | |
template <class Char> | |
class dummy_fbstring_core { | |
public: | |
dummy_fbstring_core() { | |
} | |
dummy_fbstring_core(const dummy_fbstring_core& another) | |
: backend_(another.backend_) { | |
} | |
dummy_fbstring_core(const Char* s, size_t n) : backend_(s, n) { | |
} | |
void swap(dummy_fbstring_core& rhs) { | |
backend_.swap(rhs.backend_); | |
} | |
const Char* data() const { | |
return backend_.data(); | |
} | |
Char* mutableData() { | |
return const_cast<Char*>(backend_.data()); | |
} | |
void shrink(size_t delta) { | |
(static_cast<bool>(delta <= size()) | |
? void(0) | |
: __assert_fail( | |
"delta <= size()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
939, | |
__extension__ __PRETTY_FUNCTION__)); | |
backend_.resize(size() - delta); | |
} | |
Char* expandNoinit(size_t delta) { | |
auto const sz = size(); | |
backend_.resize(size() + delta); | |
return backend_.data() + sz; | |
} | |
void push_back(Char c) { | |
backend_.push_back(c); | |
} | |
size_t size() const { | |
return backend_.size(); | |
} | |
size_t capacity() const { | |
return backend_.capacity(); | |
} | |
bool isShared() const { | |
return false; | |
} | |
void reserve(size_t minCapacity) { | |
backend_.reserve(minCapacity); | |
} | |
private: | |
std::basic_string<Char> backend_; | |
}; | |
template <typename E, | |
class T = std::char_traits<E>, | |
class A = std::allocator<E>, | |
class Storage = fbstring_core<E>> | |
class basic_fbstring { | |
static_assert(std::is_same<A, std::allocator<E>>::value, | |
"fbstring ignores custom allocators"); | |
template <typename Ex, typename... Args> | |
inline __attribute__((__always_inline__)) static void enforce( | |
bool condition, Args&&... args) { | |
if (!condition) { | |
throw_exception<Ex>(static_cast<Args&&>(args)...); | |
} | |
} | |
bool isSane() const { | |
return begin() <= end() && empty() == (size() == 0) && | |
empty() == (begin() == end()) && size() <= max_size() && | |
capacity() <= max_size() && size() <= capacity() && | |
begin()[size()] == '\0'; | |
} | |
struct Invariant { | |
Invariant& operator=(const Invariant&) = delete; | |
explicit Invariant(const basic_fbstring& s) noexcept : s_(s) { | |
(static_cast<bool>(s_.isSane()) | |
? void(0) | |
: __assert_fail("s_.isSane()", | |
"tlm/deps/folly.exploded/include/folly/" | |
"FBString.h", | |
999, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
~Invariant() noexcept { | |
(static_cast<bool>(s_.isSane()) | |
? void(0) | |
: __assert_fail("s_.isSane()", | |
"tlm/deps/folly.exploded/include/folly/" | |
"FBString.h", | |
1002, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
private: | |
const basic_fbstring& s_; | |
}; | |
public: | |
typedef T traits_type; | |
typedef typename traits_type::char_type value_type; | |
typedef A allocator_type; | |
typedef typename std::allocator_traits<A>::size_type size_type; | |
typedef typename std::allocator_traits<A>::difference_type difference_type; | |
typedef typename std::allocator_traits<A>::value_type& reference; | |
typedef typename std::allocator_traits<A>::value_type const& | |
const_reference; | |
typedef typename std::allocator_traits<A>::pointer pointer; | |
typedef typename std::allocator_traits<A>::const_pointer const_pointer; | |
typedef E* iterator; | |
typedef const E* const_iterator; | |
typedef std::reverse_iterator<iterator> reverse_iterator; | |
typedef std::reverse_iterator<const_iterator> const_reverse_iterator; | |
static constexpr size_type npos = size_type(-1); | |
typedef std::true_type IsRelocatable; | |
private: | |
static void procrustes(size_type& n, size_type nmax) { | |
if (n > nmax) { | |
n = nmax; | |
} | |
} | |
static size_type traitsLength(const value_type* s); | |
public: | |
// # 1054 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
basic_fbstring() noexcept : basic_fbstring(A()) { | |
} | |
explicit basic_fbstring(const A&) noexcept { | |
} | |
basic_fbstring(const basic_fbstring& str) : store_(str.store_) { | |
} | |
basic_fbstring(basic_fbstring&& goner) noexcept | |
: store_(std::move(goner.store_)) { | |
} | |
template <typename A2> | |
basic_fbstring(const std::basic_string<E, T, A2>& str) | |
: store_(str.data(), str.size()) { | |
} | |
basic_fbstring(const basic_fbstring& str, | |
size_type pos, | |
size_type n = npos, | |
const A& = A()) { | |
assign(str, pos, n); | |
} | |
__attribute__((__noinline__)) | |
basic_fbstring(const value_type* s, const A& = A()) | |
: store_(s, traitsLength(s)) { | |
} | |
__attribute__((__noinline__)) | |
basic_fbstring(const value_type* s, size_type n, const A& = A()) | |
: store_(s, n) { | |
} | |
__attribute__((__noinline__)) | |
basic_fbstring(size_type n, value_type c, const A& = A()) { | |
auto const pData = store_.expandNoinit(n); | |
fbstring_detail::podFill(pData, pData + n, c); | |
} | |
template <class InIt> | |
__attribute__((__noinline__)) basic_fbstring( | |
InIt begin, | |
InIt end, | |
typename std::enable_if<!std::is_same<InIt, value_type*>::value, | |
const A>::type& = A()) { | |
assign(begin, end); | |
} | |
__attribute__((__noinline__)) | |
basic_fbstring(const value_type* b, const value_type* e, const A& = A()) | |
: store_(b, size_type(e - b)) { | |
} | |
basic_fbstring(value_type* s, | |
size_type n, | |
size_type c, | |
AcquireMallocatedString a) | |
: store_(s, n, c, a) { | |
} | |
__attribute__((__noinline__)) | |
basic_fbstring(std::initializer_list<value_type> il) { | |
assign(il.begin(), il.end()); | |
} | |
~basic_fbstring() noexcept { | |
} | |
basic_fbstring& operator=(const basic_fbstring& lhs); | |
basic_fbstring& operator=(basic_fbstring&& goner) noexcept; | |
template <typename A2> | |
basic_fbstring& operator=(const std::basic_string<E, T, A2>& rhs) { | |
return assign(rhs.data(), rhs.size()); | |
} | |
std::basic_string<E, T, A> toStdString() const { | |
return std::basic_string<E, T, A>(data(), size()); | |
} | |
basic_fbstring& operator=(const value_type* s) { | |
return assign(s); | |
} | |
basic_fbstring& operator=(value_type c); | |
// # 1153 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
template <typename TP> | |
typename std::enable_if< | |
std::is_convertible<TP, | |
typename basic_fbstring<E, T, A, Storage>:: | |
value_type>::value && | |
!std::is_same<typename std::decay<TP>::type, | |
typename basic_fbstring<E, T, A, Storage>:: | |
value_type>::value, | |
basic_fbstring<E, T, A, Storage>&>::type | |
operator=(TP c) = delete; | |
basic_fbstring& operator=(std::initializer_list<value_type> il) { | |
return assign(il.begin(), il.end()); | |
} | |
operator std::basic_string_view<value_type, traits_type>() const noexcept { | |
return {data(), size()}; | |
} | |
iterator begin() { | |
return store_.mutableData(); | |
} | |
const_iterator begin() const { | |
return store_.data(); | |
} | |
const_iterator cbegin() const { | |
return begin(); | |
} | |
iterator end() { | |
return store_.mutableData() + store_.size(); | |
} | |
const_iterator end() const { | |
return store_.data() + store_.size(); | |
} | |
const_iterator cend() const { | |
return end(); | |
} | |
reverse_iterator rbegin() { | |
return reverse_iterator(end()); | |
} | |
const_reverse_iterator rbegin() const { | |
return const_reverse_iterator(end()); | |
} | |
const_reverse_iterator crbegin() const { | |
return rbegin(); | |
} | |
reverse_iterator rend() { | |
return reverse_iterator(begin()); | |
} | |
const_reverse_iterator rend() const { | |
return const_reverse_iterator(begin()); | |
} | |
const_reverse_iterator crend() const { | |
return rend(); | |
} | |
const value_type& front() const { | |
return *begin(); | |
} | |
const value_type& back() const { | |
(static_cast<bool>(!empty()) | |
? void(0) | |
: __assert_fail( | |
"!empty()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
1229, | |
__extension__ __PRETTY_FUNCTION__)); | |
return *(end() - 1); | |
} | |
value_type& front() { | |
return *begin(); | |
} | |
value_type& back() { | |
(static_cast<bool>(!empty()) | |
? void(0) | |
: __assert_fail( | |
"!empty()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
1237, | |
__extension__ __PRETTY_FUNCTION__)); | |
return *(end() - 1); | |
} | |
void pop_back() { | |
(static_cast<bool>(!empty()) | |
? void(0) | |
: __assert_fail( | |
"!empty()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
1242, | |
__extension__ __PRETTY_FUNCTION__)); | |
store_.shrink(1); | |
} | |
size_type size() const { | |
return store_.size(); | |
} | |
size_type length() const { | |
return size(); | |
} | |
size_type max_size() const { | |
return std::numeric_limits<size_type>::max(); | |
} | |
void resize(size_type n, value_type c = value_type()); | |
size_type capacity() const { | |
return store_.capacity(); | |
} | |
void reserve(size_type res_arg = 0) { | |
enforce<std::length_error>(res_arg <= max_size(), ""); | |
store_.reserve(res_arg); | |
} | |
void shrink_to_fit() { | |
if (capacity() < size() * 3 / 2) { | |
return; | |
} | |
basic_fbstring(cbegin(), cend()).swap(*this); | |
} | |
void clear() { | |
resize(0); | |
} | |
bool empty() const { | |
return size() == 0; | |
} | |
const_reference operator[](size_type pos) const { | |
return *(begin() + pos); | |
} | |
reference operator[](size_type pos) { | |
return *(begin() + pos); | |
} | |
const_reference at(size_type n) const { | |
enforce<std::out_of_range>(n < size(), ""); | |
return (*this)[n]; | |
} | |
reference at(size_type n) { | |
enforce<std::out_of_range>(n < size(), ""); | |
return (*this)[n]; | |
} | |
basic_fbstring& operator+=(const basic_fbstring& str) { | |
return append(str); | |
} | |
basic_fbstring& operator+=(const value_type* s) { | |
return append(s); | |
} | |
basic_fbstring& operator+=(const value_type c) { | |
push_back(c); | |
return *this; | |
} | |
basic_fbstring& operator+=(std::initializer_list<value_type> il) { | |
append(il); | |
return *this; | |
} | |
basic_fbstring& append(const basic_fbstring& str); | |
basic_fbstring& append(const basic_fbstring& str, | |
const size_type pos, | |
size_type n); | |
basic_fbstring& append(const value_type* s, size_type n); | |
basic_fbstring& append(const value_type* s) { | |
return append(s, traitsLength(s)); | |
} | |
basic_fbstring& append(size_type n, value_type c); | |
template <class InputIterator> | |
basic_fbstring& append(InputIterator first, InputIterator last) { | |
insert(end(), first, last); | |
return *this; | |
} | |
basic_fbstring& append(std::initializer_list<value_type> il) { | |
return append(il.begin(), il.end()); | |
} | |
void push_back(const value_type c) { | |
store_.push_back(c); | |
} | |
basic_fbstring& assign(const basic_fbstring& str) { | |
if (&str == this) { | |
return *this; | |
} | |
return assign(str.data(), str.size()); | |
} | |
basic_fbstring& assign(basic_fbstring&& str) { | |
return *this = std::move(str); | |
} | |
basic_fbstring& assign(const basic_fbstring& str, | |
const size_type pos, | |
size_type n); | |
basic_fbstring& assign(const value_type* s, const size_type n); | |
basic_fbstring& assign(const value_type* s) { | |
return assign(s, traitsLength(s)); | |
} | |
basic_fbstring& assign(std::initializer_list<value_type> il) { | |
return assign(il.begin(), il.end()); | |
} | |
template <class ItOrLength, class ItOrChar> | |
basic_fbstring& assign(ItOrLength first_or_n, ItOrChar last_or_c) { | |
return replace(begin(), end(), first_or_n, last_or_c); | |
} | |
basic_fbstring& insert(size_type pos1, const basic_fbstring& str) { | |
return insert(pos1, str.data(), str.size()); | |
} | |
basic_fbstring& insert(size_type pos1, | |
const basic_fbstring& str, | |
size_type pos2, | |
size_type n) { | |
enforce<std::out_of_range>(pos2 <= str.length(), ""); | |
procrustes(n, str.length() - pos2); | |
return insert(pos1, str.data() + pos2, n); | |
} | |
basic_fbstring& insert(size_type pos, const value_type* s, size_type n) { | |
enforce<std::out_of_range>(pos <= length(), ""); | |
insert(begin() + pos, s, s + n); | |
return *this; | |
} | |
basic_fbstring& insert(size_type pos, const value_type* s) { | |
return insert(pos, s, traitsLength(s)); | |
} | |
basic_fbstring& insert(size_type pos, size_type n, value_type c) { | |
enforce<std::out_of_range>(pos <= length(), ""); | |
insert(begin() + pos, n, c); | |
return *this; | |
} | |
iterator insert(const_iterator p, const value_type c) { | |
const size_type pos = p - cbegin(); | |
insert(p, 1, c); | |
return begin() + pos; | |
} | |
private: | |
typedef std::basic_istream<value_type, traits_type> istream_type; | |
istream_type& getlineImpl(istream_type& is, value_type delim); | |
public: | |
friend inline istream_type& getline(istream_type& is, | |
basic_fbstring& str, | |
value_type delim) { | |
return str.getlineImpl(is, delim); | |
} | |
friend inline istream_type& getline(istream_type& is, basic_fbstring& str) { | |
return getline(is, str, '\n'); | |
} | |
private: | |
iterator insertImplDiscr(const_iterator i, | |
size_type n, | |
value_type c, | |
std::true_type); | |
template <class InputIter> | |
iterator insertImplDiscr(const_iterator i, | |
InputIter b, | |
InputIter e, | |
std::false_type); | |
template <class FwdIterator> | |
iterator insertImpl(const_iterator i, | |
FwdIterator s1, | |
FwdIterator s2, | |
std::forward_iterator_tag); | |
template <class InputIterator> | |
iterator insertImpl(const_iterator i, | |
InputIterator b, | |
InputIterator e, | |
std::input_iterator_tag); | |
public: | |
template <class ItOrLength, class ItOrChar> | |
iterator insert(const_iterator p, | |
ItOrLength first_or_n, | |
ItOrChar last_or_c) { | |
using Sel = | |
bool_constant<std::numeric_limits<ItOrLength>::is_specialized>; | |
return insertImplDiscr(p, first_or_n, last_or_c, Sel()); | |
} | |
iterator insert(const_iterator p, std::initializer_list<value_type> il) { | |
return insert(p, il.begin(), il.end()); | |
} | |
basic_fbstring& erase(size_type pos = 0, size_type n = npos) { | |
Invariant checker(*this); | |
enforce<std::out_of_range>(pos <= length(), ""); | |
procrustes(n, length() - pos); | |
std::copy(begin() + pos + n, end(), begin() + pos); | |
resize(length() - n); | |
return *this; | |
} | |
iterator erase(iterator position) { | |
const size_type pos(position - begin()); | |
enforce<std::out_of_range>(pos <= size(), ""); | |
erase(pos, 1); | |
return begin() + pos; | |
} | |
iterator erase(iterator first, iterator last) { | |
const size_type pos(first - begin()); | |
erase(pos, last - first); | |
return begin() + pos; | |
} | |
basic_fbstring& replace(size_type pos1, | |
size_type n1, | |
const basic_fbstring& str) { | |
return replace(pos1, n1, str.data(), str.size()); | |
} | |
basic_fbstring& replace(size_type pos1, | |
size_type n1, | |
const basic_fbstring& str, | |
size_type pos2, | |
size_type n2) { | |
enforce<std::out_of_range>(pos2 <= str.length(), ""); | |
return replace( | |
pos1, n1, str.data() + pos2, std::min(n2, str.size() - pos2)); | |
} | |
basic_fbstring& replace(size_type pos, size_type n1, const value_type* s) { | |
return replace(pos, n1, s, traitsLength(s)); | |
} | |
// # 1518 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
template <class StrOrLength, class NumOrChar> | |
basic_fbstring& replace(size_type pos, | |
size_type n1, | |
StrOrLength s_or_n2, | |
NumOrChar n_or_c) { | |
Invariant checker(*this); | |
enforce<std::out_of_range>(pos <= size(), ""); | |
procrustes(n1, length() - pos); | |
const iterator b = begin() + pos; | |
return replace(b, b + n1, s_or_n2, n_or_c); | |
} | |
basic_fbstring& replace(iterator i1, | |
iterator i2, | |
const basic_fbstring& str) { | |
return replace(i1, i2, str.data(), str.length()); | |
} | |
basic_fbstring& replace(iterator i1, iterator i2, const value_type* s) { | |
return replace(i1, i2, s, traitsLength(s)); | |
} | |
private: | |
basic_fbstring& replaceImplDiscr(iterator i1, | |
iterator i2, | |
const value_type* s, | |
size_type n, | |
std::integral_constant<int, 2>); | |
basic_fbstring& replaceImplDiscr(iterator i1, | |
iterator i2, | |
size_type n2, | |
value_type c, | |
std::integral_constant<int, 1>); | |
template <class InputIter> | |
basic_fbstring& replaceImplDiscr(iterator i1, | |
iterator i2, | |
InputIter b, | |
InputIter e, | |
std::integral_constant<int, 0>); | |
private: | |
template <class FwdIterator> | |
bool replaceAliased( | |
iterator, iterator, FwdIterator, FwdIterator, std::false_type) { | |
return false; | |
} | |
template <class FwdIterator> | |
bool replaceAliased(iterator i1, | |
iterator i2, | |
FwdIterator s1, | |
FwdIterator s2, | |
std::true_type); | |
template <class FwdIterator> | |
void replaceImpl(iterator i1, | |
iterator i2, | |
FwdIterator s1, | |
FwdIterator s2, | |
std::forward_iterator_tag); | |
template <class InputIterator> | |
void replaceImpl(iterator i1, | |
iterator i2, | |
InputIterator b, | |
InputIterator e, | |
std::input_iterator_tag); | |
public: | |
template <class T1, class T2> | |
basic_fbstring& replace(iterator i1, | |
iterator i2, | |
T1 first_or_n_or_s, | |
T2 last_or_c_or_n) { | |
constexpr bool num1 = std::numeric_limits<T1>::is_specialized, | |
num2 = std::numeric_limits<T2>::is_specialized; | |
using Sel = | |
std::integral_constant<int, | |
num1 ? (num2 ? 1 : -1) : (num2 ? 2 : 0)>; | |
return replaceImplDiscr(i1, i2, first_or_n_or_s, last_or_c_or_n, Sel()); | |
} | |
size_type copy(value_type* s, size_type n, size_type pos = 0) const { | |
enforce<std::out_of_range>(pos <= size(), ""); | |
procrustes(n, size() - pos); | |
if (n != 0) { | |
fbstring_detail::podCopy(data() + pos, data() + pos + n, s); | |
} | |
return n; | |
} | |
void swap(basic_fbstring& rhs) { | |
store_.swap(rhs.store_); | |
} | |
const value_type* c_str() const { | |
return store_.c_str(); | |
} | |
const value_type* data() const { | |
return c_str(); | |
} | |
value_type* data() { | |
return store_.data(); | |
} | |
allocator_type get_allocator() const { | |
return allocator_type(); | |
} | |
size_type find(const basic_fbstring& str, size_type pos = 0) const { | |
return find(str.data(), pos, str.length()); | |
} | |
size_type find(const value_type* needle, | |
size_type pos, | |
size_type nsize) const; | |
size_type find(const value_type* s, size_type pos = 0) const { | |
return find(s, pos, traitsLength(s)); | |
} | |
size_type find(value_type c, size_type pos = 0) const { | |
return find(&c, pos, 1); | |
} | |
size_type rfind(const basic_fbstring& str, size_type pos = npos) const { | |
return rfind(str.data(), pos, str.length()); | |
} | |
size_type rfind(const value_type* s, size_type pos, size_type n) const; | |
size_type rfind(const value_type* s, size_type pos = npos) const { | |
return rfind(s, pos, traitsLength(s)); | |
} | |
size_type rfind(value_type c, size_type pos = npos) const { | |
return rfind(&c, pos, 1); | |
} | |
size_type find_first_of(const basic_fbstring& str, | |
size_type pos = 0) const { | |
return find_first_of(str.data(), pos, str.length()); | |
} | |
size_type find_first_of(const value_type* s, | |
size_type pos, | |
size_type n) const; | |
size_type find_first_of(const value_type* s, size_type pos = 0) const { | |
return find_first_of(s, pos, traitsLength(s)); | |
} | |
size_type find_first_of(value_type c, size_type pos = 0) const { | |
return find_first_of(&c, pos, 1); | |
} | |
size_type find_last_of(const basic_fbstring& str, | |
size_type pos = npos) const { | |
return find_last_of(str.data(), pos, str.length()); | |
} | |
size_type find_last_of(const value_type* s, | |
size_type pos, | |
size_type n) const; | |
size_type find_last_of(const value_type* s, size_type pos = npos) const { | |
return find_last_of(s, pos, traitsLength(s)); | |
} | |
size_type find_last_of(value_type c, size_type pos = npos) const { | |
return find_last_of(&c, pos, 1); | |
} | |
size_type find_first_not_of(const basic_fbstring& str, | |
size_type pos = 0) const { | |
return find_first_not_of(str.data(), pos, str.size()); | |
} | |
size_type find_first_not_of(const value_type* s, | |
size_type pos, | |
size_type n) const; | |
size_type find_first_not_of(const value_type* s, size_type pos = 0) const { | |
return find_first_not_of(s, pos, traitsLength(s)); | |
} | |
size_type find_first_not_of(value_type c, size_type pos = 0) const { | |
return find_first_not_of(&c, pos, 1); | |
} | |
size_type find_last_not_of(const basic_fbstring& str, | |
size_type pos = npos) const { | |
return find_last_not_of(str.data(), pos, str.length()); | |
} | |
size_type find_last_not_of(const value_type* s, | |
size_type pos, | |
size_type n) const; | |
size_type find_last_not_of(const value_type* s, | |
size_type pos = npos) const { | |
return find_last_not_of(s, pos, traitsLength(s)); | |
} | |
size_type find_last_not_of(value_type c, size_type pos = npos) const { | |
return find_last_not_of(&c, pos, 1); | |
} | |
basic_fbstring substr(size_type pos = 0, size_type n = npos) const& { | |
enforce<std::out_of_range>(pos <= size(), ""); | |
return basic_fbstring(data() + pos, std::min(n, size() - pos)); | |
} | |
basic_fbstring substr(size_type pos = 0, size_type n = npos) && { | |
enforce<std::out_of_range>(pos <= size(), ""); | |
erase(0, pos); | |
if (n < size()) { | |
resize(n); | |
} | |
return std::move(*this); | |
} | |
int compare(const basic_fbstring& str) const { | |
return compare(0, size(), str); | |
} | |
int compare(size_type pos1, size_type n1, const basic_fbstring& str) const { | |
return compare(pos1, n1, str.data(), str.size()); | |
} | |
int compare(size_type pos1, size_type n1, const value_type* s) const { | |
return compare(pos1, n1, s, traitsLength(s)); | |
} | |
int compare(size_type pos1, | |
size_type n1, | |
const value_type* s, | |
size_type n2) const { | |
enforce<std::out_of_range>(pos1 <= size(), ""); | |
procrustes(n1, size() - pos1); | |
const int r = traits_type::compare(pos1 + data(), s, std::min(n1, n2)); | |
return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0; | |
} | |
int compare(size_type pos1, | |
size_type n1, | |
const basic_fbstring& str, | |
size_type pos2, | |
size_type n2) const { | |
enforce<std::out_of_range>(pos2 <= str.size(), ""); | |
return compare( | |
pos1, n1, str.data() + pos2, std::min(n2, str.size() - pos2)); | |
} | |
int compare(const value_type* s) const { | |
const size_type n1(size()), n2(traitsLength(s)); | |
const int r = traits_type::compare(data(), s, std::min(n1, n2)); | |
return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0; | |
} | |
private: | |
Storage store_; | |
}; | |
template <typename E, class T, class A, class S> | |
__attribute__((__noinline__)) inline | |
typename basic_fbstring<E, T, A, S>::size_type | |
basic_fbstring<E, T, A, S>::traitsLength(const value_type* s) { | |
return s ? traits_type::length(s) | |
: (throw_exception<std::logic_error>( | |
"basic_fbstring: null pointer initializer not valid"), | |
0); | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::operator=( | |
const basic_fbstring& lhs) { | |
Invariant checker(*this); | |
if ((__builtin_expect((&lhs == this), 0))) { | |
return *this; | |
} | |
return assign(lhs.data(), lhs.size()); | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::operator=( | |
basic_fbstring&& goner) noexcept { | |
if ((__builtin_expect((&goner == this), 0))) { | |
return *this; | |
} | |
this->~basic_fbstring(); | |
new (&store_) S(std::move(goner.store_)); | |
return *this; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::operator=( | |
value_type c) { | |
Invariant checker(*this); | |
if (empty()) { | |
store_.expandNoinit(1); | |
} else if (store_.isShared()) { | |
basic_fbstring(1, c).swap(*this); | |
return *this; | |
} else { | |
store_.shrink(size() - 1); | |
} | |
front() = c; | |
return *this; | |
} | |
template <typename E, class T, class A, class S> | |
inline void basic_fbstring<E, T, A, S>::resize(const size_type n, | |
const value_type c) { | |
Invariant checker(*this); | |
auto size = this->size(); | |
if (n <= size) { | |
store_.shrink(size - n); | |
} else { | |
auto const delta = n - size; | |
auto pData = store_.expandNoinit(delta); | |
fbstring_detail::podFill(pData, pData + delta, c); | |
} | |
(static_cast<bool>(this->size() == n) | |
? void(0) | |
: __assert_fail("this->size() == n", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
1856, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::append( | |
const basic_fbstring& str) { | |
auto desiredSize = size() + str.size(); | |
append(str.data(), str.size()); | |
(static_cast<bool>(size() == desiredSize) | |
? void(0) | |
: __assert_fail("size() == desiredSize", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
1866, | |
__extension__ __PRETTY_FUNCTION__)); | |
return *this; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::append( | |
const basic_fbstring& str, const size_type pos, size_type n) { | |
const size_type sz = str.size(); | |
enforce<std::out_of_range>(pos <= sz, ""); | |
procrustes(n, sz - pos); | |
return append(str.data() + pos, n); | |
} | |
template <typename E, class T, class A, class S> | |
__attribute__((__noinline__)) inline basic_fbstring<E, T, A, S>& | |
basic_fbstring<E, T, A, S>::append(const value_type* s, size_type n) { | |
Invariant checker(*this); | |
if ((__builtin_expect((!n), 0))) { | |
return *this; | |
} | |
auto const oldSize = size(); | |
auto const oldData = data(); | |
auto pData = store_.expandNoinit(n, true); | |
std::less_equal<const value_type*> le; | |
if ((__builtin_expect((le(oldData, s) && !le(oldData + oldSize, s)), 0))) { | |
(static_cast<bool>(le(s + n, oldData + oldSize)) | |
? void(0) | |
: __assert_fail( | |
"le(s + n, oldData + oldSize)", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
1902, | |
__extension__ __PRETTY_FUNCTION__)); | |
s = data() + (s - oldData); | |
fbstring_detail::podMove(s, s + n, pData); | |
} else { | |
fbstring_detail::podCopy(s, s + n, pData); | |
} | |
(static_cast<bool>(size() == oldSize + n) | |
? void(0) | |
: __assert_fail("size() == oldSize + n", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
1910, | |
__extension__ __PRETTY_FUNCTION__)); | |
return *this; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::append( | |
size_type n, value_type c) { | |
Invariant checker(*this); | |
auto pData = store_.expandNoinit(n, true); | |
fbstring_detail::podFill(pData, pData + n, c); | |
return *this; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::assign( | |
const basic_fbstring& str, const size_type pos, size_type n) { | |
const size_type sz = str.size(); | |
enforce<std::out_of_range>(pos <= sz, ""); | |
procrustes(n, sz - pos); | |
return assign(str.data() + pos, n); | |
} | |
template <typename E, class T, class A, class S> | |
__attribute__((__noinline__)) inline basic_fbstring<E, T, A, S>& | |
basic_fbstring<E, T, A, S>::assign(const value_type* s, const size_type n) { | |
Invariant checker(*this); | |
if (n == 0) { | |
resize(0); | |
} else if (size() >= n) { | |
fbstring_detail::podMove(s, s + n, store_.mutableData()); | |
store_.shrink(size() - n); | |
(static_cast<bool>(size() == n) | |
? void(0) | |
: __assert_fail( | |
"size() == n", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
1946, | |
__extension__ __PRETTY_FUNCTION__)); | |
} else { | |
resize(0); | |
fbstring_detail::podCopy(s, s + n, store_.expandNoinit(n)); | |
} | |
(static_cast<bool>(size() == n) | |
? void(0) | |
: __assert_fail("size() == n", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
1956, | |
__extension__ __PRETTY_FUNCTION__)); | |
return *this; | |
} | |
template <typename E, class T, class A, class S> | |
inline typename basic_fbstring<E, T, A, S>::istream_type& | |
basic_fbstring<E, T, A, S>::getlineImpl(istream_type& is, value_type delim) { | |
Invariant checker(*this); | |
clear(); | |
size_t size = 0; | |
while (true) { | |
size_t avail = capacity() - size; | |
is.getline(store_.expandNoinit(avail), avail + 1, delim); | |
size += is.gcount(); | |
if (is.bad() || is.eof() || !is.fail()) { | |
if (!is.bad() && !is.eof()) { | |
--size; | |
} | |
resize(size); | |
break; | |
} | |
(static_cast<bool>(size == this->size()) | |
? void(0) | |
: __assert_fail( | |
"size == this->size()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
1983, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(size == capacity()) | |
? void(0) | |
: __assert_fail( | |
"size == capacity()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
1984, | |
__extension__ __PRETTY_FUNCTION__)); | |
reserve(std::max<size_t>(63, 3 * size / 2)); | |
is.clear(); | |
} | |
return is; | |
} | |
template <typename E, class T, class A, class S> | |
inline typename basic_fbstring<E, T, A, S>::size_type | |
basic_fbstring<E, T, A, S>::find(const value_type* needle, | |
const size_type pos, | |
const size_type nsize) const { | |
auto const size = this->size(); | |
if (nsize + pos > size || nsize + pos < pos) { | |
return npos; | |
} | |
if (nsize == 0) { | |
return pos; | |
} | |
auto const haystack = data(); | |
auto const nsize_1 = nsize - 1; | |
auto const lastNeedle = needle[nsize_1]; | |
size_type skip = 0; | |
const E* i = haystack + pos; | |
auto iEnd = haystack + size - nsize_1; | |
while (i < iEnd) { | |
while (i[nsize_1] != lastNeedle) { | |
if (++i == iEnd) { | |
return npos; | |
} | |
} | |
for (size_t j = 0;;) { | |
(static_cast<bool>(j < nsize) | |
? void(0) | |
: __assert_fail("j < nsize", | |
"tlm/deps/folly.exploded/include/folly/" | |
"FBString.h", | |
2034, | |
__extension__ __PRETTY_FUNCTION__)); | |
if (i[j] != needle[j]) { | |
if (skip == 0) { | |
skip = 1; | |
while (skip <= nsize_1 && | |
needle[nsize_1 - skip] != lastNeedle) { | |
++skip; | |
} | |
} | |
i += skip; | |
break; | |
} | |
if (++j == nsize) { | |
return i - haystack; | |
} | |
} | |
} | |
return npos; | |
} | |
template <typename E, class T, class A, class S> | |
inline typename basic_fbstring<E, T, A, S>::iterator | |
basic_fbstring<E, T, A, S>::insertImplDiscr(const_iterator i, | |
size_type n, | |
value_type c, | |
std::true_type) { | |
Invariant checker(*this); | |
(static_cast<bool>(i >= cbegin() && i <= cend()) | |
? void(0) | |
: __assert_fail("i >= cbegin() && i <= cend()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
2066, | |
__extension__ __PRETTY_FUNCTION__)); | |
const size_type pos = i - cbegin(); | |
auto oldSize = size(); | |
store_.expandNoinit(n, true); | |
auto b = begin(); | |
fbstring_detail::podMove(b + pos, b + oldSize, b + pos + n); | |
fbstring_detail::podFill(b + pos, b + pos + n, c); | |
return b + pos; | |
} | |
template <typename E, class T, class A, class S> | |
template <class InputIter> | |
inline typename basic_fbstring<E, T, A, S>::iterator | |
basic_fbstring<E, T, A, S>::insertImplDiscr(const_iterator i, | |
InputIter b, | |
InputIter e, | |
std::false_type) { | |
return insertImpl( | |
i, | |
b, | |
e, | |
typename std::iterator_traits<InputIter>::iterator_category()); | |
} | |
template <typename E, class T, class A, class S> | |
template <class FwdIterator> | |
inline typename basic_fbstring<E, T, A, S>::iterator | |
basic_fbstring<E, T, A, S>::insertImpl(const_iterator i, | |
FwdIterator s1, | |
FwdIterator s2, | |
std::forward_iterator_tag) { | |
Invariant checker(*this); | |
(static_cast<bool>(i >= cbegin() && i <= cend()) | |
? void(0) | |
: __assert_fail("i >= cbegin() && i <= cend()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
2100, | |
__extension__ __PRETTY_FUNCTION__)); | |
const size_type pos = i - cbegin(); | |
auto n = std::distance(s1, s2); | |
(static_cast<bool>(n >= 0) | |
? void(0) | |
: __assert_fail("n >= 0", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
2103, | |
__extension__ __PRETTY_FUNCTION__)); | |
auto oldSize = size(); | |
store_.expandNoinit(n, true); | |
auto b = begin(); | |
fbstring_detail::podMove(b + pos, b + oldSize, b + pos + n); | |
std::copy(s1, s2, b + pos); | |
return b + pos; | |
} | |
template <typename E, class T, class A, class S> | |
template <class InputIterator> | |
inline typename basic_fbstring<E, T, A, S>::iterator | |
basic_fbstring<E, T, A, S>::insertImpl(const_iterator i, | |
InputIterator b, | |
InputIterator e, | |
std::input_iterator_tag) { | |
const auto pos = i - cbegin(); | |
basic_fbstring temp(cbegin(), i); | |
for (; b != e; ++b) { | |
temp.push_back(*b); | |
} | |
temp.append(i, cend()); | |
swap(temp); | |
return begin() + pos; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::replaceImplDiscr( | |
iterator i1, | |
iterator i2, | |
const value_type* s, | |
size_type n, | |
std::integral_constant<int, 2>) { | |
(static_cast<bool>(i1 <= i2) | |
? void(0) | |
: __assert_fail("i1 <= i2", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
2139, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(begin() <= i1 && i1 <= end()) | |
? void(0) | |
: __assert_fail("begin() <= i1 && i1 <= end()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
2140, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(begin() <= i2 && i2 <= end()) | |
? void(0) | |
: __assert_fail("begin() <= i2 && i2 <= end()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
2141, | |
__extension__ __PRETTY_FUNCTION__)); | |
return replace(i1, i2, s, s + n); | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::replaceImplDiscr( | |
iterator i1, | |
iterator i2, | |
size_type n2, | |
value_type c, | |
std::integral_constant<int, 1>) { | |
const size_type n1 = i2 - i1; | |
if (n1 > n2) { | |
std::fill(i1, i1 + n2, c); | |
erase(i1 + n2, i2); | |
} else { | |
std::fill(i1, i2, c); | |
insert(i2, n2 - n1, c); | |
} | |
(static_cast<bool>(isSane()) | |
? void(0) | |
: __assert_fail("isSane()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
2160, | |
__extension__ __PRETTY_FUNCTION__)); | |
return *this; | |
} | |
template <typename E, class T, class A, class S> | |
template <class InputIter> | |
inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::replaceImplDiscr( | |
iterator i1, | |
iterator i2, | |
InputIter b, | |
InputIter e, | |
std::integral_constant<int, 0>) { | |
using Cat = typename std::iterator_traits<InputIter>::iterator_category; | |
replaceImpl(i1, i2, b, e, Cat()); | |
return *this; | |
} | |
template <typename E, class T, class A, class S> | |
template <class FwdIterator> | |
inline bool basic_fbstring<E, T, A, S>::replaceAliased(iterator i1, | |
iterator i2, | |
FwdIterator s1, | |
FwdIterator s2, | |
std::true_type) { | |
std::less_equal<const value_type*> le{}; | |
const bool aliased = le(&*begin(), &*s1) && le(&*s1, &*end()); | |
if (!aliased) { | |
return false; | |
} | |
basic_fbstring temp; | |
temp.reserve(size() - (i2 - i1) + std::distance(s1, s2)); | |
temp.append(begin(), i1).append(s1, s2).append(i2, end()); | |
swap(temp); | |
return true; | |
} | |
template <typename E, class T, class A, class S> | |
template <class FwdIterator> | |
inline void basic_fbstring<E, T, A, S>::replaceImpl(iterator i1, | |
iterator i2, | |
FwdIterator s1, | |
FwdIterator s2, | |
std::forward_iterator_tag) { | |
Invariant checker(*this); | |
using Sel = bool_constant<std::is_same<FwdIterator, iterator>::value || | |
std::is_same<FwdIterator, const_iterator>::value>; | |
if (replaceAliased(i1, i2, s1, s2, Sel())) { | |
return; | |
} | |
auto const n1 = i2 - i1; | |
(static_cast<bool>(n1 >= 0) | |
? void(0) | |
: __assert_fail("n1 >= 0", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
2217, | |
__extension__ __PRETTY_FUNCTION__)); | |
auto const n2 = std::distance(s1, s2); | |
(static_cast<bool>(n2 >= 0) | |
? void(0) | |
: __assert_fail("n2 >= 0", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
2219, | |
__extension__ __PRETTY_FUNCTION__)); | |
if (n1 > n2) { | |
std::copy(s1, s2, i1); | |
erase(i1 + n2, i2); | |
} else { | |
s1 = fbstring_detail::copy_n(s1, n1, i1).first; | |
insert(i2, s1, s2); | |
} | |
(static_cast<bool>(isSane()) | |
? void(0) | |
: __assert_fail("isSane()", | |
"tlm/deps/folly.exploded/include/folly/FBString.h", | |
2230, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
template <typename E, class T, class A, class S> | |
template <class InputIterator> | |
inline void basic_fbstring<E, T, A, S>::replaceImpl(iterator i1, | |
iterator i2, | |
InputIterator b, | |
InputIterator e, | |
std::input_iterator_tag) { | |
basic_fbstring temp(begin(), i1); | |
temp.append(b, e).append(i2, end()); | |
swap(temp); | |
} | |
template <typename E, class T, class A, class S> | |
inline typename basic_fbstring<E, T, A, S>::size_type | |
basic_fbstring<E, T, A, S>::rfind(const value_type* s, | |
size_type pos, | |
size_type n) const { | |
if (n > length()) { | |
return npos; | |
} | |
pos = std::min(pos, length() - n); | |
if (n == 0) { | |
return pos; | |
} | |
const_iterator i(begin() + pos); | |
for (;; --i) { | |
if (traits_type::eq(*i, *s) && traits_type::compare(&*i, s, n) == 0) { | |
return i - begin(); | |
} | |
if (i == begin()) { | |
break; | |
} | |
} | |
return npos; | |
} | |
template <typename E, class T, class A, class S> | |
inline typename basic_fbstring<E, T, A, S>::size_type | |
basic_fbstring<E, T, A, S>::find_first_of(const value_type* s, | |
size_type pos, | |
size_type n) const { | |
if (pos > length() || n == 0) { | |
return npos; | |
} | |
const_iterator i(begin() + pos), finish(end()); | |
for (; i != finish; ++i) { | |
if (traits_type::find(s, n, *i) != nullptr) { | |
return i - begin(); | |
} | |
} | |
return npos; | |
} | |
template <typename E, class T, class A, class S> | |
inline typename basic_fbstring<E, T, A, S>::size_type | |
basic_fbstring<E, T, A, S>::find_last_of(const value_type* s, | |
size_type pos, | |
size_type n) const { | |
if (!empty() && n > 0) { | |
pos = std::min(pos, length() - 1); | |
const_iterator i(begin() + pos); | |
for (;; --i) { | |
if (traits_type::find(s, n, *i) != nullptr) { | |
return i - begin(); | |
} | |
if (i == begin()) { | |
break; | |
} | |
} | |
} | |
return npos; | |
} | |
template <typename E, class T, class A, class S> | |
inline typename basic_fbstring<E, T, A, S>::size_type | |
basic_fbstring<E, T, A, S>::find_first_not_of(const value_type* s, | |
size_type pos, | |
size_type n) const { | |
if (pos < length()) { | |
const_iterator i(begin() + pos), finish(end()); | |
for (; i != finish; ++i) { | |
if (traits_type::find(s, n, *i) == nullptr) { | |
return i - begin(); | |
} | |
} | |
} | |
return npos; | |
} | |
template <typename E, class T, class A, class S> | |
inline typename basic_fbstring<E, T, A, S>::size_type | |
basic_fbstring<E, T, A, S>::find_last_not_of(const value_type* s, | |
size_type pos, | |
size_type n) const { | |
if (!this->empty()) { | |
pos = std::min(pos, size() - 1); | |
const_iterator i(begin() + pos); | |
for (;; --i) { | |
if (traits_type::find(s, n, *i) == nullptr) { | |
return i - begin(); | |
} | |
if (i == begin()) { | |
break; | |
} | |
} | |
} | |
return npos; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S> operator+( | |
const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
basic_fbstring<E, T, A, S> result; | |
result.reserve(lhs.size() + rhs.size()); | |
result.append(lhs).append(rhs); | |
return result; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S> operator+( | |
basic_fbstring<E, T, A, S>&& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return std::move(lhs.append(rhs)); | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S> operator+( | |
const basic_fbstring<E, T, A, S>& lhs, | |
basic_fbstring<E, T, A, S>&& rhs) { | |
if (rhs.capacity() >= lhs.size() + rhs.size()) { | |
return std::move(rhs.insert(0, lhs)); | |
} | |
auto const& rhsC = rhs; | |
return lhs + rhsC; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S> operator+(basic_fbstring<E, T, A, S>&& lhs, | |
basic_fbstring<E, T, A, S>&& rhs) { | |
return std::move(lhs.append(rhs)); | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S> operator+( | |
const E* lhs, const basic_fbstring<E, T, A, S>& rhs) { | |
basic_fbstring<E, T, A, S> result; | |
const auto len = basic_fbstring<E, T, A, S>::traits_type::length(lhs); | |
result.reserve(len + rhs.size()); | |
result.append(lhs, len).append(rhs); | |
return result; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S> operator+(const E* lhs, | |
basic_fbstring<E, T, A, S>&& rhs) { | |
const auto len = basic_fbstring<E, T, A, S>::traits_type::length(lhs); | |
if (rhs.capacity() >= len + rhs.size()) { | |
rhs.insert(rhs.begin(), lhs, lhs + len); | |
return std::move(rhs); | |
} | |
basic_fbstring<E, T, A, S> result; | |
result.reserve(len + rhs.size()); | |
result.append(lhs, len).append(rhs); | |
return result; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S> operator+( | |
E lhs, const basic_fbstring<E, T, A, S>& rhs) { | |
basic_fbstring<E, T, A, S> result; | |
result.reserve(1 + rhs.size()); | |
result.push_back(lhs); | |
result.append(rhs); | |
return result; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S> operator+(E lhs, | |
basic_fbstring<E, T, A, S>&& rhs) { | |
if (rhs.capacity() > rhs.size()) { | |
rhs.insert(rhs.begin(), lhs); | |
return std::move(rhs); | |
} | |
auto const& rhsC = rhs; | |
return lhs + rhsC; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S> operator+( | |
const basic_fbstring<E, T, A, S>& lhs, const E* rhs) { | |
typedef typename basic_fbstring<E, T, A, S>::size_type size_type; | |
typedef typename basic_fbstring<E, T, A, S>::traits_type traits_type; | |
basic_fbstring<E, T, A, S> result; | |
const size_type len = traits_type::length(rhs); | |
result.reserve(lhs.size() + len); | |
result.append(lhs).append(rhs, len); | |
return result; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S> operator+(basic_fbstring<E, T, A, S>&& lhs, | |
const E* rhs) { | |
return std::move(lhs += rhs); | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S> operator+( | |
const basic_fbstring<E, T, A, S>& lhs, E rhs) { | |
basic_fbstring<E, T, A, S> result; | |
result.reserve(lhs.size() + 1); | |
result.append(lhs); | |
result.push_back(rhs); | |
return result; | |
} | |
template <typename E, class T, class A, class S> | |
inline basic_fbstring<E, T, A, S> operator+(basic_fbstring<E, T, A, S>&& lhs, | |
E rhs) { | |
return std::move(lhs += rhs); | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator==(const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator==( | |
const typename basic_fbstring<E, T, A, S>::value_type* lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return rhs == lhs; | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator==( | |
const basic_fbstring<E, T, A, S>& lhs, | |
const typename basic_fbstring<E, T, A, S>::value_type* rhs) { | |
return lhs.compare(rhs) == 0; | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator!=(const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(lhs == rhs); | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator!=( | |
const typename basic_fbstring<E, T, A, S>::value_type* lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(lhs == rhs); | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator!=( | |
const basic_fbstring<E, T, A, S>& lhs, | |
const typename basic_fbstring<E, T, A, S>::value_type* rhs) { | |
return !(lhs == rhs); | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator<(const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return lhs.compare(rhs) < 0; | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator<( | |
const basic_fbstring<E, T, A, S>& lhs, | |
const typename basic_fbstring<E, T, A, S>::value_type* rhs) { | |
return lhs.compare(rhs) < 0; | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator<( | |
const typename basic_fbstring<E, T, A, S>::value_type* lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return rhs.compare(lhs) > 0; | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator>(const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return rhs < lhs; | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator>( | |
const basic_fbstring<E, T, A, S>& lhs, | |
const typename basic_fbstring<E, T, A, S>::value_type* rhs) { | |
return rhs < lhs; | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator>( | |
const typename basic_fbstring<E, T, A, S>::value_type* lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return rhs < lhs; | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator<=(const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(rhs < lhs); | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator<=( | |
const basic_fbstring<E, T, A, S>& lhs, | |
const typename basic_fbstring<E, T, A, S>::value_type* rhs) { | |
return !(rhs < lhs); | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator<=( | |
const typename basic_fbstring<E, T, A, S>::value_type* lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(rhs < lhs); | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator>=(const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(lhs < rhs); | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator>=( | |
const basic_fbstring<E, T, A, S>& lhs, | |
const typename basic_fbstring<E, T, A, S>::value_type* rhs) { | |
return !(lhs < rhs); | |
} | |
template <typename E, class T, class A, class S> | |
inline bool operator>=( | |
const typename basic_fbstring<E, T, A, S>::value_type* lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(lhs < rhs); | |
} | |
template <typename E, class T, class A, class S> | |
void swap(basic_fbstring<E, T, A, S>& lhs, basic_fbstring<E, T, A, S>& rhs) { | |
lhs.swap(rhs); | |
} | |
template <typename E, class T, class A, class S> | |
inline std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type>& | |
operator>>(std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type>& | |
is, | |
basic_fbstring<E, T, A, S>& str) { | |
typedef std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type> | |
_istream_type; | |
typename _istream_type::sentry sentry(is); | |
size_t extracted = 0; | |
typename _istream_type::iostate err = _istream_type::goodbit; | |
if (sentry) { | |
auto n = is.width(); | |
if (n <= 0) { | |
n = str.max_size(); | |
} | |
str.erase(); | |
for (auto got = is.rdbuf()->sgetc(); extracted != size_t(n); | |
++extracted) { | |
if (got == T::eof()) { | |
err |= _istream_type::eofbit; | |
is.width(0); | |
break; | |
} | |
if (isspace(got)) { | |
break; | |
} | |
str.push_back(got); | |
got = is.rdbuf()->snextc(); | |
} | |
} | |
if (!extracted) { | |
err |= _istream_type::failbit; | |
} | |
if (err) { | |
is.setstate(err); | |
} | |
return is; | |
} | |
template <typename E, class T, class A, class S> | |
inline std::basic_ostream<typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type>& | |
operator<<(std::basic_ostream<typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type>& | |
os, | |
const basic_fbstring<E, T, A, S>& str) { | |
// # 2712 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
std::__ostream_insert(os, str.data(), str.size()); | |
return os; | |
} | |
template <typename E1, class T, class A, class S> | |
constexpr typename basic_fbstring<E1, T, A, S>::size_type | |
basic_fbstring<E1, T, A, S>::npos; | |
template <typename E, class T, class A, class S, class A2> | |
inline bool operator==(const basic_fbstring<E, T, A, S>& lhs, | |
const std::basic_string<E, T, A2>& rhs) { | |
return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) == 0; | |
} | |
template <typename E, class T, class A, class S, class A2> | |
inline bool operator==(const std::basic_string<E, T, A2>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return rhs == lhs; | |
} | |
template <typename E, class T, class A, class S, class A2> | |
inline bool operator!=(const basic_fbstring<E, T, A, S>& lhs, | |
const std::basic_string<E, T, A2>& rhs) { | |
return !(lhs == rhs); | |
} | |
template <typename E, class T, class A, class S, class A2> | |
inline bool operator!=(const std::basic_string<E, T, A2>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(lhs == rhs); | |
} | |
template <typename E, class T, class A, class S, class A2> | |
inline bool operator<(const basic_fbstring<E, T, A, S>& lhs, | |
const std::basic_string<E, T, A2>& rhs) { | |
return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) < 0; | |
} | |
template <typename E, class T, class A, class S, class A2> | |
inline bool operator>(const basic_fbstring<E, T, A, S>& lhs, | |
const std::basic_string<E, T, A2>& rhs) { | |
return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) > 0; | |
} | |
template <typename E, class T, class A, class S, class A2> | |
inline bool operator<(const std::basic_string<E, T, A2>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return rhs > lhs; | |
} | |
template <typename E, class T, class A, class S, class A2> | |
inline bool operator>(const std::basic_string<E, T, A2>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return rhs < lhs; | |
} | |
template <typename E, class T, class A, class S, class A2> | |
inline bool operator<=(const basic_fbstring<E, T, A, S>& lhs, | |
const std::basic_string<E, T, A2>& rhs) { | |
return !(lhs > rhs); | |
} | |
template <typename E, class T, class A, class S, class A2> | |
inline bool operator>=(const basic_fbstring<E, T, A, S>& lhs, | |
const std::basic_string<E, T, A2>& rhs) { | |
return !(lhs < rhs); | |
} | |
template <typename E, class T, class A, class S, class A2> | |
inline bool operator<=(const std::basic_string<E, T, A2>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(lhs > rhs); | |
} | |
template <typename E, class T, class A, class S, class A2> | |
inline bool operator>=(const std::basic_string<E, T, A2>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(lhs < rhs); | |
} | |
typedef basic_fbstring<char> fbstring; | |
template <class T, class R, class A, class S> | |
struct IsRelocatable<basic_fbstring<T, R, A, S>> : std::true_type {}; | |
inline std::string toStdString(const folly::fbstring& s) { | |
return std::string(s.data(), s.size()); | |
} | |
inline const std::string& toStdString(const std::string& s) { | |
return s; | |
} | |
inline std::string&& toStdString(std::string&& s) { | |
return std::move(s); | |
} | |
} // namespace folly | |
// # 2849 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
namespace std { | |
template <> | |
struct hash<::folly::basic_fbstring<char>> { | |
size_t operator()(const ::folly::basic_fbstring<char>& s) const { | |
return ::folly::hash::fnv32_buf(s.data(), s.size() * sizeof(char)); | |
} | |
}; | |
template <> | |
struct hash<::folly::basic_fbstring<char16_t>> { | |
size_t operator()(const ::folly::basic_fbstring<char16_t>& s) const { | |
return ::folly::hash::fnv32_buf(s.data(), s.size() * sizeof(char16_t)); | |
} | |
}; | |
template <> | |
struct hash<::folly::basic_fbstring<char32_t>> { | |
size_t operator()(const ::folly::basic_fbstring<char32_t>& s) const { | |
return ::folly::hash::fnv32_buf(s.data(), s.size() * sizeof(char32_t)); | |
} | |
}; | |
template <> | |
struct hash<::folly::basic_fbstring<wchar_t>> { | |
size_t operator()(const ::folly::basic_fbstring<wchar_t>& s) const { | |
return ::folly::hash::fnv32_buf(s.data(), s.size() * sizeof(wchar_t)); | |
} | |
}; | |
} // namespace std | |
// # 2858 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
#pragma GCC diagnostic pop | |
// # 2858 "tlm/deps/folly.exploded/include/folly/FBString.h" 3 4 | |
namespace folly { | |
template <class T> | |
struct IsSomeString; | |
template <> | |
struct IsSomeString<fbstring> : std::true_type {}; | |
} // namespace folly | |
// # 20 "tlm/deps/folly.exploded/include/folly/Demangle.h" 2 3 4 | |
namespace folly { | |
// # 34 "tlm/deps/folly.exploded/include/folly/Demangle.h" 3 4 | |
fbstring demangle(const char* name); | |
inline fbstring demangle(const std::type_info& type) { | |
return demangle(type.name()); | |
} | |
// # 57 "tlm/deps/folly.exploded/include/folly/Demangle.h" 3 4 | |
size_t demangle(const char* name, char* out, size_t outSize); | |
inline size_t demangle(const std::type_info& type, char* buf, size_t bufSize) { | |
return demangle(type.name(), buf, bufSize); | |
} | |
} // namespace folly | |
// # 117 "tlm/deps/folly.exploded/include/folly/Conv.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Expected.h" 1 3 4 | |
// # 23 "tlm/deps/folly.exploded/include/folly/Expected.h" 3 4 | |
// # 35 "tlm/deps/folly.exploded/include/folly/Expected.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Optional.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/Optional.h" 3 4 | |
// # 69 "tlm/deps/folly.exploded/include/folly/Optional.h" 3 4 | |
namespace folly { | |
template <class Value> | |
class Optional; | |
namespace detail { | |
template <class Value> | |
struct OptionalPromiseReturn; | |
} | |
struct None { | |
enum class _secret { _token }; | |
explicit constexpr None(_secret) { | |
} | |
}; | |
constexpr None none{None::_secret::_token}; | |
class __attribute__((__visibility__("default"))) OptionalEmptyException | |
: public std::runtime_error { | |
public: | |
OptionalEmptyException() | |
: std::runtime_error("Empty Optional cannot be unwrapped") { | |
} | |
}; | |
template <class Value> | |
class Optional { | |
public: | |
typedef Value value_type; | |
static_assert(!std::is_reference<Value>::value, | |
"Optional may not be used with reference types"); | |
static_assert(!std::is_abstract<Value>::value, | |
"Optional may not be used with abstract types"); | |
constexpr Optional() noexcept { | |
} | |
Optional(const Optional& src) noexcept( | |
std::is_nothrow_copy_constructible<Value>::value) { | |
if (src.hasValue()) { | |
construct(src.value()); | |
} | |
} | |
Optional(Optional&& src) noexcept( | |
std::is_nothrow_move_constructible<Value>::value) { | |
if (src.hasValue()) { | |
construct(std::move(src.value())); | |
src.reset(); | |
} | |
} | |
constexpr Optional(const None&) noexcept { | |
} | |
constexpr Optional(Value&& newValue) noexcept( | |
std::is_nothrow_move_constructible<Value>::value) { | |
construct(std::move(newValue)); | |
} | |
constexpr Optional(const Value& newValue) noexcept( | |
std::is_nothrow_copy_constructible<Value>::value) { | |
construct(newValue); | |
} | |
template <typename... Args> | |
constexpr explicit Optional(in_place_t, Args&&... args) noexcept( | |
std::is_nothrow_constructible<Value, Args...>::value) | |
: Optional{PrivateConstructor{}, std::forward<Args>(args)...} { | |
} | |
template <typename U, typename... Args> | |
constexpr explicit Optional( | |
in_place_t, | |
std::initializer_list<U> il, | |
Args&&... args) noexcept(std:: | |
is_nothrow_constructible< | |
Value, | |
std::initializer_list<U>, | |
Args...>::value) | |
: Optional{PrivateConstructor{}, il, std::forward<Args>(args)...} { | |
} | |
Optional(const detail::OptionalPromiseReturn<Value>& p) : Optional{} { | |
p.promise_->value_ = this; | |
} | |
void assign(const None&) { | |
reset(); | |
} | |
void assign(Optional&& src) { | |
if (this != &src) { | |
if (src.hasValue()) { | |
assign(std::move(src.value())); | |
src.reset(); | |
} else { | |
reset(); | |
} | |
} | |
} | |
void assign(const Optional& src) { | |
if (src.hasValue()) { | |
assign(src.value()); | |
} else { | |
reset(); | |
} | |
} | |
void assign(Value&& newValue) { | |
if (hasValue()) { | |
storage_.value = std::move(newValue); | |
} else { | |
construct(std::move(newValue)); | |
} | |
} | |
void assign(const Value& newValue) { | |
if (hasValue()) { | |
storage_.value = newValue; | |
} else { | |
construct(newValue); | |
} | |
} | |
Optional& operator=(None) noexcept { | |
reset(); | |
return *this; | |
} | |
template <class Arg> | |
Optional& operator=(Arg&& arg) { | |
assign(std::forward<Arg>(arg)); | |
return *this; | |
} | |
Optional& operator=(Optional&& other) noexcept( | |
std::is_nothrow_move_assignable<Value>::value) { | |
assign(std::move(other)); | |
return *this; | |
} | |
Optional& operator=(const Optional& other) noexcept( | |
std::is_nothrow_copy_assignable<Value>::value) { | |
assign(other); | |
return *this; | |
} | |
template <class... Args> | |
Value& emplace(Args&&... args) { | |
reset(); | |
construct(std::forward<Args>(args)...); | |
return value(); | |
} | |
template <class U, class... Args> | |
typename std::enable_if<std::is_constructible<Value, | |
std::initializer_list<U>&, | |
Args&&...>::value, | |
Value&>::type | |
emplace(std::initializer_list<U> ilist, Args&&... args) { | |
reset(); | |
construct(ilist, std::forward<Args>(args)...); | |
return value(); | |
} | |
void reset() noexcept { | |
storage_.clear(); | |
} | |
void clear() noexcept { | |
reset(); | |
} | |
void swap(Optional& that) noexcept(IsNothrowSwappable<Value>::value) { | |
if (hasValue() && that.hasValue()) { | |
using std::swap; | |
swap(value(), that.value()); | |
} else if (hasValue()) { | |
that.emplace(std::move(value())); | |
reset(); | |
} else if (that.hasValue()) { | |
emplace(std::move(that.value())); | |
that.reset(); | |
} | |
} | |
constexpr const Value& value() const& { | |
require_value(); | |
return storage_.value; | |
} | |
constexpr Value& value() & { | |
require_value(); | |
return storage_.value; | |
} | |
constexpr Value&& value() && { | |
require_value(); | |
return std::move(storage_.value); | |
} | |
constexpr const Value&& value() const&& { | |
require_value(); | |
return std::move(storage_.value); | |
} | |
const Value* get_pointer() const& { | |
return storage_.hasValue ? &storage_.value : nullptr; | |
} | |
Value* get_pointer() & { | |
return storage_.hasValue ? &storage_.value : nullptr; | |
} | |
Value* get_pointer() && = delete; | |
constexpr bool has_value() const noexcept { | |
return storage_.hasValue; | |
} | |
constexpr bool hasValue() const noexcept { | |
return has_value(); | |
} | |
constexpr explicit operator bool() const noexcept { | |
return has_value(); | |
} | |
constexpr const Value& operator*() const& { | |
return value(); | |
} | |
constexpr Value& operator*() & { | |
return value(); | |
} | |
constexpr const Value&& operator*() const&& { | |
return std::move(value()); | |
} | |
constexpr Value&& operator*() && { | |
return std::move(value()); | |
} | |
constexpr const Value* operator->() const { | |
return &value(); | |
} | |
constexpr Value* operator->() { | |
return &value(); | |
} | |
template <class U> | |
constexpr Value value_or(U&& dflt) const& { | |
if (storage_.hasValue) { | |
return storage_.value; | |
} | |
return std::forward<U>(dflt); | |
} | |
template <class U> | |
constexpr Value value_or(U&& dflt) && { | |
if (storage_.hasValue) { | |
return std::move(storage_.value); | |
} | |
return std::forward<U>(dflt); | |
} | |
private: | |
template <class T> | |
friend constexpr Optional<std::decay_t<T>> make_optional(T&&); | |
template <class T, class... Args> | |
friend constexpr Optional<T> make_optional(Args&&... args); | |
template <class T, class U, class... As> | |
friend constexpr Optional<T> make_optional(std::initializer_list<U>, | |
As&&...); | |
// # 354 "tlm/deps/folly.exploded/include/folly/Optional.h" 3 4 | |
struct PrivateConstructor { | |
explicit PrivateConstructor() = default; | |
}; | |
template <typename... Args> | |
constexpr Optional(PrivateConstructor, Args&&... args) noexcept( | |
std::is_constructible<Value, Args&&...>::value) { | |
construct(std::forward<Args>(args)...); | |
} | |
void require_value() const { | |
if (!storage_.hasValue) { | |
throw_exception<OptionalEmptyException>(); | |
} | |
} | |
template <class... Args> | |
void construct(Args&&... args) { | |
const void* ptr = &storage_.value; | |
new (const_cast<void*>(ptr)) Value(std::forward<Args>(args)...); | |
storage_.hasValue = true; | |
} | |
struct StorageTriviallyDestructible { | |
union { | |
char emptyState; | |
Value value; | |
}; | |
bool hasValue; | |
constexpr StorageTriviallyDestructible() | |
: emptyState('\0'), hasValue{false} { | |
} | |
void clear() { | |
hasValue = false; | |
} | |
}; | |
struct StorageNonTriviallyDestructible { | |
union { | |
char emptyState; | |
Value value; | |
}; | |
bool hasValue; | |
StorageNonTriviallyDestructible() : hasValue{false} { | |
} | |
~StorageNonTriviallyDestructible() { | |
clear(); | |
} | |
void clear() { | |
if (hasValue) { | |
hasValue = false; | |
value.~Value(); | |
} | |
} | |
}; | |
using Storage = typename std::conditional< | |
std::is_trivially_destructible<Value>::value, | |
StorageTriviallyDestructible, | |
StorageNonTriviallyDestructible>::type; | |
Storage storage_; | |
}; | |
template <class T> | |
const T* get_pointer(const Optional<T>& opt) { | |
return opt.get_pointer(); | |
} | |
template <class T> | |
T* get_pointer(Optional<T>& opt) { | |
return opt.get_pointer(); | |
} | |
template <class T> | |
void swap(Optional<T>& a, Optional<T>& b) noexcept(noexcept(a.swap(b))) { | |
a.swap(b); | |
} | |
template <class T> | |
constexpr Optional<std::decay_t<T>> make_optional(T&& v) { | |
using PrivateConstructor = | |
typename folly::Optional<std::decay_t<T>>::PrivateConstructor; | |
return {PrivateConstructor{}, std::forward<T>(v)}; | |
} | |
template <class T, class... Args> | |
constexpr folly::Optional<T> make_optional(Args&&... args) { | |
using PrivateConstructor = typename folly::Optional<T>::PrivateConstructor; | |
return {PrivateConstructor{}, std::forward<Args>(args)...}; | |
} | |
template <class T, class U, class... Args> | |
constexpr folly::Optional<T> make_optional(std::initializer_list<U> il, | |
Args&&... args) { | |
using PrivateConstructor = typename folly::Optional<T>::PrivateConstructor; | |
return {PrivateConstructor{}, il, std::forward<Args>(args)...}; | |
} | |
template <class U, class V> | |
constexpr bool operator==(const Optional<U>& a, const V& b) { | |
return a.hasValue() && a.value() == b; | |
} | |
template <class U, class V> | |
constexpr bool operator!=(const Optional<U>& a, const V& b) { | |
return !(a == b); | |
} | |
template <class U, class V> | |
constexpr bool operator==(const U& a, const Optional<V>& b) { | |
return b.hasValue() && b.value() == a; | |
} | |
template <class U, class V> | |
constexpr bool operator!=(const U& a, const Optional<V>& b) { | |
return !(a == b); | |
} | |
template <class U, class V> | |
constexpr bool operator==(const Optional<U>& a, const Optional<V>& b) { | |
if (a.hasValue() != b.hasValue()) { | |
return false; | |
} | |
if (a.hasValue()) { | |
return a.value() == b.value(); | |
} | |
return true; | |
} | |
template <class U, class V> | |
constexpr bool operator!=(const Optional<U>& a, const Optional<V>& b) { | |
return !(a == b); | |
} | |
template <class U, class V> | |
constexpr bool operator<(const Optional<U>& a, const Optional<V>& b) { | |
if (a.hasValue() != b.hasValue()) { | |
return a.hasValue() < b.hasValue(); | |
} | |
if (a.hasValue()) { | |
return a.value() < b.value(); | |
} | |
return false; | |
} | |
template <class U, class V> | |
constexpr bool operator>(const Optional<U>& a, const Optional<V>& b) { | |
return b < a; | |
} | |
template <class U, class V> | |
constexpr bool operator<=(const Optional<U>& a, const Optional<V>& b) { | |
return !(b < a); | |
} | |
template <class U, class V> | |
constexpr bool operator>=(const Optional<U>& a, const Optional<V>& b) { | |
return !(a < b); | |
} | |
template <class V> | |
bool operator<(const Optional<V>&, const V& other) = delete; | |
template <class V> | |
bool operator<=(const Optional<V>&, const V& other) = delete; | |
template <class V> | |
bool operator>=(const Optional<V>&, const V& other) = delete; | |
template <class V> | |
bool operator>(const Optional<V>&, const V& other) = delete; | |
template <class V> | |
bool operator<(const V& other, const Optional<V>&) = delete; | |
template <class V> | |
bool operator<=(const V& other, const Optional<V>&) = delete; | |
template <class V> | |
bool operator>=(const V& other, const Optional<V>&) = delete; | |
template <class V> | |
bool operator>(const V& other, const Optional<V>&) = delete; | |
template <class V> | |
constexpr bool operator==(const Optional<V>& a, None) noexcept { | |
return !a.hasValue(); | |
} | |
template <class V> | |
constexpr bool operator==(None, const Optional<V>& a) noexcept { | |
return !a.hasValue(); | |
} | |
template <class V> | |
constexpr bool operator<(const Optional<V>&, None) noexcept { | |
return false; | |
} | |
template <class V> | |
constexpr bool operator<(None, const Optional<V>& a) noexcept { | |
return a.hasValue(); | |
} | |
template <class V> | |
constexpr bool operator>(const Optional<V>& a, None) noexcept { | |
return a.hasValue(); | |
} | |
template <class V> | |
constexpr bool operator>(None, const Optional<V>&) noexcept { | |
return false; | |
} | |
template <class V> | |
constexpr bool operator<=(None, const Optional<V>&) noexcept { | |
return true; | |
} | |
template <class V> | |
constexpr bool operator<=(const Optional<V>& a, None) noexcept { | |
return !a.hasValue(); | |
} | |
template <class V> | |
constexpr bool operator>=(const Optional<V>&, None) noexcept { | |
return true; | |
} | |
template <class V> | |
constexpr bool operator>=(None, const Optional<V>& a) noexcept { | |
return !a.hasValue(); | |
} | |
} // namespace folly | |
namespace std { | |
template <class T> | |
struct hash<folly::Optional<T>> { | |
size_t operator()(folly::Optional<T> const& obj) const { | |
if (!obj.hasValue()) { | |
return 0; | |
} | |
return hash<typename remove_const<T>::type>()(*obj); | |
} | |
}; | |
} // namespace std | |
// # 36 "tlm/deps/folly.exploded/include/folly/Expected.h" 2 3 4 | |
// # 55 "tlm/deps/folly.exploded/include/folly/Expected.h" 3 4 | |
namespace folly { | |
template <class Error> | |
class Unexpected; | |
template <class Error> | |
constexpr Unexpected<typename std::decay<Error>::type> makeUnexpected(Error&&); | |
template <class Value, class Error> | |
class Expected; | |
template <class Error, class Value> | |
constexpr Expected<typename std::decay<Value>::type, Error> makeExpected( | |
Value&&); | |
template <class Expected> | |
using ExpectedValueType = | |
typename std::remove_reference<Expected>::type::value_type; | |
template <class Expected> | |
using ExpectedErrorType = | |
typename std::remove_reference<Expected>::type::error_type; | |
namespace expected_detail { | |
template <typename Value, typename Error> | |
struct PromiseReturn; | |
template <template <class...> class Trait, class... Ts> | |
using StrictAllOf = StrictConjunction<Trait<Ts>...>; | |
template <class T> | |
using IsCopyable = StrictConjunction<std::is_copy_constructible<T>, | |
std::is_copy_assignable<T>>; | |
template <class T> | |
using IsMovable = StrictConjunction<std::is_move_constructible<T>, | |
std::is_move_assignable<T>>; | |
template <class T> | |
using IsNothrowCopyable = | |
StrictConjunction<std::is_nothrow_copy_constructible<T>, | |
std::is_nothrow_copy_assignable<T>>; | |
template <class T> | |
using IsNothrowMovable = | |
StrictConjunction<std::is_nothrow_move_constructible<T>, | |
std::is_nothrow_move_assignable<T>>; | |
template <class From, class To> | |
using IsConvertible = StrictConjunction<std::is_constructible<To, From>, | |
std::is_assignable<To&, From>>; | |
template <class T, class U> | |
auto doEmplaceAssign(int, T& t, U&& u) | |
-> decltype(void(t = static_cast<U&&>(u))) { | |
t = static_cast<U&&>(u); | |
} | |
template <class T, class U> | |
auto doEmplaceAssign(long, T& t, U&& u) | |
-> decltype(void(T(static_cast<U&&>(u)))) { | |
t.~T(); | |
::new ((void*)std::addressof(t)) T(static_cast<U&&>(u)); | |
} | |
template <class T, class... Us> | |
auto doEmplaceAssign(int, T& t, Us&&... us) | |
-> decltype(void(t = T(static_cast<Us&&>(us)...))) { | |
t = T(static_cast<Us&&>(us)...); | |
} | |
template <class T, class... Us> | |
auto doEmplaceAssign(long, T& t, Us&&... us) | |
-> decltype(void(T(static_cast<Us&&>(us)...))) { | |
t.~T(); | |
::new ((void*)std::addressof(t)) T(static_cast<Us&&>(us)...); | |
} | |
struct EmptyTag {}; | |
struct ValueTag {}; | |
struct ErrorTag {}; | |
enum class Which : unsigned char { eEmpty, eValue, eError }; | |
enum class StorageType { ePODStruct, ePODUnion, eUnion }; | |
template <class Value, class Error> | |
constexpr StorageType getStorageType() { | |
return StrictAllOf<is_trivially_copyable, Value, Error>::value | |
? (sizeof(std::pair<Value, Error>) <= sizeof(void* [2]) && | |
StrictAllOf<std::is_trivial, | |
Value, | |
Error>::value | |
? StorageType::ePODStruct | |
: StorageType::ePODUnion) | |
: StorageType::eUnion; | |
} | |
template <class Value, | |
class Error, | |
StorageType = expected_detail::getStorageType<Value, Error>()> | |
struct ExpectedStorage { | |
using value_type = Value; | |
using error_type = Error; | |
union { | |
Value value_; | |
Error error_; | |
char ch_; | |
}; | |
Which which_; | |
template <class E = Error, class = decltype(E{})> | |
constexpr ExpectedStorage() noexcept(noexcept(E{})) | |
: error_{}, which_(Which::eError) { | |
} | |
explicit constexpr ExpectedStorage(EmptyTag) noexcept | |
: ch_{}, which_(Which::eEmpty) { | |
} | |
template <class... Vs> | |
explicit constexpr ExpectedStorage(ValueTag, Vs&&... vs) noexcept( | |
noexcept(Value(static_cast<Vs&&>(vs)...))) | |
: value_(static_cast<Vs&&>(vs)...), which_(Which::eValue) { | |
} | |
template <class... Es> | |
explicit constexpr ExpectedStorage(ErrorTag, Es&&... es) noexcept( | |
noexcept(Error(static_cast<Es&&>(es)...))) | |
: error_(static_cast<Es&&>(es)...), which_(Which::eError) { | |
} | |
void clear() noexcept { | |
} | |
static constexpr bool uninitializedByException() noexcept { | |
return false; | |
} | |
template <class... Vs> | |
void assignValue(Vs&&... vs) { | |
expected_detail::doEmplaceAssign(0, value_, static_cast<Vs&&>(vs)...); | |
which_ = Which::eValue; | |
} | |
template <class... Es> | |
void assignError(Es&&... es) { | |
expected_detail::doEmplaceAssign(0, error_, static_cast<Es&&>(es)...); | |
which_ = Which::eError; | |
} | |
template <class Other> | |
void assign(Other&& that) { | |
switch (that.which_) { | |
case Which::eValue: | |
this->assignValue(static_cast<Other&&>(that).value()); | |
break; | |
case Which::eError: | |
this->assignError(static_cast<Other&&>(that).error()); | |
break; | |
case Which::eEmpty: | |
default: | |
this->clear(); | |
break; | |
} | |
} | |
Value& value() & { | |
return value_; | |
} | |
const Value& value() const& { | |
return value_; | |
} | |
Value&& value() && { | |
return std::move(value_); | |
} | |
Error& error() & { | |
return error_; | |
} | |
const Error& error() const& { | |
return error_; | |
} | |
Error&& error() && { | |
return std::move(error_); | |
} | |
}; | |
template <class Value, class Error> | |
struct ExpectedUnion { | |
union { | |
Value value_; | |
Error error_; | |
char ch_{}; | |
}; | |
Which which_ = Which::eEmpty; | |
explicit constexpr ExpectedUnion(EmptyTag) noexcept { | |
} | |
template <class... Vs> | |
explicit constexpr ExpectedUnion(ValueTag, Vs&&... vs) noexcept( | |
noexcept(Value(static_cast<Vs&&>(vs)...))) | |
: value_(static_cast<Vs&&>(vs)...), which_(Which::eValue) { | |
} | |
template <class... Es> | |
explicit constexpr ExpectedUnion(ErrorTag, Es&&... es) noexcept( | |
noexcept(Error(static_cast<Es&&>(es)...))) | |
: error_(static_cast<Es&&>(es)...), which_(Which::eError) { | |
} | |
ExpectedUnion(const ExpectedUnion&) { | |
} | |
ExpectedUnion(ExpectedUnion&&) noexcept { | |
} | |
ExpectedUnion& operator=(const ExpectedUnion&) { | |
return *this; | |
} | |
ExpectedUnion& operator=(ExpectedUnion&&) noexcept { | |
return *this; | |
} | |
~ExpectedUnion() { | |
} | |
Value& value() & { | |
return value_; | |
} | |
const Value& value() const& { | |
return value_; | |
} | |
Value&& value() && { | |
return std::move(value_); | |
} | |
Error& error() & { | |
return error_; | |
} | |
const Error& error() const& { | |
return error_; | |
} | |
Error&& error() && { | |
return std::move(error_); | |
} | |
}; | |
template <class Derived, bool, bool Noexcept> | |
struct CopyConstructible { | |
constexpr CopyConstructible() = default; | |
CopyConstructible(const CopyConstructible& that) noexcept(Noexcept) { | |
static_cast<Derived*>(this)->assign(static_cast<const Derived&>(that)); | |
} | |
constexpr CopyConstructible(CopyConstructible&&) = default; | |
CopyConstructible& operator=(const CopyConstructible&) = default; | |
CopyConstructible& operator=(CopyConstructible&&) = default; | |
}; | |
template <class Derived, bool Noexcept> | |
struct CopyConstructible<Derived, false, Noexcept> { | |
constexpr CopyConstructible() = default; | |
CopyConstructible(const CopyConstructible&) = delete; | |
constexpr CopyConstructible(CopyConstructible&&) = default; | |
CopyConstructible& operator=(const CopyConstructible&) = default; | |
CopyConstructible& operator=(CopyConstructible&&) = default; | |
}; | |
template <class Derived, bool, bool Noexcept> | |
struct MoveConstructible { | |
constexpr MoveConstructible() = default; | |
constexpr MoveConstructible(const MoveConstructible&) = default; | |
MoveConstructible(MoveConstructible&& that) noexcept(Noexcept) { | |
static_cast<Derived*>(this)->assign( | |
std::move(static_cast<Derived&>(that))); | |
} | |
MoveConstructible& operator=(const MoveConstructible&) = default; | |
MoveConstructible& operator=(MoveConstructible&&) = default; | |
}; | |
template <class Derived, bool Noexcept> | |
struct MoveConstructible<Derived, false, Noexcept> { | |
constexpr MoveConstructible() = default; | |
constexpr MoveConstructible(const MoveConstructible&) = default; | |
MoveConstructible(MoveConstructible&&) = delete; | |
MoveConstructible& operator=(const MoveConstructible&) = default; | |
MoveConstructible& operator=(MoveConstructible&&) = default; | |
}; | |
template <class Derived, bool, bool Noexcept> | |
struct CopyAssignable { | |
constexpr CopyAssignable() = default; | |
constexpr CopyAssignable(const CopyAssignable&) = default; | |
constexpr CopyAssignable(CopyAssignable&&) = default; | |
CopyAssignable& operator=(const CopyAssignable& that) noexcept(Noexcept) { | |
static_cast<Derived*>(this)->assign(static_cast<const Derived&>(that)); | |
return *this; | |
} | |
CopyAssignable& operator=(CopyAssignable&&) = default; | |
}; | |
template <class Derived, bool Noexcept> | |
struct CopyAssignable<Derived, false, Noexcept> { | |
constexpr CopyAssignable() = default; | |
constexpr CopyAssignable(const CopyAssignable&) = default; | |
constexpr CopyAssignable(CopyAssignable&&) = default; | |
CopyAssignable& operator=(const CopyAssignable&) = delete; | |
CopyAssignable& operator=(CopyAssignable&&) = default; | |
}; | |
template <class Derived, bool, bool Noexcept> | |
struct MoveAssignable { | |
constexpr MoveAssignable() = default; | |
constexpr MoveAssignable(const MoveAssignable&) = default; | |
constexpr MoveAssignable(MoveAssignable&&) = default; | |
MoveAssignable& operator=(const MoveAssignable&) = default; | |
MoveAssignable& operator=(MoveAssignable&& that) noexcept(Noexcept) { | |
static_cast<Derived*>(this)->assign( | |
std::move(static_cast<Derived&>(that))); | |
return *this; | |
} | |
}; | |
template <class Derived, bool Noexcept> | |
struct MoveAssignable<Derived, false, Noexcept> { | |
constexpr MoveAssignable() = default; | |
constexpr MoveAssignable(const MoveAssignable&) = default; | |
constexpr MoveAssignable(MoveAssignable&&) = default; | |
MoveAssignable& operator=(const MoveAssignable&) = default; | |
MoveAssignable& operator=(MoveAssignable&& that) = delete; | |
}; | |
template <class Value, class Error> | |
struct ExpectedStorage<Value, Error, StorageType::eUnion> | |
: ExpectedUnion<Value, Error>, | |
CopyConstructible< | |
ExpectedStorage<Value, Error, StorageType::eUnion>, | |
StrictAllOf<std::is_copy_constructible, Value, Error>::value, | |
StrictAllOf<std::is_nothrow_copy_constructible, Value, Error>:: | |
value>, | |
MoveConstructible< | |
ExpectedStorage<Value, Error, StorageType::eUnion>, | |
StrictAllOf<std::is_move_constructible, Value, Error>::value, | |
StrictAllOf<std::is_nothrow_move_constructible, Value, Error>:: | |
value>, | |
CopyAssignable<ExpectedStorage<Value, Error, StorageType::eUnion>, | |
StrictAllOf<IsCopyable, Value, Error>::value, | |
StrictAllOf<IsNothrowCopyable, Value, Error>::value>, | |
MoveAssignable<ExpectedStorage<Value, Error, StorageType::eUnion>, | |
StrictAllOf<IsMovable, Value, Error>::value, | |
StrictAllOf<IsNothrowMovable, Value, Error>::value> { | |
using value_type = Value; | |
using error_type = Error; | |
using Base = ExpectedUnion<Value, Error>; | |
template <class E = Error, class = decltype(E{})> | |
constexpr ExpectedStorage() noexcept(noexcept(E{})) : Base{ErrorTag{}} { | |
} | |
ExpectedStorage(const ExpectedStorage&) = default; | |
ExpectedStorage(ExpectedStorage&&) = default; | |
ExpectedStorage& operator=(const ExpectedStorage&) = default; | |
ExpectedStorage& operator=(ExpectedStorage&&) = default; | |
using ExpectedUnion<Value, Error>::ExpectedUnion; | |
~ExpectedStorage() { | |
clear(); | |
} | |
void clear() noexcept { | |
switch (this->which_) { | |
case Which::eValue: | |
this->value().~Value(); | |
break; | |
case Which::eError: | |
this->error().~Error(); | |
break; | |
case Which::eEmpty: | |
default: | |
break; | |
} | |
this->which_ = Which::eEmpty; | |
} | |
bool uninitializedByException() const noexcept { | |
return this->which_ == Which::eEmpty; | |
} | |
template <class... Vs> | |
void assignValue(Vs&&... vs) { | |
if (this->which_ == Which::eValue) { | |
expected_detail::doEmplaceAssign( | |
0, this->value(), static_cast<Vs&&>(vs)...); | |
} else { | |
this->clear(); | |
::new ((void*)std::addressof(this->value())) | |
Value(static_cast<Vs&&>(vs)...); | |
this->which_ = Which::eValue; | |
} | |
} | |
template <class... Es> | |
void assignError(Es&&... es) { | |
if (this->which_ == Which::eError) { | |
expected_detail::doEmplaceAssign( | |
0, this->error(), static_cast<Es&&>(es)...); | |
} else { | |
this->clear(); | |
::new ((void*)std::addressof(this->error())) | |
Error(static_cast<Es&&>(es)...); | |
this->which_ = Which::eError; | |
} | |
} | |
bool isSelfAssign(const ExpectedStorage* that) const { | |
return this == that; | |
} | |
constexpr bool isSelfAssign(const void*) const { | |
return false; | |
} | |
template <class Other> | |
void assign(Other&& that) { | |
if (isSelfAssign(&that)) { | |
return; | |
} | |
switch (that.which_) { | |
case Which::eValue: | |
this->assignValue(static_cast<Other&&>(that).value()); | |
break; | |
case Which::eError: | |
this->assignError(static_cast<Other&&>(that).error()); | |
break; | |
case Which::eEmpty: | |
default: | |
this->clear(); | |
break; | |
} | |
} | |
}; | |
template <class Value, class Error> | |
struct ExpectedStorage<Value, Error, StorageType::ePODStruct> { | |
using value_type = Value; | |
using error_type = Error; | |
Which which_; | |
Error error_; | |
Value value_; | |
constexpr ExpectedStorage() noexcept | |
: which_(Which::eError), error_{}, value_{} { | |
} | |
explicit constexpr ExpectedStorage(EmptyTag) noexcept | |
: which_(Which::eEmpty), error_{}, value_{} { | |
} | |
template <class... Vs> | |
explicit constexpr ExpectedStorage(ValueTag, Vs&&... vs) noexcept( | |
noexcept(Value(static_cast<Vs&&>(vs)...))) | |
: which_(Which::eValue), error_{}, value_(static_cast<Vs&&>(vs)...) { | |
} | |
template <class... Es> | |
explicit constexpr ExpectedStorage(ErrorTag, Es&&... es) noexcept( | |
noexcept(Error(static_cast<Es&&>(es)...))) | |
: which_(Which::eError), error_(static_cast<Es&&>(es)...), value_{} { | |
} | |
void clear() noexcept { | |
} | |
constexpr static bool uninitializedByException() noexcept { | |
return false; | |
} | |
template <class... Vs> | |
void assignValue(Vs&&... vs) { | |
expected_detail::doEmplaceAssign(0, value_, static_cast<Vs&&>(vs)...); | |
which_ = Which::eValue; | |
} | |
template <class... Es> | |
void assignError(Es&&... es) { | |
expected_detail::doEmplaceAssign(0, error_, static_cast<Es&&>(es)...); | |
which_ = Which::eError; | |
} | |
template <class Other> | |
void assign(Other&& that) { | |
switch (that.which_) { | |
case Which::eValue: | |
this->assignValue(static_cast<Other&&>(that).value()); | |
break; | |
case Which::eError: | |
this->assignError(static_cast<Other&&>(that).error()); | |
break; | |
case Which::eEmpty: | |
default: | |
this->clear(); | |
break; | |
} | |
} | |
Value& value() & { | |
return value_; | |
} | |
const Value& value() const& { | |
return value_; | |
} | |
Value&& value() && { | |
return std::move(value_); | |
} | |
Error& error() & { | |
return error_; | |
} | |
const Error& error() const& { | |
return error_; | |
} | |
Error&& error() && { | |
return std::move(error_); | |
} | |
}; | |
namespace expected_detail_ExpectedHelper { | |
template <class T> | |
inline T&& operator,(T&& t, Unit) noexcept { | |
return static_cast<T&&>(t); | |
} | |
struct ExpectedHelper { | |
template <class Error, class T> | |
static constexpr Expected<T, Error> return_(T t) { | |
return folly::makeExpected<Error>(t); | |
} | |
template <class Error, | |
class T, | |
class U, | |
bool FollyRequires554 = false, | |
typename std::enable_if< | |
(FollyRequires554 || | |
static_cast<bool>( | |
expected_detail::IsConvertible<U&&, | |
Error>::value)), | |
int>::type = 0> | |
static constexpr Expected<T, Error> return_(Expected<T, U> t) { | |
return t; | |
} | |
template <class This> | |
static typename std::decay<This>::type then_(This&& ex) { | |
return static_cast<This&&>(ex); | |
} | |
// # 565 "tlm/deps/folly.exploded/include/folly/Expected.h" 3 4 | |
#pragma GCC diagnostic push | |
// # 565 "tlm/deps/folly.exploded/include/folly/Expected.h" 3 4 | |
template <class This, | |
class Fn, | |
class... Fns, | |
class E = ExpectedErrorType<This>, | |
class T = ExpectedHelper> | |
static auto then_(This&& ex, Fn&& fn, Fns&&... fns) -> decltype(T::then_( | |
T::template return_<E>( | |
(std::declval<Fn>()(std::declval<This>().value()), unit)), | |
std::declval<Fns>()...)) { | |
if ((__builtin_expect((ex.which_ == expected_detail::Which::eValue), | |
1))) { | |
return T::then_(T::template return_<E>( | |
(static_cast<Fn&&>(fn)( | |
static_cast<This&&>(ex).value()), | |
unit)), | |
static_cast<Fns&&>(fns)...); | |
} | |
return makeUnexpected(static_cast<This&&>(ex).error()); | |
} | |
template <class This, | |
class Yes, | |
class No, | |
class Ret = decltype( | |
std::declval<Yes>()(std::declval<This>().value())), | |
class Err = decltype( | |
std::declval<No>()(std::declval<This>().error())), | |
bool FollyRequires595 = false, | |
typename std::enable_if< | |
(FollyRequires595 || | |
static_cast<bool>(!std::is_void<Err>::value)), | |
int>::type = 0> | |
static Ret thenOrThrow_(This&& ex, Yes&& yes, No&& no) { | |
if ((__builtin_expect((ex.which_ == expected_detail::Which::eValue), | |
1))) { | |
return Ret( | |
static_cast<Yes&&>(yes)(static_cast<This&&>(ex).value())); | |
} | |
throw_exception(static_cast<No&&>(no)(static_cast<This&&>(ex).error())); | |
} | |
template <class This, | |
class Yes, | |
class No, | |
class Ret = decltype( | |
std::declval<Yes>()(std::declval<This>().value())), | |
class Err = decltype( | |
std::declval<No>()(std::declval<This&>().error())), | |
bool FollyRequires609 = false, | |
typename std::enable_if< | |
(FollyRequires609 || | |
static_cast<bool>(std::is_void<Err>::value)), | |
int>::type = 0> | |
static Ret thenOrThrow_(This&& ex, Yes&& yes, No&& no) { | |
if ((__builtin_expect((ex.which_ == expected_detail::Which::eValue), | |
1))) { | |
return Ret( | |
static_cast<Yes&&>(yes)(static_cast<This&&>(ex).value())); | |
} | |
static_cast<No&&>(no)(ex.error()); | |
typename Unexpected<ExpectedErrorType<This>>::MakeBadExpectedAccess bad; | |
throw_exception(bad(static_cast<This&&>(ex).error())); | |
} | |
// # 618 "tlm/deps/folly.exploded/include/folly/Expected.h" 3 4 | |
#pragma GCC diagnostic pop | |
// # 618 "tlm/deps/folly.exploded/include/folly/Expected.h" 3 4 | |
}; | |
} // namespace expected_detail_ExpectedHelper | |
using expected_detail_ExpectedHelper::ExpectedHelper; | |
struct UnexpectedTag {}; | |
} // namespace expected_detail | |
using unexpected_t = | |
expected_detail::UnexpectedTag (&)(expected_detail::UnexpectedTag); | |
inline expected_detail::UnexpectedTag unexpected( | |
expected_detail::UnexpectedTag = {}) { | |
return {}; | |
} | |
class __attribute__((__visibility__("default"))) BadExpectedAccess | |
: public std::logic_error { | |
public: | |
BadExpectedAccess() : std::logic_error("bad Expected access") { | |
} | |
}; | |
namespace expected_detail {} | |
template <class Error> | |
class Unexpected final { | |
template <class E> | |
friend class Unexpected; | |
template <class V, class E> | |
friend class Expected; | |
friend struct expected_detail::ExpectedHelper; | |
public: | |
class __attribute__((__visibility__("default"))) BadExpectedAccess | |
: public folly::BadExpectedAccess { | |
public: | |
explicit BadExpectedAccess(Error err) | |
: folly::BadExpectedAccess{}, error_(std::move(err)) { | |
} | |
Error error() const { | |
return error_; | |
} | |
private: | |
Error error_; | |
}; | |
Unexpected() = default; | |
Unexpected(const Unexpected&) = default; | |
Unexpected(Unexpected&&) = default; | |
Unexpected& operator=(const Unexpected&) = default; | |
Unexpected& operator=(Unexpected&&) = default; | |
__attribute__((__cold__)) constexpr Unexpected(const Error& err) | |
: error_(err) { | |
} | |
__attribute__((__cold__)) constexpr Unexpected(Error&& err) | |
: error_(std::move(err)) { | |
} | |
template <class Other, | |
bool FollyRequires694 = false, | |
typename std::enable_if< | |
(FollyRequires694 || | |
static_cast<bool>( | |
std::is_constructible<Error, Other&&>::value)), | |
int>::type = 0> | |
constexpr Unexpected(Unexpected<Other> that) | |
: error_(std::move(that.error())) { | |
} | |
template <class Other, | |
bool FollyRequires702 = false, | |
typename std::enable_if< | |
(FollyRequires702 || | |
static_cast<bool>( | |
std::is_assignable<Error&, Other&&>::value)), | |
int>::type = 0> | |
Unexpected& operator=(Unexpected<Other> that) { | |
error_ = std::move(that.error()); | |
} | |
Error& error() & { | |
return error_; | |
} | |
const Error& error() const& { | |
return error_; | |
} | |
Error&& error() && { | |
return std::move(error_); | |
} | |
private: | |
struct MakeBadExpectedAccess { | |
template <class E> | |
BadExpectedAccess operator()(E&& err) const { | |
return BadExpectedAccess(static_cast<E&&>(err)); | |
} | |
}; | |
Error error_; | |
}; | |
template <class Error, | |
bool FollyRequires733 = false, | |
typename std::enable_if< | |
(FollyRequires733 || | |
static_cast<bool>(IsEqualityComparable<Error>::value)), | |
int>::type = 0> | |
inline bool operator==(const Unexpected<Error>& lhs, | |
const Unexpected<Error>& rhs) { | |
return lhs.error() == rhs.error(); | |
} | |
template <class Error, | |
bool FollyRequires741 = false, | |
typename std::enable_if< | |
(FollyRequires741 || | |
static_cast<bool>(IsEqualityComparable<Error>::value)), | |
int>::type = 0> | |
inline bool operator!=(const Unexpected<Error>& lhs, | |
const Unexpected<Error>& rhs) { | |
return !(lhs == rhs); | |
} | |
// # 760 "tlm/deps/folly.exploded/include/folly/Expected.h" 3 4 | |
template <class Error> | |
constexpr Unexpected<typename std::decay<Error>::type> makeUnexpected( | |
Error&& err) { | |
return Unexpected<typename std::decay<Error>::type>{ | |
static_cast<Error&&>(err)}; | |
} | |
// # 861 "tlm/deps/folly.exploded/include/folly/Expected.h" 3 4 | |
template <class Value, class Error> | |
class Expected final : expected_detail::ExpectedStorage<Value, Error> { | |
template <class, class> | |
friend class Expected; | |
template <class, class, expected_detail::StorageType> | |
friend struct expected_detail::ExpectedStorage; | |
friend struct expected_detail::ExpectedHelper; | |
using Base = expected_detail::ExpectedStorage<Value, Error>; | |
using MakeBadExpectedAccess = | |
typename Unexpected<Error>::MakeBadExpectedAccess; | |
Base& base() & { | |
return *this; | |
} | |
const Base& base() const& { | |
return *this; | |
} | |
Base&& base() && { | |
return std::move(*this); | |
} | |
public: | |
using value_type = Value; | |
using error_type = Error; | |
template <class U> | |
using rebind = Expected<U, Error>; | |
static_assert(!std::is_reference<Value>::value, | |
"Expected may not be used with reference types"); | |
static_assert(!std::is_abstract<Value>::value, | |
"Expected may not be used with abstract types"); | |
template <class B = Base, class = decltype(B{})> | |
Expected() noexcept(noexcept(B{})) : Base{} { | |
} | |
Expected(const Expected& that) = default; | |
Expected(Expected&& that) = default; | |
template <class V, | |
class E, | |
bool FollyRequires905 = false, | |
typename std::enable_if< | |
(FollyRequires905 || | |
static_cast<bool>( | |
!std::is_same<Expected<V, E>, Expected>::value && | |
std::is_constructible<Value, V&&>::value && | |
std::is_constructible<Error, E&&>::value)), | |
int>::type = 0 | |
> | |
Expected(Expected<V, E> that) : Base{expected_detail::EmptyTag{}} { | |
this->assign(std::move(that)); | |
} | |
template <bool FollyRequires913 = false, | |
typename std::enable_if< | |
(FollyRequires913 || | |
static_cast<bool>( | |
std::is_copy_constructible<Value>::value)), | |
int>::type = 0> | |
constexpr Expected(const Value& val) noexcept(noexcept(Value(val))) | |
: Base{expected_detail::ValueTag{}, val} { | |
} | |
template <bool FollyRequires918 = false, | |
typename std::enable_if< | |
(FollyRequires918 || | |
static_cast<bool>( | |
std::is_move_constructible<Value>::value)), | |
int>::type = 0> | |
constexpr Expected(Value&& val) noexcept(noexcept(Value(std::move(val)))) | |
: Base{expected_detail::ValueTag{}, std::move(val)} { | |
} | |
template < | |
class T, | |
bool FollyRequires923 = false, | |
typename std::enable_if< | |
(FollyRequires923 || | |
static_cast<bool>(std::is_convertible<T, Value>::value && | |
!std::is_convertible<T, Error>::value)), | |
int>::type = 0 | |
> | |
constexpr Expected(T&& val) noexcept(noexcept(Value(static_cast<T&&>(val)))) | |
: Base{expected_detail::ValueTag{}, static_cast<T&&>(val)} { | |
} | |
template <class... Ts, | |
bool FollyRequires930 = false, | |
typename std::enable_if< | |
(FollyRequires930 || | |
static_cast<bool>( | |
std::is_constructible<Value, Ts&&...>::value)), | |
int>::type = 0> | |
explicit constexpr Expected(in_place_t, Ts&&... ts) noexcept( | |
noexcept(Value(std::declval<Ts>()...))) | |
: Base{expected_detail::ValueTag{}, static_cast<Ts&&>(ts)...} { | |
} | |
template <class U, | |
class... Ts, | |
bool FollyRequires938 = false, | |
typename std::enable_if< | |
(FollyRequires938 || | |
static_cast<bool>( | |
std::is_constructible<Value, | |
std::initializer_list<U>&, | |
Ts&&...>::value)), | |
int>::type = 0 | |
> | |
explicit constexpr Expected( | |
in_place_t, | |
std::initializer_list<U> il, | |
Ts&&... ts) noexcept(noexcept(Value(std::declval<Ts>()...))) | |
: Base{expected_detail::ValueTag{}, il, static_cast<Ts&&>(ts)...} { | |
} | |
Expected(const Error&) = delete; | |
Expected(Error&&) = delete; | |
template <bool FollyRequires952 = false, | |
typename std::enable_if< | |
(FollyRequires952 || | |
static_cast<bool>( | |
std::is_copy_constructible<Error>::value)), | |
int>::type = 0> | |
constexpr Expected(unexpected_t, | |
const Error& err) noexcept(noexcept(Error(err))) | |
: Base{expected_detail::ErrorTag{}, err} { | |
} | |
template <bool FollyRequires957 = false, | |
typename std::enable_if< | |
(FollyRequires957 || | |
static_cast<bool>( | |
std::is_move_constructible<Error>::value)), | |
int>::type = 0> | |
constexpr Expected(unexpected_t, | |
Error&& err) noexcept(noexcept(Error(std::move(err)))) | |
: Base{expected_detail::ErrorTag{}, std::move(err)} { | |
} | |
template <bool FollyRequires962 = false, | |
typename std::enable_if< | |
(FollyRequires962 || | |
static_cast<bool>( | |
std::is_copy_constructible<Error>::value)), | |
int>::type = 0> | |
constexpr Expected(const Unexpected<Error>& err) noexcept( | |
noexcept(Error(err.error()))) | |
: Base{expected_detail::ErrorTag{}, err.error()} { | |
} | |
template <bool FollyRequires967 = false, | |
typename std::enable_if< | |
(FollyRequires967 || | |
static_cast<bool>( | |
std::is_move_constructible<Error>::value)), | |
int>::type = 0> | |
constexpr Expected(Unexpected<Error>&& err) noexcept( | |
noexcept(Error(std::move(err.error())))) | |
: Base{expected_detail::ErrorTag{}, std::move(err.error())} { | |
} | |
Expected& operator=(const Expected& that) = default; | |
Expected& operator=(Expected&& that) = default; | |
template <class V, | |
class E, | |
bool FollyRequires980 = false, | |
typename std::enable_if< | |
(FollyRequires980 || | |
static_cast<bool>( | |
!std::is_same<Expected<V, E>, Expected>::value && | |
expected_detail::IsConvertible<V&&, | |
Value>::value && | |
expected_detail::IsConvertible<E&&, | |
Error>::value)), | |
int>::type = 0 | |
> | |
Expected& operator=(Expected<V, E> that) { | |
this->assign(std::move(that)); | |
return *this; | |
} | |
template <bool FollyRequires989 = false, | |
typename std::enable_if< | |
(FollyRequires989 || | |
static_cast<bool>( | |
expected_detail::IsCopyable<Value>::value)), | |
int>::type = 0> | |
Expected& operator=(const Value& val) noexcept( | |
expected_detail::IsNothrowCopyable<Value>::value) { | |
this->assignValue(val); | |
return *this; | |
} | |
template <bool FollyRequires996 = false, | |
typename std::enable_if< | |
(FollyRequires996 || | |
static_cast<bool>( | |
expected_detail::IsMovable<Value>::value)), | |
int>::type = 0> | |
Expected& operator=(Value&& val) noexcept( | |
expected_detail::IsNothrowMovable<Value>::value) { | |
this->assignValue(std::move(val)); | |
return *this; | |
} | |
template < | |
class T, | |
bool FollyRequires1003 = false, | |
typename std::enable_if< | |
(FollyRequires1003 || | |
static_cast<bool>(std::is_convertible<T, Value>::value && | |
!std::is_convertible<T, Error>::value)), | |
int>::type = 0 | |
> | |
Expected& operator=(T&& val) { | |
this->assignValue(static_cast<T&&>(val)); | |
return *this; | |
} | |
template <bool FollyRequires1011 = false, | |
typename std::enable_if< | |
(FollyRequires1011 || | |
static_cast<bool>( | |
expected_detail::IsCopyable<Error>::value)), | |
int>::type = 0> | |
Expected& operator=(const Unexpected<Error>& err) noexcept( | |
expected_detail::IsNothrowCopyable<Error>::value) { | |
this->assignError(err.error()); | |
return *this; | |
} | |
template <bool FollyRequires1018 = false, | |
typename std::enable_if< | |
(FollyRequires1018 || | |
static_cast<bool>( | |
expected_detail::IsMovable<Error>::value)), | |
int>::type = 0> | |
Expected& operator=(Unexpected<Error>&& err) noexcept( | |
expected_detail::IsNothrowMovable<Error>::value) { | |
this->assignError(std::move(err.error())); | |
return *this; | |
} | |
Expected(const expected_detail::PromiseReturn<Value, Error>& p) | |
: Expected{} { | |
p.promise_->value_ = this; | |
} | |
template <class... Ts, | |
bool FollyRequires1031 = false, | |
typename std::enable_if< | |
(FollyRequires1031 || | |
static_cast<bool>( | |
std::is_constructible<Value, Ts&&...>::value)), | |
int>::type = 0> | |
void emplace(Ts&&... ts) { | |
this->assignValue(static_cast<Ts&&>(ts)...); | |
} | |
void swap(Expected& that) noexcept( | |
expected_detail::StrictAllOf<IsNothrowSwappable, Value, Error>:: | |
value) { | |
if (this->uninitializedByException() || | |
that.uninitializedByException()) { | |
throw_exception<BadExpectedAccess>(); | |
} | |
using std::swap; | |
if (*this) { | |
if (that) { | |
swap(this->value_, that.value_); | |
} else { | |
Error e(std::move(that.error_)); | |
that.assignValue(std::move(this->value_)); | |
this->assignError(std::move(e)); | |
} | |
} else { | |
if (!that) { | |
swap(this->error_, that.error_); | |
} else { | |
Error e(std::move(this->error_)); | |
this->assignValue(std::move(that.value_)); | |
that.assignError(std::move(e)); | |
} | |
} | |
} | |
Expected& operator=(const Error&) = delete; | |
Expected& operator=(Error&&) = delete; | |
template <class Val, class Err> | |
friend typename std::enable_if<IsEqualityComparable<Val>::value, bool>::type | |
operator==(const Expected<Val, Err>& lhs, const Expected<Val, Err>& rhs); | |
template <class Val, class Err> | |
friend typename std::enable_if<IsLessThanComparable<Val>::value, bool>::type | |
operator<(const Expected<Val, Err>& lhs, const Expected<Val, Err>& rhs); | |
constexpr bool hasValue() const noexcept { | |
return (__builtin_expect( | |
(expected_detail::Which::eValue == this->which_), 1)); | |
} | |
constexpr bool hasError() const noexcept { | |
return (__builtin_expect( | |
(expected_detail::Which::eError == this->which_), 0)); | |
} | |
using Base::uninitializedByException; | |
const Value& value() const& { | |
requireValue(); | |
return this->Base::value(); | |
} | |
Value& value() & { | |
requireValue(); | |
return this->Base::value(); | |
} | |
Value&& value() && { | |
requireValue(); | |
return std::move(this->Base::value()); | |
} | |
const Error& error() const& { | |
requireError(); | |
return this->Base::error(); | |
} | |
Error& error() & { | |
requireError(); | |
return this->Base::error(); | |
} | |
Error&& error() && { | |
requireError(); | |
return std::move(this->Base::error()); | |
} | |
template <class U> | |
Value value_or(U&& dflt) const& { | |
if ((__builtin_expect((this->which_ == expected_detail::Which::eValue), | |
1))) { | |
return this->value_; | |
} | |
return static_cast<U&&>(dflt); | |
} | |
template <class U> | |
Value value_or(U&& dflt) && { | |
if ((__builtin_expect((this->which_ == expected_detail::Which::eValue), | |
1))) { | |
return std::move(this->value_); | |
} | |
return static_cast<U&&>(dflt); | |
} | |
explicit constexpr operator bool() const noexcept { | |
return hasValue(); | |
} | |
const Value& operator*() const& { | |
return this->value(); | |
} | |
Value& operator*() & { | |
return this->value(); | |
} | |
Value&& operator*() && { | |
return std::move(this->value()); | |
} | |
const Value* operator->() const { | |
return std::addressof(this->value()); | |
} | |
Value* operator->() { | |
return std::addressof(this->value()); | |
} | |
const Value* get_pointer() const& noexcept { | |
return hasValue() ? std::addressof(this->value_) : nullptr; | |
} | |
Value* get_pointer() & noexcept { | |
return hasValue() ? std::addressof(this->value_) : nullptr; | |
} | |
Value* get_pointer() && = delete; | |
template <class... Fns, | |
bool FollyRequires1177 = false, | |
typename std::enable_if<(FollyRequires1177 || | |
static_cast<bool>(sizeof...(Fns) >= 1)), | |
int>::type = 0> | |
auto then(Fns&&... fns) const& -> decltype( | |
expected_detail::ExpectedHelper::then_(std::declval<const Base&>(), | |
std::declval<Fns>()...)) { | |
if (this->uninitializedByException()) { | |
throw_exception<BadExpectedAccess>(); | |
} | |
return expected_detail::ExpectedHelper::then_( | |
base(), static_cast<Fns&&>(fns)...); | |
} | |
template <class... Fns, | |
bool FollyRequires1189 = false, | |
typename std::enable_if<(FollyRequires1189 || | |
static_cast<bool>(sizeof...(Fns) >= 1)), | |
int>::type = 0> | |
auto then(Fns&&... fns) & -> decltype( | |
expected_detail::ExpectedHelper::then_(std::declval<Base&>(), | |
std::declval<Fns>()...)) { | |
if (this->uninitializedByException()) { | |
throw_exception<BadExpectedAccess>(); | |
} | |
return expected_detail::ExpectedHelper::then_( | |
base(), static_cast<Fns&&>(fns)...); | |
} | |
template <class... Fns, | |
bool FollyRequires1200 = false, | |
typename std::enable_if<(FollyRequires1200 || | |
static_cast<bool>(sizeof...(Fns) >= 1)), | |
int>::type = 0> | |
auto then(Fns&&... fns) && -> decltype( | |
expected_detail::ExpectedHelper::then_(std::declval<Base&&>(), | |
std::declval<Fns>()...)) { | |
if (this->uninitializedByException()) { | |
throw_exception<BadExpectedAccess>(); | |
} | |
return expected_detail::ExpectedHelper::then_( | |
std::move(base()), static_cast<Fns&&>(fns)...); | |
} | |
template <class Yes, class No = MakeBadExpectedAccess> | |
auto thenOrThrow(Yes&& yes, No&& no = No{}) const& -> decltype( | |
std::declval<Yes>()(std::declval<const Value&>())) { | |
using Ret = decltype(std::declval<Yes>()(std::declval<const Value&>())); | |
if (this->uninitializedByException()) { | |
throw_exception<BadExpectedAccess>(); | |
} | |
return Ret(expected_detail::ExpectedHelper::thenOrThrow_( | |
base(), static_cast<Yes&&>(yes), static_cast<No&&>(no))); | |
} | |
template <class Yes, class No = MakeBadExpectedAccess> | |
auto thenOrThrow(Yes&& yes, No&& no = No{}) & -> decltype( | |
std::declval<Yes>()(std::declval<Value&>())) { | |
using Ret = decltype(std::declval<Yes>()(std::declval<Value&>())); | |
if (this->uninitializedByException()) { | |
throw_exception<BadExpectedAccess>(); | |
} | |
return Ret(expected_detail::ExpectedHelper::thenOrThrow_( | |
base(), static_cast<Yes&&>(yes), static_cast<No&&>(no))); | |
} | |
template <class Yes, class No = MakeBadExpectedAccess> | |
auto thenOrThrow(Yes&& yes, No&& no = No{}) && -> decltype( | |
std::declval<Yes>()(std::declval<Value&&>())) { | |
using Ret = decltype(std::declval<Yes>()(std::declval<Value&&>())); | |
if (this->uninitializedByException()) { | |
throw_exception<BadExpectedAccess>(); | |
} | |
return Ret(expected_detail::ExpectedHelper::thenOrThrow_( | |
std::move(base()), | |
static_cast<Yes&&>(yes), | |
static_cast<No&&>(no))); | |
} | |
private: | |
void requireValue() const { | |
if ((__builtin_expect((!hasValue()), 0))) { | |
if ((__builtin_expect((hasError()), 1))) { | |
using Err = typename Unexpected<Error>::BadExpectedAccess; | |
throw_exception<Err>(this->error_); | |
} | |
throw_exception<BadExpectedAccess>(); | |
} | |
} | |
void requireError() const { | |
if ((__builtin_expect((!hasError()), 0))) { | |
throw_exception<BadExpectedAccess>(); | |
} | |
} | |
expected_detail::Which which() const noexcept { | |
return this->which_; | |
} | |
}; | |
template <class Value, class Error> | |
inline typename std::enable_if<IsEqualityComparable<Value>::value, bool>::type | |
operator==(const Expected<Value, Error>& lhs, | |
const Expected<Value, Error>& rhs) { | |
if ((__builtin_expect((lhs.uninitializedByException()), 0))) { | |
throw_exception<BadExpectedAccess>(); | |
} | |
if ((__builtin_expect((lhs.which_ != rhs.which_), 0))) { | |
return false; | |
} | |
if ((__builtin_expect((lhs.hasError()), 0))) { | |
return true; | |
} | |
return lhs.value_ == rhs.value_; | |
} | |
template <class Value, | |
class Error, | |
bool FollyRequires1288 = false, | |
typename std::enable_if< | |
(FollyRequires1288 || | |
static_cast<bool>(IsEqualityComparable<Value>::value)), | |
int>::type = 0> | |
inline bool operator!=(const Expected<Value, Error>& lhs, | |
const Expected<Value, Error>& rhs) { | |
return !(rhs == lhs); | |
} | |
template <class Value, class Error> | |
inline typename std::enable_if<IsLessThanComparable<Value>::value, bool>::type | |
operator<(const Expected<Value, Error>& lhs, | |
const Expected<Value, Error>& rhs) { | |
if ((__builtin_expect((lhs.uninitializedByException() || | |
rhs.uninitializedByException()), | |
0))) { | |
throw_exception<BadExpectedAccess>(); | |
} | |
if ((__builtin_expect((lhs.hasError()), 0))) { | |
return !rhs.hasError(); | |
} | |
if ((__builtin_expect((rhs.hasError()), 0))) { | |
return false; | |
} | |
return lhs.value_ < rhs.value_; | |
} | |
template <class Value, | |
class Error, | |
bool FollyRequires1315 = false, | |
typename std::enable_if< | |
(FollyRequires1315 || | |
static_cast<bool>(IsLessThanComparable<Value>::value)), | |
int>::type = 0> | |
inline bool operator<=(const Expected<Value, Error>& lhs, | |
const Expected<Value, Error>& rhs) { | |
return !(rhs < lhs); | |
} | |
template <class Value, | |
class Error, | |
bool FollyRequires1324 = false, | |
typename std::enable_if< | |
(FollyRequires1324 || | |
static_cast<bool>(IsLessThanComparable<Value>::value)), | |
int>::type = 0> | |
inline bool operator>(const Expected<Value, Error>& lhs, | |
const Expected<Value, Error>& rhs) { | |
return rhs < lhs; | |
} | |
template <class Value, | |
class Error, | |
bool FollyRequires1333 = false, | |
typename std::enable_if< | |
(FollyRequires1333 || | |
static_cast<bool>(IsLessThanComparable<Value>::value)), | |
int>::type = 0> | |
inline bool operator>=(const Expected<Value, Error>& lhs, | |
const Expected<Value, Error>& rhs) { | |
return !(lhs < rhs); | |
} | |
template <class Value, class Error> | |
void swap(Expected<Value, Error>& lhs, Expected<Value, Error>& rhs) noexcept( | |
expected_detail::StrictAllOf<IsNothrowSwappable, Value, Error>::value) { | |
lhs.swap(rhs); | |
} | |
template <class Value, class Error> | |
const Value* get_pointer(const Expected<Value, Error>& ex) noexcept { | |
return ex.get_pointer(); | |
} | |
template <class Value, class Error> | |
Value* get_pointer(Expected<Value, Error>& ex) noexcept { | |
return ex.get_pointer(); | |
} | |
// # 1369 "tlm/deps/folly.exploded/include/folly/Expected.h" 3 4 | |
template <class Error, class Value> | |
constexpr Expected<typename std::decay<Value>::type, Error> makeExpected( | |
Value&& val) { | |
return Expected<typename std::decay<Value>::type, Error>{ | |
in_place, static_cast<Value&&>(val)}; | |
} | |
template <class Value, class Error> | |
bool operator==(const Expected<Value, Error>&, const Value& other) = delete; | |
template <class Value, class Error> | |
bool operator!=(const Expected<Value, Error>&, const Value& other) = delete; | |
template <class Value, class Error> | |
bool operator<(const Expected<Value, Error>&, const Value& other) = delete; | |
template <class Value, class Error> | |
bool operator<=(const Expected<Value, Error>&, const Value& other) = delete; | |
template <class Value, class Error> | |
bool operator>=(const Expected<Value, Error>&, const Value& other) = delete; | |
template <class Value, class Error> | |
bool operator>(const Expected<Value, Error>&, const Value& other) = delete; | |
template <class Value, class Error> | |
bool operator==(const Value& other, const Expected<Value, Error>&) = delete; | |
template <class Value, class Error> | |
bool operator!=(const Value& other, const Expected<Value, Error>&) = delete; | |
template <class Value, class Error> | |
bool operator<(const Value& other, const Expected<Value, Error>&) = delete; | |
template <class Value, class Error> | |
bool operator<=(const Value& other, const Expected<Value, Error>&) = delete; | |
template <class Value, class Error> | |
bool operator>=(const Value& other, const Expected<Value, Error>&) = delete; | |
template <class Value, class Error> | |
bool operator>(const Value& other, const Expected<Value, Error>&) = delete; | |
} // namespace folly | |
// # 118 "tlm/deps/folly.exploded/include/folly/Conv.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Range.h" 1 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/lang/CString.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/lang/CString.h" 3 4 | |
// # 21 "tlm/deps/folly.exploded/include/folly/lang/CString.h" 2 3 4 | |
namespace folly { | |
namespace detail { | |
void* memrchr_fallback(void* s, int c, std::size_t len) noexcept; | |
void const* memrchr_fallback(void const* s, int c, std::size_t len) noexcept; | |
} // namespace detail | |
void* memrchr(void* s, int c, std::size_t len) noexcept; | |
void const* memrchr(void const* s, int c, std::size_t len) noexcept; | |
std::size_t strlcpy(char* dest, char const* src, std::size_t size); | |
} // namespace folly | |
// # 25 "tlm/deps/folly.exploded/include/folly/Range.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/Constexpr.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/Constexpr.h" 3 4 | |
// # 23 "tlm/deps/folly.exploded/include/folly/portability/Constexpr.h" 2 3 4 | |
namespace folly { | |
namespace detail { | |
template <typename Char> | |
constexpr size_t constexpr_strlen_internal(const Char* s, size_t len) { | |
return *(s + 0) == Char(0) | |
? len + 0 | |
: *(s + 1) == Char(0) | |
? len + 1 | |
: *(s + 2) == Char(0) | |
? len + 2 | |
: *(s + 3) == Char(0) | |
? len + 3 | |
: *(s + 4) == Char(0) | |
? len + 4 | |
: *(s + 5) == Char(0) | |
? len + 5 | |
: *(s + | |
6) == Char(0) | |
? len + 6 | |
: *(s + | |
7) == Char(0) | |
? len + 7 | |
: constexpr_strlen_internal( | |
s + 8, | |
len + 8); | |
} | |
static_assert(constexpr_strlen_internal("123456789", 0) == 9, | |
"Someone appears to have broken constexpr_strlen..."); | |
template <typename Char> | |
constexpr int constexpr_strcmp_internal(const Char* s1, const Char* s2) { | |
return (*s1 == '\0' || *s1 != *s2) | |
? (static_cast<int>(*s1 - *s2)) | |
: constexpr_strcmp_internal(s1 + 1, s2 + 1); | |
} | |
} // namespace detail | |
template <typename Char> | |
constexpr size_t constexpr_strlen(const Char* s) { | |
return detail::constexpr_strlen_internal(s, 0); | |
} | |
template <> | |
constexpr size_t constexpr_strlen(const char* s) { | |
return std::strlen(s); | |
} | |
template <typename Char> | |
constexpr int constexpr_strcmp(const Char* s1, const Char* s2) { | |
return detail::constexpr_strcmp_internal(s1, s2); | |
} | |
template <> | |
constexpr int constexpr_strcmp(const char* s1, const char* s2) { | |
return std::strcmp(s1, s2); | |
} | |
} // namespace folly | |
// # 27 "tlm/deps/folly.exploded/include/folly/Range.h" 2 3 4 | |
// # 31 "tlm/deps/folly.exploded/include/folly/Range.h" 2 3 4 | |
// # 32 "tlm/deps/folly.exploded/include/folly/Range.h" 2 3 4 | |
// # 34 "tlm/deps/folly.exploded/include/folly/Range.h" 2 3 4 | |
// # 44 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/CpuId.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/CpuId.h" 3 4 | |
// # 27 "tlm/deps/folly.exploded/include/folly/CpuId.h" 3 4 | |
namespace folly { | |
class CpuId { | |
public: | |
inline __attribute__((__always_inline__)) CpuId() { | |
// # 92 "tlm/deps/folly.exploded/include/folly/CpuId.h" 3 4 | |
uint32_t n; | |
__asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx"); | |
if (n >= 1) { | |
uint32_t f1a; | |
__asm__("cpuid" | |
: "=a"(f1a), "=c"(f1c_), "=d"(f1d_) | |
: "a"(1) | |
: "ebx"); | |
} | |
if (n >= 7) { | |
uint32_t f7a; | |
__asm__("cpuid" | |
: "=a"(f7a), "=b"(f7b_), "=c"(f7c_) | |
: "a"(7), "c"(0) | |
: "edx"); | |
} | |
} | |
// # 115 "tlm/deps/folly.exploded/include/folly/CpuId.h" 3 4 | |
inline __attribute__((__always_inline__)) bool sse3() const { | |
return ((f1c_) & (1U << 0)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool pclmuldq() const { | |
return ((f1c_) & (1U << 1)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool dtes64() const { | |
return ((f1c_) & (1U << 2)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool monitor() const { | |
return ((f1c_) & (1U << 3)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool dscpl() const { | |
return ((f1c_) & (1U << 4)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool vmx() const { | |
return ((f1c_) & (1U << 5)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool smx() const { | |
return ((f1c_) & (1U << 6)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool eist() const { | |
return ((f1c_) & (1U << 7)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool tm2() const { | |
return ((f1c_) & (1U << 8)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool ssse3() const { | |
return ((f1c_) & (1U << 9)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool cnxtid() const { | |
return ((f1c_) & (1U << 10)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool fma() const { | |
return ((f1c_) & (1U << 12)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool cx16() const { | |
return ((f1c_) & (1U << 13)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool xtpr() const { | |
return ((f1c_) & (1U << 14)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool pdcm() const { | |
return ((f1c_) & (1U << 15)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool pcid() const { | |
return ((f1c_) & (1U << 17)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool dca() const { | |
return ((f1c_) & (1U << 18)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool sse41() const { | |
return ((f1c_) & (1U << 19)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool sse42() const { | |
return ((f1c_) & (1U << 20)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool x2apic() const { | |
return ((f1c_) & (1U << 21)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool movbe() const { | |
return ((f1c_) & (1U << 22)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool popcnt() const { | |
return ((f1c_) & (1U << 23)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool tscdeadline() const { | |
return ((f1c_) & (1U << 24)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool aes() const { | |
return ((f1c_) & (1U << 25)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool xsave() const { | |
return ((f1c_) & (1U << 26)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool osxsave() const { | |
return ((f1c_) & (1U << 27)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool avx() const { | |
return ((f1c_) & (1U << 28)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool f16c() const { | |
return ((f1c_) & (1U << 29)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool rdrand() const { | |
return ((f1c_) & (1U << 30)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool fpu() const { | |
return ((f1d_) & (1U << 0)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool vme() const { | |
return ((f1d_) & (1U << 1)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool de() const { | |
return ((f1d_) & (1U << 2)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool pse() const { | |
return ((f1d_) & (1U << 3)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool tsc() const { | |
return ((f1d_) & (1U << 4)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool msr() const { | |
return ((f1d_) & (1U << 5)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool pae() const { | |
return ((f1d_) & (1U << 6)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool mce() const { | |
return ((f1d_) & (1U << 7)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool cx8() const { | |
return ((f1d_) & (1U << 8)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool apic() const { | |
return ((f1d_) & (1U << 9)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool sep() const { | |
return ((f1d_) & (1U << 11)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool mtrr() const { | |
return ((f1d_) & (1U << 12)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool pge() const { | |
return ((f1d_) & (1U << 13)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool mca() const { | |
return ((f1d_) & (1U << 14)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool cmov() const { | |
return ((f1d_) & (1U << 15)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool pat() const { | |
return ((f1d_) & (1U << 16)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool pse36() const { | |
return ((f1d_) & (1U << 17)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool psn() const { | |
return ((f1d_) & (1U << 18)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool clfsh() const { | |
return ((f1d_) & (1U << 19)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool ds() const { | |
return ((f1d_) & (1U << 21)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool acpi() const { | |
return ((f1d_) & (1U << 22)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool mmx() const { | |
return ((f1d_) & (1U << 23)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool fxsr() const { | |
return ((f1d_) & (1U << 24)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool sse() const { | |
return ((f1d_) & (1U << 25)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool sse2() const { | |
return ((f1d_) & (1U << 26)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool ss() const { | |
return ((f1d_) & (1U << 27)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool htt() const { | |
return ((f1d_) & (1U << 28)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool tm() const { | |
return ((f1d_) & (1U << 29)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool pbe() const { | |
return ((f1d_) & (1U << 31)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool bmi1() const { | |
return ((f7b_) & (1U << 3)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool hle() const { | |
return ((f7b_) & (1U << 4)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool avx2() const { | |
return ((f7b_) & (1U << 5)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool smep() const { | |
return ((f7b_) & (1U << 7)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool bmi2() const { | |
return ((f7b_) & (1U << 8)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool erms() const { | |
return ((f7b_) & (1U << 9)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool invpcid() const { | |
return ((f7b_) & (1U << 10)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool rtm() const { | |
return ((f7b_) & (1U << 11)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool mpx() const { | |
return ((f7b_) & (1U << 14)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool avx512f() const { | |
return ((f7b_) & (1U << 16)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool avx512dq() const { | |
return ((f7b_) & (1U << 17)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool rdseed() const { | |
return ((f7b_) & (1U << 18)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool adx() const { | |
return ((f7b_) & (1U << 19)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool smap() const { | |
return ((f7b_) & (1U << 20)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool avx512ifma() const { | |
return ((f7b_) & (1U << 21)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool pcommit() const { | |
return ((f7b_) & (1U << 22)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool clflushopt() const { | |
return ((f7b_) & (1U << 23)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool clwb() const { | |
return ((f7b_) & (1U << 24)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool avx512pf() const { | |
return ((f7b_) & (1U << 26)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool avx512er() const { | |
return ((f7b_) & (1U << 27)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool avx512cd() const { | |
return ((f7b_) & (1U << 28)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool sha() const { | |
return ((f7b_) & (1U << 29)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool avx512bw() const { | |
return ((f7b_) & (1U << 30)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool avx512vl() const { | |
return ((f7b_) & (1U << 31)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool prefetchwt1() const { | |
return ((f7c_) & (1U << 0)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool avx512vbmi() const { | |
return ((f7c_) & (1U << 1)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool vaes() const { | |
return ((f7c_) & (1U << 9)) != 0; | |
} | |
inline __attribute__((__always_inline__)) bool vpclmulqdq() const { | |
return ((f7c_) & (1U << 10)) != 0; | |
} | |
private: | |
uint32_t f1c_ = 0; | |
uint32_t f1d_ = 0; | |
uint32_t f7b_ = 0; | |
uint32_t f7c_ = 0; | |
}; | |
} // namespace folly | |
// # 45 "tlm/deps/folly.exploded/include/folly/Range.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/detail/RangeCommon.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/detail/RangeCommon.h" 3 4 | |
// # 21 "tlm/deps/folly.exploded/include/folly/detail/RangeCommon.h" 2 3 4 | |
namespace folly { | |
namespace detail { | |
// # 36 "tlm/deps/folly.exploded/include/folly/detail/RangeCommon.h" 3 4 | |
class StringPieceLite { | |
public: | |
StringPieceLite(const char* b, const char* e) : b_(b), e_(e) { | |
} | |
template <typename Range> | |
StringPieceLite(const Range& r) | |
: StringPieceLite(r.data(), r.data() + r.size()) { | |
} | |
const char* data() const { | |
return b_; | |
} | |
const char* begin() const { | |
return b_; | |
} | |
const char* end() const { | |
return e_; | |
} | |
size_t size() const { | |
return size_t(e_ - b_); | |
} | |
bool empty() const { | |
return size() == 0; | |
} | |
const char& operator[](size_t i) const { | |
(static_cast<bool>(size() > i) | |
? void(0) | |
: __assert_fail("size() > i", | |
"tlm/deps/folly.exploded/include/folly/detail/" | |
"RangeCommon.h", | |
58, | |
__extension__ __PRETTY_FUNCTION__)); | |
return b_[i]; | |
} | |
template <typename Range> | |
explicit operator Range() const { | |
return Range(begin(), end()); | |
} | |
private: | |
const char* b_; | |
const char* e_; | |
}; | |
inline size_t qfind_first_byte_of_std(const StringPieceLite haystack, | |
const StringPieceLite needles) { | |
auto ret = std::find_first_of(haystack.begin(), | |
haystack.end(), | |
needles.begin(), | |
needles.end(), | |
[](char a, char b) { return a == b; }); | |
return ret == haystack.end() ? std::string::npos : ret - haystack.begin(); | |
} | |
size_t qfind_first_byte_of_bitset(const StringPieceLite haystack, | |
const StringPieceLite needles); | |
size_t qfind_first_byte_of_byteset(const StringPieceLite haystack, | |
const StringPieceLite needles); | |
inline size_t qfind_first_byte_of_nosse(const StringPieceLite haystack, | |
const StringPieceLite needles) { | |
if ((__builtin_expect((needles.empty() || haystack.empty()), 0))) { | |
return std::string::npos; | |
} | |
if ((needles.size() >= 4 && haystack.size() <= 10) || | |
(needles.size() >= 16 && haystack.size() <= 64) || | |
needles.size() >= 32) { | |
return qfind_first_byte_of_byteset(haystack, needles); | |
} | |
return qfind_first_byte_of_std(haystack, needles); | |
} | |
} // namespace detail | |
} // namespace folly | |
// # 48 "tlm/deps/folly.exploded/include/folly/Range.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/detail/RangeSse42.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/detail/RangeSse42.h" 3 4 | |
namespace folly { | |
namespace detail { | |
size_t qfind_first_byte_of_sse42(const StringPieceLite haystack, | |
const StringPieceLite needles); | |
} | |
} // namespace folly | |
// # 49 "tlm/deps/folly.exploded/include/folly/Range.h" 2 3 4 | |
// # 51 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
#pragma GCC diagnostic push | |
// # 51 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
// # 52 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
#pragma GCC diagnostic ignored "-Wshadow" | |
// # 52 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
namespace folly { | |
template <class T> | |
struct IsSomeString : std::false_type {}; | |
template <typename Alloc> | |
struct IsSomeString<std::basic_string<char, std::char_traits<char>, Alloc>> | |
: std::true_type {}; | |
template <class Iter> | |
class Range; | |
template <class Iter, | |
class Comp = std::equal_to<typename Range<Iter>::value_type>> | |
inline size_t qfind(const Range<Iter>& haystack, | |
const Range<Iter>& needle, | |
Comp eq = Comp()); | |
template <class Iter> | |
size_t qfind(const Range<Iter>& haystack, | |
const typename Range<Iter>::value_type& needle); | |
template <class Iter> | |
size_t rfind(const Range<Iter>& haystack, | |
const typename Range<Iter>::value_type& needle); | |
template <class Iter> | |
inline size_t qfind_first_of(const Range<Iter>& haystack, | |
const Range<Iter>& needle); | |
namespace detail { | |
template <class T> | |
struct IsCharPointer {}; | |
template <> | |
struct IsCharPointer<char*> { | |
typedef int type; | |
}; | |
template <> | |
struct IsCharPointer<const char*> { | |
typedef int const_type; | |
typedef int type; | |
}; | |
} // namespace detail | |
// # 146 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
template <class Iter> | |
class Range { | |
private: | |
template <typename Alloc> | |
using string = std::basic_string<char, std::char_traits<char>, Alloc>; | |
public: | |
typedef std::size_t size_type; | |
typedef Iter iterator; | |
typedef Iter const_iterator; | |
typedef typename std::remove_reference< | |
typename std::iterator_traits<Iter>::reference>::type value_type; | |
using difference_type = | |
typename std::iterator_traits<Iter>::difference_type; | |
typedef typename std::iterator_traits<Iter>::reference reference; | |
typedef typename std::conditional< | |
std::is_same<Iter, char*>::value || | |
std::is_same<Iter, unsigned char*>::value, | |
Range<const value_type*>, | |
Range<Iter>>::type const_range_type; | |
typedef std::char_traits<typename std::remove_const<value_type>::type> | |
traits_type; | |
static const size_type npos; | |
constexpr Range() : b_(), e_() { | |
} | |
constexpr Range(const Range&) = default; | |
constexpr Range(Range&&) = default; | |
public: | |
constexpr Range(Iter start, Iter end) : b_(start), e_(end) { | |
} | |
constexpr Range(Iter start, size_t size) : b_(start), e_(start + size) { | |
} | |
Range(std::nullptr_t) = delete; | |
constexpr Range(Iter str) : b_(str), e_(str + constexpr_strlen(str)) { | |
static_assert( | |
std::is_same<int, | |
typename detail::IsCharPointer<Iter>::type>::value, | |
"This constructor is only available for character ranges"); | |
} | |
template <class Alloc, | |
class T = Iter, | |
typename detail::IsCharPointer<T>::const_type = 0> | |
Range(const string<Alloc>& str) : b_(str.data()), e_(b_ + str.size()) { | |
} | |
template <class Alloc, | |
class T = Iter, | |
typename detail::IsCharPointer<T>::const_type = 0> | |
Range(const string<Alloc>& str, | |
typename string<Alloc>::size_type startFrom) { | |
if ((__builtin_expect((startFrom > str.size()), 0))) { | |
throw_exception<std::out_of_range>("index out of range"); | |
} | |
b_ = str.data() + startFrom; | |
e_ = str.data() + str.size(); | |
} | |
template <class Alloc, | |
class T = Iter, | |
typename detail::IsCharPointer<T>::const_type = 0> | |
Range(const string<Alloc>& str, | |
typename string<Alloc>::size_type startFrom, | |
typename string<Alloc>::size_type size) { | |
if ((__builtin_expect((startFrom > str.size()), 0))) { | |
throw_exception<std::out_of_range>("index out of range"); | |
} | |
b_ = str.data() + startFrom; | |
if (str.size() - startFrom < size) { | |
e_ = str.data() + str.size(); | |
} else { | |
e_ = b_ + size; | |
} | |
} | |
Range(const Range& other, size_type first, size_type length = npos) | |
: Range(other.subpiece(first, length)) { | |
} | |
template <class Container, | |
class = typename std::enable_if<std::is_same< | |
Iter, | |
typename Container::const_pointer>::value>::type, | |
class = decltype(Iter(std::declval<Container const&>().data()), | |
Iter(std::declval<Container const&>().data() + | |
std::declval<Container const&>().size()))> | |
constexpr Range(Container const& container) | |
: b_(container.data()), e_(b_ + container.size()) { | |
} | |
template <class Container, | |
class = typename std::enable_if<std::is_same< | |
Iter, | |
typename Container::const_pointer>::value>::type, | |
class = decltype(Iter(std::declval<Container const&>().data()), | |
Iter(std::declval<Container const&>().data() + | |
std::declval<Container const&>().size()))> | |
Range(Container const& container, typename Container::size_type startFrom) { | |
auto const cdata = container.data(); | |
auto const csize = container.size(); | |
if ((__builtin_expect((startFrom > csize), 0))) { | |
throw_exception<std::out_of_range>("index out of range"); | |
} | |
b_ = cdata + startFrom; | |
e_ = cdata + csize; | |
} | |
template <class Container, | |
class = typename std::enable_if<std::is_same< | |
Iter, | |
typename Container::const_pointer>::value>::type, | |
class = decltype(Iter(std::declval<Container const&>().data()), | |
Iter(std::declval<Container const&>().data() + | |
std::declval<Container const&>().size()))> | |
Range(Container const& container, | |
typename Container::size_type startFrom, | |
typename Container::size_type size) { | |
auto const cdata = container.data(); | |
auto const csize = container.size(); | |
if ((__builtin_expect((startFrom > csize), 0))) { | |
throw_exception<std::out_of_range>("index out of range"); | |
} | |
b_ = cdata + startFrom; | |
if (csize - startFrom < size) { | |
e_ = cdata + csize; | |
} else { | |
e_ = b_ + size; | |
} | |
} | |
template <class OtherIter, | |
typename std::enable_if< | |
(std::is_same<Iter, const unsigned char*>::value && | |
(std::is_same<OtherIter, const char*>::value || | |
std::is_same<OtherIter, char*>::value)), | |
int>::type = 0> | |
Range(const Range<OtherIter>& other) | |
: b_(reinterpret_cast<const unsigned char*>(other.begin())), | |
e_(reinterpret_cast<const unsigned char*>(other.end())) { | |
} | |
template <class OtherIter, | |
typename std::enable_if< | |
(std::is_same<Iter, unsigned char*>::value && | |
std::is_same<OtherIter, char*>::value), | |
int>::type = 0> | |
Range(const Range<OtherIter>& other) | |
: b_(reinterpret_cast<unsigned char*>(other.begin())), | |
e_(reinterpret_cast<unsigned char*>(other.end())) { | |
} | |
template <class OtherIter, | |
typename std::enable_if< | |
(std::is_same<Iter, const char*>::value && | |
(std::is_same<OtherIter, const unsigned char*>::value || | |
std::is_same<OtherIter, unsigned char*>::value)), | |
int>::type = 0> | |
explicit Range(const Range<OtherIter>& other) | |
: b_(reinterpret_cast<const char*>(other.begin())), | |
e_(reinterpret_cast<const char*>(other.end())) { | |
} | |
template <class OtherIter, | |
typename std::enable_if< | |
(std::is_same<Iter, char*>::value && | |
std::is_same<OtherIter, unsigned char*>::value), | |
int>::type = 0> | |
explicit Range(const Range<OtherIter>& other) | |
: b_(reinterpret_cast<char*>(other.begin())), | |
e_(reinterpret_cast<char*>(other.end())) { | |
} | |
template <class OtherIter, | |
typename std::enable_if< | |
(!std::is_same<Iter, OtherIter>::value && | |
std::is_convertible<OtherIter, Iter>::value), | |
int>::type = 0> | |
constexpr Range(const Range<OtherIter>& other) | |
: b_(other.begin()), e_(other.end()) { | |
} | |
template <class OtherIter, | |
typename std::enable_if< | |
(!std::is_same<Iter, OtherIter>::value && | |
!std::is_convertible<OtherIter, Iter>::value && | |
std::is_constructible<Iter, const OtherIter&>::value), | |
int>::type = 0> | |
constexpr explicit Range(const Range<OtherIter>& other) | |
: b_(other.begin()), e_(other.end()) { | |
} | |
// # 374 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
template <class T, | |
size_t N, | |
typename = typename std::enable_if< | |
std::is_convertible<const T*, Iter>::value>::type> | |
constexpr explicit Range(const std::array<T, N>& array) | |
: b_{array.empty() ? nullptr : &array.at(0)}, | |
e_{array.empty() ? nullptr : &array.at(0) + N} { | |
} | |
template <class T, | |
size_t N, | |
typename = typename std::enable_if< | |
std::is_convertible<T*, Iter>::value>::type> | |
constexpr explicit Range(std::array<T, N>& array) | |
: b_{array.empty() ? nullptr : &array.at(0)}, | |
e_{array.empty() ? nullptr : &array.at(0) + N} { | |
} | |
Range& operator=(const Range& rhs) & = default; | |
Range& operator=(Range&& rhs) & = default; | |
template <class Alloc, | |
class T = Iter, | |
typename detail::IsCharPointer<T>::const_type = 0> | |
Range& operator=(string<Alloc>&& rhs) = delete; | |
void clear() { | |
b_ = Iter(); | |
e_ = Iter(); | |
} | |
void assign(Iter start, Iter end) { | |
b_ = start; | |
e_ = end; | |
} | |
void reset(Iter start, size_type size) { | |
b_ = start; | |
e_ = start + size; | |
} | |
template <typename Alloc> | |
void reset(const string<Alloc>& str) { | |
reset(str.data(), str.size()); | |
} | |
constexpr size_type size() const { | |
(static_cast<bool>(b_ <= e_) | |
? void(0) | |
: __assert_fail( | |
"b_ <= e_", | |
"tlm/deps/folly.exploded/include/folly/Range.h", | |
423, | |
__extension__ __PRETTY_FUNCTION__)); | |
return size_type(e_ - b_); | |
} | |
constexpr size_type walk_size() const { | |
return size_type(std::distance(b_, e_)); | |
} | |
constexpr bool empty() const { | |
return b_ == e_; | |
} | |
constexpr Iter data() const { | |
return b_; | |
} | |
constexpr Iter start() const { | |
return b_; | |
} | |
constexpr Iter begin() const { | |
return b_; | |
} | |
constexpr Iter end() const { | |
return e_; | |
} | |
constexpr Iter cbegin() const { | |
return b_; | |
} | |
constexpr Iter cend() const { | |
return e_; | |
} | |
value_type& front() { | |
(static_cast<bool>(b_ < e_) | |
? void(0) | |
: __assert_fail( | |
"b_ < e_", | |
"tlm/deps/folly.exploded/include/folly/Range.h", | |
452, | |
__extension__ __PRETTY_FUNCTION__)); | |
return *b_; | |
} | |
value_type& back() { | |
(static_cast<bool>(b_ < e_) | |
? void(0) | |
: __assert_fail( | |
"b_ < e_", | |
"tlm/deps/folly.exploded/include/folly/Range.h", | |
456, | |
__extension__ __PRETTY_FUNCTION__)); | |
return *std::prev(e_); | |
} | |
const value_type& front() const { | |
(static_cast<bool>(b_ < e_) | |
? void(0) | |
: __assert_fail( | |
"b_ < e_", | |
"tlm/deps/folly.exploded/include/folly/Range.h", | |
460, | |
__extension__ __PRETTY_FUNCTION__)); | |
return *b_; | |
} | |
const value_type& back() const { | |
(static_cast<bool>(b_ < e_) | |
? void(0) | |
: __assert_fail( | |
"b_ < e_", | |
"tlm/deps/folly.exploded/include/folly/Range.h", | |
464, | |
__extension__ __PRETTY_FUNCTION__)); | |
return *std::prev(e_); | |
} | |
private: | |
// # 486 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
struct NotStringView {}; | |
template <typename ValueType> | |
struct StringViewType | |
: std::conditional< | |
std::is_pod<std::remove_const_t<ValueType>>::value, | |
std::basic_string_view<std::remove_const_t<ValueType>>, | |
NotStringView> {}; | |
template <typename Target> | |
struct IsConstructibleViaStringView | |
: Conjunction<std::is_constructible<_t<StringViewType<value_type>>, | |
Iter const&, | |
size_type>, | |
std::is_constructible<Target, | |
_t<StringViewType<value_type>>>> {}; | |
public: | |
template < | |
typename Tgt, | |
std::enable_if_t< | |
std::is_constructible<Tgt, Iter const&, size_type>::value && | |
!IsConstructibleViaStringView<Tgt>::value, | |
int> = 0> | |
constexpr explicit operator Tgt() const noexcept( | |
std::is_nothrow_constructible<Tgt, Iter const&, size_type>::value) { | |
return Tgt(b_, walk_size()); | |
} | |
template <typename Tgt, | |
std::enable_if_t< | |
!std::is_constructible<Tgt, Iter const&, size_type>:: | |
value && | |
std::is_constructible<Tgt, | |
Iter const&, | |
Iter const&>::value && | |
!IsConstructibleViaStringView<Tgt>::value, | |
int> = 0> | |
constexpr explicit operator Tgt() const | |
noexcept(std::is_nothrow_constructible<Tgt, | |
Iter const&, | |
Iter const&>::value) { | |
return Tgt(b_, e_); | |
} | |
template < | |
typename Tgt, | |
typename ValueType = value_type, | |
std::enable_if_t< | |
StrictConjunction< | |
std::is_same<Tgt, _t<StringViewType<ValueType>>>, | |
std::is_constructible<_t<StringViewType<ValueType>>, | |
Iter const&, | |
size_type>>::value, | |
int> = 0> | |
constexpr operator Tgt() const noexcept( | |
std::is_nothrow_constructible<Tgt, Iter const&, size_type>::value) { | |
return Tgt(b_, walk_size()); | |
} | |
// # 569 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
template <typename Tgt, typename... Args> | |
constexpr std::enable_if_t< | |
std::is_constructible<Tgt, Iter const&, size_type>::value, | |
Tgt> | |
to(Args&&... args) const | |
noexcept(std::is_nothrow_constructible<Tgt, | |
Iter const&, | |
size_type, | |
Args&&...>::value) { | |
return Tgt(b_, walk_size(), static_cast<Args&&>(args)...); | |
} | |
template <typename Tgt, typename... Args> | |
constexpr std::enable_if_t< | |
!std::is_constructible<Tgt, Iter const&, size_type>::value && | |
std::is_constructible<Tgt, Iter const&, Iter const&>::value, | |
Tgt> | |
to(Args&&... args) const | |
noexcept(std::is_nothrow_constructible<Tgt, | |
Iter const&, | |
Iter const&, | |
Args&&...>::value) { | |
return Tgt(b_, e_, static_cast<Args&&>(args)...); | |
} | |
std::string str() const { | |
return to<std::string>(); | |
} | |
std::string toString() const { | |
return to<std::string>(); | |
} | |
const_range_type castToConst() const { | |
return const_range_type(*this); | |
} | |
int compare(const const_range_type& o) const { | |
const size_type tsize = this->size(); | |
const size_type osize = o.size(); | |
const size_type msize = std::min(tsize, osize); | |
int r = traits_type::compare(data(), o.data(), msize); | |
if (r == 0 && tsize != osize) { | |
r = (static_cast<int>((osize - tsize) >> (8 * sizeof(size_t) - 1)) | |
<< 1) - | |
1; | |
} | |
return r; | |
} | |
value_type& operator[](size_t i) { | |
(static_cast<bool>(i < size()) | |
? void(0) | |
: __assert_fail( | |
"i < size()", | |
"tlm/deps/folly.exploded/include/folly/Range.h", | |
618, | |
__extension__ __PRETTY_FUNCTION__)); | |
return b_[i]; | |
} | |
const value_type& operator[](size_t i) const { | |
(static_cast<bool>(i < size()) | |
? void(0) | |
: __assert_fail( | |
"i < size()", | |
"tlm/deps/folly.exploded/include/folly/Range.h", | |
623, | |
__extension__ __PRETTY_FUNCTION__)); | |
return b_[i]; | |
} | |
value_type& at(size_t i) { | |
if (i >= size()) { | |
throw_exception<std::out_of_range>("index out of range"); | |
} | |
return b_[i]; | |
} | |
const value_type& at(size_t i) const { | |
if (i >= size()) { | |
throw_exception<std::out_of_range>("index out of range"); | |
} | |
return b_[i]; | |
} | |
// # 659 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
[[deprecated( | |
"Replace with folly::Hash if the hash is not serialized")]] uint32_t | |
hash() const { | |
uint32_t hash = 5381; | |
for (size_t ix = 0; ix < size(); ix++) { | |
hash = ((hash << 5) + hash) + b_[ix]; | |
} | |
return hash; | |
} | |
void advance(size_type n) { | |
if ((__builtin_expect((n > size()), 0))) { | |
throw_exception<std::out_of_range>("index out of range"); | |
} | |
b_ += n; | |
} | |
void subtract(size_type n) { | |
if ((__builtin_expect((n > size()), 0))) { | |
throw_exception<std::out_of_range>("index out of range"); | |
} | |
e_ -= n; | |
} | |
Range subpiece(size_type first, size_type length = npos) const { | |
if ((__builtin_expect((first > size()), 0))) { | |
throw_exception<std::out_of_range>("index out of range"); | |
} | |
return Range(b_ + first, std::min(length, size() - first)); | |
} | |
void uncheckedAdvance(size_type n) { | |
(static_cast<bool>(n <= size()) | |
? void(0) | |
: __assert_fail( | |
"n <= size()", | |
"tlm/deps/folly.exploded/include/folly/Range.h", | |
695, | |
__extension__ __PRETTY_FUNCTION__)); | |
b_ += n; | |
} | |
void uncheckedSubtract(size_type n) { | |
(static_cast<bool>(n <= size()) | |
? void(0) | |
: __assert_fail( | |
"n <= size()", | |
"tlm/deps/folly.exploded/include/folly/Range.h", | |
700, | |
__extension__ __PRETTY_FUNCTION__)); | |
e_ -= n; | |
} | |
Range uncheckedSubpiece(size_type first, size_type length = npos) const { | |
(static_cast<bool>(first <= size()) | |
? void(0) | |
: __assert_fail( | |
"first <= size()", | |
"tlm/deps/folly.exploded/include/folly/Range.h", | |
705, | |
__extension__ __PRETTY_FUNCTION__)); | |
return Range(b_ + first, std::min(length, size() - first)); | |
} | |
void pop_front() { | |
(static_cast<bool>(b_ < e_) | |
? void(0) | |
: __assert_fail( | |
"b_ < e_", | |
"tlm/deps/folly.exploded/include/folly/Range.h", | |
710, | |
__extension__ __PRETTY_FUNCTION__)); | |
++b_; | |
} | |
void pop_back() { | |
(static_cast<bool>(b_ < e_) | |
? void(0) | |
: __assert_fail( | |
"b_ < e_", | |
"tlm/deps/folly.exploded/include/folly/Range.h", | |
715, | |
__extension__ __PRETTY_FUNCTION__)); | |
--e_; | |
} | |
size_type find(const_range_type str) const { | |
return qfind(castToConst(), str); | |
} | |
size_type find(const_range_type str, size_t pos) const { | |
if (pos > size()) { | |
return std::string::npos; | |
} | |
size_t ret = qfind(castToConst().subpiece(pos), str); | |
return ret == npos ? ret : ret + pos; | |
} | |
size_type find(Iter s, size_t pos, size_t n) const { | |
if (pos > size()) { | |
return std::string::npos; | |
} | |
auto forFinding = castToConst(); | |
size_t ret = qfind(pos ? forFinding.subpiece(pos) : forFinding, | |
const_range_type(s, n)); | |
return ret == npos ? ret : ret + pos; | |
} | |
size_type find(const Iter s) const { | |
return qfind(castToConst(), const_range_type(s)); | |
} | |
size_type find(const Iter s, size_t pos) const { | |
if (pos > size()) { | |
return std::string::npos; | |
} | |
size_type ret = qfind(castToConst().subpiece(pos), const_range_type(s)); | |
return ret == npos ? ret : ret + pos; | |
} | |
size_type find(value_type c) const { | |
return qfind(castToConst(), c); | |
} | |
size_type rfind(value_type c) const { | |
return folly::rfind(castToConst(), c); | |
} | |
size_type find(value_type c, size_t pos) const { | |
if (pos > size()) { | |
return std::string::npos; | |
} | |
size_type ret = qfind(castToConst().subpiece(pos), c); | |
return ret == npos ? ret : ret + pos; | |
} | |
size_type find_first_of(const_range_type needles) const { | |
return qfind_first_of(castToConst(), needles); | |
} | |
size_type find_first_of(const_range_type needles, size_t pos) const { | |
if (pos > size()) { | |
return std::string::npos; | |
} | |
size_type ret = qfind_first_of(castToConst().subpiece(pos), needles); | |
return ret == npos ? ret : ret + pos; | |
} | |
size_type find_first_of(Iter needles) const { | |
return find_first_of(const_range_type(needles)); | |
} | |
size_type find_first_of(Iter needles, size_t pos) const { | |
return find_first_of(const_range_type(needles), pos); | |
} | |
size_type find_first_of(Iter needles, size_t pos, size_t n) const { | |
return find_first_of(const_range_type(needles, n), pos); | |
} | |
size_type find_first_of(value_type c) const { | |
return find(c); | |
} | |
size_type find_first_of(value_type c, size_t pos) const { | |
return find(c, pos); | |
} | |
bool contains(const const_range_type& other) const { | |
return find(other) != std::string::npos; | |
} | |
bool contains(const value_type& other) const { | |
return find(other) != std::string::npos; | |
} | |
void swap(Range& rhs) { | |
std::swap(b_, rhs.b_); | |
std::swap(e_, rhs.e_); | |
} | |
bool startsWith(const const_range_type& other) const { | |
return size() >= other.size() && | |
castToConst().subpiece(0, other.size()) == other; | |
} | |
bool startsWith(value_type c) const { | |
return !empty() && front() == c; | |
} | |
template <class Comp> | |
bool startsWith(const const_range_type& other, Comp&& eq) const { | |
if (size() < other.size()) { | |
return false; | |
} | |
auto const trunc = subpiece(0, other.size()); | |
return std::equal(trunc.begin(), | |
trunc.end(), | |
other.begin(), | |
std::forward<Comp>(eq)); | |
} | |
bool endsWith(const const_range_type& other) const { | |
return size() >= other.size() && | |
castToConst().subpiece(size() - other.size()) == other; | |
} | |
bool endsWith(value_type c) const { | |
return !empty() && back() == c; | |
} | |
template <class Comp> | |
bool endsWith(const const_range_type& other, Comp&& eq) const { | |
if (size() < other.size()) { | |
return false; | |
} | |
auto const trunc = subpiece(size() - other.size()); | |
return std::equal(trunc.begin(), | |
trunc.end(), | |
other.begin(), | |
std::forward<Comp>(eq)); | |
} | |
template <class Comp> | |
bool equals(const const_range_type& other, Comp&& eq) const { | |
return size() == other.size() && | |
std::equal( | |
begin(), end(), other.begin(), std::forward<Comp>(eq)); | |
} | |
void erase(Iter b, Iter e) { | |
if (b == b_) { | |
b_ = e; | |
} else if (e == e_) { | |
e_ = b; | |
} else { | |
throw_exception<std::out_of_range>("index out of range"); | |
} | |
} | |
bool removePrefix(const const_range_type& prefix) { | |
return startsWith(prefix) && (b_ += prefix.size(), true); | |
} | |
bool removePrefix(value_type prefix) { | |
return startsWith(prefix) && (++b_, true); | |
} | |
bool removeSuffix(const const_range_type& suffix) { | |
return endsWith(suffix) && (e_ -= suffix.size(), true); | |
} | |
bool removeSuffix(value_type suffix) { | |
return endsWith(suffix) && (--e_, true); | |
} | |
// # 924 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
bool replaceAt(size_t pos, const_range_type replacement) { | |
if (size() < pos + replacement.size()) { | |
return false; | |
} | |
std::copy(replacement.begin(), replacement.end(), begin() + pos); | |
return true; | |
} | |
// # 948 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
size_t replaceAll(const_range_type source, const_range_type dest) { | |
if (source.size() != dest.size()) { | |
throw_exception<std::invalid_argument>( | |
"replacement must have the same size as source"); | |
} | |
if (dest.empty()) { | |
return 0; | |
} | |
size_t pos = 0; | |
size_t num_replaced = 0; | |
size_type found = std::string::npos; | |
while ((found = find(source, pos)) != std::string::npos) { | |
replaceAt(found, dest); | |
pos += source.size(); | |
++num_replaced; | |
} | |
return num_replaced; | |
} | |
// # 1000 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
Range split_step(value_type delimiter) { | |
auto i = std::find(b_, e_, delimiter); | |
Range result(b_, i); | |
b_ = i == e_ ? e_ : std::next(i); | |
return result; | |
} | |
Range split_step(Range delimiter) { | |
auto i = find(delimiter); | |
Range result(b_, i == std::string::npos ? size() : i); | |
b_ = result.end() == e_ | |
? e_ | |
: std::next(result.end(), | |
typename std::iterator_traits<Iter>:: | |
difference_type(delimiter.size())); | |
return result; | |
} | |
// # 1085 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
template <typename TProcess, typename... Args> | |
auto split_step(value_type delimiter, TProcess&& process, Args&&... args) | |
-> decltype(process(std::declval<Range>(), | |
std::forward<Args>(args)...)) { | |
return process(split_step(delimiter), std::forward<Args>(args)...); | |
} | |
template <typename TProcess, typename... Args> | |
auto split_step(Range delimiter, TProcess&& process, Args&&... args) | |
-> decltype(process(std::declval<Range>(), | |
std::forward<Args>(args)...)) { | |
return process(split_step(delimiter), std::forward<Args>(args)...); | |
} | |
private: | |
Iter b_, e_; | |
}; | |
template <class Iter> | |
const typename Range<Iter>::size_type Range<Iter>::npos = std::string::npos; | |
template <class Iter> | |
void swap(Range<Iter>& lhs, Range<Iter>& rhs) { | |
lhs.swap(rhs); | |
} | |
template <class Iter> | |
constexpr Range<Iter> range(Iter first, Iter last) { | |
return Range<Iter>(first, last); | |
} | |
template <class Collection> | |
constexpr auto range(Collection& v) -> Range<decltype(v.data())> { | |
return Range<decltype(v.data())>(v.data(), v.data() + v.size()); | |
} | |
template <class Collection> | |
constexpr auto range(Collection const& v) -> Range<decltype(v.data())> { | |
return Range<decltype(v.data())>(v.data(), v.data() + v.size()); | |
} | |
template <class Collection> | |
constexpr auto crange(Collection const& v) -> Range<decltype(v.data())> { | |
return Range<decltype(v.data())>(v.data(), v.data() + v.size()); | |
} | |
template <class T, size_t n> | |
constexpr Range<T*> range(T (&array)[n]) { | |
return Range<T*>(array, array + n); | |
} | |
template <class T, size_t n> | |
constexpr Range<T const*> range(T const (&array)[n]) { | |
return Range<T const*>(array, array + n); | |
} | |
template <class T, size_t n> | |
constexpr Range<T const*> crange(T const (&array)[n]) { | |
return Range<T const*>(array, array + n); | |
} | |
template <class T, size_t n> | |
constexpr Range<T*> range(std::array<T, n>& array) { | |
return Range<T*>{array}; | |
} | |
template <class T, size_t n> | |
constexpr Range<T const*> range(std::array<T, n> const& array) { | |
return Range<T const*>{array}; | |
} | |
template <class T, size_t n> | |
constexpr Range<T const*> crange(std::array<T, n> const& array) { | |
return Range<T const*>{array}; | |
} | |
typedef Range<const char*> StringPiece; | |
typedef Range<char*> MutableStringPiece; | |
typedef Range<const unsigned char*> ByteRange; | |
typedef Range<unsigned char*> MutableByteRange; | |
template <class C> | |
std::basic_ostream<C>& operator<<(std::basic_ostream<C>& os, | |
Range<C const*> piece) { | |
using StreamSize = decltype(os.width()); | |
os.write(piece.start(), static_cast<StreamSize>(piece.size())); | |
return os; | |
} | |
template <class C> | |
std::basic_ostream<C>& operator<<(std::basic_ostream<C>& os, Range<C*> piece) { | |
using StreamSize = decltype(os.width()); | |
os.write(piece.start(), static_cast<StreamSize>(piece.size())); | |
return os; | |
} | |
template <class Iter> | |
inline bool operator==(const Range<Iter>& lhs, const Range<Iter>& rhs) { | |
return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; | |
} | |
template <class Iter> | |
inline bool operator!=(const Range<Iter>& lhs, const Range<Iter>& rhs) { | |
return !(operator==(lhs, rhs)); | |
} | |
template <class Iter> | |
inline bool operator<(const Range<Iter>& lhs, const Range<Iter>& rhs) { | |
return lhs.compare(rhs) < 0; | |
} | |
template <class Iter> | |
inline bool operator<=(const Range<Iter>& lhs, const Range<Iter>& rhs) { | |
return lhs.compare(rhs) <= 0; | |
} | |
template <class Iter> | |
inline bool operator>(const Range<Iter>& lhs, const Range<Iter>& rhs) { | |
return lhs.compare(rhs) > 0; | |
} | |
template <class Iter> | |
inline bool operator>=(const Range<Iter>& lhs, const Range<Iter>& rhs) { | |
return lhs.compare(rhs) >= 0; | |
} | |
namespace detail { | |
template <class A, class B> | |
struct ComparableAsStringPiece { | |
enum { | |
value = (std::is_convertible<A, StringPiece>::value && | |
std::is_same<B, StringPiece>::value) || | |
(std::is_convertible<B, StringPiece>::value && | |
std::is_same<A, StringPiece>::value) | |
}; | |
}; | |
} // namespace detail | |
template <class T, class U> | |
std::enable_if_t<detail::ComparableAsStringPiece<T, U>::value, bool> operator==( | |
const T& lhs, const U& rhs) { | |
return StringPiece(lhs) == StringPiece(rhs); | |
} | |
template <class T, class U> | |
std::enable_if_t<detail::ComparableAsStringPiece<T, U>::value, bool> operator!=( | |
const T& lhs, const U& rhs) { | |
return StringPiece(lhs) != StringPiece(rhs); | |
} | |
template <class T, class U> | |
std::enable_if_t<detail::ComparableAsStringPiece<T, U>::value, bool> operator<( | |
const T& lhs, const U& rhs) { | |
return StringPiece(lhs) < StringPiece(rhs); | |
} | |
template <class T, class U> | |
std::enable_if_t<detail::ComparableAsStringPiece<T, U>::value, bool> operator>( | |
const T& lhs, const U& rhs) { | |
return StringPiece(lhs) > StringPiece(rhs); | |
} | |
template <class T, class U> | |
std::enable_if_t<detail::ComparableAsStringPiece<T, U>::value, bool> operator<=( | |
const T& lhs, const U& rhs) { | |
return StringPiece(lhs) <= StringPiece(rhs); | |
} | |
template <class T, class U> | |
std::enable_if_t<detail::ComparableAsStringPiece<T, U>::value, bool> operator>=( | |
const T& lhs, const U& rhs) { | |
return StringPiece(lhs) >= StringPiece(rhs); | |
} | |
template <class Iter, class Comp> | |
size_t qfind(const Range<Iter>& haystack, const Range<Iter>& needle, Comp eq) { | |
auto const nsize = needle.size(); | |
if (haystack.size() < nsize) { | |
return std::string::npos; | |
} | |
if (!nsize) { | |
return 0; | |
} | |
auto const nsize_1 = nsize - 1; | |
auto const lastNeedle = needle[nsize_1]; | |
std::string::size_type skip = 0; | |
auto i = haystack.begin(); | |
auto iEnd = haystack.end() - nsize_1; | |
while (i < iEnd) { | |
while (!eq(i[nsize_1], lastNeedle)) { | |
if (++i == iEnd) { | |
return std::string::npos; | |
} | |
} | |
for (size_t j = 0;;) { | |
(static_cast<bool>(j < nsize) | |
? void(0) | |
: __assert_fail( | |
"j < nsize", | |
"tlm/deps/folly.exploded/include/folly/Range.h", | |
1329, | |
__extension__ __PRETTY_FUNCTION__)); | |
if (!eq(i[j], needle[j])) { | |
if (skip == 0) { | |
skip = 1; | |
while (skip <= nsize_1 && | |
!eq(needle[nsize_1 - skip], lastNeedle)) { | |
++skip; | |
} | |
} | |
i += skip; | |
break; | |
} | |
if (++j == nsize) { | |
return size_t(i - haystack.begin()); | |
} | |
} | |
} | |
return std::string::npos; | |
} | |
namespace detail { | |
inline size_t qfind_first_byte_of(const StringPiece haystack, | |
const StringPiece needles) { | |
static auto const qfind_first_byte_of_fn = | |
folly::CpuId().sse42() ? qfind_first_byte_of_sse42 | |
: qfind_first_byte_of_nosse; | |
return qfind_first_byte_of_fn(haystack, needles); | |
} | |
} // namespace detail | |
template <class Iter, class Comp> | |
size_t qfind_first_of(const Range<Iter>& haystack, | |
const Range<Iter>& needles, | |
Comp eq) { | |
auto ret = std::find_first_of(haystack.begin(), | |
haystack.end(), | |
needles.begin(), | |
needles.end(), | |
eq); | |
return ret == haystack.end() ? std::string::npos : ret - haystack.begin(); | |
} | |
struct AsciiCaseSensitive { | |
bool operator()(char lhs, char rhs) const { | |
return lhs == rhs; | |
} | |
}; | |
struct AsciiCaseInsensitive { | |
bool operator()(char lhs, char rhs) const { | |
char k = lhs ^ rhs; | |
if (k == 0) { | |
return true; | |
} | |
if (k != 32) { | |
return false; | |
} | |
k = lhs | rhs; | |
return (k >= 'a' && k <= 'z'); | |
} | |
}; | |
template <class Iter> | |
size_t qfind(const Range<Iter>& haystack, | |
const typename Range<Iter>::value_type& needle) { | |
auto pos = std::find(haystack.begin(), haystack.end(), needle); | |
return pos == haystack.end() ? std::string::npos : pos - haystack.data(); | |
} | |
template <class Iter> | |
size_t rfind(const Range<Iter>& haystack, | |
const typename Range<Iter>::value_type& needle) { | |
for (auto i = haystack.size(); i-- > 0;) { | |
if (haystack[i] == needle) { | |
return i; | |
} | |
} | |
return std::string::npos; | |
} | |
template <> | |
inline size_t qfind(const Range<const char*>& haystack, const char& needle) { | |
if (haystack.empty()) { | |
return std::string::npos; | |
} | |
auto pos = static_cast<const char*>( | |
::memchr(haystack.data(), needle, haystack.size())); | |
return pos == nullptr ? std::string::npos : pos - haystack.data(); | |
} | |
template <> | |
inline size_t rfind(const Range<const char*>& haystack, const char& needle) { | |
if (haystack.empty()) { | |
return std::string::npos; | |
} | |
auto pos = static_cast<const char*>( | |
memrchr(haystack.data(), needle, haystack.size())); | |
return pos == nullptr ? std::string::npos : pos - haystack.data(); | |
} | |
template <> | |
inline size_t qfind(const Range<const unsigned char*>& haystack, | |
const unsigned char& needle) { | |
if (haystack.empty()) { | |
return std::string::npos; | |
} | |
auto pos = static_cast<const unsigned char*>( | |
::memchr(haystack.data(), needle, haystack.size())); | |
return pos == nullptr ? std::string::npos : pos - haystack.data(); | |
} | |
template <> | |
inline size_t rfind(const Range<const unsigned char*>& haystack, | |
const unsigned char& needle) { | |
if (haystack.empty()) { | |
return std::string::npos; | |
} | |
auto pos = static_cast<const unsigned char*>( | |
memrchr(haystack.data(), needle, haystack.size())); | |
return pos == nullptr ? std::string::npos : pos - haystack.data(); | |
} | |
template <class Iter> | |
size_t qfind_first_of(const Range<Iter>& haystack, const Range<Iter>& needles) { | |
return qfind_first_of(haystack, needles, AsciiCaseSensitive()); | |
} | |
template <> | |
inline size_t qfind_first_of(const Range<const char*>& haystack, | |
const Range<const char*>& needles) { | |
return detail::qfind_first_byte_of(haystack, needles); | |
} | |
template <> | |
inline size_t qfind_first_of(const Range<const unsigned char*>& haystack, | |
const Range<const unsigned char*>& needles) { | |
return detail::qfind_first_byte_of(StringPiece(haystack), | |
StringPiece(needles)); | |
} | |
template <class Key, class Enable> | |
struct hasher; | |
template <class T> | |
struct hasher<folly::Range<T*>, | |
std::enable_if_t<std::is_integral<T>::value, void>> { | |
using folly_is_avalanching = std::true_type; | |
size_t operator()(folly::Range<T*> r) const { | |
return static_cast<size_t>( | |
hash::SpookyHashV2::Hash64(r.begin(), r.size() * sizeof(T), 0)); | |
} | |
}; | |
inline namespace literals { | |
inline namespace string_piece_literals { | |
constexpr Range<char const*> operator"" _sp(char const* str, | |
size_t len) noexcept { | |
return Range<char const*>(str, len); | |
} | |
// # 1536 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
constexpr Range<char16_t const*> operator"" _sp(char16_t const* str, | |
size_t len) noexcept { | |
return Range<char16_t const*>(str, len); | |
} | |
constexpr Range<char32_t const*> operator"" _sp(char32_t const* str, | |
size_t len) noexcept { | |
return Range<char32_t const*>(str, len); | |
} | |
constexpr Range<wchar_t const*> operator"" _sp(wchar_t const* str, | |
size_t len) noexcept { | |
return Range<wchar_t const*>(str, len); | |
} | |
} // namespace string_piece_literals | |
} // namespace literals | |
} // namespace folly | |
// # 1558 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
#pragma GCC diagnostic pop | |
// # 1558 "tlm/deps/folly.exploded/include/folly/Range.h" 3 4 | |
namespace folly { | |
template <class T1> | |
struct IsRelocatable<folly::Range<T1>> : std::true_type {}; | |
} // namespace folly | |
namespace ranges { | |
template <class T> | |
extern const bool enable_view; | |
template <class Iter> | |
inline constexpr bool enable_view<::folly::Range<Iter>> = true; | |
} // namespace ranges | |
// # 121 "tlm/deps/folly.exploded/include/folly/Conv.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/lang/Pretty.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/lang/Pretty.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/lang/CArray.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/lang/CArray.h" 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/lang/CArray.h" 2 3 4 | |
namespace folly { | |
template <typename V, size_t N> | |
struct c_array { | |
V data[N]; | |
}; | |
} // namespace folly | |
// # 24 "tlm/deps/folly.exploded/include/folly/lang/Pretty.h" 2 3 4 | |
namespace folly { | |
namespace detail { | |
template <std::size_t S> | |
using pretty_carray = c_array<char, S>; | |
template <std::size_t S> | |
static constexpr pretty_carray<S> pretty_carray_from(char const (&in)[S]) { | |
pretty_carray<S> out{}; | |
for (std::size_t i = 0; i < S; ++i) { | |
out.data[i] = in[i]; | |
} | |
return out; | |
} | |
struct pretty_info { | |
std::size_t b; | |
std::size_t e; | |
}; | |
template <typename To, std::size_t S> | |
static constexpr To pretty_info_to(pretty_info info, char const (&name)[S]) { | |
return To(name + info.b, info.e - info.b); | |
} | |
template <std::size_t S> | |
static constexpr std::size_t pretty_lfind(char const (&haystack)[S], | |
char const needle) { | |
for (std::size_t i = 0; i < S - 1; ++i) { | |
if (haystack[i] == needle) { | |
return i; | |
} | |
} | |
return ~std::size_t(0); | |
} | |
template <std::size_t S> | |
static constexpr std::size_t pretty_rfind(char const (&haystack)[S], | |
char const needle) { | |
for (std::size_t i = S; i != 0; --i) { | |
if (haystack[i - 1] == needle) { | |
return i - 1; | |
} | |
} | |
return ~std::size_t(0); | |
} | |
struct pretty_tag_msc {}; | |
struct pretty_tag_gcc {}; | |
using pretty_default_tag = std:: | |
conditional_t<kMscVer && !kIsClang, pretty_tag_msc, pretty_tag_gcc>; | |
template <typename T> | |
static constexpr auto pretty_raw(pretty_tag_msc) { | |
} | |
template <typename T> | |
static constexpr auto pretty_raw(pretty_tag_gcc) { | |
return pretty_carray_from(__PRETTY_FUNCTION__); | |
} | |
template <std::size_t S> | |
static constexpr pretty_info pretty_parse(pretty_tag_msc, | |
char const (&name)[S]) { | |
auto const la = pretty_lfind(name, '<'); | |
auto const rp = pretty_rfind(name, '>'); | |
return pretty_info{la + 1, rp}; | |
} | |
template <std::size_t S> | |
static constexpr pretty_info pretty_parse(pretty_tag_gcc, | |
char const (&name)[S]) { | |
auto const eq = pretty_lfind(name, '='); | |
auto const br = pretty_rfind(name, ']'); | |
return pretty_info{eq + 2, br}; | |
} | |
template <typename T, typename Tag> | |
struct pretty_name_zarray { | |
static constexpr auto raw_() { | |
constexpr auto const raw_ = pretty_raw<T>(Tag{}); | |
return raw_; | |
} | |
static constexpr auto raw = raw_(); | |
static constexpr auto info = pretty_parse(Tag{}, raw.data); | |
static constexpr auto size = info.e - info.b; | |
static constexpr auto zarray_() { | |
pretty_carray<size + 1> data{}; | |
for (std::size_t i = 0; i < size; ++i) { | |
data.data[i] = raw.data[info.b + i]; | |
} | |
data.data[size] = 0; | |
return data; | |
} | |
static constexpr pretty_carray<size + 1> zarray = zarray_(); | |
}; | |
template <typename T, typename Tag> | |
constexpr pretty_carray<pretty_name_zarray<T, Tag>::size + 1> | |
pretty_name_zarray<T, Tag>::zarray; | |
} // namespace detail | |
// # 153 "tlm/deps/folly.exploded/include/folly/lang/Pretty.h" 3 4 | |
template <typename T> | |
constexpr char const* pretty_name() { | |
return detail::pretty_name_zarray<T, detail::pretty_default_tag>::zarray | |
.data; | |
} | |
} // namespace folly | |
// # 126 "tlm/deps/folly.exploded/include/folly/Conv.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/portability/Math.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/portability/Math.h" 3 4 | |
// # 20 "tlm/deps/folly.exploded/include/folly/portability/Math.h" 2 3 4 | |
namespace folly { | |
using std::nextafter; | |
using std::remainder; | |
// # 90 "tlm/deps/folly.exploded/include/folly/portability/Math.h" 3 4 | |
} // namespace folly | |
// # 127 "tlm/deps/folly.exploded/include/folly/Conv.h" 2 3 4 | |
namespace folly { | |
enum class ConversionCode : unsigned char { | |
SUCCESS, | |
EMPTY_INPUT_STRING, | |
NO_DIGITS, | |
BOOL_OVERFLOW, | |
BOOL_INVALID_VALUE, | |
NON_DIGIT_CHAR, | |
INVALID_LEADING_CHAR, | |
POSITIVE_OVERFLOW, | |
NEGATIVE_OVERFLOW, | |
STRING_TO_FLOAT_ERROR, | |
NON_WHITESPACE_AFTER_END, | |
ARITH_POSITIVE_OVERFLOW, | |
ARITH_NEGATIVE_OVERFLOW, | |
ARITH_LOSS_OF_PRECISION, | |
NUM_ERROR_CODES, | |
}; | |
struct ConversionErrorBase : std::range_error { | |
using std::range_error::range_error; | |
}; | |
class ConversionError : public ConversionErrorBase { | |
public: | |
ConversionError(const std::string& str, ConversionCode code) | |
: ConversionErrorBase(str), code_(code) { | |
} | |
ConversionError(const char* str, ConversionCode code) | |
: ConversionErrorBase(str), code_(code) { | |
} | |
ConversionCode errorCode() const { | |
return code_; | |
} | |
private: | |
ConversionCode code_; | |
}; | |
// # 190 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
ConversionError makeConversionError(ConversionCode code, StringPiece input); | |
namespace detail { | |
inline ConversionCode enforceWhitespaceErr(StringPiece sp) { | |
for (auto c : sp) { | |
if ((__builtin_expect((!std::isspace(c)), 0))) { | |
return ConversionCode::NON_WHITESPACE_AFTER_END; | |
} | |
} | |
return ConversionCode::SUCCESS; | |
} | |
inline void enforceWhitespace(StringPiece sp) { | |
auto err = enforceWhitespaceErr(sp); | |
if (err != ConversionCode::SUCCESS) { | |
throw_exception(makeConversionError(err, sp)); | |
} | |
} | |
} // namespace detail | |
template <class Tgt, class Src> | |
typename std::enable_if< | |
std::is_same<Tgt, typename std::decay<Src>::type>::value, | |
Expected<Tgt, ConversionCode>>::type | |
tryTo(Src&& value) { | |
return std::forward<Src>(value); | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if< | |
std::is_same<Tgt, typename std::decay<Src>::type>::value, | |
Tgt>::type | |
to(Src&& value) { | |
return std::forward<Src>(value); | |
} | |
// # 245 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
template <class Tgt, class Src> | |
typename std::enable_if<std::is_arithmetic<Src>::value && | |
!std::is_same<Tgt, Src>::value && | |
std::is_same<Tgt, bool>::value, | |
Expected<Tgt, ConversionCode>>::type | |
tryTo(const Src& value) { | |
return value != Src(); | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if<std::is_arithmetic<Src>::value && | |
!std::is_same<Tgt, Src>::value && | |
std::is_same<Tgt, bool>::value, | |
Tgt>::type | |
to(const Src& value) { | |
return value != Src(); | |
} | |
namespace detail { | |
// # 296 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
template <typename... Ts> | |
struct LastElementImpl { | |
static void call(Ignored<Ts>...) { | |
} | |
}; | |
template <typename Head, typename... Ts> | |
struct LastElementImpl<Head, Ts...> { | |
template <typename Last> | |
static Last call(Ignored<Ts>..., Last&& last) { | |
return std::forward<Last>(last); | |
} | |
}; | |
template <typename... Ts> | |
auto getLastElement(const Ts&... ts) | |
-> decltype(LastElementImpl<Ts...>::call(ts...)) { | |
return LastElementImpl<Ts...>::call(ts...); | |
} | |
template <class... Ts> | |
struct LastElement : std::decay<decltype(LastElementImpl<Ts...>::call( | |
std::declval<Ts>()...))> {}; | |
} // namespace detail | |
namespace detail { | |
template <typename IntegerType> | |
constexpr unsigned int digitsEnough() { | |
auto const digits10 = std::numeric_limits<IntegerType>::digits10; | |
return static_cast<unsigned int>(digits10) + 1; | |
} | |
inline size_t unsafeTelescope128(char* buffer, | |
size_t room, | |
unsigned __int128 x) { | |
typedef unsigned __int128 Usrc; | |
size_t p = room - 1; | |
while (x >= (Usrc(1) << 64)) { | |
const auto y = x / 10; | |
const auto digit = x % 10; | |
buffer[p--] = static_cast<char>('0' + digit); | |
x = y; | |
} | |
uint64_t xx = static_cast<uint64_t>(x); | |
while (xx >= 10) { | |
const auto y = xx / 10ULL; | |
const auto digit = xx % 10ULL; | |
buffer[p--] = static_cast<char>('0' + digit); | |
xx = y; | |
} | |
buffer[p] = static_cast<char>('0' + xx); | |
return p; | |
} | |
} // namespace detail | |
// # 378 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
inline uint32_t digits10(uint64_t v) { | |
// # 388 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
alignas(64) static const uint64_t powersOf10[20] = { | |
1, | |
10, | |
100, | |
1000, | |
10000, | |
100000, | |
1000000, | |
10000000, | |
100000000, | |
1000000000, | |
10000000000, | |
100000000000, | |
1000000000000, | |
10000000000000, | |
100000000000000, | |
1000000000000000, | |
10000000000000000, | |
100000000000000000, | |
1000000000000000000, | |
10000000000000000000UL, | |
}; | |
if ((__builtin_expect((!v), 0))) { | |
return 1; | |
} | |
const uint32_t leadingZeroes = __builtin_clzll(v); | |
const auto bits = 63 - leadingZeroes; | |
const uint32_t minLength = 1 + ((bits * 77) >> 8); | |
return minLength + uint32_t(v >= powersOf10[minLength]); | |
// # 451 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
} | |
// # 466 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
inline uint32_t uint64ToBufferUnsafe(uint64_t v, char* const buffer) { | |
auto const result = digits10(v); | |
uint32_t pos = result - 1; | |
while (v >= 10) { | |
auto const q = v / 10; | |
auto const r = v % 10; | |
buffer[pos--] = static_cast<char>('0' + r); | |
v = q; | |
} | |
buffer[pos] = static_cast<char>(v + '0'); | |
return result; | |
} | |
template <class Tgt> | |
void toAppend(char value, Tgt* result) { | |
*result += value; | |
} | |
template <class T> | |
constexpr typename std::enable_if<std::is_same<T, char>::value, size_t>::type | |
estimateSpaceNeeded(T) { | |
return 1; | |
} | |
template <size_t N> | |
constexpr size_t estimateSpaceNeeded(const char (&)[N]) { | |
return N; | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if<std::is_convertible<Src, const char*>::value && | |
IsSomeString<Tgt>::value>::type | |
toAppend(Src value, Tgt* result) { | |
const char* c = value; | |
if (c) { | |
result->append(value); | |
} | |
} | |
template <class Src> | |
typename std::enable_if<std::is_convertible<Src, const char*>::value, | |
size_t>::type | |
estimateSpaceNeeded(Src value) { | |
const char* c = value; | |
if (c) { | |
return folly::StringPiece(value).size(); | |
}; | |
return 0; | |
} | |
template <class Src> | |
typename std::enable_if<IsSomeString<Src>::value, size_t>::type | |
estimateSpaceNeeded(Src const& value) { | |
return value.size(); | |
} | |
template <class Src> | |
typename std::enable_if<std::is_convertible<Src, folly::StringPiece>::value && | |
!IsSomeString<Src>::value && | |
!std::is_convertible<Src, const char*>::value, | |
size_t>::type | |
estimateSpaceNeeded(Src value) { | |
return folly::StringPiece(value).size(); | |
} | |
template <> | |
inline size_t estimateSpaceNeeded(std::nullptr_t) { | |
return 0; | |
} | |
template <class Src> | |
typename std::enable_if<std::is_pointer<Src>::value && | |
IsSomeString<std::remove_pointer<Src>>::value, | |
size_t>::type | |
estimateSpaceNeeded(Src value) { | |
return value->size(); | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if<IsSomeString<Src>::value && | |
IsSomeString<Tgt>::value>::type | |
toAppend(const Src& value, Tgt* result) { | |
result->append(value); | |
} | |
template <class Tgt> | |
typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend( | |
StringPiece value, Tgt* result) { | |
result->append(value.data(), value.size()); | |
} | |
template <class Tgt> | |
typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend( | |
const fbstring& value, Tgt* result) { | |
result->append(value.data(), value.size()); | |
} | |
template <class Tgt> | |
void toAppend(__int128 value, Tgt* result) { | |
typedef unsigned __int128 Usrc; | |
char buffer[detail::digitsEnough<unsigned __int128>() + 1]; | |
size_t p; | |
if (value < 0) { | |
p = detail::unsafeTelescope128(buffer, sizeof(buffer), -Usrc(value)); | |
buffer[--p] = '-'; | |
} else { | |
p = detail::unsafeTelescope128(buffer, sizeof(buffer), value); | |
} | |
result->append(buffer + p, buffer + sizeof(buffer)); | |
} | |
template <class Tgt> | |
void toAppend(unsigned __int128 value, Tgt* result) { | |
char buffer[detail::digitsEnough<unsigned __int128>()]; | |
size_t p; | |
p = detail::unsafeTelescope128(buffer, sizeof(buffer), value); | |
result->append(buffer + p, buffer + sizeof(buffer)); | |
} | |
template <class T> | |
constexpr | |
typename std::enable_if<std::is_same<T, __int128>::value, size_t>::type | |
estimateSpaceNeeded(T) { | |
return detail::digitsEnough<__int128>(); | |
} | |
template <class T> | |
constexpr typename std::enable_if<std::is_same<T, unsigned __int128>::value, | |
size_t>::type | |
estimateSpaceNeeded(T) { | |
return detail::digitsEnough<unsigned __int128>(); | |
} | |
// # 647 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
template <class Tgt, class Src> | |
typename std::enable_if<std::is_integral<Src>::value && | |
std::is_signed<Src>::value && | |
IsSomeString<Tgt>::value && sizeof(Src) >= 4>::type | |
toAppend(Src value, Tgt* result) { | |
char buffer[20]; | |
if (value < 0) { | |
result->push_back('-'); | |
result->append(buffer, | |
uint64ToBufferUnsafe(~static_cast<uint64_t>(value) + 1, | |
buffer)); | |
} else { | |
result->append(buffer, uint64ToBufferUnsafe(uint64_t(value), buffer)); | |
} | |
} | |
template <class Src> | |
typename std::enable_if<std::is_integral<Src>::value && | |
std::is_signed<Src>::value && | |
sizeof(Src) >= 4 && sizeof(Src) < 16, | |
size_t>::type | |
estimateSpaceNeeded(Src value) { | |
if (value < 0) { | |
return 1 + digits10(~static_cast<uint64_t>(value) + 1); | |
} | |
return digits10(static_cast<uint64_t>(value)); | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if<std::is_integral<Src>::value && | |
!std::is_signed<Src>::value && | |
IsSomeString<Tgt>::value && sizeof(Src) >= 4>::type | |
toAppend(Src value, Tgt* result) { | |
char buffer[20]; | |
result->append(buffer, uint64ToBufferUnsafe(value, buffer)); | |
} | |
template <class Src> | |
typename std::enable_if<std::is_integral<Src>::value && | |
!std::is_signed<Src>::value && | |
sizeof(Src) >= 4 && sizeof(Src) < 16, | |
size_t>::type | |
estimateSpaceNeeded(Src value) { | |
return digits10(value); | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if<std::is_integral<Src>::value && | |
IsSomeString<Tgt>::value && sizeof(Src) < 4>::type | |
toAppend(Src value, Tgt* result) { | |
typedef typename std::conditional<std::is_signed<Src>::value, | |
int64_t, | |
uint64_t>::type Intermediate; | |
toAppend<Tgt>(static_cast<Intermediate>(value), result); | |
} | |
template <class Src> | |
typename std::enable_if<std::is_integral<Src>::value && sizeof(Src) < 4 && | |
!std::is_same<Src, char>::value, | |
size_t>::type | |
estimateSpaceNeeded(Src value) { | |
typedef typename std::conditional<std::is_signed<Src>::value, | |
int64_t, | |
uint64_t>::type Intermediate; | |
return estimateSpaceNeeded(static_cast<Intermediate>(value)); | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if<std::is_enum<Src>::value && | |
IsSomeString<Tgt>::value>::type | |
toAppend(Src value, Tgt* result) { | |
toAppend(to_underlying(value), result); | |
} | |
template <class Src> | |
typename std::enable_if<std::is_enum<Src>::value, size_t>::type | |
estimateSpaceNeeded(Src value) { | |
return estimateSpaceNeeded(to_underlying(value)); | |
} | |
namespace detail { | |
constexpr int kConvMaxDecimalInShortestLow = -6; | |
constexpr int kConvMaxDecimalInShortestHigh = 21; | |
} // namespace detail | |
template <class Tgt, class Src> | |
typename std::enable_if<std::is_floating_point<Src>::value && | |
IsSomeString<Tgt>::value>::type | |
toAppend(Src value, | |
Tgt* result, | |
double_conversion::DoubleToStringConverter::DtoaMode mode, | |
unsigned int numDigits) { | |
using namespace double_conversion; | |
DoubleToStringConverter conv(DoubleToStringConverter::NO_FLAGS, | |
"Infinity", | |
"NaN", | |
'E', | |
detail::kConvMaxDecimalInShortestLow, | |
detail::kConvMaxDecimalInShortestHigh, | |
6, | |
1); | |
char buffer[256]; | |
StringBuilder builder(buffer, sizeof(buffer)); | |
switch (mode) { | |
case DoubleToStringConverter::SHORTEST: | |
conv.ToShortest(value, &builder); | |
break; | |
case DoubleToStringConverter::SHORTEST_SINGLE: | |
conv.ToShortestSingle(static_cast<float>(value), &builder); | |
break; | |
case DoubleToStringConverter::FIXED: | |
conv.ToFixed(value, int(numDigits), &builder); | |
break; | |
case DoubleToStringConverter::PRECISION: | |
default: | |
(static_cast<bool>(mode == DoubleToStringConverter::PRECISION) | |
? void(0) | |
: __assert_fail("mode == DoubleToStringConverter::PRECISION", | |
"tlm/deps/folly.exploded/include/folly/Conv.h", | |
785, | |
__extension__ __PRETTY_FUNCTION__)); | |
conv.ToPrecision(value, int(numDigits), &builder); | |
break; | |
} | |
const size_t length = size_t(builder.position()); | |
builder.Finalize(); | |
result->append(buffer, length); | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if<std::is_floating_point<Src>::value && | |
IsSomeString<Tgt>::value>::type | |
toAppend(Src value, Tgt* result) { | |
toAppend(value, | |
result, | |
double_conversion::DoubleToStringConverter::SHORTEST, | |
0); | |
} | |
template <class Src> | |
typename std::enable_if<std::is_floating_point<Src>::value, size_t>::type | |
estimateSpaceNeeded(Src value) { | |
constexpr int kMaxMantissaSpace = | |
double_conversion::DoubleToStringConverter::kBase10MaximalLength + | |
1; | |
constexpr int kMaxExponentSpace = 2 + 3; | |
static const int kMaxPositiveSpace = std::max({ | |
kMaxMantissaSpace + kMaxExponentSpace, | |
kMaxMantissaSpace - detail::kConvMaxDecimalInShortestLow, | |
detail::kConvMaxDecimalInShortestHigh, | |
}); | |
return size_t(kMaxPositiveSpace + (value < 0 ? 1 : 0)); | |
} | |
template <class Src> | |
struct HasLengthEstimator : std::false_type {}; | |
template <class Src> | |
constexpr typename std::enable_if< | |
!std::is_fundamental<Src>::value && | |
!std::is_same<__int128, Src>::value && | |
!std::is_same<unsigned __int128, Src>::value && | |
!IsSomeString<Src>::value && | |
!std::is_convertible<Src, const char*>::value && | |
!std::is_convertible<Src, StringPiece>::value && | |
!std::is_enum<Src>::value && !HasLengthEstimator<Src>::value, | |
size_t>::type | |
estimateSpaceNeeded(const Src&) { | |
return sizeof(Src) + 1; | |
} | |
namespace detail { | |
template <class Tgt> | |
typename std::enable_if<IsSomeString<Tgt>::value, size_t>::type | |
estimateSpaceToReserve(size_t sofar, Tgt*) { | |
return sofar; | |
} | |
template <class T, class... Ts> | |
size_t estimateSpaceToReserve(size_t sofar, const T& v, const Ts&... vs) { | |
return estimateSpaceToReserve(sofar + estimateSpaceNeeded(v), vs...); | |
} | |
template <class... Ts> | |
void reserveInTarget(const Ts&... vs) { | |
getLastElement(vs...)->reserve(estimateSpaceToReserve(0, vs...)); | |
} | |
template <class Delimiter, class... Ts> | |
void reserveInTargetDelim(const Delimiter& d, const Ts&... vs) { | |
static_assert(sizeof...(vs) >= 2, "Needs at least 2 args"); | |
size_t fordelim = | |
(sizeof...(vs) - 2) * | |
estimateSpaceToReserve(0, d, static_cast<std::string*>(nullptr)); | |
getLastElement(vs...)->reserve(estimateSpaceToReserve(fordelim, vs...)); | |
} | |
template <class T, class Tgt> | |
typename std::enable_if< | |
IsSomeString<typename std::remove_pointer<Tgt>::type>::value>::type | |
toAppendStrImpl(const T& v, Tgt result) { | |
toAppend(v, result); | |
} | |
template <class T, class... Ts> | |
typename std::enable_if< | |
sizeof...(Ts) >= 2 && | |
IsSomeString<typename std::remove_pointer<typename detail::LastElement< | |
const Ts&...>::type>::type>::value>::type | |
toAppendStrImpl(const T& v, const Ts&... vs) { | |
toAppend(v, getLastElement(vs...)); | |
toAppendStrImpl(vs...); | |
} | |
template <class Delimiter, class T, class Tgt> | |
typename std::enable_if< | |
IsSomeString<typename std::remove_pointer<Tgt>::type>::value>::type | |
toAppendDelimStrImpl(const Delimiter&, const T& v, Tgt result) { | |
toAppend(v, result); | |
} | |
template <class Delimiter, class T, class... Ts> | |
typename std::enable_if< | |
sizeof...(Ts) >= 2 && | |
IsSomeString<typename std::remove_pointer<typename detail::LastElement< | |
const Ts&...>::type>::type>::value>::type | |
toAppendDelimStrImpl(const Delimiter& delim, const T& v, const Ts&... vs) { | |
toAppend(v, detail::getLastElement(vs...)); | |
toAppend(delim, detail::getLastElement(vs...)); | |
toAppendDelimStrImpl(delim, vs...); | |
} | |
} // namespace detail | |
// # 948 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
template <class... Ts> | |
typename std::enable_if< | |
sizeof...(Ts) >= 3 && | |
IsSomeString<typename std::remove_pointer<typename detail::LastElement< | |
const Ts&...>::type>::type>::value>::type | |
toAppend(const Ts&... vs) { | |
::folly::detail::toAppendStrImpl(vs...); | |
} | |
// # 977 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
template <class... Ts> | |
typename std::enable_if<IsSomeString<typename std::remove_pointer< | |
typename detail::LastElement<const Ts&...>::type>::type>::value>::type | |
toAppendFit(const Ts&... vs) { | |
::folly::detail::reserveInTarget(vs...); | |
toAppend(vs...); | |
} | |
template <class Ts> | |
void toAppendFit(const Ts&) { | |
} | |
template <class Tgt> | |
typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(Tgt*) { | |
} | |
template <class Delimiter, class Tgt> | |
typename std::enable_if<IsSomeString<Tgt>::value>::type toAppendDelim( | |
const Delimiter&, Tgt*) { | |
} | |
template <class Delimiter, class T, class Tgt> | |
typename std::enable_if<IsSomeString<Tgt>::value>::type toAppendDelim( | |
const Delimiter&, const T& v, Tgt* tgt) { | |
toAppend(v, tgt); | |
} | |
template <class Delimiter, class... Ts> | |
typename std::enable_if< | |
sizeof...(Ts) >= 3 && | |
IsSomeString<typename std::remove_pointer<typename detail::LastElement< | |
const Ts&...>::type>::type>::value>::type | |
toAppendDelim(const Delimiter& delim, const Ts&... vs) { | |
detail::toAppendDelimStrImpl(delim, vs...); | |
} | |
template <class Delimiter, class... Ts> | |
typename std::enable_if<IsSomeString<typename std::remove_pointer< | |
typename detail::LastElement<const Ts&...>::type>::type>::value>::type | |
toAppendDelimFit(const Delimiter& delim, const Ts&... vs) { | |
detail::reserveInTargetDelim(delim, vs...); | |
toAppendDelim(delim, vs...); | |
} | |
template <class De, class Ts> | |
void toAppendDelimFit(const De&, const Ts&) { | |
} | |
template <class Tgt, class... Ts> | |
typename std::enable_if< | |
IsSomeString<Tgt>::value && | |
(sizeof...(Ts) != 1 || | |
!std::is_same<Tgt, | |
typename detail::LastElement< | |
const Ts&...>::type>::value), | |
Tgt>::type | |
to(const Ts&... vs) { | |
Tgt result; | |
toAppendFit(vs..., &result); | |
return result; | |
} | |
// # 1067 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
template <class Tgt, class Src> | |
typename std::enable_if<IsSomeString<Tgt>::value && | |
std::is_floating_point<Src>::value, | |
Tgt>::type | |
to(Src value) { | |
Tgt result; | |
toAppend(value, &result); | |
return result; | |
} | |
template <class Tgt, class Delim, class Src> | |
typename std::enable_if< | |
IsSomeString<Tgt>::value && | |
std::is_same<Tgt, typename std::decay<Src>::type>::value, | |
Tgt>::type | |
toDelim(const Delim&, Src&& value) { | |
return std::forward<Src>(value); | |
} | |
template <class Tgt, class Delim, class... Ts> | |
typename std::enable_if< | |
IsSomeString<Tgt>::value && | |
(sizeof...(Ts) != 1 || | |
!std::is_same<Tgt, | |
typename detail::LastElement< | |
const Ts&...>::type>::value), | |
Tgt>::type | |
toDelim(const Delim& delim, const Ts&... vs) { | |
Tgt result; | |
toAppendDelimFit(delim, vs..., &result); | |
return result; | |
} | |
namespace detail { | |
Expected<bool, ConversionCode> str_to_bool(StringPiece* src) noexcept; | |
template <typename T> | |
Expected<T, ConversionCode> str_to_floating(StringPiece* src) noexcept; | |
extern template Expected<float, ConversionCode> str_to_floating<float>( | |
StringPiece* src) noexcept; | |
extern template Expected<double, ConversionCode> str_to_floating<double>( | |
StringPiece* src) noexcept; | |
template <class Tgt> | |
Expected<Tgt, ConversionCode> digits_to(const char* b, const char* e) noexcept; | |
extern template Expected<char, ConversionCode> digits_to<char>( | |
const char*, const char*) noexcept; | |
extern template Expected<signed char, ConversionCode> digits_to<signed char>( | |
const char*, const char*) noexcept; | |
extern template Expected<unsigned char, ConversionCode> | |
digits_to<unsigned char>(const char*, const char*) noexcept; | |
extern template Expected<short, ConversionCode> digits_to<short>( | |
const char*, const char*) noexcept; | |
extern template Expected<unsigned short, ConversionCode> | |
digits_to<unsigned short>(const char*, const char*) noexcept; | |
extern template Expected<int, ConversionCode> digits_to<int>( | |
const char*, const char*) noexcept; | |
extern template Expected<unsigned int, ConversionCode> digits_to<unsigned int>( | |
const char*, const char*) noexcept; | |
extern template Expected<long, ConversionCode> digits_to<long>( | |
const char*, const char*) noexcept; | |
extern template Expected<unsigned long, ConversionCode> | |
digits_to<unsigned long>(const char*, const char*) noexcept; | |
extern template Expected<long long, ConversionCode> digits_to<long long>( | |
const char*, const char*) noexcept; | |
extern template Expected<unsigned long long, ConversionCode> | |
digits_to<unsigned long long>(const char*, const char*) noexcept; | |
extern template Expected<__int128, ConversionCode> digits_to<__int128>( | |
const char*, const char*) noexcept; | |
extern template Expected<unsigned __int128, ConversionCode> | |
digits_to<unsigned __int128>(const char*, const char*) noexcept; | |
template <class T> | |
Expected<T, ConversionCode> str_to_integral(StringPiece* src) noexcept; | |
extern template Expected<char, ConversionCode> str_to_integral<char>( | |
StringPiece* src) noexcept; | |
extern template Expected<signed char, ConversionCode> | |
str_to_integral<signed char>(StringPiece* src) noexcept; | |
extern template Expected<unsigned char, ConversionCode> | |
str_to_integral<unsigned char>(StringPiece* src) noexcept; | |
extern template Expected<short, ConversionCode> str_to_integral<short>( | |
StringPiece* src) noexcept; | |
extern template Expected<unsigned short, ConversionCode> | |
str_to_integral<unsigned short>(StringPiece* src) noexcept; | |
extern template Expected<int, ConversionCode> str_to_integral<int>( | |
StringPiece* src) noexcept; | |
extern template Expected<unsigned int, ConversionCode> | |
str_to_integral<unsigned int>(StringPiece* src) noexcept; | |
extern template Expected<long, ConversionCode> str_to_integral<long>( | |
StringPiece* src) noexcept; | |
extern template Expected<unsigned long, ConversionCode> | |
str_to_integral<unsigned long>(StringPiece* src) noexcept; | |
extern template Expected<long long, ConversionCode> str_to_integral<long long>( | |
StringPiece* src) noexcept; | |
extern template Expected<unsigned long long, ConversionCode> | |
str_to_integral<unsigned long long>(StringPiece* src) noexcept; | |
extern template Expected<__int128, ConversionCode> str_to_integral<__int128>( | |
StringPiece* src) noexcept; | |
extern template Expected<unsigned __int128, ConversionCode> | |
str_to_integral<unsigned __int128>(StringPiece* src) noexcept; | |
template <typename T> | |
typename std::enable_if<std::is_same<T, bool>::value, | |
Expected<T, ConversionCode>>::type | |
convertTo(StringPiece* src) noexcept { | |
return str_to_bool(src); | |
} | |
template <typename T> | |
typename std::enable_if<std::is_floating_point<T>::value, | |
Expected<T, ConversionCode>>::type | |
convertTo(StringPiece* src) noexcept { | |
return str_to_floating<T>(src); | |
} | |
template <typename T> | |
typename std::enable_if<std::is_integral<T>::value && | |
!std::is_same<T, bool>::value, | |
Expected<T, ConversionCode>>::type | |
convertTo(StringPiece* src) noexcept { | |
return str_to_integral<T>(src); | |
} | |
} // namespace detail | |
template <typename Tgt> | |
typename std::enable_if<std::is_integral<Tgt>::value && | |
!std::is_same<Tgt, bool>::value, | |
Expected<Tgt, ConversionCode>>::type | |
tryTo(const char* b, const char* e) { | |
return detail::digits_to<Tgt>(b, e); | |
} | |
template <typename Tgt> | |
typename std::enable_if<std::is_integral<Tgt>::value && | |
!std::is_same<Tgt, bool>::value, | |
Tgt>::type | |
to(const char* b, const char* e) { | |
return tryTo<Tgt>(b, e).thenOrThrow([](Tgt res) { return res; }, | |
[=](ConversionCode code) { | |
return makeConversionError( | |
code, StringPiece(b, e)); | |
}); | |
} | |
// # 1260 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
template <typename Tgt> | |
[[nodiscard]] inline | |
typename std::enable_if<std::is_arithmetic<Tgt>::value, | |
Expected<StringPiece, ConversionCode>>::type | |
parseTo(StringPiece src, Tgt& out) { | |
return detail::convertTo<Tgt>(&src).then( | |
[&](Tgt res) { return void(out = res), src; }); | |
} | |
namespace detail { | |
template <class Tgt> | |
typename std::enable_if<!std::is_same<Tgt, bool>::value && | |
(std::is_integral<Tgt>::value || | |
std::is_floating_point<Tgt>::value), | |
Expected<Tgt, ConversionCode>>::type | |
convertTo(const bool& value) noexcept { | |
return static_cast<Tgt>(value ? 1 : 0); | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if< | |
std::is_integral<Src>::value && !std::is_same<Tgt, Src>::value && | |
!std::is_same<Tgt, bool>::value && std::is_integral<Tgt>::value, | |
Expected<Tgt, ConversionCode>>::type | |
convertTo(const Src& value) noexcept { | |
if (std::make_unsigned_t<Tgt>(std::numeric_limits<Tgt>::max()) < | |
std::make_unsigned_t<Src>(std::numeric_limits<Src>::max())) { | |
if (greater_than<Tgt, std::numeric_limits<Tgt>::max()>(value)) { | |
return makeUnexpected(ConversionCode::ARITH_POSITIVE_OVERFLOW); | |
} | |
} | |
if (std::is_signed<Src>::value && | |
(!std::is_signed<Tgt>::value || sizeof(Src) > sizeof(Tgt))) { | |
if (less_than<Tgt, std::numeric_limits<Tgt>::min()>(value)) { | |
return makeUnexpected(ConversionCode::ARITH_NEGATIVE_OVERFLOW); | |
} | |
} | |
return static_cast<Tgt>(value); | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if<std::is_floating_point<Tgt>::value && | |
std::is_floating_point<Src>::value && | |
!std::is_same<Tgt, Src>::value, | |
Expected<Tgt, ConversionCode>>::type | |
convertTo(const Src& value) noexcept { | |
if (std::numeric_limits<Tgt>::max() < std::numeric_limits<Src>::max()) { | |
if (value > std::numeric_limits<Tgt>::max()) { | |
return makeUnexpected(ConversionCode::ARITH_POSITIVE_OVERFLOW); | |
} | |
if (value < std::numeric_limits<Tgt>::lowest()) { | |
return makeUnexpected(ConversionCode::ARITH_NEGATIVE_OVERFLOW); | |
} | |
} | |
return static_cast<Tgt>(value); | |
} | |
template <typename Tgt, typename Src> | |
inline typename std::enable_if<std::is_floating_point<Src>::value && | |
std::is_integral<Tgt>::value && | |
!std::is_same<Tgt, bool>::value, | |
bool>::type | |
checkConversion(const Src& value) { | |
constexpr Src tgtMaxAsSrc = | |
static_cast<Src>(std::numeric_limits<Tgt>::max()); | |
constexpr Src tgtMinAsSrc = | |
static_cast<Src>(std::numeric_limits<Tgt>::min()); | |
if (value >= tgtMaxAsSrc) { | |
if (value > tgtMaxAsSrc) { | |
return false; | |
} | |
const Src mmax = folly::nextafter(tgtMaxAsSrc, Src()); | |
if (static_cast<Tgt>(value - mmax) > | |
std::numeric_limits<Tgt>::max() - static_cast<Tgt>(mmax)) { | |
return false; | |
} | |
} else if (std::is_signed<Tgt>::value && value <= tgtMinAsSrc) { | |
if (value < tgtMinAsSrc) { | |
return false; | |
} | |
const Src mmin = folly::nextafter(tgtMinAsSrc, Src()); | |
if (static_cast<Tgt>(value - mmin) < | |
std::numeric_limits<Tgt>::min() - static_cast<Tgt>(mmin)) { | |
return false; | |
} | |
} | |
return true; | |
} | |
template <typename Tgt, typename Src> | |
constexpr typename std::enable_if<std::is_integral<Src>::value && | |
std::is_floating_point<Tgt>::value, | |
bool>::type | |
checkConversion(const Src&) { | |
return true; | |
} | |
template <typename Tgt, typename Src> | |
constexpr typename std::enable_if<std::is_floating_point<Src>::value && | |
std::is_same<Tgt, bool>::value, | |
bool>::type | |
checkConversion(const Src&) { | |
return true; | |
} | |
// # 1400 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
template <typename Tgt, typename Src> | |
typename std::enable_if<(std::is_integral<Src>::value && | |
std::is_floating_point<Tgt>::value) || | |
(std::is_floating_point<Src>::value && | |
std::is_integral<Tgt>::value), | |
Expected<Tgt, ConversionCode>>::type | |
convertTo(const Src& value) noexcept { | |
if ((__builtin_expect((checkConversion<Tgt>(value)), 1))) { | |
Tgt result = static_cast<Tgt>(value); | |
if ((__builtin_expect((checkConversion<Src>(result)), 1))) { | |
Src witness = static_cast<Src>(result); | |
if ((__builtin_expect((value == witness), 1))) { | |
return result; | |
} | |
} | |
} | |
return makeUnexpected(ConversionCode::ARITH_LOSS_OF_PRECISION); | |
} | |
template <typename Tgt, typename Src> | |
inline std::string errorValue(const Src& value) { | |
return to<std::string>("(", pretty_name<Tgt>(), ") ", value); | |
} | |
template <typename Tgt, typename Src> | |
using IsArithToArith = bool_constant< | |
!std::is_same<Tgt, Src>::value && !std::is_same<Tgt, bool>::value && | |
std::is_arithmetic<Src>::value && std::is_arithmetic<Tgt>::value>; | |
} // namespace detail | |
template <typename Tgt, typename Src> | |
typename std::enable_if<detail::IsArithToArith<Tgt, Src>::value, | |
Expected<Tgt, ConversionCode>>::type | |
tryTo(const Src& value) noexcept { | |
return detail::convertTo<Tgt>(value); | |
} | |
template <typename Tgt, typename Src> | |
typename std::enable_if<detail::IsArithToArith<Tgt, Src>::value, Tgt>::type to( | |
const Src& value) { | |
return tryTo<Tgt>(value).thenOrThrow( | |
[](Tgt res) { return res; }, | |
[&](ConversionCode e) { | |
return makeConversionError(e, detail::errorValue<Tgt>(value)); | |
}); | |
} | |
// # 1460 "tlm/deps/folly.exploded/include/folly/Conv.h" 3 4 | |
template <class T> | |
[[nodiscard]] | |
typename std::enable_if<std::is_enum<T>::value, | |
Expected<StringPiece, ConversionCode>>::type | |
parseTo(StringPiece in, T& out) noexcept { | |
typename std::underlying_type<T>::type tmp{}; | |
auto restOrError = parseTo(in, tmp); | |
out = static_cast<T>(tmp); | |
return restOrError; | |
} | |
[[nodiscard]] inline Expected<StringPiece, ConversionCode> parseTo( | |
StringPiece in, StringPiece& out) noexcept { | |
out = in; | |
return StringPiece{in.end(), in.end()}; | |
} | |
[[nodiscard]] inline Expected<StringPiece, ConversionCode> parseTo( | |
StringPiece in, std::string& out) { | |
out.clear(); | |
out.append(in.data(), in.size()); | |
return StringPiece{in.end(), in.end()}; | |
} | |
[[nodiscard]] inline Expected<StringPiece, ConversionCode> parseTo( | |
StringPiece in, fbstring& out) { | |
out.clear(); | |
out.append(in.data(), in.size()); | |
return StringPiece{in.end(), in.end()}; | |
} | |
namespace detail { | |
template <typename Tgt> | |
using ParseToResult = decltype(parseTo(StringPiece{}, std::declval<Tgt&>())); | |
struct CheckTrailingSpace { | |
Expected<Unit, ConversionCode> operator()(StringPiece sp) const { | |
auto e = enforceWhitespaceErr(sp); | |
if ((__builtin_expect((e != ConversionCode::SUCCESS), 0))) { | |
return makeUnexpected(e); | |
} | |
return unit; | |
} | |
}; | |
template <class Error> | |
struct ReturnUnit { | |
template <class T> | |
constexpr Expected<Unit, Error> operator()(T&&) const { | |
return unit; | |
} | |
}; | |
template <class Tgt> | |
inline typename std::enable_if<std::is_void<ParseToResult<Tgt>>::value, | |
Expected<StringPiece, ConversionCode>>::type | |
parseToWrap(StringPiece sp, Tgt& out) { | |
parseTo(sp, out); | |
return StringPiece(sp.end(), sp.end()); | |
} | |
template <class Tgt> | |
inline typename std::enable_if<!std::is_void<ParseToResult<Tgt>>::value, | |
ParseToResult<Tgt>>::type | |
parseToWrap(StringPiece sp, Tgt& out) { | |
return parseTo(sp, out); | |
} | |
template <typename Tgt> | |
using ParseToError = ExpectedErrorType<decltype( | |
detail::parseToWrap(StringPiece{}, std::declval<Tgt&>()))>; | |
} // namespace detail | |
template <class Tgt> | |
inline typename std::enable_if<!std::is_same<StringPiece, Tgt>::value, | |
Expected<Tgt, detail::ParseToError<Tgt>>>::type | |
tryTo(StringPiece src) { | |
Tgt result{}; | |
using Error = detail::ParseToError<Tgt>; | |
using Check = typename std::conditional<std::is_arithmetic<Tgt>::value, | |
detail::CheckTrailingSpace, | |
detail::ReturnUnit<Error>>::type; | |
return parseTo(src, result).then(Check(), [&](Unit) { | |
return std::move(result); | |
}); | |
} | |
template <class Tgt, class Src> | |
inline typename std::enable_if<IsSomeString<Src>::value && | |
!std::is_same<StringPiece, Tgt>::value, | |
Tgt>::type | |
to(Src const& src) { | |
return to<Tgt>(StringPiece(src.data(), src.size())); | |
} | |
template <class Tgt> | |
inline typename std::enable_if<!std::is_same<StringPiece, Tgt>::value, | |
Tgt>::type | |
to(StringPiece src) { | |
Tgt result{}; | |
using Error = detail::ParseToError<Tgt>; | |
using Check = typename std::conditional<std::is_arithmetic<Tgt>::value, | |
detail::CheckTrailingSpace, | |
detail::ReturnUnit<Error>>::type; | |
auto tmp = detail::parseToWrap(src, result); | |
return tmp | |
.thenOrThrow(Check(), | |
[&](Error e) { | |
throw_exception(makeConversionError(e, src)); | |
}) | |
.thenOrThrow( | |
[&](Unit) { return std::move(result); }, | |
[&](Error e) { | |
throw_exception(makeConversionError(e, tmp.value())); | |
}); | |
} | |
template <class Tgt> | |
Expected<Tgt, detail::ParseToError<Tgt>> tryTo(StringPiece* src) { | |
Tgt result; | |
return parseTo(*src, result).then([&, src](StringPiece sp) -> Tgt { | |
*src = sp; | |
return std::move(result); | |
}); | |
} | |
template <class Tgt> | |
Tgt to(StringPiece* src) { | |
Tgt result{}; | |
using Error = detail::ParseToError<Tgt>; | |
return parseTo(*src, result) | |
.thenOrThrow( | |
[&, src](StringPiece sp) -> Tgt { | |
*src = sp; | |
return std::move(result); | |
}, | |
[=](Error e) { return makeConversionError(e, *src); }); | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if<std::is_enum<Src>::value && | |
!std::is_same<Src, Tgt>::value && | |
!std::is_convertible<Tgt, StringPiece>::value, | |
Expected<Tgt, ConversionCode>>::type | |
tryTo(const Src& value) { | |
return tryTo<Tgt>(to_underlying(value)); | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if<!std::is_convertible<Src, StringPiece>::value && | |
std::is_enum<Tgt>::value && | |
!std::is_same<Src, Tgt>::value, | |
Expected<Tgt, ConversionCode>>::type | |
tryTo(const Src& value) { | |
using I = typename std::underlying_type<Tgt>::type; | |
return tryTo<I>(value).then([](I i) { return static_cast<Tgt>(i); }); | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if<std::is_enum<Src>::value && | |
!std::is_same<Src, Tgt>::value && | |
!std::is_convertible<Tgt, StringPiece>::value, | |
Tgt>::type | |
to(const Src& value) { | |
return to<Tgt>(to_underlying(value)); | |
} | |
template <class Tgt, class Src> | |
typename std::enable_if<!std::is_convertible<Src, StringPiece>::value && | |
std::is_enum<Tgt>::value && | |
!std::is_same<Src, Tgt>::value, | |
Tgt>::type | |
to(const Src& value) { | |
return static_cast<Tgt>( | |
to<typename std::underlying_type<Tgt>::type>(value)); | |
} | |
} // namespace folly | |
// # 26 "tlm/deps/folly.exploded/include/folly/Exception.h" 2 3 4 | |
namespace folly { | |
inline std::system_error makeSystemErrorExplicit(int err, const char* msg) { | |
return std::system_error(err, std::system_category(), msg); | |
} | |
template <class... Args> | |
std::system_error makeSystemErrorExplicit(int err, Args&&... args) { | |
return makeSystemErrorExplicit( | |
err, to<fbstring>(std::forward<Args>(args)...).c_str()); | |
} | |
inline std::system_error makeSystemError(const char* msg) { | |
return makeSystemErrorExplicit((*__errno_location()), msg); | |
} | |
template <class... Args> | |
std::system_error makeSystemError(Args&&... args) { | |
return makeSystemErrorExplicit((*__errno_location()), | |
std::forward<Args>(args)...); | |
} | |
[[noreturn]] inline void throwSystemErrorExplicit(int err, const char* msg) { | |
throw_exception(makeSystemErrorExplicit(err, msg)); | |
} | |
template <class... Args> | |
[[noreturn]] void throwSystemErrorExplicit(int err, Args&&... args) { | |
throw_exception(makeSystemErrorExplicit(err, std::forward<Args>(args)...)); | |
} | |
template <class... Args> | |
[[noreturn]] void throwSystemError(Args&&... args) { | |
throwSystemErrorExplicit((*__errno_location()), | |
std::forward<Args>(args)...); | |
} | |
template <class... Args> | |
void checkPosixError(int err, Args&&... args) { | |
if ((__builtin_expect((err != 0), 0))) { | |
throwSystemErrorExplicit(err, std::forward<Args>(args)...); | |
} | |
} | |
template <class... Args> | |
void checkKernelError(ssize_t ret, Args&&... args) { | |
if ((__builtin_expect((ret < 0), 0))) { | |
throwSystemErrorExplicit(int(-ret), std::forward<Args>(args)...); | |
} | |
} | |
template <class... Args> | |
void checkUnixError(ssize_t ret, Args&&... args) { | |
if ((__builtin_expect((ret == -1), 0))) { | |
throwSystemError(std::forward<Args>(args)...); | |
} | |
} | |
template <class... Args> | |
void checkUnixErrorExplicit(ssize_t ret, int savedErrno, Args&&... args) { | |
if ((__builtin_expect((ret == -1), 0))) { | |
throwSystemErrorExplicit(savedErrno, std::forward<Args>(args)...); | |
} | |
} | |
template <class... Args> | |
void checkFopenError(FILE* fp, Args&&... args) { | |
if ((__builtin_expect((!fp), 0))) { | |
throwSystemError(std::forward<Args>(args)...); | |
} | |
} | |
template <class... Args> | |
void checkFopenErrorExplicit(FILE* fp, int savedErrno, Args&&... args) { | |
if ((__builtin_expect((!fp), 0))) { | |
throwSystemErrorExplicit(savedErrno, std::forward<Args>(args)...); | |
} | |
} | |
// # 142 "tlm/deps/folly.exploded/include/folly/Exception.h" 3 4 | |
} // namespace folly | |
// # 31 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/Function.h" 1 3 4 | |
// # 219 "tlm/deps/folly.exploded/include/folly/Function.h" 3 4 | |
// # 233 "tlm/deps/folly.exploded/include/folly/Function.h" 3 4 | |
namespace folly { | |
template <typename FunctionType> | |
class Function; | |
template <typename ReturnType, typename... Args> | |
Function<ReturnType(Args...) const> constCastFunction( | |
Function<ReturnType(Args...)>&&) noexcept; | |
template <typename ReturnType, typename... Args> | |
Function<ReturnType(Args...) const noexcept> constCastFunction( | |
Function<ReturnType(Args...) noexcept>&&) noexcept; | |
namespace detail { | |
namespace function { | |
enum class Op { MOVE, NUKE, HEAP }; | |
union Data { | |
Data() { | |
} | |
void* big; | |
std::aligned_storage<6 * sizeof(void*)>::type tiny; | |
}; | |
template <typename Fun, typename = Fun*> | |
using IsSmall = Conjunction<bool_constant<(sizeof(Fun) <= sizeof(Data::tiny))>, | |
std::is_nothrow_move_constructible<Fun>>; | |
using SmallTag = std::true_type; | |
using HeapTag = std::false_type; | |
template <typename T> | |
struct NotFunction : std::true_type {}; | |
template <typename T> | |
struct NotFunction<Function<T>> : std::false_type {}; | |
template <typename T> | |
using EnableIfNotFunction = | |
typename std::enable_if<NotFunction<T>::value>::type; | |
struct CoerceTag {}; | |
template <typename, typename T> | |
struct IsFunctionNullptrTestable : std::false_type {}; | |
template <typename T> | |
struct IsFunctionNullptrTestable< | |
void_t<decltype(static_cast<bool>(static_cast<T const&>(T(nullptr)) == | |
nullptr))>, | |
T> : std::true_type {}; | |
template <typename T> | |
constexpr std::enable_if_t<!IsFunctionNullptrTestable<void, T>::value, | |
std::false_type> | |
isEmptyFunction(T const&) { | |
return {}; | |
} | |
template <typename T> | |
constexpr std::enable_if_t<IsFunctionNullptrTestable<void, T>::value, bool> | |
isEmptyFunction(T const& t) { | |
return static_cast<bool>(t == nullptr); | |
} | |
template <typename F, typename... Args> | |
using CallableResult = decltype(std::declval<F>()(std::declval<Args>()...)); | |
template <typename From, | |
typename To, | |
typename = | |
typename std::enable_if<!std::is_reference<To>::value || | |
std::is_reference<From>::value>::type> | |
using SafeResultOf = decltype(static_cast<To>(std::declval<From>())); | |
// # 320 "tlm/deps/folly.exploded/include/folly/Function.h" 3 4 | |
template <typename T> | |
using CallArg = conditional_t<is_trivially_copyable<T>::value, T, T&&>; | |
template <typename F, typename R, typename... A> | |
class FunctionTraitsSharedProxy { | |
std::shared_ptr<Function<F>> sp_; | |
public: | |
explicit FunctionTraitsSharedProxy(std::nullptr_t) noexcept { | |
} | |
explicit FunctionTraitsSharedProxy(Function<F>&& func) | |
: sp_(func ? std::make_shared<Function<F>>(std::move(func)) | |
: std::shared_ptr<Function<F>>()) { | |
} | |
R operator()(A&&... args) const { | |
if (!sp_) { | |
throw_exception<std::bad_function_call>(); | |
} | |
return (*sp_)(static_cast<A&&>(args)...); | |
} | |
explicit operator bool() const noexcept { | |
return sp_ != nullptr; | |
} | |
friend bool operator==(FunctionTraitsSharedProxy<F, R, A...> const& proxy, | |
std::nullptr_t) noexcept { | |
return proxy.sp_ == nullptr; | |
} | |
friend bool operator!=(FunctionTraitsSharedProxy<F, R, A...> const& proxy, | |
std::nullptr_t) noexcept { | |
return proxy.sp_ != nullptr; | |
} | |
friend bool operator==( | |
std::nullptr_t, | |
FunctionTraitsSharedProxy<F, R, A...> const& proxy) noexcept { | |
return proxy.sp_ == nullptr; | |
} | |
friend bool operator!=( | |
std::nullptr_t, | |
FunctionTraitsSharedProxy<F, R, A...> const& proxy) noexcept { | |
return proxy.sp_ != nullptr; | |
} | |
}; | |
template <typename FunctionType> | |
struct FunctionTraits; | |
template <typename ReturnType, typename... Args> | |
struct FunctionTraits<ReturnType(Args...)> { | |
using Call = ReturnType (*)(CallArg<Args>..., Data&); | |
using IsConst = std::false_type; | |
using ConstSignature = ReturnType(Args...) const; | |
using NonConstSignature = ReturnType(Args...); | |
using OtherSignature = ConstSignature; | |
template <typename F> | |
using ResultOf = | |
SafeResultOf<CallableResult<std::decay_t<F>&, Args...>, ReturnType>; | |
template <typename Fun> | |
static ReturnType callSmall(CallArg<Args>... args, Data& p) { | |
auto& fn = *static_cast<Fun*>(static_cast<void*>(&p.tiny)); | |
if constexpr (std::is_void<ReturnType>::value) { | |
fn(static_cast<Args&&>(args)...); | |
} else { | |
return fn(static_cast<Args&&>(args)...); | |
} | |
} | |
template <typename Fun> | |
static ReturnType callBig(CallArg<Args>... args, Data& p) { | |
auto& fn = *static_cast<Fun*>(p.big); | |
if constexpr (std::is_void<ReturnType>::value) { | |
fn(static_cast<Args&&>(args)...); | |
} else { | |
return fn(static_cast<Args&&>(args)...); | |
} | |
} | |
static ReturnType uninitCall(CallArg<Args>..., Data&) { | |
throw_exception<std::bad_function_call>(); | |
} | |
ReturnType operator()(Args... args) { | |
auto& fn = *static_cast<Function<NonConstSignature>*>(this); | |
return fn.call_(static_cast<Args&&>(args)..., fn.data_); | |
} | |
using SharedProxy = | |
FunctionTraitsSharedProxy<NonConstSignature, ReturnType, Args...>; | |
}; | |
template <typename ReturnType, typename... Args> | |
struct FunctionTraits<ReturnType(Args...) const> { | |
using Call = ReturnType (*)(CallArg<Args>..., Data&); | |
using IsConst = std::true_type; | |
using ConstSignature = ReturnType(Args...) const; | |
using NonConstSignature = ReturnType(Args...); | |
using OtherSignature = NonConstSignature; | |
template <typename F> | |
using ResultOf = | |
SafeResultOf<CallableResult<const std::decay_t<F>&, Args...>, | |
ReturnType>; | |
template <typename Fun> | |
static ReturnType callSmall(CallArg<Args>... args, Data& p) { | |
auto& fn = *static_cast<const Fun*>(static_cast<void*>(&p.tiny)); | |
if constexpr (std::is_void<ReturnType>::value) { | |
fn(static_cast<Args&&>(args)...); | |
} else { | |
return fn(static_cast<Args&&>(args)...); | |
} | |
} | |
template <typename Fun> | |
static ReturnType callBig(CallArg<Args>... args, Data& p) { | |
auto& fn = *static_cast<const Fun*>(p.big); | |
if constexpr (std::is_void<ReturnType>::value) { | |
fn(static_cast<Args&&>(args)...); | |
} else { | |
return fn(static_cast<Args&&>(args)...); | |
} | |
} | |
static ReturnType uninitCall(CallArg<Args>..., Data&) { | |
throw_exception<std::bad_function_call>(); | |
} | |
ReturnType operator()(Args... args) const { | |
auto& fn = *static_cast<const Function<ConstSignature>*>(this); | |
return fn.call_(static_cast<Args&&>(args)..., fn.data_); | |
} | |
using SharedProxy = | |
FunctionTraitsSharedProxy<ConstSignature, ReturnType, Args...>; | |
}; | |
template <typename ReturnType, typename... Args> | |
struct FunctionTraits<ReturnType(Args...) noexcept> { | |
using Call = ReturnType (*)(CallArg<Args>..., Data&) noexcept; | |
using IsConst = std::false_type; | |
using ConstSignature = ReturnType(Args...) const noexcept; | |
using NonConstSignature = ReturnType(Args...) noexcept; | |
using OtherSignature = ConstSignature; | |
template <typename F> | |
using ResultOf = | |
SafeResultOf<CallableResult<std::decay_t<F>&, Args...>, ReturnType>; | |
template <typename Fun> | |
static ReturnType callSmall(CallArg<Args>... args, Data& p) noexcept { | |
auto& fn = *static_cast<Fun*>(static_cast<void*>(&p.tiny)); | |
if constexpr (std::is_void<ReturnType>::value) { | |
fn(static_cast<Args&&>(args)...); | |
} else { | |
return fn(static_cast<Args&&>(args)...); | |
} | |
} | |
template <typename Fun> | |
static ReturnType callBig(CallArg<Args>... args, Data& p) noexcept { | |
auto& fn = *static_cast<Fun*>(p.big); | |
if constexpr (std::is_void<ReturnType>::value) { | |
fn(static_cast<Args&&>(args)...); | |
} else { | |
return fn(static_cast<Args&&>(args)...); | |
} | |
} | |
static ReturnType uninitCall(CallArg<Args>..., Data&) noexcept { | |
terminate_with<std::bad_function_call>(); | |
} | |
ReturnType operator()(Args... args) noexcept { | |
auto& fn = *static_cast<Function<NonConstSignature>*>(this); | |
return fn.call_(static_cast<Args&&>(args)..., fn.data_); | |
} | |
using SharedProxy = | |
FunctionTraitsSharedProxy<NonConstSignature, ReturnType, Args...>; | |
}; | |
template <typename ReturnType, typename... Args> | |
struct FunctionTraits<ReturnType(Args...) const noexcept> { | |
using Call = ReturnType (*)(CallArg<Args>..., Data&) noexcept; | |
using IsConst = std::true_type; | |
using ConstSignature = ReturnType(Args...) const noexcept; | |
using NonConstSignature = ReturnType(Args...) noexcept; | |
using OtherSignature = NonConstSignature; | |
template <typename F> | |
using ResultOf = | |
SafeResultOf<CallableResult<const std::decay_t<F>&, Args...>, | |
ReturnType>; | |
template <typename Fun> | |
static ReturnType callSmall(CallArg<Args>... args, Data& p) noexcept { | |
auto& fn = *static_cast<const Fun*>(static_cast<void*>(&p.tiny)); | |
if constexpr (std::is_void<ReturnType>::value) { | |
fn(static_cast<Args&&>(args)...); | |
} else { | |
return fn(static_cast<Args&&>(args)...); | |
} | |
} | |
template <typename Fun> | |
static ReturnType callBig(CallArg<Args>... args, Data& p) noexcept { | |
auto& fn = *static_cast<const Fun*>(p.big); | |
if constexpr (std::is_void<ReturnType>::value) { | |
fn(static_cast<Args&&>(args)...); | |
} else { | |
return fn(static_cast<Args&&>(args)...); | |
} | |
} | |
static ReturnType uninitCall(CallArg<Args>..., Data&) noexcept { | |
throw_exception<std::bad_function_call>(); | |
} | |
ReturnType operator()(Args... args) const noexcept { | |
auto& fn = *static_cast<const Function<ConstSignature>*>(this); | |
return fn.call_(static_cast<Args&&>(args)..., fn.data_); | |
} | |
using SharedProxy = | |
FunctionTraitsSharedProxy<ConstSignature, ReturnType, Args...>; | |
}; | |
template <typename Fun> | |
std::size_t execSmall(Op o, Data* src, Data* dst) { | |
switch (o) { | |
case Op::MOVE: | |
::new (static_cast<void*>(&dst->tiny)) Fun( | |
std::move(*static_cast<Fun*>(static_cast<void*>(&src->tiny)))); | |
[[fallthrough]]; | |
case Op::NUKE: | |
static_cast<Fun*>(static_cast<void*>(&src->tiny))->~Fun(); | |
break; | |
case Op::HEAP: | |
break; | |
} | |
return 0U; | |
} | |
template <typename Fun> | |
std::size_t execBig(Op o, Data* src, Data* dst) { | |
switch (o) { | |
case Op::MOVE: | |
dst->big = src->big; | |
src->big = nullptr; | |
break; | |
case Op::NUKE: | |
delete static_cast<Fun*>(src->big); | |
break; | |
case Op::HEAP: | |
break; | |
} | |
return sizeof(Fun); | |
} | |
} // namespace function | |
} // namespace detail | |
template <typename FunctionType> | |
class Function final : private detail::function::FunctionTraits<FunctionType> { | |
using Data = detail::function::Data; | |
using Op = detail::function::Op; | |
using SmallTag = detail::function::SmallTag; | |
using HeapTag = detail::function::HeapTag; | |
using CoerceTag = detail::function::CoerceTag; | |
using Traits = detail::function::FunctionTraits<FunctionType>; | |
using Call = typename Traits::Call; | |
using Exec = std::size_t (*)(Op, Data*, Data*); | |
template <typename Fun> | |
using IsSmall = detail::function::IsSmall<Fun>; | |
mutable Data data_{}; | |
Call call_{&Traits::uninitCall}; | |
Exec exec_{nullptr}; | |
std::size_t exec(Op o, Data* src, Data* dst) const { | |
if (!exec_) { | |
return 0U; | |
} | |
return exec_(o, src, dst); | |
} | |
friend Traits; | |
friend Function<typename Traits::ConstSignature> folly::constCastFunction<>( | |
Function<typename Traits::NonConstSignature>&&) noexcept; | |
friend class Function<typename Traits::OtherSignature>; | |
template <typename Fun> | |
Function(Fun&& fun, SmallTag) noexcept { | |
using FunT = typename std::decay<Fun>::type; | |
if (!detail::function::isEmptyFunction(fun)) { | |
::new (static_cast<void*>(&data_.tiny)) | |
FunT(static_cast<Fun&&>(fun)); | |
call_ = &Traits::template callSmall<FunT>; | |
exec_ = &detail::function::execSmall<FunT>; | |
} | |
} | |
template <typename Fun> | |
Function(Fun&& fun, HeapTag) { | |
using FunT = typename std::decay<Fun>::type; | |
if (!detail::function::isEmptyFunction(fun)) { | |
data_.big = new FunT(static_cast<Fun&&>(fun)); | |
call_ = &Traits::template callBig<FunT>; | |
exec_ = &detail::function::execBig<FunT>; | |
} | |
} | |
template <typename Signature> | |
Function(Function<Signature>&& that, CoerceTag) | |
: Function(static_cast<Function<Signature>&&>(that), HeapTag{}) { | |
} | |
Function(Function<typename Traits::OtherSignature>&& that, | |
CoerceTag) noexcept | |
: call_(that.call_), exec_(that.exec_) { | |
that.call_ = &Traits::uninitCall; | |
that.exec_ = nullptr; | |
exec(Op::MOVE, &that.data_, &data_); | |
} | |
public: | |
Function() = default; | |
Function(const Function&) = delete; | |
// # 708 "tlm/deps/folly.exploded/include/folly/Function.h" 3 4 | |
Function(Function&& that) noexcept : call_(that.call_), exec_(that.exec_) { | |
that.call_ = &Traits::uninitCall; | |
that.exec_ = nullptr; | |
exec(Op::MOVE, &that.data_, &data_); | |
} | |
Function(std::nullptr_t) noexcept { | |
} | |
// # 740 "tlm/deps/folly.exploded/include/folly/Function.h" 3 4 | |
template <typename Fun, | |
typename = detail::function::EnableIfNotFunction<Fun>, | |
typename = typename Traits::template ResultOf<Fun>> | |
Function(Fun fun) noexcept( | |
IsSmall<Fun>::value&& noexcept(Fun(std::declval<Fun>()))) | |
: Function(std::move(fun), IsSmall<Fun>{}) { | |
} | |
// # 757 "tlm/deps/folly.exploded/include/folly/Function.h" 3 4 | |
template < | |
typename Signature, | |
typename = typename Traits::template ResultOf<Function<Signature>>> | |
Function(Function<Signature>&& that) noexcept( | |
noexcept(Function(std::move(that), CoerceTag{}))) | |
: Function(std::move(that), CoerceTag{}) { | |
} | |
template <typename Member, | |
typename Class, | |
typename = decltype(Function(std::mem_fn((Member Class::*)0)))> | |
Function(Member Class::*ptr) noexcept { | |
if (ptr) { | |
*this = std::mem_fn(ptr); | |
} | |
} | |
~Function() { | |
exec(Op::NUKE, &data_, nullptr); | |
} | |
Function& operator=(const Function&) = delete; | |
// # 802 "tlm/deps/folly.exploded/include/folly/Function.h" 3 4 | |
Function& operator=(Function&& that) noexcept { | |
// # 813 "tlm/deps/folly.exploded/include/folly/Function.h" 3 4 | |
this->~Function(); | |
::new (this) Function(std::move(that)); | |
return *this; | |
} | |
// # 826 "tlm/deps/folly.exploded/include/folly/Function.h" 3 4 | |
template <typename Fun, typename = decltype(Function(std::declval<Fun>()))> | |
Function& operator=(Fun fun) noexcept( | |
noexcept(Function(std::declval<Fun>()))) { | |
if (noexcept(Function(std::declval<Fun>()))) { | |
this->~Function(); | |
::new (this) Function(std::move(fun)); | |
} else { | |
Function(std::move(fun)).swap(*this); | |
} | |
return *this; | |
} | |
template < | |
typename Signature, | |
typename = typename Traits::template ResultOf<Function<Signature>>> | |
Function& operator=(Function<Signature>&& that) noexcept( | |
noexcept(Function(std::move(that)))) { | |
return (*this = Function(std::move(that))); | |
} | |
Function& operator=(std::nullptr_t) noexcept { | |
return (*this = Function()); | |
} | |
template <typename Member, typename Class> | |
auto operator=(Member Class::*ptr) noexcept | |
-> decltype(operator=(std::mem_fn(ptr))) { | |
return ptr ? (*this = std::mem_fn(ptr)) : (*this = Function()); | |
} | |
using Traits::operator(); | |
void swap(Function& that) noexcept { | |
std::swap(*this, that); | |
} | |
explicit operator bool() const noexcept { | |
return exec_ != nullptr; | |
} | |
std::size_t heapAllocatedMemory() const noexcept { | |
return exec(Op::HEAP, nullptr, nullptr); | |
} | |
using typename Traits::SharedProxy; | |
SharedProxy asSharedProxy() && { | |
return SharedProxy{std::move(*this)}; | |
} | |
std::function<typename Traits::NonConstSignature> asStdFunction() && { | |
return std::move(*this).asSharedProxy(); | |
} | |
}; | |
template <typename FunctionType> | |
void swap(Function<FunctionType>& lhs, Function<FunctionType>& rhs) noexcept { | |
lhs.swap(rhs); | |
} | |
template <typename FunctionType> | |
bool operator==(const Function<FunctionType>& fn, std::nullptr_t) { | |
return !fn; | |
} | |
template <typename FunctionType> | |
bool operator==(std::nullptr_t, const Function<FunctionType>& fn) { | |
return !fn; | |
} | |
template <typename FunctionType> | |
bool operator!=(const Function<FunctionType>& fn, std::nullptr_t) { | |
return !(fn == nullptr); | |
} | |
template <typename FunctionType> | |
bool operator!=(std::nullptr_t, const Function<FunctionType>& fn) { | |
return !(nullptr == fn); | |
} | |
template <typename ReturnType, typename... Args> | |
Function<ReturnType(Args...) const> constCastFunction( | |
Function<ReturnType(Args...)>&& that) noexcept { | |
return Function<ReturnType(Args...) const>{std::move(that), | |
detail::function::CoerceTag{}}; | |
} | |
template <typename ReturnType, typename... Args> | |
Function<ReturnType(Args...) const> constCastFunction( | |
Function<ReturnType(Args...) const>&& that) noexcept { | |
return std::move(that); | |
} | |
template <typename ReturnType, typename... Args> | |
Function<ReturnType(Args...) const noexcept> constCastFunction( | |
Function<ReturnType(Args...) noexcept>&& that) noexcept { | |
return Function<ReturnType(Args...) const noexcept>{ | |
std::move(that), detail::function::CoerceTag{}}; | |
} | |
template <typename ReturnType, typename... Args> | |
Function<ReturnType(Args...) const noexcept> constCastFunction( | |
Function<ReturnType(Args...) const noexcept>&& that) noexcept { | |
return std::move(that); | |
} | |
// # 998 "tlm/deps/folly.exploded/include/folly/Function.h" 3 4 | |
template <typename FunctionType> | |
class FunctionRef; | |
template <typename ReturnType, typename... Args> | |
class FunctionRef<ReturnType(Args...)> final { | |
template <typename Arg> | |
using CallArg = detail::function::CallArg<Arg>; | |
using Call = ReturnType (*)(CallArg<Args>..., void*); | |
static ReturnType uninitCall(CallArg<Args>..., void*) { | |
throw_exception<std::bad_function_call>(); | |
} | |
template <typename Fun> | |
static ReturnType call(CallArg<Args>... args, void* object) { | |
using Pointer = std::add_pointer_t<Fun>; | |
return static_cast<ReturnType>( | |
invoke(static_cast<Fun&&>(*static_cast<Pointer>(object)), | |
static_cast<Args&&>(args)...)); | |
} | |
void* object_{nullptr}; | |
Call call_{&FunctionRef::uninitCall}; | |
public: | |
constexpr FunctionRef() = default; | |
constexpr explicit FunctionRef(std::nullptr_t) noexcept { | |
} | |
template < | |
typename Fun, | |
typename std::enable_if< | |
Conjunction<Negation<std::is_same<FunctionRef, | |
std::decay_t<Fun>>>, | |
is_invocable_r<ReturnType, Fun&&, Args&&...>>:: | |
value, | |
int>::type = 0> | |
constexpr FunctionRef(Fun&& fun) noexcept | |
: object_(const_cast<void*>( | |
static_cast<void const*>(std::addressof(fun)))), | |
call_(&FunctionRef::template call<Fun>) { | |
} | |
ReturnType operator()(Args... args) const { | |
return call_(static_cast<Args&&>(args)..., object_); | |
} | |
constexpr explicit operator bool() const noexcept { | |
return object_; | |
} | |
constexpr friend bool operator==(FunctionRef<ReturnType(Args...)> ref, | |
std::nullptr_t) noexcept { | |
return ref.object_ == nullptr; | |
} | |
constexpr friend bool operator!=(FunctionRef<ReturnType(Args...)> ref, | |
std::nullptr_t) noexcept { | |
return ref.object_ != nullptr; | |
} | |
constexpr friend bool operator==( | |
std::nullptr_t, FunctionRef<ReturnType(Args...)> ref) noexcept { | |
return ref.object_ == nullptr; | |
} | |
constexpr friend bool operator!=( | |
std::nullptr_t, FunctionRef<ReturnType(Args...)> ref) noexcept { | |
return ref.object_ != nullptr; | |
} | |
}; | |
} // namespace folly | |
// # 32 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/container/Foreach.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/container/Foreach.h" 3 4 | |
namespace folly { | |
// # 85 "tlm/deps/folly.exploded/include/folly/container/Foreach.h" 3 4 | |
template <typename Range, typename Func> | |
constexpr Func for_each(Range&& range, Func func); | |
namespace for_each_detail { | |
enum class LoopControl : bool { BREAK, CONTINUE }; | |
} | |
constexpr auto loop_break = for_each_detail::LoopControl::BREAK; | |
constexpr auto loop_continue = for_each_detail::LoopControl::CONTINUE; | |
// # 121 "tlm/deps/folly.exploded/include/folly/container/Foreach.h" 3 4 | |
template <typename Sequence, typename Index> | |
constexpr decltype(auto) fetch(Sequence&& sequence, Index&& index); | |
} // namespace folly | |
// # 162 "tlm/deps/folly.exploded/include/folly/container/Foreach.h" 3 4 | |
namespace folly { | |
namespace detail { | |
// # 177 "tlm/deps/folly.exploded/include/folly/container/Foreach.h" 3 4 | |
template <class T, class U> | |
typename std::enable_if< | |
(std::is_arithmetic<T>::value && std::is_arithmetic<U>::value) || | |
(std::is_pointer<T>::value && std::is_pointer<U>::value), | |
bool>::type | |
notThereYet(T& iter, const U& end) { | |
return iter < end; | |
} | |
template <class T, class U> | |
typename std::enable_if< | |
!((std::is_arithmetic<T>::value && std::is_arithmetic<U>::value) || | |
(std::is_pointer<T>::value && std::is_pointer<U>::value)), | |
bool>::type | |
notThereYet(T& iter, const U& end) { | |
return iter != end; | |
} | |
} // namespace detail | |
} // namespace folly | |
// # 209 "tlm/deps/folly.exploded/include/folly/container/Foreach.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/container/Foreach-inl.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/container/Foreach-inl.h" 3 4 | |
// # 18 "tlm/deps/folly.exploded/include/folly/container/Foreach-inl.h" 2 3 4 | |
// # 30 "tlm/deps/folly.exploded/include/folly/container/Foreach-inl.h" 3 4 | |
namespace folly { | |
namespace for_each_detail { | |
namespace adl { | |
using std::begin; | |
using std::end; | |
using std::get; | |
template <std::size_t Index, typename Type> | |
auto adl_get(Type&& instance) -> decltype(get<Index>(std::declval<Type>())) { | |
return get<Index>(std::forward<Type>(instance)); | |
} | |
template <typename Type> | |
auto adl_begin(Type&& instance) -> decltype(begin(instance)) { | |
return begin(instance); | |
} | |
template <typename Type> | |
auto adl_end(Type&& instance) -> decltype(end(instance)) { | |
return end(instance); | |
} | |
} // namespace adl | |
template <typename T> | |
using EnableIfMemberGetFound = | |
void_t<decltype(std::declval<T>().template get<0>())>; | |
template <typename, typename T> | |
struct IsMemberGetFound : std::false_type {}; | |
template <typename T> | |
struct IsMemberGetFound<EnableIfMemberGetFound<T>, T> : std::true_type {}; | |
template <std::size_t Index, | |
typename Type, | |
std::enable_if_t<!IsMemberGetFound<void, Type>::value, int> = 0> | |
auto get_impl(Type&& instance) | |
-> decltype(adl::adl_get<Index>(static_cast<Type&&>(instance))) { | |
return adl::adl_get<Index>(static_cast<Type&&>(instance)); | |
} | |
template <std::size_t Index, | |
typename Type, | |
std::enable_if_t<IsMemberGetFound<void, Type>::value, int> = 0> | |
auto get_impl(Type&& instance) | |
-> decltype(static_cast<Type&&>(instance).template get<Index>()) { | |
return static_cast<Type&&>(instance).template get<Index>(); | |
} | |
template <typename Type, typename T = typename std::decay<Type>::type> | |
using EnableIfTuple = void_t<decltype(get_impl<0>(std::declval<T>())), | |
decltype(std::tuple_size<T>::value)>; | |
template <typename, typename T> | |
struct IsTuple : std::false_type {}; | |
template <typename T> | |
struct IsTuple<EnableIfTuple<T>, T> : std::true_type {}; | |
template <typename Type, typename T = typename std::decay<Type>::type> | |
using EnableIfRange = void_t<decltype(adl::adl_begin(std::declval<T>())), | |
decltype(adl::adl_end(std::declval<T>()))>; | |
template <typename, typename T> | |
struct IsRange : std::false_type {}; | |
template <typename T> | |
struct IsRange<EnableIfRange<T>, T> : std::true_type {}; | |
struct TupleTag {}; | |
struct RangeTag {}; | |
template <typename Sequence> | |
using SequenceTag = | |
std::conditional_t<IsRange<void, Sequence>::value, RangeTag, TupleTag>; | |
struct BeginAddTag {}; | |
struct IndexingTag {}; | |
template <typename Func, typename Item, typename Iter> | |
using ForEachImplTag = std::conditional_t< | |
is_invocable_v<Func, Item, index_constant<0>, Iter>, | |
index_constant<3>, | |
std::conditional_t<is_invocable_v<Func, Item, index_constant<0>>, | |
index_constant<2>, | |
std::conditional_t<is_invocable_v<Func, Item>, | |
index_constant<1>, | |
void>>>; | |
template < | |
typename Func, | |
typename... Args, | |
std::enable_if_t<is_invocable_r_v<LoopControl, Func, Args...>, int> = 0> | |
LoopControl invoke_returning_loop_control(Func&& f, Args&&... a) { | |
return static_cast<Func&&>(f)(static_cast<Args&&>(a)...); | |
} | |
template <typename Func, | |
typename... Args, | |
std::enable_if_t<!is_invocable_r_v<LoopControl, Func, Args...>, int> = | |
0> | |
LoopControl invoke_returning_loop_control(Func&& f, Args&&... a) { | |
static_assert(std::is_void<invoke_result_t<Func, Args...>>::value, | |
"return either LoopControl or void"); | |
return static_cast<Func&&>(f)(static_cast<Args&&>(a)...), loop_continue; | |
} | |
template <typename Sequence, typename Func> | |
void for_each_range_impl(index_constant<3>, Sequence&& range, Func& func) { | |
auto first = adl::adl_begin(range); | |
auto last = adl::adl_end(range); | |
for (auto index = std::size_t{0}; first != last; ++index) { | |
auto next = std::next(first); | |
auto control = | |
invoke_returning_loop_control(func, *first, index, first); | |
if (loop_break == control) { | |
break; | |
} | |
first = next; | |
} | |
} | |
template <typename Sequence, typename Func> | |
void for_each_range_impl(index_constant<2>, Sequence&& range, Func& func) { | |
auto three_arg_adaptor = | |
[&func](auto&& ele, auto index, auto) -> decltype(auto) { | |
return func(std::forward<decltype(ele)>(ele), index); | |
}; | |
for_each_range_impl(index_constant<3>{}, | |
std::forward<Sequence>(range), | |
three_arg_adaptor); | |
} | |
template <typename Sequence, typename Func> | |
void for_each_range_impl(index_constant<1>, Sequence&& range, Func& func) { | |
auto three_arg_adaptor = [&func](auto&& ele, auto, auto) -> decltype(auto) { | |
return func(std::forward<decltype(ele)>(ele)); | |
}; | |
for_each_range_impl(index_constant<3>{}, | |
std::forward<Sequence>(range), | |
three_arg_adaptor); | |
} | |
template <typename Sequence, typename Func, std::size_t... Indices> | |
void for_each_tuple_impl(std::index_sequence<Indices...>, | |
Sequence&& seq, | |
Func& func) { | |
using _ = int[]; | |
auto control = loop_continue; | |
void(_{(((control == loop_continue) | |
? (control = invoke_returning_loop_control( | |
func, | |
get_impl<Indices>(std::forward<Sequence>(seq)), | |
index_constant<Indices>{})) | |
: (loop_continue)), | |
0)...}); | |
} | |
// # 241 "tlm/deps/folly.exploded/include/folly/container/Foreach-inl.h" 3 4 | |
template <typename Sequence, typename Func> | |
void for_each_tuple_impl(index_constant<2>, Sequence&& seq, Func& func) { | |
using size = std::tuple_size<typename std::decay<Sequence>::type>; | |
for_each_tuple_impl(std::make_index_sequence<size::value>{}, | |
std::forward<Sequence>(seq), | |
func); | |
} | |
template <typename Sequence, typename Func> | |
void for_each_tuple_impl(index_constant<1>, Sequence&& seq, Func& func) { | |
auto two_arg_adaptor = [&func](auto&& ele, auto) -> decltype(auto) { | |
return func(std::forward<decltype(ele)>(ele)); | |
}; | |
for_each_tuple_impl( | |
index_constant<2>{}, std::forward<Sequence>(seq), two_arg_adaptor); | |
} | |
// # 269 "tlm/deps/folly.exploded/include/folly/container/Foreach-inl.h" 3 4 | |
template <typename Sequence, typename Func> | |
void for_each_impl(TupleTag, Sequence&& range, Func& func) { | |
using type = decltype(get_impl<0>(std::declval<Sequence>())); | |
using tag = ForEachImplTag<Func, type, void>; | |
static_assert(!std::is_same<tag, void>::value, "unknown invocability"); | |
for_each_tuple_impl(tag{}, std::forward<Sequence>(range), func); | |
} | |
template <typename Sequence, typename Func> | |
void for_each_impl(RangeTag, Sequence&& range, Func& func) { | |
using iter = decltype(adl::adl_begin(std::declval<Sequence>())); | |
using type = decltype(*std::declval<iter>()); | |
using tag = ForEachImplTag<Func, type, iter>; | |
static_assert(!std::is_same<tag, void>::value, "unknown invocability"); | |
for_each_range_impl(tag{}, std::forward<Sequence>(range), func); | |
} | |
template <typename Sequence, typename Index> | |
decltype(auto) fetch_impl(IndexingTag, Sequence&& sequence, Index&& index) { | |
return std::forward<Sequence>(sequence)[std::forward<Index>(index)]; | |
} | |
template <typename Sequence, typename Index> | |
decltype(auto) fetch_impl(BeginAddTag, Sequence&& sequence, Index index) { | |
return *(adl::adl_begin(std::forward<Sequence>(sequence)) + index); | |
} | |
template <typename Sequence, typename Index> | |
decltype(auto) fetch_impl(TupleTag, Sequence&& sequence, Index index) { | |
return get_impl<index>(std::forward<Sequence>(sequence)); | |
} | |
template <typename Sequence, typename Index> | |
decltype(auto) fetch_impl(RangeTag, Sequence&& sequence, Index&& index) { | |
using iter = decltype(adl::adl_begin(std::declval<Sequence>())); | |
using iter_traits = std::iterator_traits<remove_cvref_t<iter>>; | |
using iter_cat = typename iter_traits::iterator_category; | |
using tag = std::conditional_t< | |
std::is_same<iter_cat, std::random_access_iterator_tag>::value, | |
BeginAddTag, | |
IndexingTag>; | |
return fetch_impl(tag{}, | |
std::forward<Sequence>(sequence), | |
std::forward<Index>(index)); | |
} | |
} // namespace for_each_detail | |
template <typename Sequence, typename Func> | |
constexpr Func for_each(Sequence&& sequence, Func func) { | |
namespace fed = for_each_detail; | |
using tag = fed::SequenceTag<Sequence>; | |
fed::for_each_impl(tag{}, std::forward<Sequence>(sequence), func); | |
return func; | |
} | |
template <typename Sequence, typename Index> | |
constexpr decltype(auto) fetch(Sequence&& sequence, Index&& index) { | |
namespace fed = for_each_detail; | |
using tag = fed::SequenceTag<Sequence>; | |
return for_each_detail::fetch_impl(tag{}, | |
std::forward<Sequence>(sequence), | |
std::forward<Index>(index)); | |
} | |
} // namespace folly | |
// # 210 "tlm/deps/folly.exploded/include/folly/container/Foreach.h" 2 3 4 | |
// # 36 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/detail/AtFork.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/detail/AtFork.h" 3 4 | |
namespace folly { | |
namespace detail { | |
struct AtFork { | |
static void init(); | |
static void registerHandler(void const* handle, | |
folly::Function<bool()> prepare, | |
folly::Function<void()> parent, | |
folly::Function<void()> child); | |
static void unregisterHandler(void const* handle); | |
}; | |
} // namespace detail | |
} // namespace folly | |
// # 37 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/synchronization/MicroSpinLock.h" 1 | |
// 3 4 # 33 | |
// "tlm/deps/folly.exploded/include/folly/synchronization/MicroSpinLock.h" 3 4 | |
// # 42 "tlm/deps/folly.exploded/include/folly/synchronization/MicroSpinLock.h" | |
// 3 4 # 43 | |
// "tlm/deps/folly.exploded/include/folly/synchronization/MicroSpinLock.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/synchronization/detail/Sleeper.h" | |
// 1 3 4 # 17 | |
// "tlm/deps/folly.exploded/include/folly/synchronization/detail/Sleeper.h" 3 4 | |
// # 29 "tlm/deps/folly.exploded/include/folly/synchronization/detail/Sleeper.h" | |
// 3 4 | |
namespace folly { | |
namespace detail { | |
class Sleeper { | |
static const uint32_t kMaxActiveSpin = 4000; | |
uint32_t spinCount; | |
public: | |
Sleeper() noexcept : spinCount(0) { | |
} | |
static void sleep() noexcept { | |
struct timespec ts = {0, 500000}; | |
nanosleep(&ts, nullptr); | |
} | |
void wait() noexcept { | |
if (spinCount < kMaxActiveSpin) { | |
++spinCount; | |
asm_volatile_pause(); | |
} else { | |
sleep(); | |
} | |
} | |
}; | |
} // namespace detail | |
} // namespace folly | |
// # 51 "tlm/deps/folly.exploded/include/folly/synchronization/MicroSpinLock.h" | |
// 2 3 4 | |
namespace folly { | |
// # 66 "tlm/deps/folly.exploded/include/folly/synchronization/MicroSpinLock.h" | |
// 3 4 | |
struct MicroSpinLock { | |
enum { FREE = 0, LOCKED = 1 }; | |
uint8_t lock_; | |
void init() noexcept { | |
payload()->store(FREE); | |
} | |
bool try_lock() noexcept { | |
bool ret = cas(FREE, LOCKED); | |
annotate_rwlock_try_acquired(this, | |
annotate_rwlock_level::wrlock, | |
ret, | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/MicroSpinLock.h", | |
80); | |
return ret; | |
} | |
void lock() noexcept { | |
detail::Sleeper sleeper; | |
while (!cas(FREE, LOCKED)) { | |
do { | |
sleeper.wait(); | |
} while (payload()->load(std::memory_order_relaxed) == LOCKED); | |
} | |
(static_cast<bool>(payload()->load() == LOCKED) | |
? void(0) | |
: __assert_fail("payload()->load() == LOCKED", | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/MicroSpinLock.h", | |
91, | |
__extension__ __PRETTY_FUNCTION__)); | |
annotate_rwlock_acquired(this, | |
annotate_rwlock_level::wrlock, | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/MicroSpinLock.h", | |
93); | |
} | |
void unlock() noexcept { | |
(static_cast<bool>(payload()->load() == LOCKED) | |
? void(0) | |
: __assert_fail("payload()->load() == LOCKED", | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/MicroSpinLock.h", | |
97, | |
__extension__ __PRETTY_FUNCTION__)); | |
annotate_rwlock_released(this, | |
annotate_rwlock_level::wrlock, | |
"tlm/deps/folly.exploded/include/folly/" | |
"synchronization/MicroSpinLock.h", | |
99); | |
payload()->store(FREE, std::memory_order_release); | |
} | |
private: | |
std::atomic<uint8_t>* payload() noexcept { | |
return reinterpret_cast<std::atomic<uint8_t>*>(&this->lock_); | |
} | |
bool cas(uint8_t compare, uint8_t newVal) noexcept { | |
return std::atomic_compare_exchange_strong_explicit( | |
payload(), | |
&compare, | |
newVal, | |
std::memory_order_acquire, | |
std::memory_order_relaxed); | |
} | |
}; | |
static_assert(std::is_pod<MicroSpinLock>::value, | |
"MicroSpinLock must be kept a POD type."); | |
// # 129 "tlm/deps/folly.exploded/include/folly/synchronization/MicroSpinLock.h" | |
// 3 4 | |
template <class T, size_t N> | |
struct alignas(max_align_v) SpinLockArray { | |
T& operator[](size_t i) noexcept { | |
return data_[i].lock; | |
} | |
const T& operator[](size_t i) const noexcept { | |
return data_[i].lock; | |
} | |
constexpr size_t size() const noexcept { | |
return N; | |
} | |
private: | |
struct PaddedSpinLock { | |
PaddedSpinLock() : lock() { | |
} | |
T lock; | |
char padding[hardware_destructive_interference_size - sizeof(T)]; | |
}; | |
static_assert(sizeof(PaddedSpinLock) == | |
hardware_destructive_interference_size, | |
"Invalid size of PaddedSpinLock"); | |
static_assert(max_align_v > 0 && | |
hardware_destructive_interference_size % | |
max_align_v == | |
0 && | |
sizeof(T) <= max_align_v, | |
"T can cross cache line boundaries"); | |
char padding_[hardware_destructive_interference_size]; | |
std::array<PaddedSpinLock, N> data_; | |
}; | |
typedef std::lock_guard<MicroSpinLock> MSLGuard; | |
} // namespace folly | |
// # 40 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/detail/StaticSingletonManager.h" 1 | |
// 3 4 # 17 | |
// "tlm/deps/folly.exploded/include/folly/detail/StaticSingletonManager.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/detail/Singleton.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/detail/Singleton.h" 3 4 | |
namespace folly { | |
namespace detail { | |
struct DefaultTag {}; | |
template <typename T> | |
struct DefaultMake { | |
struct Heap { | |
std::unique_ptr<T> ptr{std::make_unique<T>()}; | |
operator T&() { | |
return *ptr; | |
} | |
}; | |
using is_returnable = StrictDisjunction<bool_constant<201703L >= 201703ULL>, | |
std::is_copy_constructible<T>, | |
std::is_move_constructible<T>>; | |
using type = std::conditional_t<is_returnable::value, T, Heap>; | |
type operator()() const { | |
return type(); | |
} | |
}; | |
} // namespace detail | |
} // namespace folly | |
// # 26 "tlm/deps/folly.exploded/include/folly/detail/StaticSingletonManager.h" | |
// 2 3 4 # 1 "tlm/deps/folly.exploded/include/folly/lang/TypeInfo.h" 1 3 4 # 17 | |
// "tlm/deps/folly.exploded/include/folly/lang/TypeInfo.h" 3 4 | |
// # 33 "tlm/deps/folly.exploded/include/folly/lang/TypeInfo.h" 3 4 | |
namespace folly { | |
template <typename T> | |
inline __attribute__((__always_inline__)) static std::type_info const* | |
type_info_of() { | |
return (&typeid(T)); | |
} | |
template <typename T> | |
inline __attribute__((__always_inline__)) static std::type_info const* | |
type_info_of(T const& t) { | |
return (&typeid(t)); | |
} | |
} // namespace folly | |
// # 27 "tlm/deps/folly.exploded/include/folly/detail/StaticSingletonManager.h" | |
// 2 3 4 | |
namespace folly { | |
namespace detail { | |
class StaticSingletonManagerSansRtti { | |
public: | |
template <typename T, typename Tag> | |
__attribute__((__visibility__("default"))) inline | |
__attribute__((__always_inline__)) static T& | |
create() { | |
static std::atomic<T*> cache{}; | |
auto const pointer = cache.load(std::memory_order_acquire); | |
return (__builtin_expect((!!pointer), 1)) ? *pointer | |
: create_<T, Tag>(cache); | |
} | |
private: | |
template <typename T, typename Tag> | |
__attribute__((__visibility__("default"))) | |
__attribute__((__noinline__)) static T& | |
create_(std::atomic<T*>& cache) { | |
static Indestructible<T> instance; | |
cache.store(&*instance, std::memory_order_release); | |
return *instance; | |
} | |
}; | |
class StaticSingletonManagerWithRtti { | |
public: | |
template <typename T, typename Tag> | |
__attribute__((__visibility__("default"))) inline | |
__attribute__((__always_inline__)) static T& | |
create() { | |
static Arg arg{{nullptr}, (&typeid(tag_t<T, Tag>)), make<T>}; | |
auto const v = arg.cache.load(std::memory_order_acquire); | |
auto const p = | |
(__builtin_expect((!!v), 1)) ? v : create_<noexcept(T())>(arg); | |
return *static_cast<T*>(p); | |
} | |
private: | |
using Key = std::type_info; | |
using Make = void*(); | |
using Cache = std::atomic<void*>; | |
struct Arg { | |
Cache cache; | |
Key const* key; | |
Make& make; | |
}; | |
template <typename T> | |
static void* make() { | |
return new T(); | |
} | |
template <bool Noexcept> | |
inline __attribute__((__always_inline__)) | |
__attribute__((__visibility__("hidden"))) static void* | |
create_(Arg& arg) noexcept(Noexcept) { | |
return create_(arg); | |
} | |
__attribute__((__noinline__)) static void* create_(Arg& arg); | |
}; | |
using StaticSingletonManager = | |
std::conditional_t<kHasRtti, | |
StaticSingletonManagerWithRtti, | |
StaticSingletonManagerSansRtti>; | |
template <typename T, typename Tag> | |
inline __attribute__((__always_inline__)) | |
__attribute__((__visibility__("hidden"))) T& | |
createGlobal() { | |
return StaticSingletonManager::create<T, Tag>(); | |
} | |
} // namespace detail | |
} // namespace folly | |
// # 43 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 2 3 4 | |
// # 56 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 3 4 | |
namespace folly { | |
enum class TLPDestructionMode { THIS_THREAD, ALL_THREADS }; | |
struct AccessModeStrict {}; | |
namespace threadlocal_detail { | |
constexpr uint32_t kEntryIDInvalid = std::numeric_limits<uint32_t>::max(); | |
struct ThreadEntry; | |
// # 75 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 3 4 | |
struct ThreadEntryNode { | |
uint32_t id : 31; | |
bool isZero : 1; | |
ThreadEntry* parent; | |
ThreadEntry* prev; | |
ThreadEntry* next; | |
void initIfZero(bool locked); | |
void init(ThreadEntry* entry, uint32_t newId) { | |
id = newId; | |
isZero = false; | |
parent = prev = next = entry; | |
} | |
void initZero(ThreadEntry* entry, uint32_t newId) { | |
id = newId; | |
isZero = true; | |
parent = entry; | |
prev = next = nullptr; | |
} | |
inline __attribute__((__always_inline__)) bool empty() const { | |
return (next == parent); | |
} | |
inline __attribute__((__always_inline__)) bool zero() const { | |
return isZero; | |
} | |
inline __attribute__((__always_inline__)) ThreadEntry* getThreadEntry() { | |
return parent; | |
} | |
inline __attribute__((__always_inline__)) ThreadEntryNode* getPrev(); | |
inline __attribute__((__always_inline__)) ThreadEntryNode* getNext(); | |
void push_back(ThreadEntry* head); | |
void eraseZero(); | |
}; | |
struct ElementWrapper { | |
using DeleterFunType = void(void*, TLPDestructionMode); | |
bool dispose(TLPDestructionMode mode) { | |
if (ptr == nullptr) { | |
return false; | |
} | |
static_cast<void>(0), | |
!((__builtin_expect(!(deleter1 != nullptr), 0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/" | |
"folly/detail/ThreadLocalDetail.h", | |
131) | |
.stream() | |
<< "Check failed: " | |
"deleter1 != nullptr" | |
" "; | |
ownsDeleter ? (*deleter2)(ptr, mode) : (*deleter1)(ptr, mode); | |
return true; | |
} | |
void* release() { | |
auto retPtr = ptr; | |
if (ptr != nullptr) { | |
cleanup(); | |
} | |
return retPtr; | |
} | |
template <class Ptr> | |
void set(Ptr p) { | |
auto guard = makeGuard([&] { delete p; }); | |
static_cast<void>(0), | |
!((__builtin_expect(!(ptr == nullptr), 0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/" | |
"folly/detail/ThreadLocalDetail.h", | |
149) | |
.stream() | |
<< "Check failed: " | |
"ptr == nullptr" | |
" "; | |
static_cast<void>(0), | |
!((__builtin_expect(!(deleter1 == nullptr), 0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/" | |
"folly/detail/ThreadLocalDetail.h", | |
150) | |
.stream() | |
<< "Check failed: " | |
"deleter1 == nullptr" | |
" "; | |
if (p) { | |
node.initIfZero(true); | |
ptr = p; | |
deleter1 = [](void* pt, TLPDestructionMode) { | |
delete static_cast<Ptr>(pt); | |
}; | |
ownsDeleter = false; | |
guard.dismiss(); | |
} | |
} | |
template <class Ptr, class Deleter> | |
void set(Ptr p, const Deleter& d) { | |
auto guard = makeGuard([&] { | |
if (p) { | |
d(p, TLPDestructionMode::THIS_THREAD); | |
} | |
}); | |
static_cast<void>(0), | |
!((__builtin_expect(!(ptr == nullptr), 0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/" | |
"folly/detail/ThreadLocalDetail.h", | |
170) | |
.stream() | |
<< "Check failed: " | |
"ptr == nullptr" | |
" "; | |
static_cast<void>(0), | |
!((__builtin_expect(!(deleter2 == nullptr), 0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/" | |
"folly/detail/ThreadLocalDetail.h", | |
171) | |
.stream() | |
<< "Check failed: " | |
"deleter2 == nullptr" | |
" "; | |
if (p) { | |
node.initIfZero(true); | |
ptr = p; | |
auto d2 = d; | |
deleter2 = new std::function<DeleterFunType>( | |
[d2](void* pt, TLPDestructionMode mode) { | |
d2(static_cast<Ptr>(pt), mode); | |
}); | |
ownsDeleter = true; | |
guard.dismiss(); | |
} | |
} | |
void cleanup() { | |
if (ownsDeleter) { | |
delete deleter2; | |
} | |
ptr = nullptr; | |
deleter1 = nullptr; | |
ownsDeleter = false; | |
} | |
void* ptr; | |
union { | |
DeleterFunType* deleter1; | |
std::function<DeleterFunType>* deleter2; | |
}; | |
bool ownsDeleter; | |
ThreadEntryNode node; | |
}; | |
struct StaticMetaBase; | |
struct ThreadEntryList; | |
// # 214 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 3 4 | |
struct ThreadEntry { | |
ElementWrapper* elements{nullptr}; | |
std::atomic<size_t> elementsCapacity{0}; | |
ThreadEntryList* list{nullptr}; | |
ThreadEntry* listNext{nullptr}; | |
StaticMetaBase* meta{nullptr}; | |
bool removed_{false}; | |
uint64_t tid_os{}; | |
aligned_storage_for_t<std::thread::id> tid_data{}; | |
size_t getElementsCapacity() const noexcept { | |
return elementsCapacity.load(std::memory_order_relaxed); | |
} | |
void setElementsCapacity(size_t capacity) noexcept { | |
elementsCapacity.store(capacity, std::memory_order_relaxed); | |
} | |
std::thread::id& tid() { | |
return *reinterpret_cast<std::thread::id*>(&tid_data); | |
} | |
}; | |
struct ThreadEntryList { | |
ThreadEntry* head{nullptr}; | |
size_t count{0}; | |
}; | |
struct PthreadKeyUnregisterTester; | |
inline __attribute__((__always_inline__)) ThreadEntryNode* | |
ThreadEntryNode::getPrev() { | |
return &prev->elements[id].node; | |
} | |
inline __attribute__((__always_inline__)) ThreadEntryNode* | |
ThreadEntryNode::getNext() { | |
return &next->elements[id].node; | |
} | |
// # 265 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 3 4 | |
class PthreadKeyUnregister { | |
public: | |
static constexpr size_t kMaxKeys = 1UL << 16; | |
~PthreadKeyUnregister() { | |
MSLGuard lg(lock_); | |
while (size_) { | |
pthread_key_delete(keys_[--size_]); | |
} | |
} | |
static void registerKey(pthread_key_t key) { | |
instance_.registerKeyImpl(key); | |
} | |
private: | |
constexpr PthreadKeyUnregister() : lock_(), size_(0), keys_() { | |
} | |
friend struct folly::threadlocal_detail::PthreadKeyUnregisterTester; | |
void registerKeyImpl(pthread_key_t key) { | |
MSLGuard lg(lock_); | |
if (size_ == kMaxKeys) { | |
throw std::logic_error( | |
"pthread_key limit has already been reached"); | |
} | |
keys_[size_++] = key; | |
} | |
MicroSpinLock lock_; | |
size_t size_; | |
pthread_key_t keys_[kMaxKeys]; | |
static PthreadKeyUnregister instance_; | |
}; | |
struct StaticMetaBase { | |
class EntryID { | |
public: | |
std::atomic<uint32_t> value; | |
constexpr EntryID() : value(kEntryIDInvalid) { | |
} | |
EntryID(EntryID&& other) noexcept : value(other.value.load()) { | |
other.value = kEntryIDInvalid; | |
} | |
EntryID& operator=(EntryID&& other) noexcept { | |
(static_cast<bool>(this != &other) | |
? void(0) | |
: __assert_fail("this != &other", | |
"tlm/deps/folly.exploded/include/folly/" | |
"detail/ThreadLocalDetail.h", | |
324, | |
__extension__ __PRETTY_FUNCTION__)); | |
value = other.value.load(); | |
other.value = kEntryIDInvalid; | |
return *this; | |
} | |
EntryID(const EntryID& other) = delete; | |
EntryID& operator=(const EntryID& other) = delete; | |
uint32_t getOrInvalid() { | |
return value.load(std::memory_order_acquire); | |
} | |
uint32_t getOrAllocate(StaticMetaBase& meta) { | |
uint32_t id = getOrInvalid(); | |
if (id != kEntryIDInvalid) { | |
return id; | |
} | |
return meta.allocate(this); | |
} | |
}; | |
StaticMetaBase(ThreadEntry* (*threadEntry)(), bool strict); | |
__attribute__((__visibility__("default"))) static ThreadEntryList* | |
getThreadEntryList(); | |
static bool dying(); | |
static void onThreadExit(void* ptr); | |
uint32_t elementsCapacity() const; | |
uint32_t allocate(EntryID* ent); | |
void destroy(EntryID* ent); | |
void reserve(EntryID* id); | |
ElementWrapper& getElement(EntryID* ent); | |
void reserveHeadUnlocked(uint32_t id); | |
void pushBackLocked(ThreadEntry* t, uint32_t id); | |
void pushBackUnlocked(ThreadEntry* t, uint32_t id); | |
static ElementWrapper* reallocate(ThreadEntry* threadEntry, | |
uint32_t idval, | |
size_t& newCapacity); | |
uint32_t nextId_; | |
std::vector<uint32_t> freeIds_; | |
std::mutex lock_; | |
SharedMutex accessAllThreadsLock_; | |
pthread_key_t pthreadKey_; | |
ThreadEntry head_; | |
ThreadEntry* (*threadEntry_)(); | |
bool strict_; | |
}; | |
// # 404 "tlm/deps/folly.exploded/include/folly/detail/ThreadLocalDetail.h" 3 4 | |
template <class Tag, class AccessMode> | |
struct StaticMeta final : StaticMetaBase { | |
StaticMeta() | |
: StaticMetaBase(&StaticMeta::getThreadEntrySlow, | |
std::is_same<AccessMode, AccessModeStrict>::value) { | |
detail::AtFork::registerHandler(this, | |
&StaticMeta::preFork, | |
&StaticMeta::onForkParent, | |
&StaticMeta::onForkChild); | |
} | |
static StaticMeta<Tag, AccessMode>& instance() { | |
return detail::createGlobal<StaticMeta<Tag, AccessMode>, void>(); | |
} | |
__attribute__((__visibility__("default"))) inline | |
__attribute__((__always_inline__)) static ElementWrapper& | |
get(EntryID* ent) { | |
uint32_t id = ent->getOrInvalid(); | |
static __thread ThreadEntry* threadEntry{}; | |
static __thread size_t capacity{}; | |
if ((__builtin_expect((capacity <= id), 0))) { | |
getSlowReserveAndCache(ent, id, threadEntry, capacity); | |
} | |
return threadEntry->elements[id]; | |
} | |
__attribute__((__noinline__)) static void getSlowReserveAndCache( | |
EntryID* ent, | |
uint32_t& id, | |
ThreadEntry*& threadEntry, | |
size_t& capacity) { | |
auto& inst = instance(); | |
threadEntry = inst.threadEntry_(); | |
if ((__builtin_expect((threadEntry->getElementsCapacity() <= id), 0))) { | |
inst.reserve(ent); | |
id = ent->getOrInvalid(); | |
} | |
capacity = threadEntry->getElementsCapacity(); | |
(static_cast<bool>(capacity > id) | |
? void(0) | |
: __assert_fail("capacity > id", | |
"tlm/deps/folly.exploded/include/folly/detail/" | |
"ThreadLocalDetail.h", | |
452, | |
__extension__ __PRETTY_FUNCTION__)); | |
} | |
__attribute__((__visibility__("default"))) | |
__attribute__((__noinline__)) static ThreadEntry* | |
getThreadEntrySlow() { | |
auto& meta = instance(); | |
auto key = meta.pthreadKey_; | |
ThreadEntry* threadEntry = | |
static_cast<ThreadEntry*>(pthread_getspecific(key)); | |
if (!threadEntry) { | |
ThreadEntryList* threadEntryList = StaticMeta::getThreadEntryList(); | |
static __thread ThreadEntry threadEntrySingleton; | |
threadEntry = &threadEntrySingleton; | |
if (!threadEntry->list) { | |
threadEntry->list = threadEntryList; | |
threadEntry->listNext = threadEntryList->head; | |
threadEntryList->head = threadEntry; | |
} | |
threadEntry->tid() = std::this_thread::get_id(); | |
threadEntry->tid_os = folly::getOSThreadID(); | |
threadEntryList->count++; | |
threadEntry->meta = &meta; | |
int ret = pthread_setspecific(key, threadEntry); | |
checkPosixError(ret, "pthread_setspecific failed"); | |
} | |
return threadEntry; | |
} | |
static bool preFork() { | |
return instance().lock_.try_lock(); | |
} | |
static void onForkParent() { | |
instance().lock_.unlock(); | |
} | |
static void onForkChild() { | |
auto& head = instance().head_; | |
auto elementsCapacity = head.getElementsCapacity(); | |
for (size_t i = 0u; i < elementsCapacity; ++i) { | |
head.elements[i].node.init(&head, static_cast<uint32_t>(i)); | |
} | |
ThreadEntry* threadEntry = instance().threadEntry_(); | |
elementsCapacity = threadEntry->getElementsCapacity(); | |
for (size_t i = 0u; i < elementsCapacity; ++i) { | |
if (!threadEntry->elements[i].node.zero()) { | |
threadEntry->elements[i].node.initZero( | |
threadEntry, static_cast<uint32_t>(i)); | |
threadEntry->elements[i].node.initIfZero(false); | |
} | |
} | |
instance().lock_.unlock(); | |
} | |
}; | |
} // namespace threadlocal_detail | |
} // namespace folly | |
// # 53 "tlm/deps/folly.exploded/include/folly/ThreadLocal.h" 2 3 4 | |
namespace folly { | |
template <class T, class Tag, class AccessMode> | |
class ThreadLocalPtr; | |
template <class T, class Tag = void, class AccessMode = void> | |
class ThreadLocal { | |
public: | |
constexpr ThreadLocal() : constructor_([]() { return new T(); }) { | |
} | |
template <typename F, std::enable_if_t<is_invocable_r_v<T*, F>, int> = 0> | |
explicit ThreadLocal(F&& constructor) | |
: constructor_(std::forward<F>(constructor)) { | |
} | |
inline __attribute__((__always_inline__)) | |
__attribute__((__visibility__("hidden"))) T* | |
get() const { | |
auto const ptr = tlp_.get(); | |
return (__builtin_expect((!!ptr), 1)) ? ptr : makeTlp(); | |
} | |
inline __attribute__((__always_inline__)) | |
__attribute__((__visibility__("hidden"))) T* | |
getIfExist() const { | |
return tlp_.get(); | |
} | |
T* operator->() const { | |
return get(); | |
} | |
T& operator*() const { | |
return *get(); | |
} | |
void reset(T* newPtr = nullptr) { | |
tlp_.reset(newPtr); | |
} | |
typedef typename ThreadLocalPtr<T, Tag, AccessMode>::Accessor Accessor; | |
Accessor accessAllThreads() const { | |
return tlp_.accessAllThreads(); | |
} | |
ThreadLocal(ThreadLocal&&) = default; | |
ThreadLocal& operator=(ThreadLocal&&) = default; | |
private: | |
ThreadLocal(const ThreadLocal&) = delete; | |
ThreadLocal& operator=(const ThreadLocal&) = delete; | |
__attribute__((__noinline__)) T* makeTlp() const { | |
auto const ptr = constructor_(); | |
tlp_.reset(ptr); | |
return ptr; | |
} | |
mutable ThreadLocalPtr<T, Tag, AccessMode> tlp_; | |
std::function<T*()> constructor_; | |
}; | |
// # 140 "tlm/deps/folly.exploded/include/folly/ThreadLocal.h" 3 4 | |
template <class T, class Tag = void, class AccessMode = void> | |
class ThreadLocalPtr { | |
private: | |
typedef threadlocal_detail::StaticMeta<Tag, AccessMode> StaticMeta; | |
using AccessAllThreadsEnabled = Negation<std::is_same<Tag, void>>; | |
public: | |
constexpr ThreadLocalPtr() : id_() { | |
} | |
ThreadLocalPtr(ThreadLocalPtr&& other) noexcept | |
: id_(std::move(other.id_)) { | |
} | |
ThreadLocalPtr& operator=(ThreadLocalPtr&& other) { | |
(static_cast<bool>(this != &other) | |
? void(0) | |
: __assert_fail("this != &other", | |
"tlm/deps/folly.exploded/include/folly/" | |
"ThreadLocal.h", | |
153, | |
__extension__ __PRETTY_FUNCTION__)); | |
destroy(); | |
id_ = std::move(other.id_); | |
return *this; | |
} | |
~ThreadLocalPtr() { | |
destroy(); | |
} | |
T* get() const { | |
threadlocal_detail::ElementWrapper& w = StaticMeta::get(&id_); | |
return static_cast<T*>(w.ptr); | |
} | |
T* operator->() const { | |
return get(); | |
} | |
T& operator*() const { | |
return *get(); | |
} | |
T* release() { | |
auto rlock = getAccessAllThreadsLockReadHolderIfEnabled(); | |
threadlocal_detail::ElementWrapper& w = StaticMeta::get(&id_); | |
return static_cast<T*>(w.release()); | |
} | |
void reset(T* newPtr = nullptr) { | |
auto rlock = getAccessAllThreadsLockReadHolderIfEnabled(); | |
auto guard = makeGuard([&] { delete newPtr; }); | |
threadlocal_detail::ElementWrapper* w = &StaticMeta::get(&id_); | |
w->dispose(TLPDestructionMode::THIS_THREAD); | |
w = &StaticMeta::get(&id_); | |
w->cleanup(); | |
guard.dismiss(); | |
w->set(newPtr); | |
} | |
explicit operator bool() const { | |
return get() != nullptr; | |
} | |
template <typename SourceT, | |
typename Deleter, | |
typename = typename std::enable_if< | |
std::is_convertible<SourceT*, T*>::value>::type> | |
void reset(std::unique_ptr<SourceT, Deleter> source) { | |
auto deleter = [delegate = source.get_deleter()]( | |
T* ptr, TLPDestructionMode) { delegate(ptr); }; | |
reset(source.release(), deleter); | |
} | |
template <typename SourceT, | |
typename = typename std::enable_if< | |
std::is_convertible<SourceT*, T*>::value>::type> | |
void reset(std::unique_ptr<SourceT> source) { | |
reset(source.release()); | |
} | |
// # 237 "tlm/deps/folly.exploded/include/folly/ThreadLocal.h" 3 4 | |
template <class Deleter> | |
void reset(T* newPtr, const Deleter& deleter) { | |
auto rlock = getAccessAllThreadsLockReadHolderIfEnabled(); | |
auto guard = makeGuard([&] { | |
if (newPtr) { | |
deleter(newPtr, TLPDestructionMode::THIS_THREAD); | |
} | |
}); | |
threadlocal_detail::ElementWrapper* w = &StaticMeta::get(&id_); | |
w->dispose(TLPDestructionMode::THIS_THREAD); | |
w = &StaticMeta::get(&id_); | |
w->cleanup(); | |
guard.dismiss(); | |
w->set(newPtr, deleter); | |
} | |
class Accessor { | |
friend class ThreadLocalPtr<T, Tag, AccessMode>; | |
threadlocal_detail::StaticMetaBase& meta_; | |
SharedMutex* accessAllThreadsLock_; | |
std::mutex* lock_; | |
uint32_t id_; | |
public: | |
class Iterator; | |
friend class Iterator; | |
class Iterator { | |
friend class Accessor; | |
const Accessor* accessor_; | |
threadlocal_detail::ThreadEntryNode* e_; | |
void increment() { | |
e_ = e_->getNext(); | |
incrementToValid(); | |
} | |
void decrement() { | |
e_ = e_->getPrev(); | |
decrementToValid(); | |
} | |
const T& dereference() const { | |
return *static_cast<T*>( | |
e_->getThreadEntry()->elements[accessor_->id_].ptr); | |
} | |
T& dereference() { | |
return *static_cast<T*>( | |
e_->getThreadEntry()->elements[accessor_->id_].ptr); | |
} | |
bool equal(const Iterator& other) const { | |
return (accessor_->id_ == other.accessor_->id_ && | |
e_ == other.e_); | |
} | |
explicit Iterator(const Accessor* accessor) | |
: accessor_(accessor), | |
e_(&accessor_->meta_.head_.elements[accessor_->id_].node) { | |
} | |
bool valid() const { | |
return (e_->getThreadEntry()->elements[accessor_->id_].ptr); | |
} | |
void incrementToValid() { | |
for (; e_ != &accessor_->meta_.head_.elements[accessor_->id_] | |
.node && | |
!valid(); | |
e_ = e_->getNext()) { | |
} | |
} | |
void decrementToValid() { | |
for (; e_ != &accessor_->meta_.head_.elements[accessor_->id_] | |
.node && | |
!valid(); | |
e_ = e_->getPrev()) { | |
} | |
} | |
public: | |
using difference_type = ssize_t; | |
using value_type = T; | |
using reference = T const&; | |
using pointer = T const*; | |
using iterator_category = std::bidirectional_iterator_tag; | |
Iterator& operator++() { | |
increment(); | |
return *this; | |
} | |
Iterator& operator++(int) { | |
Iterator copy(*this); | |
increment(); | |
return copy; | |
} | |
Iterator& operator--() { | |
decrement(); | |
return *this; | |
} | |
Iterator& operator--(int) { | |
Iterator copy(*this); | |
decrement(); | |
return copy; | |
} | |
T& operator*() { | |
return dereference(); | |
} | |
T const& operator*() const { | |
return dereference(); | |
} | |
T* operator->() { | |
return &dereference(); | |
} | |
T const* operator->() const { | |
return &dereference(); | |
} | |
bool operator==(Iterator const& rhs) const { | |
return equal(rhs); | |
} | |
bool operator!=(Iterator const& rhs) const { | |
return !equal(rhs); | |
} | |
std::thread::id getThreadId() const { | |
return e_->getThreadEntry()->tid(); | |
} | |
uint64_t getOSThreadId() const { | |
return e_->getThreadEntry()->tid_os; | |
} | |
}; | |
~Accessor() { | |
release(); | |
} | |
Iterator begin() const { | |
return ++Iterator(this); | |
} | |
Iterator end() const { | |
return Iterator(this); | |
} | |
Accessor(const Accessor&) = delete; | |
Accessor& operator=(const Accessor&) = delete; | |
Accessor(Accessor&& other) noexcept | |
: meta_(other.meta_), | |
accessAllThreadsLock_(other.accessAllThreadsLock_), | |
lock_(other.lock_), | |
id_(other.id_) { | |
other.id_ = 0; | |
other.accessAllThreadsLock_ = nullptr; | |
other.lock_ = nullptr; | |
} | |
Accessor& operator=(Accessor&& other) noexcept { | |
(static_cast<bool>(&meta_ == &other.meta_) | |
? void(0) | |
: __assert_fail("&meta_ == &other.meta_", | |
"tlm/deps/folly.exploded/include/folly/" | |
"ThreadLocal.h", | |
419, | |
__extension__ __PRETTY_FUNCTION__)); | |
(static_cast<bool>(lock_ == nullptr) | |
? void(0) | |
: __assert_fail("lock_ == nullptr", | |
"tlm/deps/folly.exploded/include/folly/" | |
"ThreadLocal.h", | |
420, | |
__extension__ __PRETTY_FUNCTION__)); | |
using std::swap; | |
swap(accessAllThreadsLock_, other.accessAllThreadsLock_); | |
swap(lock_, other.lock_); | |
swap(id_, other.id_); | |
} | |
Accessor() | |
: meta_(threadlocal_detail::StaticMeta<Tag, | |
AccessMode>::instance()), | |
accessAllThreadsLock_(nullptr), | |
lock_(nullptr), | |
id_(0) { | |
} | |
private: | |
explicit Accessor(uint32_t id) | |
: meta_(threadlocal_detail::StaticMeta<Tag, | |
AccessMode>::instance()), | |
accessAllThreadsLock_(&meta_.accessAllThreadsLock_), | |
lock_(&meta_.lock_) { | |
accessAllThreadsLock_->lock(); | |
lock_->lock(); | |
id_ = id; | |
} | |
void release() { | |
if (lock_) { | |
lock_->unlock(); | |
static_cast<void>(0), | |
!((__builtin_expect(!(accessAllThreadsLock_ != nullptr), | |
0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/" | |
"include/folly/ThreadLocal.h", | |
446) | |
.stream() | |
<< "Check failed: " | |
"accessAllThreadsLock_ != " | |
"nullptr" | |
" "; | |
accessAllThreadsLock_->unlock(); | |
id_ = 0; | |
lock_ = nullptr; | |
accessAllThreadsLock_ = nullptr; | |
} | |
} | |
}; | |
Accessor accessAllThreads() const { | |
static_assert( | |
AccessAllThreadsEnabled::value, | |
"Must use a unique Tag to use the accessAllThreads feature"); | |
return Accessor(id_.getOrAllocate(StaticMeta::instance())); | |
} | |
private: | |
void destroy() { | |
StaticMeta::instance().destroy(&id_); | |
} | |
ThreadLocalPtr(const ThreadLocalPtr&) = delete; | |
ThreadLocalPtr& operator=(const ThreadLocalPtr&) = delete; | |
static auto getAccessAllThreadsLockReadHolderIfEnabled() { | |
return SharedMutex::ReadHolder( | |
AccessAllThreadsEnabled::value | |
? &StaticMeta::instance().accessAllThreadsLock_ | |
: nullptr); | |
} | |
mutable typename StaticMeta::EntryID id_; | |
}; | |
namespace threadlocal_detail { | |
template <typename> | |
struct static_meta_of; | |
template <typename T, typename Tag, typename AccessMode> | |
struct static_meta_of<ThreadLocalPtr<T, Tag, AccessMode>> { | |
using type = StaticMeta<Tag, AccessMode>; | |
}; | |
template <typename T, typename Tag, typename AccessMode> | |
struct static_meta_of<ThreadLocal<T, Tag, AccessMode>> { | |
using type = StaticMeta<Tag, AccessMode>; | |
}; | |
} // namespace threadlocal_detail | |
} // namespace folly | |
// # 29 "tlm/deps/folly.exploded/include/folly/ThreadCachedInt.h" 2 3 4 | |
namespace folly { | |
template <class IntT, class Tag = IntT> | |
class ThreadCachedInt { | |
struct IntCache; | |
public: | |
explicit ThreadCachedInt(IntT initialVal = 0, uint32_t cacheSize = 1000) | |
: target_(initialVal), cacheSize_(cacheSize) { | |
} | |
ThreadCachedInt(const ThreadCachedInt&) = delete; | |
ThreadCachedInt& operator=(const ThreadCachedInt&) = delete; | |
void increment(IntT inc) { | |
auto cache = cache_.get(); | |
if ((__builtin_expect((cache == nullptr), 0))) { | |
cache = new IntCache(*this); | |
cache_.reset(cache); | |
} | |
cache->increment(inc); | |
} | |
IntT readFast() const { | |
return target_.load(std::memory_order_relaxed); | |
} | |
IntT readFull() const { | |
const auto accessor = cache_.accessAllThreads(); | |
IntT ret = readFast(); | |
for (const auto& cache : accessor) { | |
if (!cache.reset_.load(std::memory_order_acquire)) { | |
ret += cache.val_.load(std::memory_order_relaxed); | |
} | |
} | |
return ret; | |
} | |
IntT readFastAndReset() { | |
return target_.exchange(0, std::memory_order_release); | |
} | |
IntT readFullAndReset() { | |
auto accessor = cache_.accessAllThreads(); | |
IntT ret = readFastAndReset(); | |
for (auto& cache : accessor) { | |
if (!cache.reset_.load(std::memory_order_acquire)) { | |
ret += cache.val_.load(std::memory_order_relaxed); | |
cache.reset_.store(true, std::memory_order_release); | |
} | |
} | |
return ret; | |
} | |
void setCacheSize(uint32_t newSize) { | |
cacheSize_.store(newSize, std::memory_order_release); | |
} | |
uint32_t getCacheSize() const { | |
return cacheSize_.load(); | |
} | |
ThreadCachedInt& operator+=(IntT inc) { | |
increment(inc); | |
return *this; | |
} | |
ThreadCachedInt& operator-=(IntT inc) { | |
increment(-inc); | |
return *this; | |
} | |
ThreadCachedInt& operator++() { | |
increment(1); | |
return *this; | |
} | |
ThreadCachedInt& operator--() { | |
increment(IntT(-1)); | |
return *this; | |
} | |
void set(IntT newVal) { | |
for (auto& cache : cache_.accessAllThreads()) { | |
cache.reset_.store(true, std::memory_order_release); | |
} | |
target_.store(newVal, std::memory_order_release); | |
} | |
private: | |
std::atomic<IntT> target_; | |
std::atomic<uint32_t> cacheSize_; | |
ThreadLocalPtr<IntCache, Tag, AccessModeStrict> cache_; | |
struct IntCache { | |
ThreadCachedInt* parent_; | |
mutable std::atomic<IntT> val_; | |
mutable uint32_t numUpdates_; | |
std::atomic<bool> reset_; | |
explicit IntCache(ThreadCachedInt& parent) | |
: parent_(&parent), val_(0), numUpdates_(0), reset_(false) { | |
} | |
void increment(IntT inc) { | |
if ((__builtin_expect((!reset_.load(std::memory_order_acquire)), | |
1))) { | |
val_.store(val_.load(std::memory_order_relaxed) + inc, | |
std::memory_order_release); | |
} else { | |
val_.store(inc, std::memory_order_relaxed); | |
reset_.store(false, std::memory_order_release); | |
} | |
++numUpdates_; | |
if ((__builtin_expect( | |
(numUpdates_ > | |
parent_->cacheSize_.load(std::memory_order_acquire)), | |
0)) | |
) { | |
flush(); | |
} | |
} | |
void flush() const { | |
parent_->target_.fetch_add(val_, std::memory_order_release); | |
val_.store(0, std::memory_order_release); | |
numUpdates_ = 0; | |
} | |
~IntCache() { | |
flush(); | |
} | |
}; | |
}; | |
} // namespace folly | |
// # 38 "tlm/deps/folly.exploded/include/folly/AtomicHashArray.h" 2 3 4 | |
namespace folly { | |
struct AtomicHashArrayLinearProbeFcn { | |
inline size_t operator()(size_t idx, size_t, size_t capacity) const { | |
idx += 1; | |
return (__builtin_expect((idx < capacity), 1)) ? idx : (idx - capacity); | |
} | |
}; | |
struct AtomicHashArrayQuadraticProbeFcn { | |
inline size_t operator()(size_t idx, | |
size_t numProbes, | |
size_t capacity) const { | |
idx += numProbes; | |
return (__builtin_expect((idx < capacity), 1)) ? idx : (idx - capacity); | |
} | |
}; | |
namespace detail { | |
template <typename NotKeyT, typename KeyT> | |
inline void checkLegalKeyIfKeyTImpl(NotKeyT, KeyT, KeyT, KeyT) { | |
} | |
template <typename KeyT> | |
inline void checkLegalKeyIfKeyTImpl(KeyT key_in, | |
KeyT emptyKey, | |
KeyT lockedKey, | |
KeyT erasedKey) { | |
while (google::_Check_string* _result = | |
google::Check_NEImpl(google::GetReferenceableValue(key_in), | |
google::GetReferenceableValue(emptyKey), | |
"key_in" | |
" " | |
"!=" | |
" " | |
"emptyKey")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashArray.h", | |
78, | |
google::CheckOpString(_result)) | |
.stream(); | |
while (google::_Check_string* _result = google::Check_NEImpl( | |
google::GetReferenceableValue(key_in), | |
google::GetReferenceableValue(lockedKey), | |
"key_in" | |
" " | |
"!=" | |
" " | |
"lockedKey")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashArray.h", | |
79, | |
google::CheckOpString(_result)) | |
.stream(); | |
while (google::_Check_string* _result = google::Check_NEImpl( | |
google::GetReferenceableValue(key_in), | |
google::GetReferenceableValue(erasedKey), | |
"key_in" | |
" " | |
"!=" | |
" " | |
"erasedKey")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashArray.h", | |
80, | |
google::CheckOpString(_result)) | |
.stream(); | |
} | |
} // namespace detail | |
template <class KeyT, | |
class ValueT, | |
class HashFcn = std::hash<KeyT>, | |
class EqualFcn = std::equal_to<KeyT>, | |
class Allocator = std::allocator<char>, | |
class ProbeFcn = AtomicHashArrayLinearProbeFcn, | |
class KeyConvertFcn = Identity> | |
class AtomicHashMap; | |
template <class KeyT, | |
class ValueT, | |
class HashFcn = std::hash<KeyT>, | |
class EqualFcn = std::equal_to<KeyT>, | |
class Allocator = std::allocator<char>, | |
class ProbeFcn = AtomicHashArrayLinearProbeFcn, | |
class KeyConvertFcn = Identity> | |
class AtomicHashArray { | |
static_assert( | |
(std::is_convertible<KeyT, int32_t>::value || | |
std::is_convertible<KeyT, int64_t>::value || | |
std::is_convertible<KeyT, const void*>::value), | |
"You are trying to use AtomicHashArray with disallowed key " | |
"types. You must use atomically compare-and-swappable integer " | |
"keys, or a different container class."); | |
public: | |
typedef KeyT key_type; | |
typedef ValueT mapped_type; | |
typedef HashFcn hasher; | |
typedef EqualFcn key_equal; | |
typedef KeyConvertFcn key_convert; | |
typedef std::pair<const KeyT, ValueT> value_type; | |
typedef std::size_t size_type; | |
typedef std::ptrdiff_t difference_type; | |
typedef value_type& reference; | |
typedef const value_type& const_reference; | |
typedef value_type* pointer; | |
typedef const value_type* const_pointer; | |
const size_t capacity_; | |
const size_t maxEntries_; | |
const KeyT kEmptyKey_; | |
const KeyT kLockedKey_; | |
const KeyT kErasedKey_; | |
template <class ContT, class IterVal> | |
struct aha_iterator; | |
typedef aha_iterator<const AtomicHashArray, const value_type> | |
const_iterator; | |
typedef aha_iterator<AtomicHashArray, value_type> iterator; | |
static void destroy(AtomicHashArray*); | |
private: | |
const size_t kAnchorMask_; | |
struct Deleter { | |
void operator()(AtomicHashArray* ptr) { | |
AtomicHashArray::destroy(ptr); | |
} | |
}; | |
public: | |
typedef std::unique_ptr<AtomicHashArray, Deleter> SmartPtr; | |
// # 174 "tlm/deps/folly.exploded/include/folly/AtomicHashArray.h" 3 4 | |
struct Config { | |
KeyT emptyKey; | |
KeyT lockedKey; | |
KeyT erasedKey; | |
double maxLoadFactor; | |
double growthFactor; | |
uint32_t entryCountThreadCacheSize; | |
size_t capacity; | |
Config() | |
: emptyKey((KeyT)-1), | |
lockedKey((KeyT)-2), | |
erasedKey((KeyT)-3), | |
maxLoadFactor(0.8), | |
growthFactor(-1), | |
entryCountThreadCacheSize(1000), | |
capacity(0) { | |
} | |
}; | |
static SmartPtr create(size_t maxSize, const Config& c = Config()); | |
// # 214 "tlm/deps/folly.exploded/include/folly/AtomicHashArray.h" 3 4 | |
template <typename LookupKeyT = key_type, | |
typename LookupHashFcn = hasher, | |
typename LookupEqualFcn = key_equal> | |
iterator find(LookupKeyT k) { | |
return iterator( | |
this, | |
findInternal<LookupKeyT, LookupHashFcn, LookupEqualFcn>(k).idx); | |
} | |
template <typename LookupKeyT = key_type, | |
typename LookupHashFcn = hasher, | |
typename LookupEqualFcn = key_equal> | |
const_iterator find(LookupKeyT k) const { | |
return const_cast<AtomicHashArray*>(this) | |
->find<LookupKeyT, LookupHashFcn, LookupEqualFcn>(k); | |
} | |
// # 243 "tlm/deps/folly.exploded/include/folly/AtomicHashArray.h" 3 4 | |
std::pair<iterator, bool> insert(const value_type& r) { | |
return emplace(r.first, r.second); | |
} | |
std::pair<iterator, bool> insert(value_type&& r) { | |
return emplace(r.first, std::move(r.second)); | |
} | |
// # 261 "tlm/deps/folly.exploded/include/folly/AtomicHashArray.h" 3 4 | |
template <typename LookupKeyT = key_type, | |
typename LookupHashFcn = hasher, | |
typename LookupEqualFcn = key_equal, | |
typename LookupKeyToKeyFcn = key_convert, | |
typename... ArgTs> | |
std::pair<iterator, bool> emplace(LookupKeyT key_in, ArgTs&&... vCtorArgs) { | |
SimpleRetT ret = insertInternal<LookupKeyT, | |
LookupHashFcn, | |
LookupEqualFcn, | |
LookupKeyToKeyFcn>( | |
key_in, std::forward<ArgTs>(vCtorArgs)...); | |
return std::make_pair(iterator(this, ret.idx), ret.success); | |
} | |
size_t erase(KeyT k); | |
void clear(); | |
size_t size() const { | |
return numEntries_.readFull() - | |
numErases_.load(std::memory_order_relaxed); | |
} | |
bool empty() const { | |
return size() == 0; | |
} | |
iterator begin() { | |
iterator it(this, 0); | |
it.advancePastEmpty(); | |
return it; | |
} | |
const_iterator begin() const { | |
const_iterator it(this, 0); | |
it.advancePastEmpty(); | |
return it; | |
} | |
iterator end() { | |
return iterator(this, capacity_); | |
} | |
const_iterator end() const { | |
return const_iterator(this, capacity_); | |
} | |
iterator findAt(uint32_t idx) { | |
while (google::_Check_string* _result = google::Check_LTImpl( | |
google::GetReferenceableValue(idx), | |
google::GetReferenceableValue(capacity_), | |
"idx" | |
" " | |
"<" | |
" " | |
"capacity_")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashArray.h", | |
315, | |
google::CheckOpString(_result)) | |
.stream(); | |
return iterator(this, idx); | |
} | |
const_iterator findAt(uint32_t idx) const { | |
return const_cast<AtomicHashArray*>(this)->findAt(idx); | |
} | |
iterator makeIter(size_t idx) { | |
return iterator(this, idx); | |
} | |
const_iterator makeIter(size_t idx) const { | |
return const_iterator(this, idx); | |
} | |
double maxLoadFactor() const { | |
return ((double)maxEntries_) / capacity_; | |
} | |
void setEntryCountThreadCacheSize(uint32_t newSize) { | |
numEntries_.setCacheSize(newSize); | |
numPendingEntries_.setCacheSize(newSize); | |
} | |
uint32_t getEntryCountThreadCacheSize() const { | |
return numEntries_.getCacheSize(); | |
} | |
private: | |
friend class AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn>; | |
struct SimpleRetT { | |
size_t idx; | |
bool success; | |
SimpleRetT(size_t i, bool s) : idx(i), success(s) { | |
} | |
SimpleRetT() = default; | |
}; | |
template <typename LookupKeyT = key_type, | |
typename LookupHashFcn = hasher, | |
typename LookupEqualFcn = key_equal, | |
typename LookupKeyToKeyFcn = Identity, | |
typename... ArgTs> | |
SimpleRetT insertInternal(LookupKeyT key, ArgTs&&... vCtorArgs); | |
template <typename LookupKeyT = key_type, | |
typename LookupHashFcn = hasher, | |
typename LookupEqualFcn = key_equal> | |
SimpleRetT findInternal(const LookupKeyT key); | |
template <typename MaybeKeyT> | |
void checkLegalKeyIfKey(MaybeKeyT key) { | |
detail::checkLegalKeyIfKeyTImpl( | |
key, kEmptyKey_, kLockedKey_, kErasedKey_); | |
} | |
static std::atomic<KeyT>* cellKeyPtr(const value_type& r) { | |
static_assert( | |
sizeof(std::atomic<KeyT>) == sizeof(KeyT), | |
"std::atomic is implemented in an unexpected way for AHM"); | |
return const_cast<std::atomic<KeyT>*>( | |
reinterpret_cast<std::atomic<KeyT> const*>(&r.first)); | |
} | |
static KeyT relaxedLoadKey(const value_type& r) { | |
return cellKeyPtr(r)->load(std::memory_order_relaxed); | |
} | |
static KeyT acquireLoadKey(const value_type& r) { | |
return cellKeyPtr(r)->load(std::memory_order_acquire); | |
} | |
ThreadCachedInt<uint64_t> numEntries_; | |
ThreadCachedInt<uint64_t> numPendingEntries_; | |
std::atomic<int64_t> isFull_; | |
std::atomic<int64_t> numErases_; | |
value_type cells_[0]; | |
AtomicHashArray(size_t capacity, | |
KeyT emptyKey, | |
KeyT lockedKey, | |
KeyT erasedKey, | |
double maxLoadFactor, | |
uint32_t cacheSize); | |
AtomicHashArray(const AtomicHashArray&) = delete; | |
AtomicHashArray& operator=(const AtomicHashArray&) = delete; | |
~AtomicHashArray() = default; | |
inline void unlockCell(value_type* const cell, KeyT newKey) { | |
cellKeyPtr(*cell)->store(newKey, std::memory_order_release); | |
} | |
inline bool tryLockCell(value_type* const cell) { | |
KeyT expect = kEmptyKey_; | |
return cellKeyPtr(*cell)->compare_exchange_strong( | |
expect, kLockedKey_, std::memory_order_acq_rel); | |
} | |
template <class LookupKeyT = key_type, class LookupHashFcn = hasher> | |
inline size_t keyToAnchorIdx(const LookupKeyT k) const { | |
const size_t hashVal = LookupHashFcn()(k); | |
const size_t probe = hashVal & kAnchorMask_; | |
return (__builtin_expect((probe < capacity_), 1)) ? probe | |
: hashVal % capacity_; | |
} | |
}; | |
} // namespace folly | |
// # 1 "tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h" 1 3 4 | |
// # 23 "tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h" 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/detail/AtomicHashUtils.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/detail/AtomicHashUtils.h" 3 4 | |
// # 26 "tlm/deps/folly.exploded/include/folly/detail/AtomicHashUtils.h" 3 4 | |
namespace folly { | |
namespace detail { | |
template <typename Cond> | |
void atomic_hash_spin_wait(Cond condition) { | |
constexpr size_t kPauseLimit = 10000; | |
for (size_t i = 0; condition(); ++i) { | |
if (i < kPauseLimit) { | |
folly::asm_volatile_pause(); | |
} else { | |
std::this_thread::yield(); | |
} | |
} | |
} | |
} // namespace detail | |
} // namespace folly | |
// # 24 "tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h" 2 3 4 | |
// # 1 "tlm/deps/folly.exploded/include/folly/detail/Iterators.h" 1 3 4 | |
// # 17 "tlm/deps/folly.exploded/include/folly/detail/Iterators.h" 3 4 | |
// # 49 "tlm/deps/folly.exploded/include/folly/detail/Iterators.h" 3 4 | |
namespace folly { | |
namespace detail { | |
// # 71 "tlm/deps/folly.exploded/include/folly/detail/Iterators.h" 3 4 | |
template <class D, class V, class Tag> | |
class IteratorFacade { | |
public: | |
using value_type = V; | |
using reference = value_type&; | |
using pointer = value_type*; | |
using difference_type = ssize_t; | |
using iterator_category = Tag; | |
bool operator==(D const& rhs) const { | |
return asDerivedConst().equal(rhs); | |
} | |
bool operator!=(D const& rhs) const { | |
return !operator==(rhs); | |
} | |
// # 96 "tlm/deps/folly.exploded/include/folly/detail/Iterators.h" 3 4 | |
template <class D2, | |
std::enable_if_t<!std::is_same<D, D2>::value, int> = 0, | |
std::enable_if_t<std::is_convertible<D, D2>::value, int> = 0> | |
bool operator==(D2 const& rhs) const { | |
return D2(asDerivedConst()) == rhs; | |
} | |
template <class D2> | |
bool operator!=(D2 const& rhs) const { | |
return !operator==(rhs); | |
} | |
V& operator*() const { | |
return asDerivedConst().dereference(); | |
} | |
V* operator->() const { | |
return std::addressof(operator*()); | |
} | |
D& operator++() { | |
asDerived().increment(); | |
return asDerived(); | |
} | |
D operator++(int) { | |
auto ret = asDerived(); | |
asDerived().increment(); | |
return ret; | |
} | |
D& operator--() { | |
asDerived().decrement(); | |
return asDerived(); | |
} | |
D operator--(int) { | |
auto ret = asDerived(); | |
asDerived().decrement(); | |
return ret; | |
} | |
private: | |
D& asDerived() { | |
return static_cast<D&>(*this); | |
} | |
D const& asDerivedConst() const { | |
return static_cast<D const&>(*this); | |
} | |
}; | |
// # 158 "tlm/deps/folly.exploded/include/folly/detail/Iterators.h" 3 4 | |
template <class D, class I, class V, class Tag> | |
class IteratorAdaptor : public IteratorFacade<D, V, Tag> { | |
public: | |
using Super = IteratorFacade<D, V, Tag>; | |
using value_type = typename Super::value_type; | |
using iterator_category = typename Super::iterator_category; | |
using reference = typename Super::reference; | |
using pointer = typename Super::pointer; | |
using difference_type = typename Super::difference_type; | |
explicit IteratorAdaptor(I base) : base_(base) { | |
} | |
void increment() { | |
++base_; | |
} | |
void decrement() { | |
--base_; | |
} | |
V& dereference() const { | |
return *base_; | |
} | |
bool equal(D const& rhs) const { | |
return base_ == rhs.base_; | |
} | |
I const& base() const { | |
return base_; | |
} | |
I& base() { | |
return base_; | |
} | |
private: | |
I base_; | |
}; | |
} // namespace detail | |
} // namespace folly | |
// # 25 "tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h" 2 3 4 | |
namespace folly { | |
template <class KeyT, | |
class ValueT, | |
class HashFcn, | |
class EqualFcn, | |
class Allocator, | |
class ProbeFcn, | |
class KeyConvertFcn> | |
AtomicHashArray<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::AtomicHashArray(size_t capacity, | |
KeyT emptyKey, | |
KeyT lockedKey, | |
KeyT erasedKey, | |
double _maxLoadFactor, | |
uint32_t cacheSize) | |
: capacity_(capacity), | |
maxEntries_(size_t(_maxLoadFactor * capacity_ + 0.5)), | |
kEmptyKey_(emptyKey), | |
kLockedKey_(lockedKey), | |
kErasedKey_(erasedKey), | |
kAnchorMask_(nextPowTwo(capacity_) - 1), | |
numEntries_(0, cacheSize), | |
numPendingEntries_(0, cacheSize), | |
isFull_(0), | |
numErases_(0) { | |
if (capacity == 0) { | |
throw_exception<std::invalid_argument>("capacity"); | |
} | |
} | |
// # 76 "tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h" 3 4 | |
template <class KeyT, | |
class ValueT, | |
class HashFcn, | |
class EqualFcn, | |
class Allocator, | |
class ProbeFcn, | |
class KeyConvertFcn> | |
template <class LookupKeyT, class LookupHashFcn, class LookupEqualFcn> | |
typename AtomicHashArray<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::SimpleRetT | |
AtomicHashArray<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::findInternal(const LookupKeyT key_in) { | |
checkLegalKeyIfKey<LookupKeyT>(key_in); | |
for (size_t idx = keyToAnchorIdx<LookupKeyT, LookupHashFcn>(key_in), | |
numProbes = 0; | |
; | |
idx = ProbeFcn()(idx, numProbes, capacity_)) { | |
const KeyT key = acquireLoadKey(cells_[idx]); | |
if ((__builtin_expect((LookupEqualFcn()(key, key_in)), 1))) { | |
return SimpleRetT(idx, true); | |
} | |
if ((__builtin_expect((key == kEmptyKey_), 0))) { | |
return SimpleRetT(capacity_, false); | |
} | |
++numProbes; | |
if ((__builtin_expect((numProbes >= capacity_), 0))) { | |
return SimpleRetT(capacity_, false); | |
} | |
} | |
} | |
// # 135 "tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h" 3 4 | |
template <class KeyT, | |
class ValueT, | |
class HashFcn, | |
class EqualFcn, | |
class Allocator, | |
class ProbeFcn, | |
class KeyConvertFcn> | |
template <typename LookupKeyT, | |
typename LookupHashFcn, | |
typename LookupEqualFcn, | |
typename LookupKeyToKeyFcn, | |
typename... ArgTs> | |
typename AtomicHashArray<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::SimpleRetT | |
AtomicHashArray<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::insertInternal(LookupKeyT key_in, | |
ArgTs&&... vCtorArgs) { | |
const short NO_NEW_INSERTS = 1; | |
const short NO_PENDING_INSERTS = 2; | |
checkLegalKeyIfKey<LookupKeyT>(key_in); | |
size_t idx = keyToAnchorIdx<LookupKeyT, LookupHashFcn>(key_in); | |
size_t numProbes = 0; | |
for (;;) { | |
while (google::_Check_string* _result = google::Check_LTImpl( | |
google::GetReferenceableValue(idx), | |
google::GetReferenceableValue(capacity_), | |
"idx" | |
" " | |
"<" | |
" " | |
"capacity_")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/" | |
"AtomicHashArray-inl.h", | |
172, | |
google::CheckOpString(_result)) | |
.stream(); | |
value_type* cell = &cells_[idx]; | |
if (relaxedLoadKey(*cell) == kEmptyKey_) { | |
++numPendingEntries_; | |
if (isFull_.load(std::memory_order_acquire)) { | |
--numPendingEntries_; | |
// # 189 | |
// "tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h" | |
// 3 4 | |
detail::atomic_hash_spin_wait([&] { | |
return (isFull_.load(std::memory_order_acquire) != | |
NO_PENDING_INSERTS) && | |
(numPendingEntries_.readFull() != 0); | |
}); | |
isFull_.store(NO_PENDING_INSERTS, std::memory_order_release); | |
if (relaxedLoadKey(*cell) == kEmptyKey_) { | |
return SimpleRetT(capacity_, false); | |
} | |
} else { | |
if (tryLockCell(cell)) { | |
KeyT key_new; | |
try { | |
key_new = LookupKeyToKeyFcn()(key_in); | |
typedef typename std::remove_const<LookupKeyT>::type | |
LookupKeyTNoConst; | |
constexpr bool kAlreadyChecked = | |
std::is_same<KeyT, LookupKeyTNoConst>::value; | |
if (!kAlreadyChecked) { | |
checkLegalKeyIfKey(key_new); | |
} | |
static_cast<void>(0), | |
!((__builtin_expect( | |
!(relaxedLoadKey(*cell) == kLockedKey_), | |
0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/" | |
"folly.exploded/" | |
"include/folly/" | |
"AtomicHashArray-inl." | |
"h", | |
216) | |
.stream() | |
<< "Check failed: " | |
"relaxedLoadKey(*" | |
"cell) == " | |
"kLockedKey_" | |
" "; | |
using mapped = | |
typename std::remove_const<mapped_type>::type; | |
new (const_cast<mapped*>(&cell->second)) | |
ValueT(std::forward<ArgTs>(vCtorArgs)...); | |
unlockCell(cell, key_new); | |
} catch (...) { | |
unlockCell(cell, kEmptyKey_); | |
--numPendingEntries_; | |
throw; | |
} | |
static_cast<void>(0), | |
!((__builtin_expect( | |
!(relaxedLoadKey(*cell) == key_new || | |
relaxedLoadKey(*cell) == kErasedKey_), | |
0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/" | |
"include/folly/" | |
"AtomicHashArray-inl.h", | |
233) | |
.stream() | |
<< "Check failed: " | |
"relaxedLoadKey(*cell)" | |
" == key_new || " | |
"relaxedLoadKey(*cell)" | |
" == kErasedKey_" | |
" " | |
; | |
--numPendingEntries_; | |
++numEntries_; | |
if (numEntries_.readFast() >= maxEntries_) { | |
isFull_.store(NO_NEW_INSERTS, | |
std::memory_order_relaxed); | |
} | |
return SimpleRetT(idx, true); | |
} | |
--numPendingEntries_; | |
} | |
} | |
static_cast<void>(0), | |
!((__builtin_expect(!(relaxedLoadKey(*cell) != kEmptyKey_), 0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/" | |
"folly/AtomicHashArray-inl.h", | |
246) | |
.stream() | |
<< "Check failed: " | |
"relaxedLoadKey(*cell) != " | |
"kEmptyKey_" | |
" "; | |
if (kLockedKey_ == acquireLoadKey(*cell)) { | |
detail::atomic_hash_spin_wait( | |
[&] { return kLockedKey_ == acquireLoadKey(*cell); }); | |
} | |
const KeyT thisKey = acquireLoadKey(*cell); | |
if (LookupEqualFcn()(thisKey, key_in)) { | |
return SimpleRetT(idx, false); | |
} else if (thisKey == kEmptyKey_ || thisKey == kLockedKey_) { | |
continue; | |
} | |
++numProbes; | |
if ((__builtin_expect((numProbes >= capacity_), 0))) { | |
return SimpleRetT(capacity_, false); | |
} | |
idx = ProbeFcn()(idx, numProbes, capacity_); | |
} | |
} | |
// # 286 "tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h" 3 4 | |
template <class KeyT, | |
class ValueT, | |
class HashFcn, | |
class EqualFcn, | |
class Allocator, | |
class ProbeFcn, | |
class KeyConvertFcn> | |
size_t AtomicHashArray<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::erase(KeyT key_in) { | |
while (google::_Check_string* _result = google::Check_NEImpl( | |
google::GetReferenceableValue(key_in), | |
google::GetReferenceableValue(kEmptyKey_), | |
"key_in" | |
" " | |
"!=" | |
" " | |
"kEmptyKey_")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h", | |
302, | |
google::CheckOpString(_result)) | |
.stream(); | |
while (google::_Check_string* _result = google::Check_NEImpl( | |
google::GetReferenceableValue(key_in), | |
google::GetReferenceableValue(kLockedKey_), | |
"key_in" | |
" " | |
"!=" | |
" " | |
"kLockedKey_")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h", | |
303, | |
google::CheckOpString(_result)) | |
.stream(); | |
while (google::_Check_string* _result = google::Check_NEImpl( | |
google::GetReferenceableValue(key_in), | |
google::GetReferenceableValue(kErasedKey_), | |
"key_in" | |
" " | |
"!=" | |
" " | |
"kErasedKey_")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h", | |
304, | |
google::CheckOpString(_result)) | |
.stream(); | |
for (size_t idx = keyToAnchorIdx(key_in), numProbes = 0;; | |
idx = ProbeFcn()(idx, numProbes, capacity_)) { | |
while (google::_Check_string* _result = google::Check_LTImpl( | |
google::GetReferenceableValue(idx), | |
google::GetReferenceableValue(capacity_), | |
"idx" | |
" " | |
"<" | |
" " | |
"capacity_")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/" | |
"AtomicHashArray-inl.h", | |
308, | |
google::CheckOpString(_result)) | |
.stream(); | |
value_type* cell = &cells_[idx]; | |
KeyT currentKey = acquireLoadKey(*cell); | |
if (currentKey == kEmptyKey_ || currentKey == kLockedKey_) { | |
return 0; | |
} | |
if (EqualFcn()(currentKey, key_in)) { | |
KeyT expect = currentKey; | |
if (cellKeyPtr(*cell)->compare_exchange_strong(expect, | |
kErasedKey_)) { | |
numErases_.fetch_add(1, std::memory_order_relaxed); | |
return 1; | |
} | |
return 0; | |
} | |
++numProbes; | |
if ((__builtin_expect((numProbes >= capacity_), 0))) { | |
return 0; | |
} | |
} | |
} | |
template <class KeyT, | |
class ValueT, | |
class HashFcn, | |
class EqualFcn, | |
class Allocator, | |
class ProbeFcn, | |
class KeyConvertFcn> | |
typename AtomicHashArray<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::SmartPtr | |
AtomicHashArray<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::create(size_t maxSize, const Config& c) { | |
while (google::_Check_string* _result = google::Check_LEImpl( | |
google::GetReferenceableValue(c.maxLoadFactor), | |
google::GetReferenceableValue(1.0), | |
"c.maxLoadFactor" | |
" " | |
"<=" | |
" " | |
"1.0")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h", | |
369, | |
google::CheckOpString(_result)) | |
.stream(); | |
while (google::_Check_string* _result = google::Check_GTImpl( | |
google::GetReferenceableValue(c.maxLoadFactor), | |
google::GetReferenceableValue(0.0), | |
"c.maxLoadFactor" | |
" " | |
">" | |
" " | |
"0.0")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h", | |
370, | |
google::CheckOpString(_result)) | |
.stream(); | |
while (google::_Check_string* _result = google::Check_NEImpl( | |
google::GetReferenceableValue(c.emptyKey), | |
google::GetReferenceableValue(c.lockedKey), | |
"c.emptyKey" | |
" " | |
"!=" | |
" " | |
"c.lockedKey")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h", | |
371, | |
google::CheckOpString(_result)) | |
.stream(); | |
size_t capacity = size_t(maxSize / c.maxLoadFactor); | |
size_t sz = sizeof(AtomicHashArray) + sizeof(value_type) * capacity; | |
auto const mem = Allocator().allocate(sz); | |
try { | |
new (mem) AtomicHashArray(capacity, | |
c.emptyKey, | |
c.lockedKey, | |
c.erasedKey, | |
c.maxLoadFactor, | |
c.entryCountThreadCacheSize); | |
} catch (...) { | |
Allocator().deallocate(mem, sz); | |
throw; | |
} | |
SmartPtr map(static_cast<AtomicHashArray*>((void*)mem)); | |
// # 403 "tlm/deps/folly.exploded/include/folly/AtomicHashArray-inl.h" 3 4 | |
for (auto i = (true ? (0) : (map->capacity_)); | |
::folly::detail::notThereYet(i, (map->capacity_)); | |
++i) { | |
cellKeyPtr(map->cells_[i]) | |
->store(map->kEmptyKey_, std::memory_order_relaxed); | |
} | |
return map; | |
} | |
template <class KeyT, | |
class ValueT, | |
class HashFcn, | |
class EqualFcn, | |
class Allocator, | |
class ProbeFcn, | |
class KeyConvertFcn> | |
void AtomicHashArray<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::destroy(AtomicHashArray* p) { | |
(static_cast<bool>(p) ? void(0) | |
: __assert_fail("p", | |
"tlm/deps/folly.exploded/include/" | |
"folly/AtomicHashArray-inl.h", | |
426, | |
__extension__ __PRETTY_FUNCTION__)); | |
size_t sz = sizeof(AtomicHashArray) + sizeof(value_type) * p->capacity_; | |
for (auto i = (true ? (0) : (p->capacity_)); | |
::folly::detail::notThereYet(i, (p->capacity_)); | |
++i) { | |
if (p->cells_[i].first != p->kEmptyKey_) { | |
p->cells_[i].~value_type(); | |
} | |
} | |
p->~AtomicHashArray(); | |
Allocator().deallocate((char*)p, sz); | |
} | |
template <class KeyT, | |
class ValueT, | |
class HashFcn, | |
class EqualFcn, | |
class Allocator, | |
class ProbeFcn, | |
class KeyConvertFcn> | |
void AtomicHashArray<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::clear() { | |
for (auto i = (true ? (0) : (capacity_)); | |
::folly::detail::notThereYet(i, (capacity_)); | |
++i) { | |
if (cells_[i].first != kEmptyKey_) { | |
cells_[i].~value_type(); | |
*const_cast<KeyT*>(&cells_[i].first) = kEmptyKey_; | |
} | |
static_cast<void>(0), | |
!((__builtin_expect(!(cells_[i].first == kEmptyKey_), 0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/" | |
"folly/AtomicHashArray-inl.h", | |
462) | |
.stream() | |
<< "Check failed: " | |
"cells_[i].first == kEmptyKey_" | |
" "; | |
} | |
numEntries_.set(0); | |
numPendingEntries_.set(0); | |
isFull_.store(0, std::memory_order_relaxed); | |
numErases_.store(0, std::memory_order_relaxed); | |
} | |
template <class KeyT, | |
class ValueT, | |
class HashFcn, | |
class EqualFcn, | |
class Allocator, | |
class ProbeFcn, | |
class KeyConvertFcn> | |
template <class ContT, class IterVal> | |
struct AtomicHashArray<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::aha_iterator | |
: detail::IteratorFacade<aha_iterator<ContT, IterVal>, | |
IterVal, | |
std::forward_iterator_tag> { | |
explicit aha_iterator() : aha_(nullptr) { | |
} | |
template <class OtherContT, class OtherVal> | |
aha_iterator( | |
const aha_iterator<OtherContT, OtherVal>& o, | |
typename std::enable_if< | |
std::is_convertible<OtherVal*, IterVal*>::value>::type* = | |
nullptr) | |
: aha_(o.aha_), offset_(o.offset_) { | |
} | |
explicit aha_iterator(ContT* array, size_t offset) | |
: aha_(array), offset_(offset) { | |
} | |
uint32_t getIndex() const { | |
return offset_; | |
} | |
void advancePastEmpty() { | |
while (offset_ < aha_->capacity_ && !isValid()) { | |
++offset_; | |
} | |
} | |
private: | |
friend class AtomicHashArray; | |
friend class detail:: | |
IteratorFacade<aha_iterator, IterVal, std::forward_iterator_tag>; | |
void increment() { | |
++offset_; | |
advancePastEmpty(); | |
} | |
bool equal(const aha_iterator& o) const { | |
return aha_ == o.aha_ && offset_ == o.offset_; | |
} | |
IterVal& dereference() const { | |
return aha_->cells_[offset_]; | |
} | |
bool isValid() const { | |
KeyT key = acquireLoadKey(aha_->cells_[offset_]); | |
return key != aha_->kEmptyKey_ && key != aha_->kLockedKey_ && | |
key != aha_->kErasedKey_; | |
} | |
private: | |
ContT* aha_; | |
size_t offset_; | |
}; | |
} // namespace folly | |
// # 449 "tlm/deps/folly.exploded/include/folly/AtomicHashArray.h" 2 3 4 | |
// # 90 "tlm/deps/folly.exploded/include/folly/AtomicHashMap.h" 2 3 4 | |
namespace folly { | |
// # 149 "tlm/deps/folly.exploded/include/folly/AtomicHashMap.h" 3 4 | |
struct __attribute__((__visibility__("default"))) AtomicHashMapFullError | |
: std::runtime_error { | |
explicit AtomicHashMapFullError() | |
: std::runtime_error("AtomicHashMap is full") { | |
} | |
}; | |
template <class KeyT, | |
class ValueT, | |
class HashFcn, | |
class EqualFcn, | |
class Allocator, | |
class ProbeFcn, | |
class KeyConvertFcn> | |
class AtomicHashMap { | |
typedef AtomicHashArray<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn> | |
SubMap; | |
public: | |
typedef KeyT key_type; | |
typedef ValueT mapped_type; | |
typedef std::pair<const KeyT, ValueT> value_type; | |
typedef HashFcn hasher; | |
typedef EqualFcn key_equal; | |
typedef KeyConvertFcn key_convert; | |
typedef value_type* pointer; | |
typedef value_type& reference; | |
typedef const value_type& const_reference; | |
typedef std::ptrdiff_t difference_type; | |
typedef std::size_t size_type; | |
typedef typename SubMap::Config Config; | |
template <class ContT, class IterVal, class SubIt> | |
struct ahm_iterator; | |
typedef ahm_iterator<const AtomicHashMap, | |
const value_type, | |
typename SubMap::const_iterator> | |
const_iterator; | |
typedef ahm_iterator<AtomicHashMap, value_type, typename SubMap::iterator> | |
iterator; | |
public: | |
const float kGrowthFrac_; | |
explicit AtomicHashMap(size_t finalSizeEst, const Config& c = Config()); | |
AtomicHashMap(const AtomicHashMap&) = delete; | |
AtomicHashMap& operator=(const AtomicHashMap&) = delete; | |
~AtomicHashMap() { | |
const unsigned int numMaps = | |
numMapsAllocated_.load(std::memory_order_relaxed); | |
for (auto i = (true ? (0) : (numMaps)); | |
::folly::detail::notThereYet(i, (numMaps)); | |
++i) { | |
SubMap* thisMap = subMaps_[i].load(std::memory_order_relaxed); | |
static_cast<void>(0), | |
!((__builtin_expect(!(thisMap), 0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/" | |
"folly/AtomicHashMap.h", | |
214) | |
.stream() | |
<< "Check failed: " | |
"thisMap" | |
" "; | |
SubMap::destroy(thisMap); | |
} | |
} | |
key_equal key_eq() const { | |
return key_equal(); | |
} | |
hasher hash_function() const { | |
return hasher(); | |
} | |
// # 241 "tlm/deps/folly.exploded/include/folly/AtomicHashMap.h" 3 4 | |
std::pair<iterator, bool> insert(const value_type& r) { | |
return emplace(r.first, r.second); | |
} | |
std::pair<iterator, bool> insert(key_type k, const mapped_type& v) { | |
return emplace(k, v); | |
} | |
std::pair<iterator, bool> insert(value_type&& r) { | |
return emplace(r.first, std::move(r.second)); | |
} | |
std::pair<iterator, bool> insert(key_type k, mapped_type&& v) { | |
return emplace(k, std::move(v)); | |
} | |
// # 265 "tlm/deps/folly.exploded/include/folly/AtomicHashMap.h" 3 4 | |
template <typename LookupKeyT = key_type, | |
typename LookupHashFcn = hasher, | |
typename LookupEqualFcn = key_equal, | |
typename LookupKeyToKeyFcn = key_convert, | |
typename... ArgTs> | |
std::pair<iterator, bool> emplace(LookupKeyT k, ArgTs&&... vCtorArg); | |
// # 289 "tlm/deps/folly.exploded/include/folly/AtomicHashMap.h" 3 4 | |
template <typename LookupKeyT = key_type, | |
typename LookupHashFcn = hasher, | |
typename LookupEqualFcn = key_equal> | |
iterator find(LookupKeyT k); | |
template <typename LookupKeyT = key_type, | |
typename LookupHashFcn = hasher, | |
typename LookupEqualFcn = key_equal> | |
const_iterator find(LookupKeyT k) const; | |
// # 308 "tlm/deps/folly.exploded/include/folly/AtomicHashMap.h" 3 4 | |
size_type erase(key_type k); | |
// # 318 "tlm/deps/folly.exploded/include/folly/AtomicHashMap.h" 3 4 | |
void clear(); | |
// # 328 "tlm/deps/folly.exploded/include/folly/AtomicHashMap.h" 3 4 | |
size_t size() const; | |
bool empty() const { | |
return size() == 0; | |
} | |
size_type count(key_type k) const { | |
return find(k) == end() ? 0 : 1; | |
} | |
// # 347 "tlm/deps/folly.exploded/include/folly/AtomicHashMap.h" 3 4 | |
iterator findAt(uint32_t idx) { | |
SimpleRetT ret = findAtInternal(idx); | |
while (google::_Check_string* _result = google::Check_LTImpl( | |
google::GetReferenceableValue(ret.i), | |
google::GetReferenceableValue(numSubMaps()), | |
"ret.i" | |
" " | |
"<" | |
" " | |
"numSubMaps()")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashMap.h", | |
349, | |
google::CheckOpString(_result)) | |
.stream(); | |
return iterator(this, | |
ret.i, | |
subMaps_[ret.i] | |
.load(std::memory_order_relaxed) | |
->makeIter(ret.j)); | |
} | |
const_iterator findAt(uint32_t idx) const { | |
return const_cast<AtomicHashMap*>(this)->findAt(idx); | |
} | |
size_t capacity() const; | |
size_t spaceRemaining() const; | |
void setEntryCountThreadCacheSize(int32_t newSize) { | |
const int numMaps = numMapsAllocated_.load(std::memory_order_acquire); | |
for (int i = 0; i < numMaps; ++i) { | |
SubMap* map = subMaps_[i].load(std::memory_order_relaxed); | |
map->setEntryCountThreadCacheSize(newSize); | |
} | |
} | |
int numSubMaps() const { | |
return numMapsAllocated_.load(std::memory_order_acquire); | |
} | |
iterator begin() { | |
iterator it( | |
this, 0, subMaps_[0].load(std::memory_order_relaxed)->begin()); | |
it.checkAdvanceToNextSubmap(); | |
return it; | |
} | |
const_iterator begin() const { | |
const_iterator it( | |
this, 0, subMaps_[0].load(std::memory_order_relaxed)->begin()); | |
it.checkAdvanceToNextSubmap(); | |
return it; | |
} | |
iterator end() { | |
return iterator(); | |
} | |
const_iterator end() const { | |
return const_iterator(); | |
} | |
inline uint32_t recToIdx(const value_type& r, bool mayInsert = true) { | |
SimpleRetT ret = mayInsert ? insertInternal(r.first, r.second) | |
: findInternal(r.first); | |
return encodeIndex(ret.i, ret.j); | |
} | |
inline uint32_t recToIdx(value_type&& r, bool mayInsert = true) { | |
SimpleRetT ret = mayInsert | |
? insertInternal(r.first, std::move(r.second)) | |
: findInternal(r.first); | |
return encodeIndex(ret.i, ret.j); | |
} | |
inline uint32_t recToIdx(key_type k, | |
const mapped_type& v, | |
bool mayInsert = true) { | |
SimpleRetT ret = mayInsert ? insertInternal(k, v) : findInternal(k); | |
return encodeIndex(ret.i, ret.j); | |
} | |
inline uint32_t recToIdx(key_type k, | |
mapped_type&& v, | |
bool mayInsert = true) { | |
SimpleRetT ret = | |
mayInsert ? insertInternal(k, std::move(v)) : findInternal(k); | |
return encodeIndex(ret.i, ret.j); | |
} | |
inline uint32_t keyToIdx(const KeyT k, bool mayInsert = false) { | |
return recToIdx(value_type(k), mayInsert); | |
} | |
inline const value_type& idxToRec(uint32_t idx) const { | |
SimpleRetT ret = findAtInternal(idx); | |
return subMaps_[ret.i].load(std::memory_order_relaxed)->idxToRec(ret.j); | |
} | |
private: | |
static const uint32_t kNumSubMapBits_ = 4; | |
static const uint32_t kSecondaryMapBit_ = 1u << 31; | |
static const uint32_t kSubMapIndexShift_ = 32 - kNumSubMapBits_ - 1; | |
static const uint32_t kSubMapIndexMask_ = (1 << kSubMapIndexShift_) - 1; | |
static const uint32_t kNumSubMaps_ = 1 << kNumSubMapBits_; | |
static const uintptr_t kLockedPtr_ = 0x88ULL << 48; | |
struct SimpleRetT { | |
uint32_t i; | |
size_t j; | |
bool success; | |
SimpleRetT(uint32_t ii, size_t jj, bool s) : i(ii), j(jj), success(s) { | |
} | |
SimpleRetT() = default; | |
}; | |
template <typename LookupKeyT = key_type, | |
typename LookupHashFcn = hasher, | |
typename LookupEqualFcn = key_equal, | |
typename LookupKeyToKeyFcn = key_convert, | |
typename... ArgTs> | |
SimpleRetT insertInternal(LookupKeyT key, ArgTs&&... value); | |
template <typename LookupKeyT = key_type, | |
typename LookupHashFcn = hasher, | |
typename LookupEqualFcn = key_equal> | |
SimpleRetT findInternal(const LookupKeyT k) const; | |
SimpleRetT findAtInternal(uint32_t idx) const; | |
std::atomic<SubMap*> subMaps_[kNumSubMaps_]; | |
std::atomic<uint32_t> numMapsAllocated_; | |
inline bool tryLockMap(unsigned int idx) { | |
SubMap* val = nullptr; | |
return subMaps_[idx].compare_exchange_strong( | |
val, (SubMap*)kLockedPtr_, std::memory_order_acquire); | |
} | |
static inline uint32_t encodeIndex(uint32_t subMap, uint32_t subMapIdx); | |
}; | |
template <class KeyT, | |
class ValueT, | |
class HashFcn = std::hash<KeyT>, | |
class EqualFcn = std::equal_to<KeyT>, | |
class Allocator = std::allocator<char>> | |
using QuadraticProbingAtomicHashMap = | |
AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
AtomicHashArrayQuadraticProbeFcn>; | |
} // namespace folly | |
// # 1 "tlm/deps/folly.exploded/include/folly/AtomicHashMap-inl.h" 1 3 4 | |
// # 26 "tlm/deps/folly.exploded/include/folly/AtomicHashMap-inl.h" 3 4 | |
namespace folly { | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::AtomicHashMap(size_t finalSizeEst, | |
const Config& config) | |
: kGrowthFrac_(config.growthFactor < 0 ? 1.0f - config.maxLoadFactor | |
: config.growthFactor) { | |
static_cast<void>(0), | |
!((__builtin_expect(!(config.maxLoadFactor > 0.0f && | |
config.maxLoadFactor < 1.0f), | |
0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/" | |
"AtomicHashMap-inl.h", | |
49) | |
.stream() | |
<< "Check failed: " | |
"config.maxLoadFactor > 0.0f && " | |
"config.maxLoadFactor < 1.0f" | |
" "; | |
subMaps_[0].store(SubMap::create(finalSizeEst, config).release(), | |
std::memory_order_relaxed); | |
auto subMapCount = kNumSubMaps_; | |
for (auto i = (true ? (1) : (subMapCount)); | |
::folly::detail::notThereYet(i, (subMapCount)); | |
++i) { | |
subMaps_[i].store(nullptr, std::memory_order_relaxed); | |
} | |
numMapsAllocated_.store(1, std::memory_order_relaxed); | |
} | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
template <typename LookupKeyT, | |
typename LookupHashFcn, | |
typename LookupEqualFcn, | |
typename LookupKeyToKeyFcn, | |
typename... ArgTs> | |
std::pair<typename AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::iterator, | |
bool> | |
AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::emplace(LookupKeyT k, ArgTs&&... vCtorArgs) { | |
SimpleRetT ret = insertInternal<LookupKeyT, | |
LookupHashFcn, | |
LookupEqualFcn, | |
LookupKeyToKeyFcn>( | |
k, std::forward<ArgTs>(vCtorArgs)...); | |
SubMap* subMap = subMaps_[ret.i].load(std::memory_order_relaxed); | |
return std::make_pair(iterator(this, ret.i, subMap->makeIter(ret.j)), | |
ret.success); | |
} | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
template <typename LookupKeyT, | |
typename LookupHashFcn, | |
typename LookupEqualFcn, | |
typename LookupKeyToKeyFcn, | |
typename... ArgTs> | |
typename AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::SimpleRetT | |
AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::insertInternal(LookupKeyT key, | |
ArgTs&&... vCtorArgs) { | |
beginInsertInternal: | |
auto nextMapIdx = numMapsAllocated_.load(std::memory_order_acquire); | |
typename SubMap::SimpleRetT ret; | |
for (auto i = (true ? (0) : (nextMapIdx)); | |
::folly::detail::notThereYet(i, (nextMapIdx)); | |
++i) { | |
SubMap* subMap = subMaps_[i].load(std::memory_order_relaxed); | |
ret = subMap->template insertInternal<LookupKeyT, | |
LookupHashFcn, | |
LookupEqualFcn, | |
LookupKeyToKeyFcn>( | |
key, std::forward<ArgTs>(vCtorArgs)...); | |
if (ret.idx == subMap->capacity_) { | |
continue; | |
} | |
return SimpleRetT(i, ret.idx, ret.success); | |
} | |
SubMap* primarySubMap = subMaps_[0].load(std::memory_order_relaxed); | |
if (nextMapIdx >= kNumSubMaps_ || | |
primarySubMap->capacity_ * kGrowthFrac_ < 1.0) { | |
throw AtomicHashMapFullError(); | |
} | |
if (tryLockMap(nextMapIdx)) { | |
size_t numCellsAllocated = | |
(size_t)(primarySubMap->capacity_ * | |
std::pow(1.0 + kGrowthFrac_, nextMapIdx - 1)); | |
size_t newSize = size_t(numCellsAllocated * kGrowthFrac_); | |
static_cast<void>(0), | |
!((__builtin_expect(!(subMaps_[nextMapIdx].load( | |
std::memory_order_relaxed) == | |
(SubMap*)kLockedPtr_), | |
0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/" | |
"folly/AtomicHashMap-inl.h", | |
170) | |
.stream() | |
<< "Check failed: " | |
"subMaps_[nextMapIdx].load(std::" | |
"memory_order_relaxed) == " | |
"(SubMap*)kLockedPtr_" | |
" " | |
; | |
Config config; | |
config.emptyKey = primarySubMap->kEmptyKey_; | |
config.lockedKey = primarySubMap->kLockedKey_; | |
config.erasedKey = primarySubMap->kErasedKey_; | |
config.maxLoadFactor = primarySubMap->maxLoadFactor(); | |
config.entryCountThreadCacheSize = | |
primarySubMap->getEntryCountThreadCacheSize(); | |
subMaps_[nextMapIdx].store(SubMap::create(newSize, config).release(), | |
std::memory_order_relaxed); | |
numMapsAllocated_.fetch_add(1, std::memory_order_release); | |
while (google::_Check_string* _result = google::Check_EQImpl( | |
google::GetReferenceableValue(nextMapIdx + 1), | |
google::GetReferenceableValue(numMapsAllocated_.load( | |
std::memory_order_relaxed)), | |
"nextMapIdx + 1" | |
" " | |
"==" | |
" " | |
"numMapsAllocated_.load(std::memory_order_relaxed)")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashMap-inl.h", | |
187, | |
google::CheckOpString(_result)) | |
.stream(); | |
} else { | |
detail::atomic_hash_spin_wait([&] { | |
return nextMapIdx >= | |
numMapsAllocated_.load(std::memory_order_acquire); | |
}); | |
} | |
SubMap* loadedMap = subMaps_[nextMapIdx].load(std::memory_order_relaxed); | |
static_cast<void>(0), | |
!((__builtin_expect( | |
!(loadedMap && loadedMap != (SubMap*)kLockedPtr_), 0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/" | |
"AtomicHashMap-inl.h", | |
200) | |
.stream() | |
<< "Check failed: " | |
"loadedMap && loadedMap != " | |
"(SubMap*)kLockedPtr_" | |
" "; | |
ret = loadedMap->insertInternal(key, std::forward<ArgTs>(vCtorArgs)...); | |
if (ret.idx != loadedMap->capacity_) { | |
return SimpleRetT(nextMapIdx, ret.idx, ret.success); | |
} | |
goto beginInsertInternal; | |
} | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
template <class LookupKeyT, class LookupHashFcn, class LookupEqualFcn> | |
typename AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::iterator | |
AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::find(LookupKeyT k) { | |
SimpleRetT ret = findInternal<LookupKeyT, LookupHashFcn, LookupEqualFcn>(k); | |
if (!ret.success) { | |
return end(); | |
} | |
SubMap* subMap = subMaps_[ret.i].load(std::memory_order_relaxed); | |
return iterator(this, ret.i, subMap->makeIter(ret.j)); | |
} | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
template <class LookupKeyT, class LookupHashFcn, class LookupEqualFcn> | |
typename AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::const_iterator | |
AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::find(LookupKeyT k) const { | |
return const_cast<AtomicHashMap*>(this) | |
->find<LookupKeyT, LookupHashFcn, LookupEqualFcn>(k); | |
} | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
template <class LookupKeyT, class LookupHashFcn, class LookupEqualFcn> | |
typename AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::SimpleRetT | |
AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::findInternal(const LookupKeyT k) const { | |
SubMap* const primaryMap = subMaps_[0].load(std::memory_order_relaxed); | |
typename SubMap::SimpleRetT ret = | |
primaryMap->template findInternal<LookupKeyT, | |
LookupHashFcn, | |
LookupEqualFcn>(k); | |
if ((__builtin_expect((ret.idx != primaryMap->capacity_), 1))) { | |
return SimpleRetT(0, ret.idx, ret.success); | |
} | |
const unsigned int numMaps = | |
numMapsAllocated_.load(std::memory_order_acquire); | |
for (auto i = (true ? (1) : (numMaps)); | |
::folly::detail::notThereYet(i, (numMaps)); | |
++i) { | |
SubMap* thisMap = subMaps_[i].load(std::memory_order_relaxed); | |
ret = thisMap->template findInternal<LookupKeyT, | |
LookupHashFcn, | |
LookupEqualFcn>(k); | |
if ((__builtin_expect((ret.idx != thisMap->capacity_), 1))) { | |
return SimpleRetT(i, ret.idx, ret.success); | |
} | |
} | |
return SimpleRetT(numMaps, 0, false); | |
} | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
typename AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::SimpleRetT | |
AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::findAtInternal(uint32_t idx) const { | |
uint32_t subMapIdx, subMapOffset; | |
if (idx & kSecondaryMapBit_) { | |
idx &= ~kSecondaryMapBit_; | |
subMapIdx = idx >> kSubMapIndexShift_; | |
while (google::_Check_string* _result = google::Check_LTImpl( | |
google::GetReferenceableValue(subMapIdx), | |
google::GetReferenceableValue(numMapsAllocated_.load( | |
std::memory_order_relaxed)), | |
"subMapIdx" | |
" " | |
"<" | |
" " | |
"numMapsAllocated_.load(std::memory_order_relaxed)")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashMap-inl.h", | |
353, | |
google::CheckOpString(_result)) | |
.stream(); | |
subMapOffset = idx & kSubMapIndexMask_; | |
} else { | |
subMapIdx = 0; | |
subMapOffset = idx; | |
} | |
return SimpleRetT(subMapIdx, subMapOffset, true); | |
} | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
typename AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::size_type | |
AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::erase(const KeyT k) { | |
int const numMaps = numMapsAllocated_.load(std::memory_order_acquire); | |
for (auto i = (true ? (0) : (numMaps)); | |
::folly::detail::notThereYet(i, (numMaps)); | |
++i) { | |
if (subMaps_[i].load(std::memory_order_relaxed)->erase(k)) { | |
return 1; | |
} | |
} | |
return 0; | |
} | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
size_t AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::capacity() const { | |
size_t totalCap(0); | |
int const numMaps = numMapsAllocated_.load(std::memory_order_acquire); | |
for (auto i = (true ? (0) : (numMaps)); | |
::folly::detail::notThereYet(i, (numMaps)); | |
++i) { | |
totalCap += subMaps_[i].load(std::memory_order_relaxed)->capacity_; | |
} | |
return totalCap; | |
} | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
size_t AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::spaceRemaining() const { | |
size_t spaceRem(0); | |
int const numMaps = numMapsAllocated_.load(std::memory_order_acquire); | |
for (auto i = (true ? (0) : (numMaps)); | |
::folly::detail::notThereYet(i, (numMaps)); | |
++i) { | |
SubMap* thisMap = subMaps_[i].load(std::memory_order_relaxed); | |
spaceRem += std::max( | |
0, thisMap->maxEntries_ - &thisMap->numEntries_.readFull()); | |
} | |
return spaceRem; | |
} | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
void AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::clear() { | |
subMaps_[0].load(std::memory_order_relaxed)->clear(); | |
int const numMaps = numMapsAllocated_.load(std::memory_order_relaxed); | |
for (auto i = (true ? (1) : (numMaps)); | |
::folly::detail::notThereYet(i, (numMaps)); | |
++i) { | |
SubMap* thisMap = subMaps_[i].load(std::memory_order_relaxed); | |
static_cast<void>(0), | |
!((__builtin_expect(!(thisMap), 0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/" | |
"folly/AtomicHashMap-inl.h", | |
474) | |
.stream() | |
<< "Check failed: " | |
"thisMap" | |
" "; | |
SubMap::destroy(thisMap); | |
subMaps_[i].store(nullptr, std::memory_order_relaxed); | |
} | |
numMapsAllocated_.store(1, std::memory_order_relaxed); | |
} | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
size_t AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::size() const { | |
size_t totalSize(0); | |
int const numMaps = numMapsAllocated_.load(std::memory_order_acquire); | |
for (auto i = (true ? (0) : (numMaps)); | |
::folly::detail::notThereYet(i, (numMaps)); | |
++i) { | |
totalSize += subMaps_[i].load(std::memory_order_relaxed)->size(); | |
} | |
return totalSize; | |
} | |
// # 524 "tlm/deps/folly.exploded/include/folly/AtomicHashMap-inl.h" 3 4 | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
inline uint32_t AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::encodeIndex(uint32_t subMap, | |
uint32_t offset) { | |
while (google::_Check_string* _result = google::Check_EQImpl( | |
google::GetReferenceableValue(offset & kSecondaryMapBit_), | |
google::GetReferenceableValue(0), | |
"offset & kSecondaryMapBit_" | |
" " | |
"==" | |
" " | |
"0")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashMap-inl.h", | |
540, | |
google::CheckOpString(_result)) | |
.stream(); | |
if (subMap == 0) { | |
return offset; | |
} | |
while (google::_Check_string* _result = google::Check_EQImpl( | |
google::GetReferenceableValue(subMap >> kNumSubMapBits_), | |
google::GetReferenceableValue(0), | |
"subMap >> kNumSubMapBits_" | |
" " | |
"==" | |
" " | |
"0")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashMap-inl.h", | |
545, | |
google::CheckOpString(_result)) | |
.stream(); | |
while (google::_Check_string* _result = google::Check_EQImpl( | |
google::GetReferenceableValue( | |
offset & (~kSubMapIndexMask_ | kSecondaryMapBit_)), | |
google::GetReferenceableValue(0), | |
"offset & (~kSubMapIndexMask_ | kSecondaryMapBit_)" | |
" " | |
"==" | |
" " | |
"0")) | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/folly/AtomicHashMap-inl.h", | |
547, | |
google::CheckOpString(_result)) | |
.stream(); | |
return offset | (subMap << kSubMapIndexShift_) | kSecondaryMapBit_; | |
} | |
template <typename KeyT, | |
typename ValueT, | |
typename HashFcn, | |
typename EqualFcn, | |
typename Allocator, | |
typename ProbeFcn, | |
typename KeyConvertFcn> | |
template <class ContT, class IterVal, class SubIt> | |
struct AtomicHashMap<KeyT, | |
ValueT, | |
HashFcn, | |
EqualFcn, | |
Allocator, | |
ProbeFcn, | |
KeyConvertFcn>::ahm_iterator | |
: detail::IteratorFacade<ahm_iterator<ContT, IterVal, SubIt>, | |
IterVal, | |
std::forward_iterator_tag> { | |
explicit ahm_iterator() : ahm_(nullptr) { | |
} | |
template <class OtherContT, class OtherVal, class OtherSubIt> | |
ahm_iterator(const ahm_iterator<OtherContT, OtherVal, OtherSubIt>& o, | |
typename std::enable_if< | |
std::is_convertible<OtherSubIt, SubIt>::value>::type* = | |
nullptr) | |
: ahm_(o.ahm_), subMap_(o.subMap_), subIt_(o.subIt_) { | |
} | |
uint32_t getIndex() const { | |
static_cast<void>(0), | |
!((__builtin_expect(!(!isEnd()), 0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/" | |
"folly/AtomicHashMap-inl.h", | |
593) | |
.stream() | |
<< "Check failed: " | |
"!isEnd()" | |
" "; | |
return ahm_->encodeIndex(subMap_, subIt_.getIndex()); | |
} | |
private: | |
friend class AtomicHashMap; | |
explicit ahm_iterator(ContT* ahm, uint32_t subMap, const SubIt& subIt) | |
: ahm_(ahm), subMap_(subMap), subIt_(subIt) { | |
} | |
friend class detail:: | |
IteratorFacade<ahm_iterator, IterVal, std::forward_iterator_tag>; | |
void increment() { | |
static_cast<void>(0), | |
!((__builtin_expect(!(!isEnd()), 0))) | |
? (void)0 | |
: google::LogMessageVoidify() & | |
google::LogMessageFatal( | |
"tlm/deps/folly.exploded/include/" | |
"folly/AtomicHashMap-inl.h", | |
606) | |
.stream() | |
<< "Check failed: " | |
"!isEnd()" | |
" "; | |
++subIt_; | |
checkAdvanceToNextSubmap(); | |
} | |
bool equal(const ahm_iterator& other) const { | |
if (ahm_ != other.ahm_) { | |
return false; | |
} | |
if (isEnd() || other.isEnd()) { | |
return isEnd() == other.isEnd(); | |
} | |
return subMap_ == other.subMap_ && subIt_ == other.subIt_; | |
} | |
IterVal& dereference() const { | |
return *subIt_; | |
} | |
bool isEnd() const { | |
return ahm_ == nullptr; | |
} | |
void checkAdvanceToNextSubmap() { | |
if (isEnd()) { | |
return; | |
} | |
SubMap* thisMap = | |
ahm_->subMaps_[subMap_].load(std::memory_order_relaxed); | |
while (subIt_ == thisMap->end()) { | |
if (subMap_ + 1 < | |
ahm_->numMapsAllocated_.load(std::memory_order_acquire)) { | |
++subMap_; | |
thisMap = | |
ahm_->subMaps_[subMap_].load(std::memory_order_relaxed); | |
subIt_ = thisMap->begin(); | |
} else { | |
ahm_ = nullptr; | |
return; | |
} | |
} | |
} | |
private: | |
ContT* ahm_; | |
uint32_t subMap_; | |
SubIt subIt_; | |
}; | |
} // namespace folly | |
// # 501 "tlm/deps/folly.exploded/include/folly/AtomicHashMap.h" 2 3 4 | |
// # 19 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/dcp/producer.cc" 2 | |
// # 20 "/mnt/Code/couchbase/docker/kv_engine/engines/ep/src/dcp/producer.cc" | |
void DcpProducer::bufferAcknowledgement(uint32_t opaque, Vbid vbucket) { | |
logger->warn("{}", vbucket); | |
} | |
void makeStreamsMap(size_t maxNumVBuckets) { | |
auto p = folly::AtomicHashArray<char, char>::create(maxNumVBuckets); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment