diff options
Diffstat (limited to 'third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat')
13 files changed, 2964 insertions, 0 deletions
diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/bit.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/bit.h new file mode 100644 index 000000000..1e9309417 --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/bit.h @@ -0,0 +1,185 @@ +// Copyright 2020 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_BIT_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_BIT_H_ + +#include <cstring> +#include <limits> + +#include "internal/bit.h" +#include "memory.h" +#include "version.h" + +#if __has_include(<bit>) && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#include <bit> + +#endif //__has_include(<bit>) && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +namespace cpp20 { + +#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::bit_cast; + +#else // Use builtin to provide constexpr bit_cast. + +#if defined(__has_builtin) && !defined(LIB_STDCOMPAT_NO_BUILTIN_BITCAST) +#if __has_builtin(__builtin_bit_cast) + +template <typename To, typename From> +constexpr std::enable_if_t<sizeof(To) == sizeof(From) && std::is_trivially_copyable<To>::value && + std::is_trivially_copyable<From>::value, + To> +bit_cast(const From& from) { + return __builtin_bit_cast(To, from); +} + +// Since there are two #if checks, using #else would require code duplication. +// Define a temporary internal macro to indicate that bit_cast was defined. +#define LIB_STDCOMPAT_BIT_CAST_DEFINED_ + +#endif // __has_builtin(__builtin_bit_cast) +#endif // defined(__has_builtin) && !defined(LIB_STDCOMPAT_NO_BUILTIN_BITCAST) + +// Use memcpy instead, not constexpr though. +#ifndef LIB_STDCOMPAT_BIT_CAST_DEFINED_ + +#define LIB_STDCOMPAT_NONCONSTEXPR_BITCAST 1 + +template <typename To, typename From> +std::enable_if_t<sizeof(To) == sizeof(From) && std::is_trivially_copyable<To>::value && + std::is_trivially_copyable<From>::value, + To> +bit_cast(const From& from) { + std::aligned_storage_t<sizeof(To)> uninitialized_to; + std::memcpy(static_cast<void*>(&uninitialized_to), + static_cast<const void*>(cpp17::addressof(from)), sizeof(To)); + return *reinterpret_cast<const To*>(&uninitialized_to); +} + +#endif // LIB_STDCOMPAT_BIT_CAST_DEFINED_ + +#undef LIB_STDCOMPAT_BIT_CAST_DEFINED_ + +#endif // __cpp_lib_bit_cast >= 201806L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#if defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::countl_one; +using std::countl_zero; +using std::countr_one; +using std::countr_zero; +using std::popcount; +using std::rotl; +using std::rotr; + +#else + +template <class T> +constexpr std::enable_if_t<std::is_unsigned<T>::value, int> countr_zero(T x) noexcept { + if (x == 0) { + return std::numeric_limits<T>::digits; + } + + return internal::count_zeros_from_right(x); +} + +template <class T> +constexpr std::enable_if_t<std::is_unsigned<T>::value, int> countl_zero(T x) noexcept { + if (x == 0) { + return std::numeric_limits<T>::digits; + } + + return internal::count_zeros_from_left(x); +} + +template <class T> +constexpr std::enable_if_t<std::is_unsigned<T>::value, int> countl_one(T x) noexcept { + return countl_zero(static_cast<T>(~x)); +} + +template <class T> +constexpr std::enable_if_t<std::is_unsigned<T>::value, int> countr_one(T x) noexcept { + return countr_zero(static_cast<T>(~x)); +} + +template <class T> +[[gnu::warn_unused_result]] constexpr std::enable_if_t<std::is_unsigned<T>::value, T> rotl( + T x, int s) noexcept { + return internal::rotl(x, s); +} + +template <class T> +[[gnu::warn_unused_result]] constexpr std::enable_if_t<std::is_unsigned<T>::value, T> rotr( + T x, int s) noexcept { + return internal::rotr(x, s); +} + +template <class T> +constexpr int popcount(T x) noexcept { + return internal::popcount(x); +} + +#endif + +#if defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::bit_ceil; +using std::bit_floor; +using std::bit_width; +using std::has_single_bit; + +#else // Provide polyfills for power of two bit functions. + +template <typename T> +constexpr std::enable_if_t<std::is_unsigned<T>::value, bool> has_single_bit(T value) { + return popcount(value) == static_cast<T>(1); +} + +template <typename T> +constexpr std::enable_if_t<std::is_unsigned<T>::value, T> bit_width(T value) { + return internal::bit_width(value); +} + +template <typename T> +constexpr std::enable_if_t<std::is_unsigned<T>::value, T> bit_ceil(T value) { + if (value <= 1) { + return T(1); + } + return internal::bit_ceil<T>(value); +} + +template <typename T> +constexpr std::enable_if_t<std::is_unsigned<T>::value, T> bit_floor(T value) { + if (value == 0) { + return 0; + } + return internal::bit_floor(value); +} + +#endif // __cpp_lib_int_pow2 >= 202002L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#if defined(__cpp_lib_endian) && __cpp_lib_endian >= 201907L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::endian; + +#else // Provide polyfill for endian enum. + +enum class endian { + little = 0x11771E, + big = 0xB16, + native = internal::native_endianess<little, big>(), +}; + +#endif + +} // namespace cpp20 + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_BIT_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/functional.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/functional.h new file mode 100644 index 000000000..34d44e0d5 --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/functional.h @@ -0,0 +1,50 @@ +// Copyright 2021 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_FUNCTIONAL_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_FUNCTIONAL_H_ + +#include "internal/functional.h" + +namespace cpp20 { + +// This version is always constexpr-qualified, with no other changes from C++17. + +#if defined(__cpp_lib_invoke) && defined(__cpp_lib_constexpr_functional) && \ + __cpp_lib_invoke >= 201411L && __cpp_lib_constexpr_functional >= 201907L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::invoke; + +#else // Provide invoke() polyfill + +template <typename F, typename... Args> +constexpr cpp17::invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) noexcept( + cpp17::is_nothrow_invocable_v<F, Args...>) { + return ::cpp17::internal::invoke(std::forward<F>(f), std::forward<Args>(args)...); +} + +#endif // __cpp_lib_invoke >= 201411L && __cpp_lib_constexpr_functional >= 201907L && + // !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#if defined(__cpp_lib_bind_front) && __cpp_lib_bind_front >= 201907L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::bind_front; + +#else // Provide bind_front() polyfill + +template <typename F, typename... Args> +constexpr ::cpp20::internal::front_binder_t<F, Args...> bind_front(F&& f, Args&&... args) noexcept( + cpp17::is_nothrow_constructible_v<::cpp20::internal::front_binder_t<F, Args...>, + cpp17::in_place_t, F, Args...>) { + return ::cpp20::internal::front_binder_t<F, Args...>(cpp17::in_place, std::forward<F>(f), + std::forward<Args>(args)...); +} + +#endif // __cpp_lib_bind_front >= 201907L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +} // namespace cpp20 + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_FUNCTIONAL_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/bit.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/bit.h new file mode 100644 index 000000000..92b33a633 --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/bit.h @@ -0,0 +1,230 @@ +// Copyright 2020 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_BIT_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_BIT_H_ + +#include <limits> +#include <type_traits> + +#include "../type_traits.h" + +namespace cpp20 { +namespace internal { + +// Helper for exclusing specific char types when char is considered unsigned by the compiler. +template <typename T> +struct is_bit_type + : std::integral_constant< + bool, std::is_unsigned<T>::value && !std::is_same<bool, T>::value && + !std::is_same<T, char>::value && !std::is_same<T, char16_t>::value && + !std::is_same<T, char32_t>::value && !std::is_same<T, wchar_t>::value> {}; + +// Rotation implementation. +// Only internal for usage in implementation of certain methods. +template <class T> +[[gnu::warn_unused_result]] constexpr std::enable_if_t<is_bit_type<T>::value, T> rotl( + T x, int s) noexcept { + const auto digits = std::numeric_limits<T>::digits; + const auto rotate_by = s % digits; + + if (rotate_by > 0) { + return static_cast<T>((x << rotate_by) | (x >> (digits - rotate_by))); + } + + if (rotate_by < 0) { + return static_cast<T>((x >> -rotate_by) | (x << (digits + rotate_by))); + } + + return x; +} + +template <class T> +[[gnu::warn_unused_result]] constexpr std::enable_if_t<is_bit_type<T>::value, T> rotr( + T x, int s) noexcept { + int digits = std::numeric_limits<T>::digits; + int rotate_by = s % digits; + + if (rotate_by > 0) { + return static_cast<T>((x >> rotate_by) | (x << (digits - rotate_by))); + } + + if (rotate_by < 0) { + return rotl(x, -rotate_by); + } + + return x; +} + +// Overloads for intrinsics. +// Precondition: |value| != 0. +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && sizeof(T) <= sizeof(unsigned), int> +count_zeros_from_right(T value) noexcept { + return __builtin_ctz(static_cast<unsigned>(value)); +} + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && sizeof(unsigned) < sizeof(T) && + sizeof(T) <= sizeof(unsigned long), + int> +count_zeros_from_right(T value) noexcept { + return __builtin_ctzl(static_cast<unsigned long>(value)); +} + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && sizeof(unsigned long) < sizeof(T) && + sizeof(T) <= sizeof(unsigned long long), + int> +count_zeros_from_right(T value) noexcept { + return __builtin_ctzll(static_cast<unsigned long long>(value)); +} + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && sizeof(unsigned long long) < sizeof(T), int> +count_zeros_from_right(T value) noexcept { + int count = 0; + int iter_count = 0; + const unsigned long long max_digits = std::numeric_limits<unsigned long long>::digits; + + for (int slot = 0; slot * max_digits < std::numeric_limits<T>::digits; ++slot) { + const unsigned long long chunk = + static_cast<unsigned long long>(internal::rotr(value, (slot)*max_digits)); + iter_count = (chunk == 0) ? static_cast<int>(max_digits) : count_zeros_from_right(chunk); + count += iter_count; + if (iter_count != max_digits) { + break; + } + } + return count - static_cast<int>(std::numeric_limits<T>::digits % max_digits); +} + +template <typename T, typename U, + typename std::enable_if<sizeof(T) >= sizeof(U), bool>::type = true> +struct digit_diff + : std::integral_constant<T, std::numeric_limits<T>::digits - std::numeric_limits<U>::digits> {}; + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && sizeof(T) <= sizeof(unsigned), int> +count_zeros_from_left(T value) noexcept { + return __builtin_clz(static_cast<unsigned>(value)) - + static_cast<int>(digit_diff<unsigned, T>::value); +} + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && sizeof(unsigned) < sizeof(T) && + sizeof(T) <= sizeof(unsigned long), + int> +count_zeros_from_left(T value) noexcept { + return __builtin_clzl(static_cast<unsigned long>(value)) - + static_cast<int>(digit_diff<unsigned long, T>::value); +} + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && sizeof(unsigned long) < sizeof(T) && + sizeof(T) <= sizeof(unsigned long long), + int> +count_zeros_from_left(T value) noexcept { + return __builtin_clzll(static_cast<unsigned long long>(value)) - + static_cast<int>(digit_diff<unsigned long long, T>::value); +} + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && sizeof(unsigned long long) < sizeof(T), int> +count_zeros_from_left(T value) noexcept { + int count = 0; + int iter_count = 0; + const unsigned int max_digits = std::numeric_limits<unsigned long long>::digits; + + for (int slot = 0; slot * max_digits < std::numeric_limits<T>::digits; ++slot) { + const unsigned long long chunk = + static_cast<unsigned long long>(internal::rotl(value, (slot + 1) * max_digits)); + iter_count = (chunk == 0) ? static_cast<int>(max_digits) : count_zeros_from_left(chunk); + count += iter_count; + if (iter_count != max_digits) { + break; + } + } + return count - static_cast<int>(std::numeric_limits<T>::digits % max_digits); +} + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && sizeof(T) <= sizeof(unsigned), int> popcount( + T value) noexcept { + return __builtin_popcount(static_cast<unsigned>(value)); +} + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && sizeof(unsigned) < sizeof(T) && + sizeof(T) <= sizeof(unsigned long), + int> +popcount(T value) noexcept { + return __builtin_popcountl(static_cast<unsigned long>(value)); +} + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && sizeof(unsigned long) < sizeof(T) && + sizeof(T) <= sizeof(unsigned long long), + int> +popcount(T value) noexcept { + return __builtin_popcountll(static_cast<unsigned long long>(value)); +} + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && sizeof(unsigned long long) < sizeof(T), int> +popcount(T value) noexcept { + int accumulated_count = 0; + while (value != 0) { + accumulated_count += popcount(static_cast<unsigned long long>(value)); + value >>= std::numeric_limits<unsigned long long>::digits; + } + return accumulated_count; +} + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value, T> bit_width(T value) { + const T zeros_left = + (value == 0) ? std::numeric_limits<T>::digits : static_cast<T>(count_zeros_from_left(value)); + return std::numeric_limits<T>::digits - zeros_left; +} + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && !std::is_same<T, decltype(+T())>::value, T> +bit_ceil(T value) { + unsigned ub_offset = std::numeric_limits<unsigned>::digits - std::numeric_limits<T>::digits; + return static_cast<T>(1 << (bit_width(static_cast<T>(value - 1)) + ub_offset) >> ub_offset); +} + +// When there is no integer promotion. +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value && std::is_same<T, decltype(+T())>::value, T> +bit_ceil(T value) { + auto width = bit_width(value - 1); + if (!cpp20::is_constant_evaluated() && width == std::numeric_limits<T>::digits) { + __builtin_abort(); + } + return static_cast<T>(1) << width; +} + +template <typename T> +constexpr std::enable_if_t<is_bit_type<T>::value, T> bit_floor(T value) { + return static_cast<T>(T(1) << (bit_width(value) - T(1))); +} + +template <unsigned little, unsigned big> +constexpr unsigned native_endianess() { + auto curr = __BYTE_ORDER__; + if (curr == __ORDER_LITTLE_ENDIAN__) { + return little; + } + if (curr == __ORDER_BIG_ENDIAN__) { + return big; + } + return 0x404; +} + +} // namespace internal +} // namespace cpp20 + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_BIT_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/constructors.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/constructors.h new file mode 100644 index 000000000..e86f2f108 --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/constructors.h @@ -0,0 +1,100 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_CONSTRUCTORS_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_CONSTRUCTORS_H_ + +#include <cstddef> +#include <type_traits> +#include <utility> + +namespace cpp17 { +namespace internal { + +// Mixin that implicitly deletes the subclass default constructor when type T +// is not default constructible. +template <typename T, bool = std::is_default_constructible<T>::value> +struct modulate_default_constructor {}; +template <typename T> +struct modulate_default_constructor<T, false> { + constexpr modulate_default_constructor() = delete; +}; + +// Mixin that implicitly deletes the subclass copy constructor when type T is +// not copy constructible. +template <std::size_t Index, typename T, bool = std::is_copy_constructible<T>::value> +struct modulate_copy_constructor {}; +template <std::size_t Index, typename T> +struct modulate_copy_constructor<Index, T, false> { + constexpr modulate_copy_constructor() = default; + constexpr modulate_copy_constructor(const modulate_copy_constructor&) = delete; + constexpr modulate_copy_constructor& operator=(const modulate_copy_constructor&) = default; + constexpr modulate_copy_constructor(modulate_copy_constructor&&) = default; + constexpr modulate_copy_constructor& operator=(modulate_copy_constructor&&) = default; +}; + +// Mixin that implicitly deletes the subclass copy assignment operator when type +// T is not copy assignable. +template <std::size_t Index, typename T, bool = std::is_copy_assignable<T>::value> +struct modulate_copy_assignment {}; +template <std::size_t Index, typename T> +struct modulate_copy_assignment<Index, T, false> { + constexpr modulate_copy_assignment() = default; + constexpr modulate_copy_assignment(const modulate_copy_assignment&) = default; + constexpr modulate_copy_assignment& operator=(const modulate_copy_assignment&) = delete; + constexpr modulate_copy_assignment(modulate_copy_assignment&&) = default; + constexpr modulate_copy_assignment& operator=(modulate_copy_assignment&&) = default; +}; + +// Mixin that implicitly deletes the subclass move constructor when type T is +// not move constructible. +template <std::size_t Index, typename T, bool = std::is_move_constructible<T>::value> +struct modulate_move_constructor {}; +template <std::size_t Index, typename T> +struct modulate_move_constructor<Index, T, false> { + constexpr modulate_move_constructor() = default; + constexpr modulate_move_constructor(const modulate_move_constructor&) = default; + constexpr modulate_move_constructor& operator=(const modulate_move_constructor&) = default; + constexpr modulate_move_constructor(modulate_move_constructor&&) = delete; + constexpr modulate_move_constructor& operator=(modulate_move_constructor&&) = default; +}; + +// Mixin that implicitly deletes the subclass move assignment operator when type +// T is not move assignable. +template <std::size_t Index, typename T, bool = std::is_move_assignable<T>::value> +struct modulate_move_assignment {}; +template <std::size_t Index, typename T> +struct modulate_move_assignment<Index, T, false> { + constexpr modulate_move_assignment() = default; + constexpr modulate_move_assignment(const modulate_move_assignment&) = default; + constexpr modulate_move_assignment& operator=(const modulate_move_assignment&) = default; + constexpr modulate_move_assignment(modulate_move_assignment&&) = default; + constexpr modulate_move_assignment& operator=(modulate_move_assignment&&) = delete; +}; + +// Utility that takes an index sequence and an equally sized parameter pack and +// mixes in each of the above copy/move construction/assignment modulators for +// each type in Ts. The indices are used to avoid duplicate direct base errors +// by ensuring that each mixin type is unique, even when there are duplicate +// types within the parameter pack Ts. +template <typename IndexSequence, typename... Ts> +struct modulate_copy_and_move_index; + +template <std::size_t... Is, typename... Ts> +struct modulate_copy_and_move_index<std::index_sequence<Is...>, Ts...> + : modulate_copy_constructor<Is, Ts>..., + modulate_copy_assignment<Is, Ts>..., + modulate_move_constructor<Is, Ts>..., + modulate_move_assignment<Is, Ts>... {}; + +// Mixin that modulates the subclass copy/move constructors and assignment +// operators based on the copy/move characteristics of each type in Ts. +template <typename... Ts> +struct modulate_copy_and_move + : modulate_copy_and_move_index<std::index_sequence_for<Ts...>, Ts...> {}; + +} // namespace internal +} // namespace cpp17 + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_CONSTRUCTORS_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/exception.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/exception.h new file mode 100644 index 000000000..74f4e8c08 --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/exception.h @@ -0,0 +1,56 @@ +// Copyright 2021 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_EXCEPTION_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_EXCEPTION_H_ + +#include <exception> + +#include "../type_traits.h" + +namespace cpp17 { +namespace internal { + +// When exceptions are enabled, will generate an exception of the right type, when disabled will +// simply abort execution. +// +// Note: both clang and gcc support gnu::unused, which makes it a portable alternative for +// [[maybe_unused]]. +template <typename T, + typename std::enable_if<std::is_base_of<std::exception, T>::value, bool>::type = true> +[[noreturn]] inline constexpr void throw_or_abort([[gnu::unused]] const char* reason) { +#if defined(__cpp_exceptions) && __cpp_exceptions >= 199711L + throw T(reason); +#else + __builtin_abort(); +#endif +} + +template <typename T> +inline constexpr void throw_or_abort_if_any_impl(const char* reason, bool should_abort) { + if (should_abort) { + throw_or_abort<T>(reason); + } +} + +template <typename T, typename... AbortIf> +inline constexpr void throw_or_abort_if_any_impl(const char* reason, bool head, AbortIf... tail) { + if (head) { + throw_or_abort<T>(reason); + } + throw_or_abort_if_any_impl<T>(reason, tail...); +} + +template <typename T, typename... AbortIf> +inline constexpr void throw_or_abort_if_any(const char* reason, AbortIf... abort_if) { + static_assert(sizeof...(AbortIf) > 0, "Must provide an |abort_if| clause."); + static_assert(cpp17::conjunction_v<std::is_same<bool, AbortIf>...>, + "|abort_if| arguments must be boolean."); + throw_or_abort_if_any_impl<T>(reason, abort_if...); +} + +} // namespace internal +} // namespace cpp17 + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_EXCEPTION_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/storage.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/storage.h new file mode 100644 index 000000000..16c64d559 --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/storage.h @@ -0,0 +1,847 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_STORAGE_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_STORAGE_H_ + +#include <cstddef> +#include <cstdint> +#include <limits> +#include <type_traits> + +#include "utility.h" + +namespace cpp17 { +namespace internal { + +// Type tag to select overloads based on type T. +template <typename T> +struct type_tag { + using type = T; +}; + +// Type tag to select overloads based on index Index. +template <std::size_t Index> +struct index_tag { + static constexpr std::size_t index = Index; +}; + +// Type tag to select trivial initialization. +enum trivial_init_t { trivial_init_v }; + +// Type tag to select default initialization. +enum default_init_t { default_init_v }; + +// Type tag to select conditional initialization. +enum maybe_init_t { maybe_init_v }; + +// Represents the pair (T, Index) in the type system. +template <typename T, std::size_t Index> +struct type_index {}; + +// Represents whether a type is trivially/non-trivially destructible. +enum class destructor_class { + trivial, + non_trivial, +}; + +// Represents whether a type is trivially/non-trivially copyable. +enum class copy_class { + trivial, + non_trivial, +}; + +// Represents whether a type is trivially/non-trivially movable. +enum class move_class { + trivial, + non_trivial, +}; + +// Represents the full complement of move/copy/destruct classes for a type. +template <destructor_class DestructorClass, copy_class CopyClass, move_class MoveClass> +struct storage_class {}; + +template <typename... Ts> +using make_storage_class = + storage_class<is_trivially_destructible_v<Ts...> ? destructor_class::trivial + : destructor_class::non_trivial, + is_trivially_copyable_v<Ts...> ? copy_class::trivial : copy_class::non_trivial, + is_trivially_movable_v<Ts...> ? move_class::trivial : move_class::non_trivial>; + +// A trivial type for the empty alternative of union-based storage. +struct empty_type {}; + +// Index type used to track the active variant. Tracking uses zero-based +// indices. Empty is denoted by the maximum representable value. +using index_type = std::size_t; + +// Index denoting that no user-specified variant is active. Take care not to +// ODR-use this value. +constexpr index_type empty_index = std::numeric_limits<index_type>::max(); + +#ifdef NDEBUG +#define LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT __builtin_unreachable +#else +#define LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT __builtin_abort +#endif + +// Base type for lazy-initialized union storage types. This type implements a +// recursive union of the element types in Ts. Specializations handle the +// recursive and terminal cases, and the different storage requirements for +// trivially/non-trivially destructible types. +template <destructor_class, typename...> +union storage_base; + +// Non-trivial terminal case. +template <> +union storage_base<destructor_class::non_trivial, type_index<empty_type, empty_index>> { + storage_base() : empty{} {} + + template <typename... Args> + storage_base(type_tag<empty_type>, Args&&...) : empty{} {} + template <typename... Args> + storage_base(index_tag<empty_index>, Args&&...) : empty{} {} + + // Non-trivial destructor. + ~storage_base() {} + + storage_base(const storage_base&) = default; + storage_base(storage_base&&) = default; + storage_base& operator=(const storage_base&) = default; + storage_base& operator=(storage_base&&) = default; + + void construct_at(std::size_t index, const storage_base&) { + if (index == empty_index) { + new (&empty) empty_type{}; + } else { + LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT(); + } + } + void construct_at(std::size_t index, storage_base&&) { + if (index == empty_index) { + new (&empty) empty_type{}; + } else { + LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT(); + } + } + + void assign_at(std::size_t index, const storage_base& other) { + if (index == empty_index) { + empty = other.empty; + } else { + LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT(); + } + } + void assign_at(std::size_t index, storage_base&& other) { + if (index == empty_index) { + empty = std::move(other.empty); + } else { + LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT(); + } + } + + void swap_at(std::size_t index, storage_base& other) { + if (index == empty_index) { + using std::swap; + swap(empty, other.empty); + } else { + LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT(); + } + } + + template <typename... Args> + std::size_t construct(type_tag<empty_type>, Args&&...) { + new (&empty) empty_type{}; + return empty_index; + } + template <typename... Args> + std::size_t construct(index_tag<empty_index>, Args&&...) { + new (&empty) empty_type{}; + return empty_index; + } + + void reset(std::size_t index) { + if (index == empty_index) { + empty.empty_type::~empty_type(); + } else { + LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT(); + } + } + + empty_type& get(type_tag<empty_type>) { return empty; } + const empty_type& get(type_tag<empty_type>) const { return empty; } + empty_type& get(index_tag<empty_index>) { return empty; } + const empty_type& get(index_tag<empty_index>) const { return empty; } + + std::size_t index(type_tag<empty_type>) const { return empty_index; } + + template <typename V> + bool visit(std::size_t, V&&) { + return false; + } + template <typename V> + bool visit(std::size_t, V&&) const { + return false; + } + + empty_type empty; +}; + +// Trivial terminal case. +template <> +union storage_base<destructor_class::trivial, type_index<empty_type, empty_index>> { + constexpr storage_base() : empty{} {} + + template <typename... Args> + constexpr storage_base(type_tag<empty_type>, Args&&...) : empty{} {} + template <typename... Args> + constexpr storage_base(index_tag<empty_index>, Args&&...) : empty{} {} + + // Trivial destructor. + ~storage_base() = default; + + constexpr storage_base(const storage_base&) = default; + constexpr storage_base(storage_base&&) = default; + constexpr storage_base& operator=(const storage_base&) = default; + constexpr storage_base& operator=(storage_base&&) = default; + + constexpr void construct_at(std::size_t index, const storage_base&) { + if (index == empty_index) { + new (&empty) empty_type{}; + } else { + LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT(); + } + } + constexpr void construct_at(std::size_t index, storage_base&&) { + if (index == empty_index) { + new (&empty) empty_type{}; + } else { + LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT(); + } + } + + constexpr void assign_at(std::size_t index, const storage_base& other) { + if (index == empty_index) { + empty = other.empty; + } else { + LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT(); + } + } + constexpr void assign_at(std::size_t index, storage_base&& other) { + if (index == empty_index) { + empty = std::move(other.empty); + } else { + LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT(); + } + } + + constexpr void swap_at(std::size_t index, storage_base& other) { + if (index == empty_index) { + using std::swap; + swap(empty, other.empty); + } else { + LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT(); + } + } + + template <typename... Args> + constexpr std::size_t construct(type_tag<empty_type>, Args&&...) { + new (&empty) empty_type{}; + return empty_index; + } + template <typename... Args> + constexpr std::size_t construct(index_tag<empty_index>, Args&&...) { + new (&empty) empty_type{}; + return empty_index; + } + + constexpr void reset(std::size_t index) { + if (index == empty_index) { + empty.empty_type::~empty_type(); + } else { + LIB_STDCOMPAT_INTERNAL_UNREACHABLE_OR_ABORT(); + } + } + + constexpr empty_type& get(type_tag<empty_type>) { return empty; } + constexpr const empty_type& get(type_tag<empty_type>) const { return empty; } + constexpr empty_type& get(index_tag<empty_index>) { return empty; } + constexpr const empty_type& get(index_tag<empty_index>) const { return empty; } + + constexpr std::size_t index(type_tag<empty_type>) const { return empty_index; } + + template <typename V> + constexpr bool visit(std::size_t, V&&) { + return false; + } + template <typename V> + constexpr bool visit(std::size_t, V&&) const { + return false; + } + + empty_type empty; +}; + +template <typename T, std::size_t Index, typename... Ts, std::size_t... Is> +union storage_base<destructor_class::non_trivial, type_index<T, Index>, type_index<Ts, Is>...> { + storage_base() : empty{} {} + + template <typename... Args> + storage_base(type_tag<T>, Args&&... args) : value(std::forward<Args>(args)...) {} + template <typename... Args> + storage_base(index_tag<Index>, Args&&... args) : value(std::forward<Args>(args)...) {} + + template <typename U, typename... Args> + storage_base(type_tag<U>, Args&&... args) : rest(type_tag<U>{}, std::forward<Args>(args)...) {} + template <std::size_t OtherIndex, typename... Args> + storage_base(index_tag<OtherIndex>, Args&&... args) + : rest(index_tag<OtherIndex>{}, std::forward<Args>(args)...) {} + + // Non-trivial destructor. + ~storage_base() {} + + // Trival copy/move construction and assignment. + storage_base(const storage_base&) = default; + storage_base(storage_base&&) = default; + storage_base& operator=(const storage_base&) = default; + storage_base& operator=(storage_base&&) = default; + + void construct_at(std::size_t index, const storage_base& other) { + if (index == Index) { + new (&value) T{other.value}; + } else { + rest.construct_at(index, other.rest); + } + } + void construct_at(std::size_t index, storage_base&& other) { + if (index == Index) { + new (&value) T{std::move(other.value)}; + } else { + rest.construct_at(index, std::move(other.rest)); + } + } + + void assign_at(std::size_t index, const storage_base& other) { + if (index == Index) { + value = other.value; + } else { + rest.assign_at(index, other.rest); + } + } + void assign_at(std::size_t index, storage_base&& other) { + if (index == Index) { + value = std::move(other.value); + } else { + rest.assign_at(index, std::move(other.rest)); + } + } + + void swap_at(std::size_t index, storage_base& other) { + if (index == Index) { + using std::swap; + swap(value, other.value); + } else { + rest.swap_at(index, other.rest); + } + } + + template <typename... Args> + std::size_t construct(type_tag<T>, Args&&... args) { + new (&value) T(std::forward<Args>(args)...); + return Index; + } + template <typename U, typename... Args> + std::size_t construct(type_tag<U>, Args&&... args) { + return rest.construct(type_tag<U>{}, std::forward<Args>(args)...); + } + template <typename... Args> + std::size_t construct(index_tag<Index>, Args&&... args) { + new (&value) T(std::forward<Args>(args)...); + return Index; + } + template <std::size_t OtherIndex, typename... Args> + std::size_t construct(index_tag<OtherIndex>, Args&&... args) { + return rest.construct(index_tag<OtherIndex>{}, std::forward<Args>(args)...); + } + + void reset(std::size_t index) { + if (index == Index) { + value.~T(); + } else { + rest.reset(index); + } + } + + T& get(type_tag<T>) { return value; } + const T& get(type_tag<T>) const { return value; } + template <typename U> + U& get(type_tag<U>) { + return rest.get(type_tag<U>{}); + } + template <typename U> + const U& get(type_tag<U>) const { + return rest.get(type_tag<U>{}); + } + T& get(index_tag<Index>) { return value; } + const T& get(index_tag<Index>) const { return value; } + template <std::size_t OtherIndex> + auto& get(index_tag<OtherIndex>) { + return rest.get(index_tag<OtherIndex>{}); + } + template <std::size_t OtherIndex> + const auto& get(index_tag<OtherIndex>) const { + return rest.get(index_tag<OtherIndex>{}); + } + + std::size_t index(type_tag<T>) const { return Index; } + template <typename U> + std::size_t index(type_tag<U>) const { + return rest.index(type_tag<U>{}); + } + + template <typename V> + bool visit(std::size_t index, V&& visitor) { + if (index == Index) { + std::forward<V>(visitor)(type_tag<T>{}, index_tag<Index>{}, this); + return true; + } else { + return rest.visit(index, std::forward<V>(visitor)); + } + } + template <typename V> + bool visit(std::size_t index, V&& visitor) const { + if (index == Index) { + std::forward<V>(visitor)(type_tag<T>{}, index_tag<Index>{}, this); + return true; + } else { + return rest.visit(index, std::forward<V>(visitor)); + } + } + + empty_type empty; + T value; + storage_base<destructor_class::non_trivial, type_index<Ts, Is>...> rest; +}; + +template <typename T, std::size_t Index, typename... Ts, std::size_t... Is> +union storage_base<destructor_class::trivial, type_index<T, Index>, type_index<Ts, Is>...> { + constexpr storage_base() : empty{} {} + + template <typename... Args> + constexpr storage_base(type_tag<T>, Args&&... args) : value(std::forward<Args>(args)...) {} + template <typename... Args> + constexpr storage_base(index_tag<Index>, Args&&... args) : value(std::forward<Args>(args)...) {} + + template <typename U, typename... Args> + constexpr storage_base(type_tag<U>, Args&&... args) + : rest(type_tag<U>{}, std::forward<Args>(args)...) {} + template <std::size_t OtherIndex, typename... Args> + constexpr storage_base(index_tag<OtherIndex>, Args&&... args) + : rest(index_tag<OtherIndex>{}, std::forward<Args>(args)...) {} + + // Trivial destructor. + ~storage_base() = default; + + // Trival copy/move construction and assignment. + constexpr storage_base(const storage_base&) = default; + constexpr storage_base(storage_base&&) = default; + constexpr storage_base& operator=(const storage_base&) = default; + constexpr storage_base& operator=(storage_base&&) = default; + + constexpr void construct_at(std::size_t index, const storage_base& other) { + if (index == Index) { + new (&value) T{other.value}; + } else { + rest.construct_at(index, other.rest); + } + } + constexpr void construct_at(std::size_t index, storage_base&& other) { + if (index == Index) { + new (&value) T{std::move(other.value)}; + } else { + rest.construct_at(index, std::move(other.rest)); + } + } + + constexpr void assign_at(std::size_t index, const storage_base& other) { + if (index == Index) { + value = other.value; + } else { + rest.assign_at(index, other.rest); + } + } + constexpr void assign_at(std::size_t index, storage_base&& other) { + if (index == Index) { + value = std::move(other.value); + } else { + rest.assign_at(index, std::move(other.rest)); + } + } + + constexpr void swap_at(std::size_t index, storage_base& other) { + if (index == Index) { + using std::swap; + swap(value, other.value); + } else { + rest.swap_at(index, other.rest); + } + } + + template <typename... Args> + constexpr std::size_t construct(type_tag<T>, Args&&... args) { + new (&value) T(std::forward<Args>(args)...); + return Index; + } + template <typename U, typename... Args> + constexpr std::size_t construct(type_tag<U>, Args&&... args) { + return rest.construct(type_tag<U>{}, std::forward<Args>(args)...); + } + template <typename... Args> + constexpr std::size_t construct(index_tag<Index>, Args&&... args) { + new (&value) T(std::forward<Args>(args)...); + return Index; + } + template <std::size_t OtherIndex, typename... Args> + constexpr std::size_t construct(index_tag<OtherIndex>, Args&&... args) { + return rest.construct(index_tag<OtherIndex>{}, std::forward<Args>(args)...); + } + + constexpr void reset(std::size_t) {} + + constexpr T& get(type_tag<T>) { return value; } + constexpr const T& get(type_tag<T>) const { return value; } + template <typename U> + constexpr U& get(type_tag<U>) { + return rest.get(type_tag<U>{}); + } + template <typename U> + constexpr const U& get(type_tag<U>) const { + return rest.get(type_tag<U>{}); + } + constexpr T& get(index_tag<Index>) { return value; } + constexpr const T& get(index_tag<Index>) const { return value; } + template <std::size_t OtherIndex> + constexpr auto& get(index_tag<OtherIndex>) { + return rest.get(index_tag<OtherIndex>{}); + } + template <std::size_t OtherIndex> + constexpr const auto& get(index_tag<OtherIndex>) const { + return rest.get(index_tag<OtherIndex>{}); + } + + constexpr std::size_t index(type_tag<T>) const { return Index; } + template <typename U> + constexpr std::size_t index(type_tag<U>) const { + return rest.index(type_tag<U>{}); + } + + template <typename V> + constexpr bool visit(std::size_t index, V&& visitor) { + if (index == Index) { + std::forward<V>(visitor)(type_tag<T>{}, index_tag<Index>{}, this); + return true; + } else { + return rest.visit(index, std::forward<V>(visitor)); + } + } + template <typename V> + constexpr bool visit(std::size_t index, V&& visitor) const { + if (index == Index) { + std::forward<V>(visitor)(type_tag<T>{}, index_tag<Index>{}, this); + return true; + } else { + return rest.visit(index, std::forward<V>(visitor)); + } + } + + empty_type empty; + T value; + storage_base<destructor_class::trivial, type_index<Ts, Is>...> rest; +}; + +// Lazy-initialized union storage type that tracks the index of the active +// variant. +template <destructor_class, typename...> +class indexed_storage; + +template <destructor_class DestructorClass, typename... Ts, std::size_t... Is> +class indexed_storage<DestructorClass, type_index<Ts, Is>...> { + private: + using base_type = + storage_base<DestructorClass, type_index<Ts, Is>..., type_index<empty_type, empty_index>>; + + public: + static constexpr bool nothrow_default_constructible = + std::is_nothrow_default_constructible<first_t<Ts...>>::value; + static constexpr bool nothrow_move_constructible = + conjunction_v<std::is_nothrow_move_constructible<Ts>...>; + static constexpr bool nothrow_move_assignable = + conjunction_v<std::is_nothrow_move_assignable<Ts>...>; + + constexpr indexed_storage() = default; + + constexpr indexed_storage(trivial_init_t) : indexed_storage{} {} + + constexpr indexed_storage(default_init_t) : index_{0}, base_{index_tag<0>{}} {} + + // Only used by trivial copy/move types. + constexpr indexed_storage(const indexed_storage& other) = default; + constexpr indexed_storage& operator=(const indexed_storage& other) = default; + constexpr indexed_storage(indexed_storage&& other) = default; + constexpr indexed_storage& operator=(indexed_storage&& other) = default; + + template <typename T, typename... Args> + constexpr indexed_storage(type_tag<T>, Args&&... args) + : base_(type_tag<T>{}, std::forward<Args>(args)...) { + index_ = base_.index(type_tag<T>{}); + } + template <std::size_t Index, typename... Args> + constexpr indexed_storage(index_tag<Index>, Args&&... args) + : index_{Index}, base_(index_tag<Index>{}, std::forward<Args>(args)...) {} + + constexpr indexed_storage(maybe_init_t, const indexed_storage& other) + : index_{other.index()}, base_{} { + base_.construct_at(other.index(), other.base_); + } + constexpr indexed_storage(maybe_init_t, indexed_storage&& other) + : index_{other.index()}, base_{} { + base_.construct_at(other.index(), std::move(other.base_)); + } + + ~indexed_storage() = default; + + constexpr index_type index() const { return index_; } + constexpr bool is_empty() const { return index() == empty_index; } + template <typename T> + constexpr bool has_value(type_tag<T>) const { + return index() == base_.index(type_tag<T>{}); + } + template <std::size_t Index> + constexpr bool has_value(index_tag<Index>) const { + return index() == Index; + } + + template <typename T> + constexpr auto& get(type_tag<T>) { + return base_.get(type_tag<T>{}); + } + template <typename T> + constexpr const auto& get(type_tag<T>) const { + return base_.get(type_tag<T>{}); + } + template <std::size_t Index> + constexpr auto& get(index_tag<Index>) { + return base_.get(index_tag<Index>{}); + } + template <std::size_t Index> + constexpr const auto& get(index_tag<Index>) const { + return base_.get(index_tag<Index>{}); + } + + template <typename T, typename... Args> + constexpr void construct(type_tag<T>, Args&&... args) { + index_ = base_.construct(type_tag<T>{}, std::forward<Args>(args)...); + } + template <std::size_t Index, typename... Args> + constexpr void construct(index_tag<Index>, Args&&... args) { + index_ = base_.construct(index_tag<Index>{}, std::forward<Args>(args)...); + } + + constexpr void assign(const indexed_storage& other) { + if (index() == other.index()) { + base_.assign_at(index_, other.base_); + } else { + reset(); + base_.construct_at(other.index_, other.base_); + index_ = other.index_; + } + } + constexpr void assign(indexed_storage&& other) { + if (index() == other.index()) { + base_.assign_at(index_, std::move(other.base_)); + } else { + reset(); + base_.construct_at(other.index_, std::move(other.base_)); + index_ = other.index_; + } + } + + template <typename V> + constexpr bool visit(V&& visitor) { + return base_.visit(index_, std::forward<V>(visitor)); + } + template <typename V> + constexpr bool visit(V&& visitor) const { + return base_.visit(index_, std::forward<V>(visitor)); + } + + constexpr void swap(indexed_storage& other) { + if (index() == other.index()) { + // Swap directly when the variants are the same, including empty. + base_.swap_at(index_, other.base_); + } else { + // Swap when the variants are different, including one being empty. + // This approach avoids GCC -Wmaybe-uninitialized warnings by + // initializing and accessing |temp| unconditionally within a + // conditional scope. The alternative, using the maybe_init_t + // constructor confuses GCC because it doesn't understand that the + // index checks prevent uninitialized access. + auto do_swap = [](indexed_storage& a, indexed_storage& b) { + return a.base_.visit(a.index_, [&a, &b](auto, auto index_tag_v, auto* element) { + indexed_storage temp{index_tag_v, std::move(element->value)}; + a.reset(); + + a.base_.construct_at(b.index_, std::move(b.base_)); + a.index_ = b.index_; + b.reset(); + + b.base_.construct_at(temp.index_, std::move(temp.base_)); + b.index_ = temp.index_; + temp.reset(); + }); + }; + + // The visitor above returns false when the first argument is empty + // and no action is taken. In that case, the other order is tried to + // complete the half-empty swap. + do_swap(*this, other) || do_swap(other, *this); + } + } + + // Destroys the active variant. Does nothing when already empty. + constexpr void reset() { + base_.reset(index_); + index_ = empty_index; + } + + private: + index_type index_{empty_index}; + base_type base_; +}; + +// Internal variant storage type used by cpp17::optional and cpp17::variant. +// Specializations of this type select trivial vs. non-trivial copy/move +// construction, assignment operators, and destructor based on the storage class +// of the types in Ts. +template <typename StorageClass, typename... Ts> +struct storage; + +template <typename... Ts, std::size_t... Is> +struct storage<storage_class<destructor_class::trivial, copy_class::trivial, move_class::trivial>, + type_index<Ts, Is>...> + : indexed_storage<destructor_class::trivial, type_index<Ts, Is>...> { + using base_type = indexed_storage<destructor_class::trivial, type_index<Ts, Is>...>; + using base_type::base_type; + constexpr storage() = default; +}; + +template <typename... Ts, std::size_t... Is> +struct storage< + storage_class<destructor_class::trivial, copy_class::non_trivial, move_class::trivial>, + type_index<Ts, Is>...> : indexed_storage<destructor_class::trivial, type_index<Ts, Is>...> { + using base_type = indexed_storage<destructor_class::trivial, type_index<Ts, Is>...>; + using base_type::base_type; + + ~storage() = default; + constexpr storage() = default; + + constexpr storage(const storage& other) : base_type{maybe_init_v, other} {} + + constexpr storage& operator=(const storage& other) { + this->assign(other); + return *this; + } + + constexpr storage(storage&&) = default; + constexpr storage& operator=(storage&&) = default; +}; + +template <typename... Ts, std::size_t... Is> +struct storage< + storage_class<destructor_class::trivial, copy_class::trivial, move_class::non_trivial>, + type_index<Ts, Is>...> : indexed_storage<destructor_class::trivial, type_index<Ts, Is>...> { + using base_type = indexed_storage<destructor_class::trivial, type_index<Ts, Is>...>; + using base_type::base_type; + + ~storage() = default; + constexpr storage() = default; + constexpr storage(const storage&) = default; + constexpr storage& operator=(const storage&) = default; + + constexpr storage(storage&& other) noexcept(base_type::nothrow_move_constructible) + : base_type{maybe_init_v, std::move(other)} {} + + constexpr storage& operator=(storage&& other) noexcept(base_type::nothrow_move_assignable) { + this->assign(std::move(other)); + return *this; + } +}; + +template <typename... Ts, std::size_t... Is> +struct storage< + storage_class<destructor_class::trivial, copy_class::non_trivial, move_class::non_trivial>, + type_index<Ts, Is>...> : indexed_storage<destructor_class::trivial, type_index<Ts, Is>...> { + using base_type = indexed_storage<destructor_class::trivial, type_index<Ts, Is>...>; + using base_type::base_type; + + ~storage() = default; + constexpr storage() = default; + + constexpr storage(const storage& other) : base_type{maybe_init_v, other} {} + + constexpr storage& operator=(const storage& other) { + this->assign(other); + return *this; + } + + constexpr storage(storage&& other) noexcept(base_type::nothrow_move_constructible) + : base_type{maybe_init_v, std::move(other)} {} + + constexpr storage& operator=(storage&& other) noexcept(base_type::nothrow_move_assignable) { + this->assign(std::move(other)); + return *this; + } +}; + +// Specialization for non-trivially movable/copyable types. Types with a non- +// trivial destructor are always non-trivially movable/copyable. +template <copy_class CopyClass, move_class MoveClass, typename... Ts, std::size_t... Is> +struct storage<storage_class<destructor_class::non_trivial, CopyClass, MoveClass>, + type_index<Ts, Is>...> + : indexed_storage<destructor_class::non_trivial, type_index<Ts, Is>...> { + using base_type = indexed_storage<destructor_class::non_trivial, type_index<Ts, Is>...>; + using base_type::base_type; + + ~storage() { this->reset(); } + + constexpr storage() = default; + + constexpr storage(const storage& other) : base_type{maybe_init_v, other} {} + + constexpr storage& operator=(const storage& other) { + this->assign(other); + return *this; + } + + constexpr storage(storage&& other) noexcept(base_type::nothrow_move_constructible) + : base_type{maybe_init_v, std::move(other)} {} + + constexpr storage& operator=(storage&& other) noexcept(base_type::nothrow_move_assignable) { + this->assign(std::move(other)); + return *this; + } +}; + +template <typename... Ts, std::size_t... Is> +constexpr auto make_storage(std::index_sequence<Is...>) { + return storage<make_storage_class<Ts...>, type_index<Ts, Is>...>{}; +} + +template <typename... Ts> +using storage_type = decltype(make_storage<Ts...>(std::index_sequence_for<Ts...>{})); + +} // namespace internal +} // namespace cpp17 + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_STORAGE_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/type_traits.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/type_traits.h new file mode 100644 index 000000000..dced28d9f --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/type_traits.h @@ -0,0 +1,112 @@ +// Copyright 2021 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_TYPE_TRAITS_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_TYPE_TRAITS_H_ + +#include <type_traits> + +namespace cpp17 { +namespace internal { + +template <typename T> +static constexpr bool is_reference_wrapper = false; +template <typename T> +static constexpr bool is_reference_wrapper<std::reference_wrapper<T>> = true; + +// These are from [func.require] ΒΆ 1.1-7 +template <typename MemFn, typename Class, typename T> +static constexpr bool invoke_pmf_base = std::is_member_function_pointer<MemFn Class::*>::value&& + std::is_base_of<Class, std::remove_reference_t<T>>::value; + +template <typename MemFn, typename Class, typename T> +static constexpr bool invoke_pmf_refwrap = std::is_member_function_pointer<MemFn Class::*>::value&& + is_reference_wrapper<std::remove_cv_t<std::remove_reference_t<T>>>; + +template <typename MemFn, typename Class, typename T> +static constexpr bool invoke_pmf_other = + std::is_member_function_pointer<MemFn Class::*>::value && !invoke_pmf_base<MemFn, Class, T> && + !invoke_pmf_refwrap<MemFn, Class, T>; + +template <typename MemObj, typename Class, typename T> +static constexpr bool invoke_pmd_base = std::is_member_object_pointer<MemObj Class::*>::value&& + std::is_base_of<Class, std::remove_reference_t<T>>::value; + +template <typename MemObj, typename Class, typename T> +static constexpr bool invoke_pmd_refwrap = std::is_member_object_pointer<MemObj Class::*>::value&& + is_reference_wrapper<std::remove_cv_t<std::remove_reference_t<T>>>; + +template <typename MemObj, typename Class, typename T> +static constexpr bool invoke_pmd_other = + std::is_member_object_pointer<MemObj Class::*>::value && !invoke_pmd_base<MemObj, Class, T> && + !invoke_pmd_refwrap<MemObj, Class, T>; + +// ΒΆ 1.7 says to just return f(t1, t2, ..., tn) in all other cases + +// Just internal forward declarations for SFINAE; cpp20::invoke is defined in +// lib/stdcompat/functional.h +template <typename MemFn, typename Class, typename T, typename... Args> +constexpr auto invoke(MemFn Class::*f, T&& obj, Args&&... args) + -> std::enable_if_t<invoke_pmf_base<MemFn, Class, T>, + decltype((std::forward<T>(obj).*f)(std::forward<Args>(args)...))>; + +template <typename MemFn, typename Class, typename T, typename... Args> +constexpr auto invoke(MemFn Class::*f, T&& obj, Args&&... args) + -> std::enable_if_t<invoke_pmf_refwrap<MemFn, Class, T>, + decltype((obj.get().*f)(std::forward<Args>(args)...))>; + +template <typename MemFn, typename Class, typename T, typename... Args> +constexpr auto invoke(MemFn Class::*f, T&& obj, Args&&... args) + -> std::enable_if_t<invoke_pmf_other<MemFn, Class, T>, + decltype(((*std::forward<T>(obj)).*f)(std::forward<Args>(args)...))>; + +template <typename MemObj, typename Class, typename T> +constexpr auto invoke(MemObj Class::*f, T&& obj) + -> std::enable_if_t<invoke_pmd_base<MemObj, Class, T>, decltype(std::forward<T>(obj).*f)>; + +template <typename MemObj, typename Class, typename T> +constexpr auto invoke(MemObj Class::*f, T&& obj) + -> std::enable_if_t<invoke_pmd_refwrap<MemObj, Class, T>, decltype(obj.get().*f)>; + +template <typename MemObj, typename Class, typename T> +constexpr auto invoke(MemObj Class::*f, T&& obj) + -> std::enable_if_t<invoke_pmd_other<MemObj, Class, T>, decltype((*std::forward<T>(obj)).*f)>; + +template <typename F, typename... Args> +constexpr auto invoke(F&& f, Args&&... args) + -> decltype(std::forward<F>(f)(std::forward<Args>(args)...)); + +template <typename R, typename F, typename... Args, + typename = std::enable_if_t<std::is_void<R>::value>> +constexpr auto invoke_r(F&& f, Args&&... args) + -> decltype(static_cast<void>(::cpp17::internal::invoke(std::forward<F>(f), + std::forward<Args>(args)...))); + +template <typename R, typename F, typename... Args, + typename = std::enable_if_t<!std::is_void<R>::value>> +constexpr auto invoke_r(F&& f, Args&&... args) + -> std::enable_if_t<std::is_convertible<decltype(::cpp17::internal::invoke( + std::forward<F>(f), std::forward<Args>(args)...)), + R>::value, + R>; + +template <typename R, typename F, typename... Args> +constexpr auto is_valid_invoke(std::nullptr_t) + -> decltype(invoke_r<R>(std::declval<F>(), std::declval<Args>()...), std::true_type()); + +template <typename R, typename F, typename... Args> +constexpr std::false_type is_valid_invoke(...); + +template <bool Enable, typename F, typename... Args> +struct invoke_result {}; + +template <typename F, typename... Args> +struct invoke_result<true, F, Args...> { + using type = decltype(::cpp17::internal::invoke(std::declval<F>(), std::declval<Args>()...)); +}; + +} // namespace internal +} // namespace cpp17 + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_TYPE_TRAITS_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/utility.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/utility.h new file mode 100644 index 000000000..a5da381ae --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/utility.h @@ -0,0 +1,137 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_UTILITY_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_UTILITY_H_ + +#include <cstddef> +#include <utility> + +#include "../type_traits.h" + +namespace cpp17 { +namespace internal { + +template <typename Tag> +struct instantiate_templated_tag { + static constexpr const Tag storage{}; +}; + +template <typename Tag> +constexpr const Tag instantiate_templated_tag<Tag>::storage; + +template <typename T, typename ValueType, ValueType Value> +struct inline_storage { + static constexpr const ValueType storage{Value}; +}; + +template <typename T, typename ValueType, ValueType Value> +constexpr const ValueType inline_storage<T, ValueType, Value>::storage; + +// Utility to return the first type in a parameter pack. +template <typename... Ts> +struct first; +template <typename First, typename... Rest> +struct first<First, Rest...> { + using type = First; +}; + +template <typename... Ts> +using first_t = typename first<Ts...>::type; + +// Utility to count the occurences of type T in the parameter pack Ts. +template <typename T, typename... Ts> +struct occurences_of : std::integral_constant<std::size_t, 0> {}; +template <typename T, typename U> +struct occurences_of<T, U> : std::integral_constant<std::size_t, std::is_same<T, U>::value> {}; +template <typename T, typename First, typename... Rest> +struct occurences_of<T, First, Rest...> + : std::integral_constant<std::size_t, + occurences_of<T, First>::value + occurences_of<T, Rest...>::value> {}; + +template <typename T, typename... Ts> +constexpr std::size_t occurences_of_v = occurences_of<T, Ts...>::value; + +// Evaluates to truth-like when type T matches type U with cv-reference removed. +template <typename T, typename U> +using not_same_type = negation<std::is_same<T, ::cpp20::remove_cvref_t<U>>>; + +// Concept helper for constructors. +template <typename... Conditions> +using requires_conditions = std::enable_if_t<conjunction_v<Conditions...>, bool>; + +// Concept helper for assignment operators. +template <typename Return, typename... Conditions> +using assignment_requires_conditions = + std::enable_if_t<conjunction_v<Conditions...>, std::add_lvalue_reference_t<Return>>; + +// Evaluates to true when every element type of Ts is trivially destructible. +template <typename... Ts> +constexpr bool is_trivially_destructible_v = conjunction_v<std::is_trivially_destructible<Ts>...>; + +// Evaluates to true when every element type of Ts is trivially copyable. +template <typename... Ts> +constexpr bool is_trivially_copyable_v = + (conjunction_v<std::is_trivially_copy_assignable<Ts>...> && + conjunction_v<std::is_trivially_copy_constructible<Ts>...>); + +// Evaluates to true when every element type of Ts is trivially movable. +template <typename... Ts> +constexpr bool is_trivially_movable_v = + (conjunction_v<std::is_trivially_move_assignable<Ts>...> && + conjunction_v<std::is_trivially_move_constructible<Ts>...>); + +// Enable if relational operator is convertible to bool and the optional +// conditions are true. +template <typename Op, typename... Conditions> +using enable_relop_t = + std::enable_if_t<(std::is_convertible<Op, bool>::value && conjunction_v<Conditions...>), bool>; + +// Returns true when T is a complete type or an unbounded array. +template <typename T, std::size_t = sizeof(T)> +constexpr bool is_complete_or_unbounded_array(::cpp20::type_identity<T>) { + return true; +} +template <typename Identity, typename T = typename Identity::type> +constexpr bool is_complete_or_unbounded_array(Identity) { + return disjunction<std::is_reference<T>, std::is_function<T>, std::is_void<T>, + ::cpp20::is_unbounded_array<T>>::value; +} + +// Using swap for ADL. This directive is contained within the cpp17::internal +// namespace, which prevents leaking std::swap into user namespaces. Doing this +// at namespace scope is necessary to lookup swap via ADL while preserving the +// noexcept() specification of the resulting lookup. +using std::swap; + +// Evaluates to true when T is swappable. +template <typename T, typename = void> +struct is_swappable : std::false_type { + static_assert(is_complete_or_unbounded_array(::cpp20::type_identity<T>{}), + "T must be a complete type or an unbounded array!"); +}; +template <typename T> +struct is_swappable<T, void_t<decltype(swap(std::declval<T&>(), std::declval<T&>()))>> + : std::true_type { + static_assert(is_complete_or_unbounded_array(::cpp20::type_identity<T>{}), + "T must be a complete type or an unbounded array!"); +}; + +// Evaluates to true when T is nothrow swappable. +template <typename T, typename = void> +struct is_nothrow_swappable : std::false_type { + static_assert(is_complete_or_unbounded_array(::cpp20::type_identity<T>{}), + "T must be a complete type or an unbounded array!"); +}; +template <typename T> +struct is_nothrow_swappable<T, void_t<decltype(swap(std::declval<T&>(), std::declval<T&>()))>> + : std::integral_constant<bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))> { + static_assert(is_complete_or_unbounded_array(::cpp20::type_identity<T>{}), + "T must be a complete type or an unbounded array!"); +}; + +} // namespace internal +} // namespace cpp17 + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_UTILITY_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/memory.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/memory.h new file mode 100644 index 000000000..2dc3198a4 --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/memory.h @@ -0,0 +1,66 @@ +// Copyright 2020 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_MEMORY_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_MEMORY_H_ + +#include <memory> + +#include "version.h" + +namespace cpp17 { + +#if defined(__cpp_lib_addressof_constexpr) && __cpp_lib_addressof_constexpr >= 201603L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::addressof; + +#else // Provide constexpr polyfill for addressof. + +template <typename T> +constexpr T* addressof(T& arg) noexcept { + return __builtin_addressof(arg); +} + +template <typename T> +const T* addressof(const T&&) = delete; + +#endif // __cpp_lib_addressof_constexpr >= 201603L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +} // namespace cpp17 + +namespace cpp20 { + +#if defined(__cpp_lib_to_address) && __cpp_lib_to_address >= 201711L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::to_address; + +#else // Provide to_address polyfill. + +template <typename T> +constexpr T* to_address(T* pointer) noexcept { + static_assert(!std::is_function<T>::value, "Cannot pass function pointers to std::to_address()"); + return pointer; +} + +// TODO(fxbug.dev/70523): This std::pointer_traits stuff is only to be bug-compatible with the +// standard library implementations; switch back to auto when the linked bug is resolved. +template <typename T> +constexpr typename std::pointer_traits<T>::element_type* to_address(const T& pointer) noexcept { + static_assert( + std::is_same<decltype(pointer.operator->()), + typename std::pointer_traits<T>::element_type*>::value, + "For compatibility with libc++ and libstdc++, operator->() must return " + "typename std::pointer_traits<T>::element_type*. 'Chaining' operator->() in " + "cpp20::to_address() will not be permitted until https://fxbug.dev/70523 is resolved."); + + return to_address(pointer.operator->()); +} + +#endif // __cpp_lib_to_address >= 201711L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +} // namespace cpp20 + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_MEMORY_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/optional.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/optional.h new file mode 100644 index 000000000..bc6a421a0 --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/optional.h @@ -0,0 +1,475 @@ +// Copyright 2018 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_OPTIONAL_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_OPTIONAL_H_ + +#include "utility.h" +#include "version.h" + +#if defined(__cpp_lib_optional) && __cpp_lib_optional >= 201606L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#include <optional> + +namespace cpp17 { + +using std::bad_optional_access; +using std::make_optional; +using std::nullopt; +using std::nullopt_t; +using std::optional; + +} // namespace cpp17 + +#else // Provide std::optional and std::nullopt_t polyfill. + +#include <cstdlib> +#include <exception> +#include <new> + +#include "internal/constructors.h" +#include "internal/exception.h" +#include "internal/storage.h" +#include "internal/utility.h" +#include "type_traits.h" + +namespace cpp17 { + +// A sentinel value for indicating that it contains no value. +struct nullopt_t { + explicit constexpr nullopt_t(int) {} +}; +static constexpr nullopt_t nullopt{0}; + +// Exception type to report bad accesses to optional. +class bad_optional_access : public std::exception { + public: + bad_optional_access() noexcept {} + + const char* what() const noexcept override { return reason_; } + + private: + template <typename T> + friend class optional; + + bad_optional_access(const char* reason) noexcept : reason_{reason} {} + + // String describing the reason for the bad access. Must point to a string + // with static storage duration. + const char* reason_; + + template <typename T, + typename std::enable_if<std::is_base_of<std::exception, T>::value, bool>::type> + friend constexpr void cpp17::internal::throw_or_abort(const char*); +}; + +// A reasonably complete implementation of std::optional compatible with C++14. +template <typename T> +class optional : private ::cpp17::internal::modulate_copy_and_move<T> { + private: + // Helper types and values for SFINAE and noexcept rules. + static constexpr bool nothrow_move_constructible = std::is_nothrow_move_constructible<T>::value; + + static constexpr bool nothrow_swappable = std::is_nothrow_move_constructible<T>::value && + ::cpp17::internal::is_nothrow_swappable<T>::value; + + static constexpr auto trivial_init_v = ::cpp17::internal::trivial_init_v; + static constexpr auto maybe_init_v = ::cpp17::internal::maybe_init_v; + using type_tag = ::cpp17::internal::type_tag<T>; + + template <typename U, typename V> + using converts_from_optional = disjunction< + std::is_constructible<U, const optional<V>&>, std::is_constructible<U, optional<V>&>, + std::is_constructible<U, const optional<V>&&>, std::is_constructible<U, optional<V>&&>, + std::is_convertible<const optional<V>&, U>, std::is_convertible<optional<V>&, U>, + std::is_convertible<const optional<V>&&, U>, std::is_convertible<optional<V>&&, U>>; + + template <typename U, typename V> + using assigns_from_optional = + disjunction<std::is_assignable<U&, const optional<V>&>, std::is_assignable<U&, optional<V>&>, + std::is_assignable<U&, const optional<V>&&>, + std::is_assignable<U&, optional<V>&&>>; + + template <typename U> + using not_self_type = ::cpp17::internal::not_same_type<optional, U>; + + template <typename U> + using not_in_place = ::cpp17::internal::not_same_type<in_place_t, U>; + + template <typename... Conditions> + using requires_conditions = ::cpp17::internal::requires_conditions<Conditions...>; + + template <typename... Conditions> + using assignment_requires_conditions = + ::cpp17::internal::assignment_requires_conditions<optional&, Conditions...>; + + template <typename... Args> + using emplace_constructible = std::enable_if_t<std::is_constructible<T, Args...>::value, T&>; + + public: + using value_type = T; + + // Default constructors. + + constexpr optional() = default; + + constexpr optional(nullopt_t) noexcept {} + + // Copy/move constructors and assignment operators. + + constexpr optional(const optional&) = default; + constexpr optional& operator=(const optional&) = default; + + constexpr optional(optional&&) = default; + constexpr optional& operator=(optional&&) = default; + + // Converting constructors. + + template <typename U = T, + requires_conditions<not_self_type<U>, not_in_place<U>, std::is_constructible<T, U&&>, + std::is_convertible<U&&, T>> = true> + constexpr optional(U&& value) : storage_(type_tag{}, std::forward<U>(value)) {} + + template <typename U = T, + requires_conditions<not_self_type<U>, not_in_place<U>, std::is_constructible<T, U&&>, + negation<std::is_convertible<U&&, T>>> = false> + explicit constexpr optional(U&& value) : storage_{type_tag{}, std::forward<U>(value)} {} + + template <typename U, + requires_conditions<negation<std::is_same<T, U>>, std::is_constructible<T, const U&>, + std::is_convertible<const U&, T>, + negation<converts_from_optional<T, U>>> = true> + constexpr optional(const optional<U>& other) : storage_{maybe_init_v, other.storage_} {} + + template <typename U, + requires_conditions<negation<std::is_same<T, U>>, std::is_constructible<T, const U&>, + negation<std::is_convertible<const U&, T>>, + negation<converts_from_optional<T, U>>> = false> + explicit constexpr optional(const optional<U>& other) : storage_{maybe_init_v, other.storage_} {} + + template <typename U, + requires_conditions<negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, + std::is_convertible<U&&, T>, + negation<converts_from_optional<T, U>>> = true> + constexpr optional(optional<U>&& other) : storage_{maybe_init_v, std::move(other.storage_)} {} + + template <typename U, + requires_conditions<negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, + negation<std::is_convertible<U&&, T>>, + negation<converts_from_optional<T, U>>> = false> + explicit constexpr optional(optional<U>&& other) + : storage_{maybe_init_v, std::move(other.storage_)} {} + + template <typename... Args, requires_conditions<std::is_constructible<T, Args&&...>> = false> + explicit constexpr optional(in_place_t, Args&&... args) + : storage_(type_tag{}, std::forward<Args>(args)...) {} + + template < + typename U, typename... Args, + requires_conditions<std::is_constructible<T, std::initializer_list<U>&, Args&&...>> = false> + explicit constexpr optional(in_place_t, std::initializer_list<U> init_list, Args&&... args) + : storage_(type_tag{}, init_list, std::forward<Args>(args)...) {} + + // Destructor. + + ~optional() = default; + + // Checked accessors. + + constexpr T& value() & { + if (has_value()) { + return storage_.get(type_tag{}); + } + internal::throw_or_abort<bad_optional_access>("Accessed value of empty optional!"); + } + constexpr const T& value() const& { + if (has_value()) { + return storage_.get(type_tag{}); + } + internal::throw_or_abort<bad_optional_access>("Accessed value of empty optional!"); + } + constexpr T&& value() && { + if (has_value()) { + return std::move(storage_.get(type_tag{})); + } + internal::throw_or_abort<bad_optional_access>("Accessed value of empty optional!"); + } + constexpr const T&& value() const&& { + if (has_value()) { + return std::move(storage_.get(type_tag{})); + } + internal::throw_or_abort<bad_optional_access>("Accessed value of empty optional!"); + } + + template <typename U> + constexpr T value_or(U&& default_value) const& { + static_assert(std::is_copy_constructible<T>::value, + "value_or() requires copy-constructible value_type!"); + static_assert(std::is_convertible<U&&, T>::value, + "Default value must be convertible to value_type!"); + + return has_value() ? storage_.get(type_tag{}) : static_cast<T>(std::forward<U>(default_value)); + } + template <typename U> + constexpr T value_or(U&& default_value) && { + static_assert(std::is_move_constructible<T>::value, + "value_or() requires move-constructible value_type!"); + static_assert(std::is_convertible<U&&, T>::value, + "Default value must be convertible to value_type!"); + + return has_value() ? std::move(storage_.get(type_tag{})) + : static_cast<T>(std::forward<U>(default_value)); + } + + // Unchecked accessors. + + constexpr T* operator->() { return std::addressof(storage_.get(type_tag{})); } + constexpr const T* operator->() const { return std::addressof(storage_.get(type_tag{})); } + + constexpr T& operator*() { return storage_.get(type_tag{}); } + constexpr const T& operator*() const { return storage_.get(type_tag{}); } + + // Availability accessors/operators. + + constexpr bool has_value() const { return !storage_.is_empty(); } + constexpr explicit operator bool() const { return has_value(); } + + // Assignment operators. + + template <typename U> + constexpr assignment_requires_conditions< + not_self_type<U>, negation<conjunction<std::is_scalar<T>, std::is_same<T, std::decay_t<U>>>>, + std::is_constructible<T, U>, std::is_assignable<T&, U>> + operator=(U&& value) { + if (has_value()) { + storage_.get(type_tag{}) = std::forward<U>(value); + } else { + storage_.construct(type_tag{}, std::forward<U>(value)); + } + return *this; + } + + template <typename U> + constexpr assignment_requires_conditions< + negation<std::is_same<T, U>>, std::is_constructible<T, const U&>, std::is_assignable<T&, U>, + negation<converts_from_optional<T, U>>, negation<assigns_from_optional<T, U>>> + operator=(const optional<U>& other) { + storage_.assign(other.storage_); + return *this; + } + + template <typename U> + constexpr assignment_requires_conditions< + negation<std::is_same<T, U>>, std::is_constructible<T, U>, std::is_assignable<T&, U>, + negation<converts_from_optional<T, U>>, negation<assigns_from_optional<T, U>>> + operator=(optional<U>&& other) { + storage_.assign(std::move(other.storage_)); + return *this; + } + + constexpr optional& operator=(nullopt_t) { + storage_.reset(); + return *this; + } + + // Swap. + + constexpr void swap(optional& other) noexcept(nothrow_swappable) { + storage_.swap(other.storage_); + } + + // Emplacement. + + template <typename... Args> + constexpr emplace_constructible<Args&&...> emplace(Args&&... args) { + storage_.reset(); + storage_.construct(type_tag{}, std::forward<Args>(args)...); + return storage_.get(type_tag{}); + } + + template <typename U, typename... Args> + constexpr emplace_constructible<std::initializer_list<U>&, Args&&...> emplace( + std::initializer_list<U> init_list, Args&&... args) { + storage_.reset(); + storage_.construct(type_tag{}, init_list, std::forward<Args>(args)...); + return storage_.get(type_tag{}); + } + + // Reset. + + void reset() noexcept { storage_.reset(); } + + private: + ::cpp17::internal::storage_type<T> storage_; +}; + +// Swap. +template <typename T> +inline std::enable_if_t<(std::is_move_constructible<T>::value && + ::cpp17::internal::is_swappable<T>::value)> +swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) { + a.swap(b); +} +template <typename T> +inline std::enable_if_t<(!std::is_move_constructible<T>::value && + ::cpp17::internal::is_swappable<T>::value)> +swap(optional<T>& a, optional<T>& b) = delete; + +// Make optional. +template <typename T> +constexpr optional<std::decay_t<T>> make_optional(T&& value) { + return optional<std::decay_t<T>>{std::forward<T>(value)}; +} +template <typename T, typename... Args> +constexpr optional<T> make_optional(Args&&... args) { + return optional<T>{in_place, std::forward<Args>(args)...}; +} +template <typename T, typename U, typename... Args> +constexpr optional<T> make_optional(std::initializer_list<U> init_list, Args&&... args) { + return optional<T>{in_place, init_list, std::forward<Args>(args)...}; +} + +// Empty. +template <typename T> +constexpr bool operator==(const optional<T>& lhs, nullopt_t) { + return !lhs.has_value(); +} +template <typename T> +constexpr bool operator!=(const optional<T>& lhs, nullopt_t) { + return lhs.has_value(); +} + +template <typename T> +constexpr bool operator==(nullopt_t, const optional<T>& rhs) { + return !rhs.has_value(); +} +template <typename T> +constexpr bool operator!=(nullopt_t, const optional<T>& rhs) { + return rhs.has_value(); +} + +// Equal/not equal. +template < + typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() == std::declval<U>())> = true> +constexpr bool operator==(const optional<T>& lhs, const optional<U>& rhs) { + return (lhs.has_value() == rhs.has_value()) && (!lhs.has_value() || *lhs == *rhs); +} +template < + typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() != std::declval<U>())> = true> +constexpr bool operator!=(const optional<T>& lhs, const optional<U>& rhs) { + return (lhs.has_value() != rhs.has_value()) || (lhs.has_value() && *lhs != *rhs); +} + +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() == std::declval<U>()), + ::cpp17::internal::not_same_type<nullopt_t, U>> = true> +constexpr bool operator==(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() && *lhs == rhs; +} +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() != std::declval<U>()), + ::cpp17::internal::not_same_type<nullopt_t, U>> = true> +constexpr bool operator!=(const optional<T>& lhs, const U& rhs) { + return !lhs.has_value() || *lhs != rhs; +} + +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() == std::declval<U>()), + ::cpp17::internal::not_same_type<nullopt_t, T>> = true> +constexpr bool operator==(const T& lhs, const optional<U>& rhs) { + return rhs.has_value() && lhs == *rhs; +} +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() != std::declval<U>()), + ::cpp17::internal::not_same_type<nullopt_t, T>> = true> +constexpr bool operator!=(const T& lhs, const optional<U>& rhs) { + return !rhs.has_value() || lhs != *rhs; +} + +// Less than/greater than. +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() < std::declval<U>())> = true> +constexpr bool operator<(const optional<T>& lhs, const optional<U>& rhs) { + return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); +} +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() > std::declval<U>())> = true> +constexpr bool operator>(const optional<T>& lhs, const optional<U>& rhs) { + return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); +} + +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() < std::declval<U>()), + ::cpp17::internal::not_same_type<nullopt_t, U>> = true> +constexpr bool operator<(const optional<T>& lhs, const U& rhs) { + return !lhs.has_value() || *lhs < rhs; +} +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() > std::declval<U>()), + ::cpp17::internal::not_same_type<nullopt_t, U>> = true> +constexpr bool operator>(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() && *lhs > rhs; +} + +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() < std::declval<U>()), + ::cpp17::internal::not_same_type<nullopt_t, T>> = true> +constexpr bool operator<(const T& lhs, const optional<U>& rhs) { + return rhs.has_value() && lhs < *rhs; +} +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() > std::declval<U>()), + ::cpp17::internal::not_same_type<nullopt_t, T>> = true> +constexpr bool operator>(const T& lhs, const optional<U>& rhs) { + return !rhs.has_value() || lhs > *rhs; +} + +// Less than or equal/greater than or equal. +template < + typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() <= std::declval<U>())> = true> +constexpr bool operator<=(const optional<T>& lhs, const optional<U>& rhs) { + return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); +} +template < + typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() >= std::declval<U>())> = true> +constexpr bool operator>=(const optional<T>& lhs, const optional<U>& rhs) { + return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); +} + +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() <= std::declval<U>()), + ::cpp17::internal::not_same_type<nullopt_t, U>> = true> +constexpr bool operator<=(const optional<T>& lhs, const U& rhs) { + return !lhs.has_value() || *lhs <= rhs; +} +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() >= std::declval<U>()), + ::cpp17::internal::not_same_type<nullopt_t, U>> = true> +constexpr bool operator>=(const optional<T>& lhs, const U& rhs) { + return lhs.has_value() && *lhs >= rhs; +} + +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() <= std::declval<U>()), + ::cpp17::internal::not_same_type<nullopt_t, T>> = true> +constexpr bool operator<=(const T& lhs, const optional<U>& rhs) { + return rhs.has_value() && lhs <= *rhs; +} +template <typename T, typename U, + ::cpp17::internal::enable_relop_t<decltype(std::declval<T>() >= std::declval<U>()), + ::cpp17::internal::not_same_type<nullopt_t, T>> = true> +constexpr bool operator>=(const T& lhs, const optional<U>& rhs) { + return !rhs.has_value() || lhs >= *rhs; +} + +} // namespace cpp17 + +#endif + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_OPTIONAL_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/type_traits.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/type_traits.h new file mode 100644 index 000000000..8f0d80ede --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/type_traits.h @@ -0,0 +1,509 @@ +// Copyright 2018 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_TYPE_TRAITS_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_TYPE_TRAITS_H_ + +#include <cstddef> +#include <tuple> +#include <type_traits> + +#include "internal/type_traits.h" +#include "version.h" + +namespace cpp17 { + +#if defined(__cpp_lib_void_t) && __cpp_lib_void_t >= 201411L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) +using std::void_t; +#else // Provide std::void_t polyfill. +template <typename... T> +using void_t = void; +#endif // __cpp_lib_void_t >= 201411L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#if defined(__cpp_lib_logical_traits) && __cpp_lib_logical_traits >= 201510L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::conjunction; +using std::conjunction_v; +using std::disjunction; +using std::disjunction_v; +using std::negation; +using std::negation_v; + +#else // Provide polyfills for std::{negation, conjunction, disjunction} and the *_v helpers. + +template <typename... Ts> +struct conjunction : std::true_type {}; +template <typename T> +struct conjunction<T> : T {}; +template <typename First, typename... Rest> +struct conjunction<First, Rest...> + : std::conditional_t<bool(First::value), conjunction<Rest...>, First> {}; + +template <typename... Ts> +static constexpr bool conjunction_v = conjunction<Ts...>::value; + +template <typename... Ts> +struct disjunction : std::false_type {}; +template <typename T> +struct disjunction<T> : T {}; +template <typename First, typename... Rest> +struct disjunction<First, Rest...> + : std::conditional_t<bool(First::value), First, disjunction<Rest...>> {}; + +template <typename... Ts> +static constexpr bool disjunction_v = disjunction<Ts...>::value; + +// Utility type that negates its truth-like parameter type. +template <typename T> +struct negation : std::integral_constant<bool, !bool(T::value)> {}; + +template <typename T> +static constexpr bool negation_v = negation<T>::value; + +#endif // __cpp_lib_logical_traits >= 201510L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#if defined(__cpp_lib_bool_constant) && __cpp_lib_bool_constant >= 201505L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::bool_constant; + +#else // Provide polyfill for std::bool_constant + +template <bool B> +using bool_constant = std::integral_constant<bool, B>; + +#endif // __cpp_lib_bool_constant >= 201505L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#if defined(__cpp_lib_type_trait_variable_templates) && \ + __cpp_lib_type_trait_variable_templates >= 201510L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::is_array_v; +using std::is_class_v; +using std::is_enum_v; +using std::is_floating_point_v; +using std::is_function_v; +using std::is_integral_v; +using std::is_lvalue_reference_v; +using std::is_member_function_pointer_v; +using std::is_member_object_pointer_v; +using std::is_null_pointer_v; +using std::is_pointer_v; +using std::is_rvalue_reference_v; +using std::is_union_v; +using std::is_void_v; + +using std::is_arithmetic_v; +using std::is_compound_v; +using std::is_fundamental_v; +using std::is_member_pointer_v; +using std::is_object_v; +using std::is_reference_v; +using std::is_scalar_v; + +using std::is_abstract_v; +using std::is_const_v; +using std::is_empty_v; +using std::is_final_v; +using std::is_pod_v; +using std::is_polymorphic_v; +using std::is_signed_v; +using std::is_standard_layout_v; +using std::is_trivial_v; +using std::is_trivially_copyable_v; +using std::is_unsigned_v; +using std::is_volatile_v; + +using std::is_constructible_v; +using std::is_nothrow_constructible_v; +using std::is_trivially_constructible_v; + +using std::is_default_constructible_v; +using std::is_nothrow_default_constructible_v; +using std::is_trivially_default_constructible_v; + +using std::is_copy_constructible_v; +using std::is_nothrow_copy_constructible_v; +using std::is_trivially_copy_constructible_v; + +using std::is_move_constructible_v; +using std::is_nothrow_move_constructible_v; +using std::is_trivially_move_constructible_v; + +using std::is_assignable_v; +using std::is_nothrow_assignable_v; +using std::is_trivially_assignable_v; + +using std::is_copy_assignable_v; +using std::is_nothrow_copy_assignable_v; +using std::is_trivially_copy_assignable_v; + +using std::is_move_assignable_v; +using std::is_nothrow_move_assignable_v; +using std::is_trivially_move_assignable_v; + +using std::is_destructible_v; +using std::is_nothrow_destructible_v; +using std::is_trivially_destructible_v; + +using std::has_virtual_destructor_v; + +using std::alignment_of_v; +using std::extent_v; +using std::rank_v; + +using std::is_base_of_v; +using std::is_convertible_v; +using std::is_same_v; + +#else // Provide polyfills for the bulk of the *_v helpers + +template <typename T> +static constexpr bool is_void_v = std::is_void<T>::value; +template <typename T> +static constexpr bool is_null_pointer_v = std::is_null_pointer<T>::value; +template <typename T> +static constexpr bool is_integral_v = std::is_integral<T>::value; +template <typename T> +static constexpr bool is_floating_point_v = std::is_floating_point<T>::value; +template <typename T> +static constexpr bool is_array_v = std::is_array<T>::value; +template <typename T> +static constexpr bool is_enum_v = std::is_enum<T>::value; +template <typename T> +static constexpr bool is_union_v = std::is_union<T>::value; +template <typename T> +static constexpr bool is_class_v = std::is_class<T>::value; +template <typename T> +static constexpr bool is_function_v = std::is_function<T>::value; +template <typename T> +static constexpr bool is_pointer_v = std::is_pointer<T>::value; +template <typename T> +static constexpr bool is_lvalue_reference_v = std::is_lvalue_reference<T>::value; +template <typename T> +static constexpr bool is_rvalue_reference_v = std::is_rvalue_reference<T>::value; +template <typename T> +static constexpr bool is_member_object_pointer_v = std::is_member_object_pointer<T>::value; +template <typename T> +static constexpr bool is_member_function_pointer_v = std::is_member_function_pointer<T>::value; + +template <typename T> +static constexpr bool is_fundamental_v = std::is_fundamental<T>::value; +template <typename T> +static constexpr bool is_arithmetic_v = std::is_arithmetic<T>::value; +template <typename T> +static constexpr bool is_scalar_v = std::is_scalar<T>::value; +template <typename T> +static constexpr bool is_object_v = std::is_object<T>::value; +template <typename T> +static constexpr bool is_compound_v = std::is_compound<T>::value; +template <typename T> +static constexpr bool is_reference_v = std::is_reference<T>::value; +template <typename T> +static constexpr bool is_member_pointer_v = std::is_member_pointer<T>::value; + +template <typename T> +static constexpr bool is_const_v = std::is_const<T>::value; +template <typename T> +static constexpr bool is_volatile_v = std::is_volatile<T>::value; +template <typename T> +static constexpr bool is_trivial_v = std::is_trivial<T>::value; +template <typename T> +static constexpr bool is_trivially_copyable_v = std::is_trivially_copyable<T>::value; +template <typename T> +static constexpr bool is_standard_layout_v = std::is_standard_layout<T>::value; +template <typename T> +[[deprecated]] static constexpr bool is_pod_v = std::is_pod<T>::value; +template <typename T> +static constexpr bool is_empty_v = std::is_empty<T>::value; +template <typename T> +static constexpr bool is_polymorphic_v = std::is_polymorphic<T>::value; +template <typename T> +static constexpr bool is_abstract_v = std::is_abstract<T>::value; +template <typename T> +static constexpr bool is_final_v = std::is_final<T>::value; +template <typename T> +static constexpr bool is_signed_v = std::is_signed<T>::value; +template <typename T> +static constexpr bool is_unsigned_v = std::is_unsigned<T>::value; + +template <typename T, typename... Args> +static constexpr bool is_constructible_v = std::is_constructible<T, Args...>::value; +template <typename T, typename... Args> +static constexpr bool is_trivially_constructible_v = + std::is_trivially_constructible<T, Args...>::value; +template <typename T, typename... Args> +static constexpr bool is_nothrow_constructible_v = std::is_nothrow_constructible<T, Args...>::value; + +template <typename T> +static constexpr bool is_default_constructible_v = std::is_default_constructible<T>::value; +template <typename T> +static constexpr bool is_trivially_default_constructible_v = + std::is_trivially_default_constructible<T>::value; +template <typename T> +static constexpr bool is_nothrow_default_constructible_v = + std::is_nothrow_default_constructible<T>::value; + +template <typename T> +static constexpr bool is_copy_constructible_v = std::is_copy_constructible<T>::value; +template <typename T> +static constexpr bool is_trivially_copy_constructible_v = + std::is_trivially_copy_constructible<T>::value; +template <typename T> +static constexpr bool is_nothrow_copy_constructible_v = + std::is_nothrow_copy_constructible<T>::value; + +template <typename T> +static constexpr bool is_move_constructible_v = std::is_move_constructible<T>::value; +template <typename T> +static constexpr bool is_trivially_move_constructible_v = + std::is_trivially_move_constructible<T>::value; +template <typename T> +static constexpr bool is_nothrow_move_constructible_v = + std::is_nothrow_move_constructible<T>::value; + +template <typename T, typename U> +static constexpr bool is_assignable_v = std::is_assignable<T, U>::value; +template <typename T, typename U> +static constexpr bool is_trivially_assignable_v = std::is_trivially_assignable<T, U>::value; +template <typename T, typename U> +static constexpr bool is_nothrow_assignable_v = std::is_nothrow_assignable<T, U>::value; + +template <typename T> +static constexpr bool is_copy_assignable_v = std::is_copy_assignable<T>::value; +template <typename T> +static constexpr bool is_trivially_copy_assignable_v = std::is_trivially_copy_assignable<T>::value; +template <typename T> +static constexpr bool is_nothrow_copy_assignable_v = std::is_nothrow_copy_assignable<T>::value; + +template <typename T> +static constexpr bool is_move_assignable_v = std::is_move_assignable<T>::value; +template <typename T> +static constexpr bool is_trivially_move_assignable_v = std::is_trivially_move_assignable<T>::value; +template <typename T> +static constexpr bool is_nothrow_move_assignable_v = std::is_nothrow_move_assignable<T>::value; + +template <typename T> +static constexpr bool is_destructible_v = std::is_destructible<T>::value; +template <typename T> +static constexpr bool is_trivially_destructible_v = std::is_trivially_destructible<T>::value; +template <typename T> +static constexpr bool is_nothrow_destructible_v = std::is_nothrow_destructible<T>::value; + +template <typename T> +static constexpr bool has_virtual_destructor_v = std::has_virtual_destructor<T>::value; + +template <typename T> +static constexpr bool alignment_of_v = std::alignment_of<T>::value; +template <typename T> +static constexpr bool rank_v = std::rank<T>::value; +template <typename T, unsigned N = 0> +static constexpr bool extent_v = std::extent<T, N>::value; + +template <typename T, typename U> +static constexpr bool is_same_v = std::is_same<T, U>::value; +template <typename T, typename U> +static constexpr bool is_base_of_v = std::is_base_of<T, U>::value; +template <typename T, typename U> +static constexpr bool is_convertible_v = std::is_convertible<T, U>::value; + +#endif // __cpp_lib_type_trait_variable_templates >= 201510L && + // !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#if defined(__cpp_lib_is_aggregate) && __cpp_lib_is_aggregate >= 201703L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::is_aggregate; +using std::is_aggregate_v; + +#else // Provide std::is_aggregate polyfill + +template <typename T> +struct is_aggregate : bool_constant<__is_aggregate(T)> {}; + +template <typename T> +static constexpr bool is_aggregate_v = is_aggregate<T>::value; + +#endif // __cpp_lib_is_aggregate >= 201703L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::is_invocable; +using std::is_invocable_r; +using std::is_nothrow_invocable; +using std::is_nothrow_invocable_r; + +using std::is_invocable_r_v; +using std::is_invocable_v; +using std::is_nothrow_invocable_r_v; +using std::is_nothrow_invocable_v; + +using std::invoke_result; +using std::invoke_result_t; + +#else + +template <typename R, typename F, typename... Args> +struct is_invocable_r : decltype(::cpp17::internal::is_valid_invoke<R, F, Args...>(nullptr)) {}; + +template <typename R, typename F, typename... Args> +static constexpr bool is_invocable_r_v = is_invocable_r<R, F, Args...>::value; + +// INVOKE() is a subexpression of INVOKE<R>() +// INVOKE<void>(f, t1, t2, ..., tn) results in a call to +// static_cast<void>(INVOKE(f, t1, t2, ..., tn)) per [func.require] ΒΆ 2 +template <typename F, typename... Args> +struct is_invocable : is_invocable_r<void, F, Args...> {}; + +template <typename F, typename... Args> +static constexpr bool is_invocable_v = is_invocable<F, Args...>::value; + +template <typename F, typename... Args> +struct is_nothrow_invocable : bool_constant<is_invocable_v<F, Args...> && + noexcept(::cpp17::internal::invoke( + std::declval<F>(), std::declval<Args>()...))> {}; + +template <typename F, typename... Args> +static constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<F, Args...>::value; + +template <typename R, typename F, typename... Args> +struct is_nothrow_invocable_r : bool_constant<is_invocable_r_v<R, F, Args...> && + noexcept(::cpp17::internal::invoke_r<R>( + std::declval<F>(), std::declval<Args>()...))> {}; + +template <typename R, typename F, typename... Args> +static constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<R, F, Args...>::value; + +template <typename F, typename... Args> +struct invoke_result : ::cpp17::internal::invoke_result<is_invocable_v<F, Args...>, F, Args...> {}; + +template <typename F, typename... Args> +using invoke_result_t = typename invoke_result<F, Args...>::type; + +#endif // __cpp_lib_is_invocable >= 201703L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +} // namespace cpp17 + +namespace cpp20 { + +#if defined(__cpp_lib_bounded_array_traits) && __cpp_lib_bounded_array_traits >= 201902L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::is_bounded_array; +using std::is_bounded_array_v; + +using std::is_unbounded_array; +using std::is_unbounded_array_v; + +#else // Provide polyfills for std::is_{,un}bounded_array{,_v} + +template <typename T> +struct is_bounded_array : std::false_type {}; +template <typename T, std::size_t N> +struct is_bounded_array<T[N]> : std::true_type {}; + +template <typename T> +static constexpr bool is_bounded_array_v = is_bounded_array<T>::value; + +template <typename T> +struct is_unbounded_array : std::false_type {}; +template <typename T> +struct is_unbounded_array<T[]> : std::true_type {}; + +template <typename T> +static constexpr bool is_unbounded_array_v = is_unbounded_array<T>::value; + +#endif // __cpp_lib_bounded_array_traits >= 201902L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#if defined(__cpp_lib_remove_cvref) && __cpp_lib_remove_cvref >= 201711L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::remove_cvref; +using std::remove_cvref_t; + +#else // Provide polyfill for std::remove_cvref{,_t} + +template <typename T> +struct remove_cvref { + using type = std::remove_cv_t<std::remove_reference_t<T>>; +}; + +template <typename T> +using remove_cvref_t = typename remove_cvref<T>::type; + +#endif // __cpp_lib_remove_cvref >= 201711L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#if defined(__cpp_lib_type_identity) && __cpp_lib_type_identity >= 201806L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::type_identity; +using std::type_identity_t; + +#else // Provide polyfill for std::type_identity{,_t} + +template <typename T> +struct type_identity { + using type = T; +}; + +template <typename T> +using type_identity_t = typename type_identity<T>::type; + +#endif // __cpp_lib_type_identity >= 201806L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#if defined(__cpp_lib_is_constant_evaluated) && __cpp_lib_is_constant_evaluated >= 201811L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#define LIB_STDCOMPAT_CONSTEVAL_SUPPORT 1 +using std::is_constant_evaluated; + +#else // Provide polyfill for std::is_constant_evaluated + +#ifdef __has_builtin +#if __has_builtin(__builtin_is_constant_evaluated) + +#define LIB_STDCOMPAT_CONSTEVAL_SUPPORT 1 +inline constexpr bool is_constant_evaluated() noexcept { return __builtin_is_constant_evaluated(); } + +#endif // __has_builtin(__builtin_is_constant_evaluated) +#endif // __has_builtin + +#ifndef LIB_STDCOMPAT_CONSTEVAL_SUPPORT + +#define LIB_STDCOMPAT_CONSTEVAL_SUPPORT 0 +inline constexpr bool is_constant_evaluated() noexcept { return false; } + +#endif // LIB_STDCOMPAT_CONSTEVAL_SUPPORT + +#endif // __cpp_lib_is_constant_evaluated >= 201811L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +} // namespace cpp20 + +namespace cpp23 { + +#if defined(__cpp_lib_is_scoped_enum) && __cpp_lib_is_scoped_enum >= 202011L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::is_scoped_enum; +using std::is_scoped_enum_v; + +#else // Provide polyfill for std::is_scoped_enum{,_v} + +template <typename T, typename = void> +struct is_scoped_enum : std::false_type {}; + +template <typename T> +struct is_scoped_enum<T, std::enable_if_t<cpp17::is_enum_v<T>>> + : cpp17::bool_constant<!cpp17::is_convertible_v<T, std::underlying_type_t<T>>> {}; + +template <typename T> +static constexpr bool is_scoped_enum_v = is_scoped_enum<T>::value; + +#endif // __cpp_lib_is_scoped_enum >= 202011L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +} // namespace cpp23 + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_TYPE_TRAITS_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/utility.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/utility.h new file mode 100644 index 000000000..fe0993d47 --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/utility.h @@ -0,0 +1,118 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_UTILITY_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_UTILITY_H_ + +#include <cstddef> +#include <type_traits> +#include <utility> + +#include "internal/utility.h" +#include "version.h" + +namespace cpp17 { +// Use alias for cpp17 and above. +#if __cplusplus >= 201411L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::in_place; +using std::in_place_t; + +using std::in_place_index; +using std::in_place_index_t; + +using std::in_place_type; +using std::in_place_type_t; + +#else // Provide provide polyfills for |in_place*| types and variables. + +// Tag for requesting in-place initialization. +struct in_place_t { + explicit constexpr in_place_t() = default; +}; + +// Tag for requesting in-place initialization by type. +template <typename T> +struct in_place_type_t { + explicit constexpr in_place_type_t() = default; +}; + +// Tag for requesting in-place initialization by index. +template <std::size_t Index> +struct in_place_index_t final { + explicit constexpr in_place_index_t() = default; +}; + +// Use inline variables if available. +#if defined(__cpp_inline_variables) && __cpp_inline_variables >= 201606L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +constexpr in_place_t in_place{}; + +template <typename T> +constexpr in_place_type_t<T> in_place_type{}; + +template <std::size_t Index> +constexpr in_place_index_t<Index> in_place_index{}; + +#else // Provide polyfill reference to provided variable storage. + +static constexpr const in_place_t& in_place = + internal::instantiate_templated_tag<in_place_t>::storage; + +template <typename T> +static constexpr const in_place_type_t<T>& in_place_type = + internal::instantiate_templated_tag<in_place_type_t<T>>::storage; + +template <std::size_t Index> +static constexpr const in_place_index_t<Index>& in_place_index = + internal::instantiate_templated_tag<in_place_index_t<Index>>::storage; + +#endif // __cpp_inline_variables >= 201606L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#endif // __cplusplus >= 201411L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#if defined(__cpp_lib_as_const) && __cpp_lib_as_const >= 201510L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::as_const; + +#else // Provide as_const polyfill. + +template <typename T> +constexpr std::add_const_t<T>& as_const(T& t) noexcept { + return t; +} + +template <typename T> +void as_const(T&&) = delete; + +#endif // __cpp_lib_as_const >= 201510L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +} // namespace cpp17 + +namespace cpp20 { + +#if defined(__cpp_lib_constexpr_algorithms) && __cpp_lib_constexpr_algorithms >= 201806L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::exchange; + +#else // Add swap constexpr polyfill. + +template < + typename T, typename U = T, + typename std::enable_if<std::is_move_assignable<T>::value && cpp17::is_assignable_v<T&, U>, + bool>::type = true> +constexpr T exchange(T& obj, U&& new_value) { + T old = std::move(obj); + obj = std::forward<U>(new_value); + return old; +} + +#endif // __cpp_lib_constexpr_algorithms >= 201806L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +} // namespace cpp20 + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_UTILITY_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/version.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/version.h new file mode 100644 index 000000000..c022e4b30 --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/version.h @@ -0,0 +1,79 @@ +// Copyright 2020 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_VERSION_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_VERSION_H_ + +// This <version> polyfills is meant to provide the feature testing macros for the rest of +// the stdcompat library. It is not meant to be a full polyfill of <version>. + +#if __has_include(<version>) && !defined(LIB_STDCOMPAT_USE_POLYFILLS) +#include <version> +#elif __cplusplus > 201703L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) +#error "cpp=std20 must provide a '<version>' header." +#else + +#if __has_include(<optional>) && !defined(__cpp_lib_optional) && __cplusplus >= 201606L +#define __cpp_lib_optional 201606L +#endif + +#if __has_include(<string_view>) && !defined(__cpp_lib_string_view) && __cplusplus >= 201606L +#define __cpp_lib_string_view 201606L +#endif + +#if __has_include(<variant>) && !defined(__cpp_lib_variant) && __cplusplus >= 201606L +#define __cpp_lib_variant 201606L +#endif + +#if !defined(__cpp_lib_void_t) && __cplusplus >= 201411L +#define __cpp_lib_void_t 201411L +#endif + +#if !defined(__cpp_lib_logical_traits) && __cplusplus >= 201510L +#define __cpp_lib_logical_traits 201510L +#endif + +#if !defined(__cpp_lib_addressof_constexpr) && __cplusplus >= 201603L +#define __cpp_lib_addressof_constexpr 201603L +#endif + +#if !defined(__cpp_lib_nonmember_container_access) && __cplusplus >= 201411L +#define __cpp_lib_nonmember_container_access 201411L +#endif + +#if !defined(__cpp_lib_byte) && __cplusplus >= 201603L +#define __cpp_lib_byte 201603L +#endif + +#if !defined(__cpp_lib_bool_constant) && __cplusplus >= 201505L +#define __cpp_lib_bool_constant 201505L +#endif + +#if !defined(__cpp_lib_type_trait_variable_templates) && __cplusplus >= 201510L +#define __cpp_lib_type_trait_variable_templates 201510L +#endif + +#if !defined(__cpp_lib_is_aggregate) && __cplusplus >= 201703L +#define __cpp_lib_is_aggregate 201703L +#endif + +#if !defined(__cpp_lib_is_invocable) && __cplusplus >= 201703L +#define __cpp_lib_is_invocable 201703L +#endif + +#if !defined(__cpp_lib_invoke) && __cplusplus >= 201411L +#define __cpp_lib_invoke 201411L +#endif + +#if !defined(__cpp_lib_apply) && __cplusplus >= 201603L +#define __cpp_lib_apply 201603L +#endif + +#if !defined(__cpp_lib_as_const) && __cplusplus >= 201510L +#define __cpp_lib_as_const 201510L +#endif + +#endif // __has_include(<version>) && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_VERSION_H_ |