- 551e205ef49682a1cb7e6e0cda46957fbcf88edd Release absl::variant. by Xiaoyi Zhang <zhangxy@google.com>
- 01c52f640594d073c6e54c47e7853b25522cf085 Update comments in absl::variant (and minor changes to ab... by Tom Manshreck <shreck@google.com> - 064465e1e6b158abd8c38fd1942b4fc464b57d6a Documentation change. by Abseil Team <absl-team@google.com> - 58df2c8a27e80c9ea21d87c1acee8019246377c9 Relocates SetCountdown and UnsetCountdown to the exceptio... by Abseil Team <absl-team@google.com> - fd9d248d0948d472f2543f7fd9c0ae4a1cd60d01 Clarify thread_annotation.h documentation around local va... by Abseil Team <absl-team@google.com> - 0d0abaf7f0945ac5f2c5f49e78afe1b326d5aca0 Typo fix in comments. by Abseil Team <absl-team@google.com> - 67286d587cbd07508a81e5b8147c245a5b5538b4 Internal change. by Xiaoyi Zhang <zhangxy@google.com> GitOrigin-RevId: 551e205ef49682a1cb7e6e0cda46957fbcf88edd Change-Id: I1a343b080187293cb5f892a309618b5712e7aa14pull/117/head
parent
5b53540166
commit
faf0a1b903
19 changed files with 5172 additions and 52 deletions
@ -0,0 +1,58 @@ |
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "absl/types/bad_variant_access.h" |
||||
|
||||
#include <cstdlib> |
||||
#include <stdexcept> |
||||
|
||||
#include "absl/base/config.h" |
||||
#include "absl/base/internal/raw_logging.h" |
||||
|
||||
namespace absl { |
||||
|
||||
//////////////////////////
|
||||
// [variant.bad.access] //
|
||||
//////////////////////////
|
||||
|
||||
bad_variant_access::~bad_variant_access() = default; |
||||
|
||||
const char* bad_variant_access::what() const noexcept { |
||||
return "Bad variant access"; |
||||
} |
||||
|
||||
namespace variant_internal { |
||||
|
||||
void ThrowBadVariantAccess() { |
||||
#ifdef ABSL_HAVE_EXCEPTIONS |
||||
throw bad_variant_access(); |
||||
#else |
||||
ABSL_RAW_LOG(FATAL, "Bad variant access"); |
||||
abort(); // TODO(calabrese) Remove once RAW_LOG FATAL is noreturn.
|
||||
#endif |
||||
} |
||||
|
||||
void Rethrow() { |
||||
#ifdef ABSL_HAVE_EXCEPTIONS |
||||
throw; |
||||
#else |
||||
ABSL_RAW_LOG(FATAL, |
||||
"Internal error in absl::variant implementation. Attempted to " |
||||
"rethrow an exception when building with exceptions disabled."); |
||||
abort(); // TODO(calabrese) Remove once RAW_LOG FATAL is noreturn.
|
||||
#endif |
||||
} |
||||
|
||||
} // namespace variant_internal
|
||||
} // namespace absl
|
@ -0,0 +1,64 @@ |
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// bad_variant_access.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines the `absl::bad_variant_access` type.
|
||||
|
||||
#ifndef ABSL_TYPES_BAD_VARIANT_ACCESS_H_ |
||||
#define ABSL_TYPES_BAD_VARIANT_ACCESS_H_ |
||||
|
||||
#include <stdexcept> |
||||
|
||||
namespace absl { |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// bad_variant_access
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// An `absl::bad_variant_access` type is an exception type that is thrown in
|
||||
// the following cases:
|
||||
//
|
||||
// * Calling `absl::get(absl::variant) with an index or type that does not
|
||||
// match the currently selected alternative type
|
||||
// * Calling `absl::visit on an `absl::variant` that is in the
|
||||
// `variant::valueless_by_exception` state.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::variant<int, std::string> v;
|
||||
// v = 1;
|
||||
// try {
|
||||
// absl::get<std::string>(v);
|
||||
// } catch(const absl::bad_variant_access& e) {
|
||||
// std::cout << "Bad variant access: " << e.what() << '\n';
|
||||
// }
|
||||
class bad_variant_access : public std::exception { |
||||
public: |
||||
bad_variant_access() noexcept = default; |
||||
~bad_variant_access() override; |
||||
const char* what() const noexcept override; |
||||
}; |
||||
|
||||
namespace variant_internal { |
||||
|
||||
[[noreturn]] void ThrowBadVariantAccess(); |
||||
[[noreturn]] void Rethrow(); |
||||
|
||||
} // namespace variant_internal
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TYPES_BAD_VARIANT_ACCESS_H_
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,838 @@ |
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// variant.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines an `absl::variant` type for holding a type-safe
|
||||
// value of some prescribed set of types (noted as alternative types), and
|
||||
// associated functions for managing variants.
|
||||
//
|
||||
// The `absl::variant` type is a form of type-safe union. An `absl::variant`
|
||||
// should always hold a value of one of its alternative types (except in the
|
||||
// "valueless by exception state" -- see below). A default-constructed
|
||||
// `absl::variant` will hold the value of its first alternative type, provided
|
||||
// it is default-constructable.
|
||||
//
|
||||
// In exceptional cases due to error, an `absl::variant` can hold no
|
||||
// value (known as a "valueless by exception" state), though this is not the
|
||||
// norm.
|
||||
//
|
||||
// As with `absl::optional`, an `absl::variant` -- when it holds a value --
|
||||
// allocates a value of that type directly within the `variant` itself; it
|
||||
// cannot hold a reference, array, or the type `void`; it can, however, hold a
|
||||
// pointer to externally managed memory.
|
||||
//
|
||||
// `absl::variant` is a C++11 compatible version of the C++17 `std::variant`
|
||||
// abstraction and is designed to be a drop-in replacement for code compliant
|
||||
// with C++17.
|
||||
|
||||
#ifndef ABSL_TYPES_VARIANT_H_ |
||||
#define ABSL_TYPES_VARIANT_H_ |
||||
|
||||
#include "absl/base/config.h" |
||||
#include "absl/utility/utility.h" |
||||
|
||||
#ifdef ABSL_HAVE_STD_VARIANT |
||||
|
||||
#include <variant> |
||||
|
||||
namespace absl { |
||||
using std::bad_variant_access; |
||||
using std::get; |
||||
using std::get_if; |
||||
using std::holds_alternative; |
||||
using std::monostate; |
||||
using std::variant; |
||||
using std::variant_alternative; |
||||
using std::variant_alternative_t; |
||||
using std::variant_npos; |
||||
using std::variant_size; |
||||
using std::variant_size_v; |
||||
using std::visit; |
||||
} // namespace absl
|
||||
|
||||
#else // ABSL_HAVE_STD_VARIANT
|
||||
|
||||
#include <functional> |
||||
#include <new> |
||||
#include <type_traits> |
||||
#include <utility> |
||||
|
||||
#include "absl/base/macros.h" |
||||
#include "absl/base/port.h" |
||||
#include "absl/meta/type_traits.h" |
||||
#include "absl/types/internal/variant.h" |
||||
|
||||
namespace absl { |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// absl::variant
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// An 'absl::variant` type is a form of type-safe union. An `absl::variant` --
|
||||
// except in exceptional cases -- always holds a value of one of its alternative
|
||||
// types.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Construct a variant that holds either an integer or a std::string and
|
||||
// // assign it to a std::string.
|
||||
// absl::variant<int, std::string> v = std::string("abc");
|
||||
//
|
||||
// // A default-contructed variant will hold a value-initialized value of
|
||||
// // the first alternative type.
|
||||
// auto a = absl::variant<int, std::string>(); // Holds an int of value '0'.
|
||||
//
|
||||
// // variants are assignable.
|
||||
//
|
||||
// // copy assignment
|
||||
// auto v1 = absl::variant<int, std::string>("abc");
|
||||
// auto v2 = absl::variant<int, std::string>(10);
|
||||
// v2 = v1; // copy assign
|
||||
//
|
||||
// // move assignment
|
||||
// auto v1 = absl::variant<int, std::string>("abc");
|
||||
// v1 = absl::variant<int, std::string>(10);
|
||||
//
|
||||
// // assignment through type conversion
|
||||
// a = 128; // variant contains int
|
||||
// a = "128"; // variant contains std::string
|
||||
//
|
||||
// An `absl::variant` holding a value of one of its alternative types `T` holds
|
||||
// an allocation of `T` directly within the variant itself. An `absl::variant`
|
||||
// is not allowed to allocate additional storage, such as dynamic memory, to
|
||||
// allocate the contained value. The contained value shall be allocated in a
|
||||
// region of the variant storage suitably aligned for all alternative types.
|
||||
template <typename... Ts> |
||||
class variant; |
||||
|
||||
// swap()
|
||||
//
|
||||
// Swaps two `absl::variant` values. This function is equivalent to `v.swap(w)`
|
||||
// where `v` and `w` are `absl::variant` types.
|
||||
//
|
||||
// Note that this function requires all alternative types to be both swappable
|
||||
// and move-constructible, because any two variants may refer to either the same
|
||||
// type (in which case, they will be swapped) or to two different types (in
|
||||
// which case the values will need to be moved).
|
||||
//
|
||||
template <typename... Ts> |
||||
void swap(variant<Ts...>& v, variant<Ts...>& w) noexcept(noexcept(v.swap(w))) { |
||||
v.swap(w); |
||||
} |
||||
|
||||
// variant_size
|
||||
//
|
||||
// Returns the number of alterative types available for a given `absl::variant`
|
||||
// type as a compile-time constant expression. As this is a class template, it
|
||||
// is not generally useful for accessing the number of alternative types of
|
||||
// any given `absl::variant` instance.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// auto a = absl::variant<int, std::string>;
|
||||
// constexpr int num_types =
|
||||
// absl::variant_size<absl::variant<int, std::string>>();
|
||||
//
|
||||
// // You can also use the member constant `value`.
|
||||
// constexpr int num_types =
|
||||
// absl::variant_size<absl::variant<int, std::string>>::value;
|
||||
//
|
||||
// // `absl::variant_size` is more valuable for use in generic code:
|
||||
// template <typename Variant>
|
||||
// constexpr bool IsVariantMultivalue() {
|
||||
// return absl::variant_size<Variant>() > 1;
|
||||
// }
|
||||
//
|
||||
// Note that the set of cv-qualified specializations of `variant_size` are
|
||||
// provided to ensure that those specializations compile (especially when passed
|
||||
// within template logic).
|
||||
template <class T> |
||||
struct variant_size; |
||||
|
||||
template <class... Ts> |
||||
struct variant_size<variant<Ts...>> |
||||
: std::integral_constant<std::size_t, sizeof...(Ts)> {}; |
||||
|
||||
// Specialization of `variant_size` for const qualified variants.
|
||||
template <class T> |
||||
struct variant_size<const T> : variant_size<T>::type {}; |
||||
|
||||
// Specialization of `variant_size` for volatile qualified variants.
|
||||
template <class T> |
||||
struct variant_size<volatile T> : variant_size<T>::type {}; |
||||
|
||||
// Specialization of `variant_size` for const volatile qualified variants.
|
||||
template <class T> |
||||
struct variant_size<const volatile T> : variant_size<T>::type {}; |
||||
|
||||
// variant_alternative
|
||||
//
|
||||
// Returns the alternative type for a given `absl::variant` at the passed
|
||||
// index value as a compile-time constant expression. As this is a class
|
||||
// template resulting in a type, it is not useful for access of the run-time
|
||||
// value of any given `absl::variant` variable.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // The type of the 0th alternative is "int".
|
||||
// using alternative_type_0
|
||||
// = absl::variant_alternative<0, absl::variant<int, std::string>>::type;
|
||||
//
|
||||
// static_assert(std::is_same<alternative_type_0, int>::value, "");
|
||||
//
|
||||
// // `absl::variant_alternative` is more valuable for use in generic code:
|
||||
// template <typename Variant>
|
||||
// constexpr bool IsFirstElementTrivial() {
|
||||
// return std::is_trivial_v<variant_alternative<0, Variant>::type>;
|
||||
// }
|
||||
//
|
||||
// Note that the set of cv-qualified specializations of `variant_alternative`
|
||||
// are provided to ensure that those specializations compile (especially when
|
||||
// passed within template logic).
|
||||
template <std::size_t I, class T> |
||||
struct variant_alternative; |
||||
|
||||
template <std::size_t I, class... Types> |
||||
struct variant_alternative<I, variant<Types...>> { |
||||
using type = |
||||
variant_internal::VariantAlternativeSfinaeT<I, variant<Types...>>; |
||||
}; |
||||
|
||||
// Specialization of `variant_alternative` for const qualified variants.
|
||||
template <std::size_t I, class T> |
||||
struct variant_alternative<I, const T> { |
||||
using type = const typename variant_alternative<I, T>::type; |
||||
}; |
||||
|
||||
// Specialization of `variant_alternative` for volatile qualified variants.
|
||||
template <std::size_t I, class T> |
||||
struct variant_alternative<I, volatile T> { |
||||
using type = volatile typename variant_alternative<I, T>::type; |
||||
}; |
||||
|
||||
// Specialization of `variant_alternative` for const volatile qualified
|
||||
// variants.
|
||||
template <std::size_t I, class T> |
||||
struct variant_alternative<I, const volatile T> { |
||||
using type = const volatile typename variant_alternative<I, T>::type; |
||||
}; |
||||
|
||||
// Template type alias for variant_alternative<I, T>::type.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// using alternative_type_0
|
||||
// = absl::variant_alternative_t<0, absl::variant<int, std::string>>;
|
||||
// static_assert(std::is_same<alternative_type_0, int>::value, "");
|
||||
template <std::size_t I, class T> |
||||
using variant_alternative_t = typename variant_alternative<I, T>::type; |
||||
|
||||
// holds_alternative()
|
||||
//
|
||||
// Checks whether the given variant currently holds a given alternative type,
|
||||
// returning `true` if so.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::variant<int, std::string> bar = 42;
|
||||
// if (absl::holds_alternative<int>(foo)) {
|
||||
// std::cout << "The variant holds an integer";
|
||||
// }
|
||||
template <class T, class... Types> |
||||
constexpr bool holds_alternative(const variant<Types...>& v) noexcept { |
||||
static_assert( |
||||
variant_internal::UnambiguousIndexOfImpl<variant<Types...>, T, |
||||
0>::value != sizeof...(Types), |
||||
"The type T must occur exactly once in Types..."); |
||||
return v.index() == |
||||
variant_internal::UnambiguousIndexOf<variant<Types...>, T>::value; |
||||
} |
||||
|
||||
// get()
|
||||
//
|
||||
// Returns a reference to the value currently within a given variant, using
|
||||
// either a unique alternative type amongst the variant's set of alternative
|
||||
// types, or the variant's index value. Attempting to get a variant's value
|
||||
// using a type that is not unique within the variant's set of alternative types
|
||||
// is a compile-time error. If the index of the alternative being specified is
|
||||
// different from the index of the alternative that is currently stored, throws
|
||||
// `absl::bad_variant_access`.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// auto a = absl::variant<int, std::string>;
|
||||
//
|
||||
// // Get the value by type (if unique).
|
||||
// int i = absl::get<int>(a);
|
||||
//
|
||||
// auto b = absl::variant<int, int>;
|
||||
//
|
||||
// // Getting the value by a type that is not unique is ill-formed.
|
||||
// int j = absl::get<int>(b); // Compile Error!
|
||||
//
|
||||
// // Getting value by index not ambiguous and allowed.
|
||||
// int k = absl::get<1>(b);
|
||||
|
||||
// Overload for getting a variant's lvalue by type.
|
||||
template <class T, class... Types> |
||||
constexpr T& get(variant<Types...>& v) { // NOLINT
|
||||
return variant_internal::VariantCoreAccess::Access< |
||||
variant_internal::IndexOf<T, Types...>::value>(v); |
||||
} |
||||
|
||||
// Overload for getting a variant's rvalue by type.
|
||||
// Note: `absl::move()` is required to allow use of constexpr in C++11.
|
||||
template <class T, class... Types> |
||||
constexpr T&& get(variant<Types...>&& v) { |
||||
return variant_internal::VariantCoreAccess::Access< |
||||
variant_internal::IndexOf<T, Types...>::value>(absl::move(v)); |
||||
} |
||||
|
||||
// Overload for getting a variant's const lvalue by type.
|
||||
template <class T, class... Types> |
||||
constexpr const T& get(const variant<Types...>& v) { |
||||
return variant_internal::VariantCoreAccess::Access< |
||||
variant_internal::IndexOf<T, Types...>::value>(v); |
||||
} |
||||
|
||||
// Overload for getting a variant's const rvalue by type.
|
||||
// Note: `absl::move()` is required to allow use of constexpr in C++11.
|
||||
template <class T, class... Types> |
||||
constexpr const T&& get(const variant<Types...>&& v) { |
||||
return variant_internal::VariantCoreAccess::Access< |
||||
variant_internal::IndexOf<T, Types...>::value>(absl::move(v)); |
||||
} |
||||
|
||||
// Overload for getting a variant's lvalue by index.
|
||||
template <std::size_t I, class... Types> |
||||
constexpr variant_alternative_t<I, variant<Types...>>& get( |
||||
variant<Types...>& v) { // NOLINT
|
||||
return variant_internal::VariantCoreAccess::Access<I>(v); |
||||
} |
||||
|
||||
// Overload for getting a variant's rvalue by index.
|
||||
// Note: `absl::move()` is required to allow use of constexpr in C++11.
|
||||
template <std::size_t I, class... Types> |
||||
constexpr variant_alternative_t<I, variant<Types...>>&& get( |
||||
variant<Types...>&& v) { |
||||
return variant_internal::VariantCoreAccess::Access<I>(absl::move(v)); |
||||
} |
||||
|
||||
// Overload for getting a variant's const lvalue by index.
|
||||
template <std::size_t I, class... Types> |
||||
constexpr const variant_alternative_t<I, variant<Types...>>& get( |
||||
const variant<Types...>& v) { |
||||
return variant_internal::VariantCoreAccess::Access<I>(v); |
||||
} |
||||
|
||||
// Overload for getting a variant's const rvalue by index.
|
||||
// Note: `absl::move()` is required to allow use of constexpr in C++11.
|
||||
template <std::size_t I, class... Types> |
||||
constexpr const variant_alternative_t<I, variant<Types...>>&& get( |
||||
const variant<Types...>&& v) { |
||||
return variant_internal::VariantCoreAccess::Access<I>(absl::move(v)); |
||||
} |
||||
|
||||
// get_if()
|
||||
//
|
||||
// Returns a pointer to the value currently stored within a given variant, if
|
||||
// present, using either a unique alternative type amonst the variant's set of
|
||||
// alternative types, or the variant's index value. If such a value does not
|
||||
// exist, returns `nullptr`.
|
||||
//
|
||||
// As with `get`, attempting to get a variant's value using a type that is not
|
||||
// unique within the variant's set of alternative types is a compile-time error.
|
||||
|
||||
// Overload for getting a pointer to the value stored in the given variant by
|
||||
// index.
|
||||
template <std::size_t I, class... Types> |
||||
constexpr absl::add_pointer_t<variant_alternative_t<I, variant<Types...>>> |
||||
get_if(variant<Types...>* v) noexcept { |
||||
return (v != nullptr && v->index() == I) ? std::addressof(absl::get<I>(*v)) |
||||
: nullptr; |
||||
} |
||||
|
||||
// Overload for getting a pointer to the const value stored in the given
|
||||
// variant by index.
|
||||
template <std::size_t I, class... Types> |
||||
constexpr absl::add_pointer_t<const variant_alternative_t<I, variant<Types...>>> |
||||
get_if(const variant<Types...>* v) noexcept { |
||||
return (v != nullptr && v->index() == I) ? std::addressof(absl::get<I>(*v)) |
||||
: nullptr; |
||||
} |
||||
|
||||
// Overload for getting a pointer to the value stored in the given variant by
|
||||
// type.
|
||||
template <class T, class... Types> |
||||
constexpr absl::add_pointer_t<T> get_if(variant<Types...>* v) noexcept { |
||||
return absl::get_if<variant_internal::IndexOf<T, Types...>::value>(v); |
||||
} |
||||
|
||||
// Overload for getting a pointer to the const value stored in the given variant
|
||||
// by type.
|
||||
template <class T, class... Types> |
||||
constexpr absl::add_pointer_t<const T> get_if( |
||||
const variant<Types...>* v) noexcept { |
||||
return absl::get_if<variant_internal::IndexOf<T, Types...>::value>(v); |
||||
} |
||||
|
||||
// visit()
|
||||
//
|
||||
// Calls a provided functor on a given set of variants. `absl::visit()` is
|
||||
// commonly used to conditionally inspect the state of a given variant (or set
|
||||
// of variants).
|
||||
// Requires: The expression in the Effects: element shall be a valid expression
|
||||
// of the same type and value category, for all combinations of alternative
|
||||
// types of all variants. Otherwise, the program is ill-formed.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Define a visitor functor
|
||||
// struct GetVariant {
|
||||
// template<typename T>
|
||||
// void operator()(const T& i) const {
|
||||
// std::cout << "The variant's value is: " << i;
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// // Declare our variant, and call `absl::visit()` on it.
|
||||
// std::variant<int, std::string> foo = std::string("foo");
|
||||
// GetVariant visitor;
|
||||
// std::visit(visitor, foo); // Prints `The variant's value is: foo'
|
||||
template <typename Visitor, typename... Variants> |
||||
variant_internal::VisitResult<Visitor, Variants...> visit(Visitor&& vis, |
||||
Variants&&... vars) { |
||||
return variant_internal::visit_indices< |
||||
variant_size<absl::decay_t<Variants>>::value...>( |
||||
variant_internal::PerformVisitation<Visitor, Variants...>{ |
||||
std::forward_as_tuple(absl::forward<Variants>(vars)...), |
||||
absl::forward<Visitor>(vis)}, |
||||
vars.index()...); |
||||
} |
||||
|
||||
// monostate
|
||||
//
|
||||
// The monostate class serves as a first alternative type for a variant for
|
||||
// which the first variant type is otherwise not default-constructible.
|
||||
struct monostate {}; |
||||
|
||||
// `absl::monostate` Relational Operators
|
||||
|
||||
constexpr bool operator<(monostate, monostate) noexcept { return false; } |
||||
constexpr bool operator>(monostate, monostate) noexcept { return false; } |
||||
constexpr bool operator<=(monostate, monostate) noexcept { return true; } |
||||
constexpr bool operator>=(monostate, monostate) noexcept { return true; } |
||||
constexpr bool operator==(monostate, monostate) noexcept { return true; } |
||||
constexpr bool operator!=(monostate, monostate) noexcept { return false; } |
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// `absl::variant` Template Definition
|
||||
//------------------------------------------------------------------------------
|
||||
template <typename T0, typename... Tn> |
||||
class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> { |
||||
static_assert(absl::conjunction<std::is_object<T0>, std::is_object<Tn>..., |
||||
absl::negation<std::is_array<T0>>, |
||||
absl::negation<std::is_array<Tn>>..., |
||||
std::is_nothrow_destructible<T0>, |
||||
std::is_nothrow_destructible<Tn>...>::value, |
||||
"Attempted to instantiate a variant with an unsupported type."); |
||||
|
||||
friend struct variant_internal::VariantCoreAccess; |
||||
|
||||
private: |
||||
using Base = variant_internal::VariantBase<T0, Tn...>; |
||||
|
||||
public: |
||||
// Constructors
|
||||
|
||||
// Constructs a variant holding a default-initialized value of the first
|
||||
// alternative type.
|
||||
constexpr variant() /*noexcept(see 111above)*/ = default; |
||||
|
||||
// Copy constructor, standard semantics
|
||||
variant(const variant& other) = default; |
||||
|
||||
// Move constructor, standard semantics
|
||||
variant(variant&& other) /*noexcept(see above)*/ = default; |
||||
|
||||
// Constructs a variant of an alternative type specified by overload
|
||||
// resolution of the provided forwarding arguments through
|
||||
// direct-initialization.
|
||||
//
|
||||
// Note: If the selected constructor is a constexpr constructor, this
|
||||
// constructor shall be a constexpr constructor.
|
||||
//
|
||||
// NOTE: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r1.html
|
||||
// has been voted passed the design phase in the C++ standard meeting in Mar
|
||||
// 2018. It will be implemented and integrated into `absl::variant`.
|
||||
template < |
||||
class T, |
||||
std::size_t I = std::enable_if< |
||||
variant_internal::IsNeitherSelfNorInPlace<variant, |
||||
absl::decay_t<T>>::value, |
||||
variant_internal::IndexOfConstructedType<variant, T>>::type::value, |
||||
class Tj = absl::variant_alternative_t<I, variant>, |
||||
absl::enable_if_t<std::is_constructible<Tj, T>::value>* = |
||||
nullptr> |
||||
constexpr variant(T&& t) noexcept(std::is_nothrow_constructible<Tj, T>::value) |
||||
: Base(variant_internal::EmplaceTag<I>(), absl::forward<T>(t)) {} |
||||
|
||||
// Constructs a variant of an alternative type from the arguments through
|
||||
// direct-initialization.
|
||||
//
|
||||
// Note: If the selected constructor is a constexpr constructor, this
|
||||
// constructor shall be a constexpr constructor.
|
||||
template <class T, class... Args, |
||||
typename std::enable_if<std::is_constructible< |
||||
variant_internal::UnambiguousTypeOfT<variant, T>, |
||||
Args...>::value>::type* = nullptr> |
||||
constexpr explicit variant(in_place_type_t<T>, Args&&... args) |
||||
: Base(variant_internal::EmplaceTag< |
||||
variant_internal::UnambiguousIndexOf<variant, T>::value>(), |
||||
absl::forward<Args>(args)...) {} |
||||
|
||||
// Constructs a variant of an alternative type from an initializer list
|
||||
// and other arguments through direct-initialization.
|
||||
//
|
||||
// Note: If the selected constructor is a constexpr constructor, this
|
||||
// constructor shall be a constexpr constructor.
|
||||
template <class T, class U, class... Args, |
||||
typename std::enable_if<std::is_constructible< |
||||
variant_internal::UnambiguousTypeOfT<variant, T>, |
||||
std::initializer_list<U>&, Args...>::value>::type* = nullptr> |
||||
constexpr explicit variant(in_place_type_t<T>, std::initializer_list<U> il, |
||||
Args&&... args) |
||||
: Base(variant_internal::EmplaceTag< |
||||
variant_internal::UnambiguousIndexOf<variant, T>::value>(), |
||||
il, absl::forward<Args>(args)...) {} |
||||
|
||||
// Constructs a variant of an alternative type from a provided index,
|
||||
// through value-initialization using the provided forwarded arguments.
|
||||
template <std::size_t I, class... Args, |
||||
typename std::enable_if<std::is_constructible< |
||||
variant_internal::VariantAlternativeSfinaeT<I, variant>, |
||||
Args...>::value>::type* = nullptr> |
||||
constexpr explicit variant(in_place_index_t<I>, Args&&... args) |
||||
: Base(variant_internal::EmplaceTag<I>(), absl::forward<Args>(args)...) {} |
||||
|
||||
// Constructs a variant of an alternative type from a provided index,
|
||||
// through value-initialization of an initializer list and the provided
|
||||
// forwarded arguments.
|
||||
template <std::size_t I, class U, class... Args, |
||||
typename std::enable_if<std::is_constructible< |
||||
variant_internal::VariantAlternativeSfinaeT<I, variant>, |
||||
std::initializer_list<U>&, Args...>::value>::type* = nullptr> |
||||
constexpr explicit variant(in_place_index_t<I>, std::initializer_list<U> il, |
||||
Args&&... args) |
||||
: Base(variant_internal::EmplaceTag<I>(), il, |
||||
absl::forward<Args>(args)...) {} |
||||
|
||||
// Destructors
|
||||
|
||||
// Destroys the variant's currently contained value, provided that
|
||||
// `absl::valueless_by_exception()` is false.
|
||||
~variant() = default; |
||||
|
||||
// Assignment Operators
|
||||
|
||||
// Copy assignement operator
|
||||
variant& operator=(const variant& other) = default; |
||||
|
||||
// Move assignment operator
|
||||
variant& operator=(variant&& other) /*noexcept(see above)*/ = default; |
||||
|
||||
// Converting assignment operator
|
||||
//
|
||||
// NOTE: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r1.html
|
||||
// has been voted passed the design phase in the C++ standard meeting in Mar
|
||||
// 2018. It will be implemented and integrated into `absl::variant`.
|
||||
template < |
||||
class T, |
||||
std::size_t I = std::enable_if< |
||||
!std::is_same<absl::decay_t<T>, variant>::value, |
||||
variant_internal::IndexOfConstructedType<variant, T>>::type::value, |
||||
class Tj = absl::variant_alternative_t<I, variant>, |
||||
typename std::enable_if<std::is_assignable<Tj&, T>::value && |
||||
std::is_constructible<Tj, T>::value>::type* = |
||||
nullptr> |
||||
variant& operator=(T&& t) noexcept( |
||||
std::is_nothrow_assignable<Tj&, T>::value&& |
||||
std::is_nothrow_constructible<Tj, T>::value) { |
||||
variant_internal::visit_indices<sizeof...(Tn) + 1>( |
||||
variant_internal::VariantCoreAccess::MakeConversionAssignVisitor( |
||||
this, absl::forward<T>(t)), |
||||
index()); |
||||
|
||||
return *this; |
||||
} |
||||
|
||||
|
||||
// emplace() Functions
|
||||
|
||||
// Constructs a value of the given alternative type T within the variant.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::variant<std::vector<int>, int, std::string> v;
|
||||
// v.emplace<int>(99);
|
||||
// v.emplace<std::string>("abc");
|
||||
template < |
||||
class T, class... Args, |
||||
typename std::enable_if<std::is_constructible< |
||||
absl::variant_alternative_t< |
||||
variant_internal::UnambiguousIndexOf<variant, T>::value, variant>, |
||||
Args...>::value>::type* = nullptr> |
||||
T& emplace(Args&&... args) { |
||||
return variant_internal::VariantCoreAccess::Replace< |
||||
variant_internal::UnambiguousIndexOf<variant, T>::value>( |
||||
this, absl::forward<Args>(args)...); |
||||
} |
||||
|
||||
// Constructs a value of the given alternative type T within the variant using
|
||||
// an initializer list.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::variant<std::vector<int>, int, std::string> v;
|
||||
// v.emplace<std::vector<int>>({0, 1, 2});
|
||||
template < |
||||
class T, class U, class... Args, |
||||
typename std::enable_if<std::is_constructible< |
||||
absl::variant_alternative_t< |
||||
variant_internal::UnambiguousIndexOf<variant, T>::value, variant>, |
||||
std::initializer_list<U>&, Args...>::value>::type* = nullptr> |
||||
T& emplace(std::initializer_list<U> il, Args&&... args) { |
||||
return variant_internal::VariantCoreAccess::Replace< |
||||
variant_internal::UnambiguousIndexOf<variant, T>::value>( |
||||
this, il, absl::forward<Args>(args)...); |
||||
} |
||||
|
||||
// Destroys the current value of the variant (provided that
|
||||
// `absl::valueless_by_exception()` is false, and constructs a new value at
|
||||
// the given index.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::variant<std::vector<int>, int, int> v;
|
||||
// v.emplace<1>(99);
|
||||
// v.emplace<2>(98);
|
||||
// v.emplace<int>(99); // Won't compile. 'int' isn't a unique type.
|
||||
template <std::size_t I, class... Args, |
||||
typename std::enable_if< |
||||
std::is_constructible<absl::variant_alternative_t<I, variant>, |
||||
Args...>::value>::type* = nullptr> |
||||
absl::variant_alternative_t<I, variant>& emplace(Args&&... args) { |
||||
return variant_internal::VariantCoreAccess::Replace<I>( |
||||
this, absl::forward<Args>(args)...); |
||||
} |
||||
|
||||
// Destroys the current value of the variant (provided that
|
||||
// `absl::valueless_by_exception()` is false, and constructs a new value at
|
||||
// the given index using an initializer list and the provided arguments.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::variant<std::vector<int>, int, int> v;
|
||||
// v.emplace<0>({0, 1, 2});
|
||||
template <std::size_t I, class U, class... Args, |
||||
typename std::enable_if<std::is_constructible< |
||||
absl::variant_alternative_t<I, variant>, |
||||
std::initializer_list<U>&, Args...>::value>::type* = nullptr> |
||||
absl::variant_alternative_t<I, variant>& emplace(std::initializer_list<U> il, |
||||
Args&&... args) { |
||||
return variant_internal::VariantCoreAccess::Replace<I>( |
||||
this, il, absl::forward<Args>(args)...); |
||||
} |
||||
|
||||
// variant::valueless_by_exception()
|
||||
//
|
||||
// Returns false if and only if the variant currently holds a valid value.
|
||||
constexpr bool valueless_by_exception() const noexcept { |
||||
return this->index_ == absl::variant_npos; |
||||
} |
||||
|
||||
// variant::index()
|
||||
//
|
||||
// Returns the index value of the variant's currently selected alternative
|
||||
// type.
|
||||
constexpr std::size_t index() const noexcept { return this->index_; } |
||||
|
||||
// variant::swap()
|
||||
//
|
||||
// Swaps the values of two variant objects.
|
||||
//
|
||||
// TODO(calabrese)
|
||||
// `variant::swap()` and `swap()` rely on `std::is_(nothrow)_swappable()`
|
||||
// which is introduced in C++17. So we assume `is_swappable()` is always
|
||||
// true and `is_nothrow_swappable()` is same as `std::is_trivial()`.
|
||||
void swap(variant& rhs) noexcept( |
||||
absl::conjunction<std::is_trivial<T0>, std::is_trivial<Tn>...>::value) { |
||||
return variant_internal::visit_indices<sizeof...(Tn) + 1>( |
||||
variant_internal::Swap<T0, Tn...>{this, &rhs}, rhs.index()); |
||||
} |
||||
}; |
||||
|
||||
// We need a valid declaration of variant<> for SFINAE and overload resolution
|
||||
// to work properly above, but we don't need a full declaration since this type
|
||||
// will never be constructed. This declaration, though incomplete, suffices.
|
||||
template <> |
||||
class variant<>; |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Relational Operators
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// If neither operand is in the `variant::valueless_by_exception` state:
|
||||
//
|
||||
// * If the index of both variants is the same, the relational operator
|
||||
// returns the result of the corresponding relational operator for the
|
||||
// corresponding alternative type.
|
||||
// * If the index of both variants is not the same, the relational operator
|
||||
// returns the result of that operation applied to the value of the left
|
||||
// operand's index and the value of the right operand's index.
|
||||
// * If at least one operand is in the valueless_by_exception state:
|
||||
// - A variant in the valueless_by_exception state is only considered equal
|
||||
// to another variant in the valueless_by_exception state.
|
||||
// - If exactly one operand is in the valueless_by_exception state, the
|
||||
// variant in the valueless_by_exception state is less than the variant
|
||||
// that is not in the valueless_by_exception state.
|
||||
//
|
||||
// Note: The value 1 is added to each index in the relational comparisons such
|
||||
// that the index corresponding to the valueless_by_exception state wraps around
|
||||
// to 0 (the lowest value for the index type), and the remaining indices stay in
|
||||
// the same relative order.
|
||||
|
||||
// Equal-to operator
|
||||
template <typename... Types> |
||||
constexpr variant_internal::RequireAllHaveEqualT<Types...> operator==( |
||||
const variant<Types...>& a, const variant<Types...>& b) { |
||||
return (a.index() == b.index()) && |
||||
variant_internal::visit_indices<sizeof...(Types)>( |
||||
variant_internal::EqualsOp<Types...>{&a, &b}, a.index()); |
||||
} |
||||
|
||||
// Not equal operator
|
||||
template <typename... Types> |
||||
constexpr variant_internal::RequireAllHaveNotEqualT<Types...> operator!=( |
||||
const variant<Types...>& a, const variant<Types...>& b) { |
||||
return (a.index() != b.index()) || |
||||
variant_internal::visit_indices<sizeof...(Types)>( |
||||
variant_internal::NotEqualsOp<Types...>{&a, &b}, a.index()); |
||||
} |
||||
|
||||
// Less-than operator
|
||||
template <typename... Types> |
||||
constexpr variant_internal::RequireAllHaveLessThanT<Types...> operator<( |
||||
const variant<Types...>& a, const variant<Types...>& b) { |
||||
return (a.index() != b.index()) |
||||
? (a.index() + 1) < (b.index() + 1) |
||||
: variant_internal::visit_indices<sizeof...(Types)>( |
||||
variant_internal::LessThanOp<Types...>{&a, &b}, a.index()); |
||||
} |
||||
|
||||
// Greater-than operator
|
||||
template <typename... Types> |
||||
constexpr variant_internal::RequireAllHaveGreaterThanT<Types...> operator>( |
||||
const variant<Types...>& a, const variant<Types...>& b) { |
||||
return (a.index() != b.index()) |
||||
? (a.index() + 1) > (b.index() + 1) |
||||
: variant_internal::visit_indices<sizeof...(Types)>( |
||||
variant_internal::GreaterThanOp<Types...>{&a, &b}, |
||||
a.index()); |
||||
} |
||||
|
||||
// Less-than or equal-to operator
|
||||
template <typename... Types> |
||||
constexpr variant_internal::RequireAllHaveLessThanOrEqualT<Types...> operator<=( |
||||
const variant<Types...>& a, const variant<Types...>& b) { |
||||
return (a.index() != b.index()) |
||||
? (a.index() + 1) < (b.index() + 1) |
||||
: variant_internal::visit_indices<sizeof...(Types)>( |
||||
variant_internal::LessThanOrEqualsOp<Types...>{&a, &b}, |
||||
a.index()); |
||||
} |
||||
|
||||
// Greater-than or equal-to operator
|
||||
template <typename... Types> |
||||
constexpr variant_internal::RequireAllHaveGreaterThanOrEqualT<Types...> |
||||
operator>=(const variant<Types...>& a, const variant<Types...>& b) { |
||||
return (a.index() != b.index()) |
||||
? (a.index() + 1) > (b.index() + 1) |
||||
: variant_internal::visit_indices<sizeof...(Types)>( |
||||
variant_internal::GreaterThanOrEqualsOp<Types...>{&a, &b}, |
||||
a.index()); |
||||
} |
||||
|
||||
} // namespace absl
|
||||
|
||||
namespace std { |
||||
|
||||
// hash()
|
||||
template <> // NOLINT
|
||||
struct hash<absl::monostate> { |
||||
std::size_t operator()(absl::monostate) const { return 0; } |
||||
}; |
||||
|
||||
template <class... T> // NOLINT
|
||||
struct hash<absl::variant<T...>> |
||||
: absl::variant_internal::VariantHashBase<absl::variant<T...>, void, |
||||
absl::remove_const_t<T>...> {}; |
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // ABSL_HAVE_STD_VARIANT
|
||||
|
||||
namespace absl { |
||||
namespace variant_internal { |
||||
|
||||
// Helper visitor for converting a variant<Ts...>` into another type (mostly
|
||||
// variant) that can be constructed from any type.
|
||||
template <typename To> |
||||
struct ConversionVisitor { |
||||
template <typename T> |
||||
To operator()(T&& v) const { |
||||
return To(std::forward<T>(v)); |
||||
} |
||||
}; |
||||
|
||||
} // namespace variant_internal
|
||||
|
||||
// ConvertVariantTo()
|
||||
//
|
||||
// Helper functions to convert an `absl::variant` to a variant of another set of
|
||||
// types, provided that the alternative type of the new variant type can be
|
||||
// converted from any type in the source variant.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::variant<name1, name2, float> InternalReq(const Req&);
|
||||
//
|
||||
// // name1 and name2 are convertible to name
|
||||
// absl::variant<name, float> ExternalReq(const Req& req) {
|
||||
// return absl::ConvertVariantTo<absl::variant<name, float>>(
|
||||
// InternalReq(req));
|
||||
// }
|
||||
template <typename To, typename Variant> |
||||
To ConvertVariantTo(Variant&& variant) { |
||||
return absl::visit(variant_internal::ConversionVisitor<To>{}, |
||||
std::forward<Variant>(variant)); |
||||
} |
||||
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TYPES_VARIANT_H_
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue