- 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: I1a343b080187293cb5f892a309618b5712e7aa14
This commit is contained in:
parent
5b53540166
commit
faf0a1b903
19 changed files with 5172 additions and 52 deletions
|
@ -382,6 +382,19 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_STD_VARIANT
|
||||
//
|
||||
// Checks whether C++17 std::optional is available.
|
||||
#ifdef ABSL_HAVE_STD_VARIANT
|
||||
#error "ABSL_HAVE_STD_VARIANT cannot be directly set."
|
||||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<variant>) && __cplusplus >= 201703L
|
||||
#define ABSL_HAVE_STD_VARIANT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_STD_STRING_VIEW
|
||||
//
|
||||
// Checks whether C++17 std::string_view is available.
|
||||
|
@ -396,17 +409,18 @@
|
|||
#endif
|
||||
|
||||
// For MSVC, `__has_include` is supported in VS 2017 15.3, which is later than
|
||||
// the support for <optional>, <any>, <string_view>. So we use _MSC_VER to check
|
||||
// whether we have VS 2017 RTM (when <optional>, <any>, <string_view> is
|
||||
// implemented) or higher.
|
||||
// Also, `__cplusplus` is not correctly set by MSVC, so we use `_MSVC_LANG` to
|
||||
// check the language version.
|
||||
// the support for <optional>, <any>, <string_view>, <variant>. So we use
|
||||
// _MSC_VER to check whether we have VS 2017 RTM (when <optional>, <any>,
|
||||
// <string_view>, <variant> is implemented) or higher. Also, `__cplusplus` is
|
||||
// not correctly set by MSVC, so we use `_MSVC_LANG` to check the language
|
||||
// version.
|
||||
// TODO(zhangxy): fix tests before enabling aliasing for `std::any`,
|
||||
// `std::string_view`.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1910 && \
|
||||
((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402)
|
||||
// #define ABSL_HAVE_STD_ANY 1
|
||||
#define ABSL_HAVE_STD_OPTIONAL 1
|
||||
#define ABSL_HAVE_STD_VARIANT 1
|
||||
// #define ABSL_HAVE_STD_STRING_VIEW 1
|
||||
#endif
|
||||
|
||||
|
|
|
@ -27,7 +27,9 @@
|
|||
|
||||
namespace absl {
|
||||
namespace {
|
||||
using ::absl::exceptions_internal::SetCountdown;
|
||||
using ::absl::exceptions_internal::TestException;
|
||||
using ::absl::exceptions_internal::UnsetCountdown;
|
||||
|
||||
// EXPECT_NO_THROW can't inspect the thrown inspection in general.
|
||||
template <typename F>
|
||||
|
@ -54,7 +56,7 @@ TEST_F(ThrowingValueTest, Throws) {
|
|||
// It's not guaranteed that every operator only throws *once*. The default
|
||||
// ctor only throws once, though, so use it to make sure we only throw when
|
||||
// the countdown hits 0
|
||||
exceptions_internal::countdown = 2;
|
||||
SetCountdown(2);
|
||||
ExpectNoThrow([]() { ThrowingValue<> bomb; });
|
||||
ExpectNoThrow([]() { ThrowingValue<> bomb; });
|
||||
EXPECT_THROW(ThrowingValue<> bomb, TestException);
|
||||
|
|
|
@ -94,6 +94,12 @@ class TestBadAllocException : public std::bad_alloc, public TestException {
|
|||
|
||||
extern int countdown;
|
||||
|
||||
// Allows the countdown variable to be set manually (defaulting to the initial
|
||||
// value of 0)
|
||||
inline void SetCountdown(int i = 0) { countdown = i; }
|
||||
// Sets the countdown to the terminal value -1
|
||||
inline void UnsetCountdown() { SetCountdown(-1); }
|
||||
|
||||
void MaybeThrow(absl::string_view msg, bool throw_bad_alloc = false);
|
||||
|
||||
testing::AssertionResult FailureMessage(const TestException& e,
|
||||
|
@ -134,7 +140,7 @@ absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl(
|
|||
const Invariant& invariant) {
|
||||
auto t_ptr = factory();
|
||||
absl::optional<testing::AssertionResult> current_res;
|
||||
exceptions_internal::countdown = count;
|
||||
SetCountdown(count);
|
||||
try {
|
||||
operation(t_ptr.get());
|
||||
} catch (const exceptions_internal::TestException& e) {
|
||||
|
@ -143,7 +149,7 @@ absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl(
|
|||
*current_res << e.what() << " failed invariant check";
|
||||
}
|
||||
}
|
||||
exceptions_internal::countdown = -1;
|
||||
UnsetCountdown();
|
||||
return current_res;
|
||||
}
|
||||
|
||||
|
@ -196,11 +202,6 @@ inline absl::optional<testing::AssertionResult> TestAllInvariantsAtCountdown(
|
|||
extern exceptions_internal::NoThrowTag no_throw_ctor;
|
||||
extern exceptions_internal::StrongGuaranteeTagType strong_guarantee;
|
||||
|
||||
// These are useful for tests which just construct objects and make sure there
|
||||
// are no leaks.
|
||||
inline void SetCountdown() { exceptions_internal::countdown = 0; }
|
||||
inline void UnsetCountdown() { exceptions_internal::countdown = -1; }
|
||||
|
||||
// A test class which is convertible to bool. The conversion can be
|
||||
// instrumented to throw at a controlled time.
|
||||
class ThrowingBool {
|
||||
|
@ -731,10 +732,10 @@ struct ConstructorTracker {
|
|||
template <typename T, typename... Args>
|
||||
T TestThrowingCtor(Args&&... args) {
|
||||
struct Cleanup {
|
||||
~Cleanup() { UnsetCountdown(); }
|
||||
~Cleanup() { exceptions_internal::UnsetCountdown(); }
|
||||
} c;
|
||||
for (int count = 0;; ++count) {
|
||||
exceptions_internal::countdown = count;
|
||||
exceptions_internal::SetCountdown(count);
|
||||
try {
|
||||
return T(std::forward<Args>(args)...);
|
||||
} catch (const exceptions_internal::TestException&) {
|
||||
|
|
|
@ -47,10 +47,17 @@
|
|||
// mutex. GUARDED_BY() allows the user to specify a particular mutex that
|
||||
// should be held when accessing the annotated variable.
|
||||
//
|
||||
// Although this annotation (and PT_GUARDED_BY, below) cannot be applied to
|
||||
// local variables, a local variable and its associated mutex can often be
|
||||
// combined into a small class or struct, thereby allowing the annotation.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// Mutex mu;
|
||||
// int p1 GUARDED_BY(mu);
|
||||
// class Foo {
|
||||
// Mutex mu_;
|
||||
// int p1_ GUARDED_BY(mu_);
|
||||
// ...
|
||||
// };
|
||||
#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
|
||||
|
||||
// PT_GUARDED_BY()
|
||||
|
@ -59,17 +66,20 @@
|
|||
// by a mutex when dereferencing the pointer.
|
||||
//
|
||||
// Example:
|
||||
// Mutex mu;
|
||||
// int *p1 PT_GUARDED_BY(mu);
|
||||
// class Foo {
|
||||
// Mutex mu_;
|
||||
// int *p1_ PT_GUARDED_BY(mu_);
|
||||
// ...
|
||||
// };
|
||||
//
|
||||
// Note that a pointer variable to a shared memory location could itself be a
|
||||
// shared variable.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // `q`, guarded by `mu1`, points to a shared memory location that is
|
||||
// // guarded by `mu2`:
|
||||
// int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
|
||||
// // `q_`, guarded by `mu1_`, points to a shared memory location that is
|
||||
// // guarded by `mu2_`:
|
||||
// int *q_ GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_);
|
||||
#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
|
||||
|
||||
// ACQUIRED_AFTER() / ACQUIRED_BEFORE()
|
||||
|
@ -80,10 +90,13 @@
|
|||
// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
|
||||
// and ACQUIRED_BEFORE.)
|
||||
//
|
||||
// As with GUARDED_BY, this is only applicable to mutexes that are shared
|
||||
// fields or global variables.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// Mutex m1;
|
||||
// Mutex m2 ACQUIRED_AFTER(m1);
|
||||
// Mutex m1_;
|
||||
// Mutex m2_ ACQUIRED_AFTER(m1_);
|
||||
#define ACQUIRED_AFTER(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#define ABSL_META_TYPE_TRAITS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
@ -349,5 +350,23 @@ using underlying_type_t = typename std::underlying_type<T>::type;
|
|||
template <typename T>
|
||||
using result_of_t = typename std::result_of<T>::type;
|
||||
|
||||
namespace type_traits_internal {
|
||||
template <typename Key, typename = size_t>
|
||||
struct IsHashable : std::false_type {};
|
||||
|
||||
template <typename Key>
|
||||
struct IsHashable<Key,
|
||||
decltype(std::declval<std::hash<Key>>()(std::declval<Key>()))>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename Key>
|
||||
struct IsHashEnabled
|
||||
: absl::conjunction<std::is_default_constructible<std::hash<Key>>,
|
||||
std::is_copy_constructible<std::hash<Key>>,
|
||||
std::is_destructible<std::hash<Key>>,
|
||||
std::is_copy_assignable<std::hash<Key>>,
|
||||
IsHashable<Key>> {};
|
||||
} // namespace type_traits_internal
|
||||
|
||||
} // namespace absl
|
||||
#endif // ABSL_META_TYPE_TRAITS_H_
|
||||
|
|
|
@ -165,7 +165,7 @@ DereferenceFormatter() {
|
|||
//
|
||||
// Example 1:
|
||||
// // Joins a collection of strings. This pattern also works with a collection
|
||||
// // of `asbl::string_view` or even `const char*`.
|
||||
// // of `absl::string_view` or even `const char*`.
|
||||
// std::vector<std::string> v = {"foo", "bar", "baz"};
|
||||
// std::string s = absl::StrJoin(v, "-");
|
||||
// EXPECT_EQ("foo-bar-baz", s);
|
||||
|
|
|
@ -880,7 +880,8 @@ extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z
|
|||
// provided format std::string. Uses strftime()-like formatting options, with
|
||||
// the following extensions:
|
||||
//
|
||||
// - %Ez - RFC3339-compatible numeric time zone (+hh:mm or -hh:mm)
|
||||
// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
|
||||
// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
|
||||
// - %E#S - Seconds with # digits of fractional precision
|
||||
// - %E*S - Seconds with full fractional precision (a literal '*')
|
||||
// - %E#f - Fractional seconds with # digits of precision
|
||||
|
@ -894,8 +895,8 @@ extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z
|
|||
// year. A year outside of [-999:9999] when formatted with %E4Y will produce
|
||||
// more than four characters, just like %Y.
|
||||
//
|
||||
// We recommend that format strings include %Ez so that the result uniquely
|
||||
// identifies a time instant.
|
||||
// We recommend that format strings include the UTC offset (%z, %Ez, or %E*z)
|
||||
// so that the result uniquely identifies a time instant.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
|
@ -929,7 +930,8 @@ inline std::ostream& operator<<(std::ostream& os, Time t) {
|
|||
// Parses an input std::string according to the provided format std::string and
|
||||
// returns the corresponding `absl::Time`. Uses strftime()-like formatting
|
||||
// options, with the same extensions as FormatTime(), but with the
|
||||
// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f.
|
||||
// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez
|
||||
// and %E*z also accept the same inputs.
|
||||
//
|
||||
// %Y consumes as many numeric characters as it can, so the matching data
|
||||
// should always be terminated with a non-numeric. %E4Y always consumes
|
||||
|
@ -940,10 +942,11 @@ inline std::ostream& operator<<(std::ostream& os, Time t) {
|
|||
// "1970-01-01 00:00:00.0 +0000"
|
||||
//
|
||||
// For example, parsing a std::string of "15:45" (%H:%M) will return an absl::Time
|
||||
// that represents "1970-01-01 15:45:00.0 +0000". Note: Since ParseTime()
|
||||
// returns time instants, it makes the most sense to parse fully-specified
|
||||
// date/time strings that include a UTC offset (%z/%Ez), such as those
|
||||
// matching RFC3339_full above.
|
||||
// that represents "1970-01-01 15:45:00.0 +0000".
|
||||
//
|
||||
// Note that since ParseTime() returns time instants, it makes the most sense
|
||||
// to parse fully-specified date/time strings that include a UTC offset (%z,
|
||||
// %Ez, or %E*z).
|
||||
//
|
||||
// Note also that `absl::ParseTime()` only heeds the fields year, month, day,
|
||||
// hour, minute, (fractional) second, and UTC offset. Other fields, like
|
||||
|
@ -974,8 +977,8 @@ bool ParseTime(const std::string& format, const std::string& input, Time* time,
|
|||
std::string* err);
|
||||
|
||||
// Like ParseTime() above, but if the format std::string does not contain a UTC
|
||||
// offset specification (%z/%Ez) then the input is interpreted in the given
|
||||
// TimeZone. This means that the input, by itself, does not identify a
|
||||
// offset specification (%z/%Ez/%E*z) then the input is interpreted in the
|
||||
// given TimeZone. This means that the input, by itself, does not identify a
|
||||
// unique instant. Being time-zone dependent, it also admits the possibility
|
||||
// of ambiguity or non-existence, in which case the "pre" time (as defined
|
||||
// for ConvertDateTime()) is returned. For these reasons we recommend that
|
||||
|
|
|
@ -165,6 +165,17 @@ cc_library(
|
|||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "bad_variant_access",
|
||||
srcs = ["bad_variant_access.cc"],
|
||||
hdrs = ["bad_variant_access.h"],
|
||||
copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS,
|
||||
deps = [
|
||||
"//absl/base",
|
||||
"//absl/base:config",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "optional_test",
|
||||
size = "small",
|
||||
|
@ -181,3 +192,34 @@ cc_test(
|
|||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "variant",
|
||||
srcs = ["internal/variant.h"],
|
||||
hdrs = ["variant.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
deps = [
|
||||
":bad_variant_access",
|
||||
"//absl/base:base_internal",
|
||||
"//absl/base:config",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/utility",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "variant_test",
|
||||
size = "small",
|
||||
srcs = ["variant_test.cc"],
|
||||
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
|
||||
deps = [
|
||||
":variant",
|
||||
"//absl/base:config",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/memory",
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/strings",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -20,6 +20,7 @@ list(APPEND TYPES_PUBLIC_HEADERS
|
|||
"bad_optional_access.h"
|
||||
"optional.h"
|
||||
"span.h"
|
||||
"variant.h"
|
||||
)
|
||||
|
||||
|
||||
|
@ -95,7 +96,19 @@ absl_library(
|
|||
bad_optional_access
|
||||
)
|
||||
|
||||
|
||||
# variant library
|
||||
absl_library(
|
||||
TARGET
|
||||
absl_variant
|
||||
SOURCES
|
||||
"bad_variant_access.h" "bad_variant_access.cc" "variant.h" "internal/variant.h"
|
||||
PUBLIC_LIBRARIES
|
||||
absl::base absl::meta absl::utility
|
||||
PRIVATE_COMPILE_FLAGS
|
||||
${ABSL_EXCEPTIONS_FLAG}
|
||||
EXPORT_NAME
|
||||
variant
|
||||
)
|
||||
|
||||
#
|
||||
## TESTS
|
||||
|
|
|
@ -172,7 +172,9 @@ const ValueType* any_cast(const any* operand) noexcept;
|
|||
template <typename ValueType>
|
||||
ValueType* any_cast(any* operand) noexcept;
|
||||
|
||||
// any
|
||||
// -----------------------------------------------------------------------------
|
||||
// absl::any
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// An `absl::any` object provides the facility to either store an instance of a
|
||||
// type, known as the "contained object", or no value. An `absl::any` is used to
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Abseil Authors.
|
||||
// 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.
|
||||
|
@ -11,6 +11,12 @@
|
|||
// 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_any_cast.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines the `absl::bad_any_cast` type.
|
||||
|
||||
#ifndef ABSL_TYPES_BAD_ANY_CAST_H_
|
||||
#define ABSL_TYPES_BAD_ANY_CAST_H_
|
||||
|
@ -19,21 +25,28 @@
|
|||
|
||||
namespace absl {
|
||||
|
||||
////////////////////////
|
||||
// [any.bad_any_cast] //
|
||||
////////////////////////
|
||||
|
||||
// Objects of type bad_any_cast are thrown by a failed any_cast.
|
||||
// -----------------------------------------------------------------------------
|
||||
// bad_any_cast
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// An `absl::bad_any_cast` type is an exception type that is thrown when
|
||||
// failing to successfully cast the return value of an `absl::any` object.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// auto a = absl::any(65);
|
||||
// absl::any_cast<int>(a); // 65
|
||||
// try {
|
||||
// absl::any_cast<char>(a);
|
||||
// } catch(const absl::bad_any_cast& e) {
|
||||
// std::cout << "Bad any cast: " << e.what() << '\n';
|
||||
// }
|
||||
class bad_any_cast : public std::bad_cast {
|
||||
public:
|
||||
~bad_any_cast() override;
|
||||
const char* what() const noexcept override;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Implementation-details beyond this point //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
namespace any_internal {
|
||||
|
||||
[[noreturn]] void ThrowBadAnyCast();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 The Abseil Authors.
|
||||
// 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.
|
||||
|
@ -11,6 +11,12 @@
|
|||
// 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_optional_access.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines the `absl::bad_optional_access` type.
|
||||
|
||||
#ifndef ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
|
||||
#define ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
|
||||
|
@ -19,6 +25,23 @@
|
|||
|
||||
namespace absl {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// bad_optional_access
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// An `absl::bad_optional_access` type is an exception type that is thrown when
|
||||
// attempting to access an `absl::optional` object that does not contain a
|
||||
// value.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::optional<int> o;
|
||||
//
|
||||
// try {
|
||||
// int n = o.value();
|
||||
// } catch(const absl::bad_optional_access& e) {
|
||||
// std::cout << "Bad optional access: " << e.what() << '\n';
|
||||
// }
|
||||
class bad_optional_access : public std::exception {
|
||||
public:
|
||||
bad_optional_access() = default;
|
||||
|
|
58
absl/types/bad_variant_access.cc
Normal file
58
absl/types/bad_variant_access.cc
Normal file
|
@ -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
|
64
absl/types/bad_variant_access.h
Normal file
64
absl/types/bad_variant_access.h
Normal file
|
@ -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_
|
1387
absl/types/internal/variant.h
Normal file
1387
absl/types/internal/variant.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,3 @@
|
|||
//
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -94,7 +93,9 @@ using std::nullopt;
|
|||
|
||||
namespace absl {
|
||||
|
||||
// optional
|
||||
// -----------------------------------------------------------------------------
|
||||
// absl::optional
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// A value of type `absl::optional<T>` holds either a value of `T` or an
|
||||
// "empty" value. When it holds a value of `T`, it stores it as a direct
|
||||
|
|
838
absl/types/variant.h
Normal file
838
absl/types/variant.h
Normal file
|
@ -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_
|
2622
absl/types/variant_test.cc
Normal file
2622
absl/types/variant_test.cc
Normal file
File diff suppressed because it is too large
Load diff
|
@ -161,7 +161,7 @@ ABSL_INTERNAL_INLINE_CONSTEXPR(in_place_t, in_place, {});
|
|||
|
||||
#endif // ABSL_HAVE_STD_OPTIONAL
|
||||
|
||||
#ifdef ABSL_HAVE_STD_ANY
|
||||
#if defined(ABSL_HAVE_STD_ANY) || defined(ABSL_HAVE_STD_VARIANT)
|
||||
using std::in_place_type_t;
|
||||
#else
|
||||
|
||||
|
@ -172,7 +172,11 @@ using std::in_place_type_t;
|
|||
// for C++17's `std::in_place_type_t`.
|
||||
template <typename T>
|
||||
struct in_place_type_t {};
|
||||
#endif // ABSL_HAVE_STD_ANY
|
||||
#endif // ABSL_HAVE_STD_ANY || ABSL_HAVE_STD_VARIANT
|
||||
|
||||
#ifdef ABSL_HAVE_STD_VARIANT
|
||||
using std::in_place_index_t;
|
||||
#else
|
||||
|
||||
// in_place_index_t
|
||||
//
|
||||
|
@ -181,6 +185,7 @@ struct in_place_type_t {};
|
|||
// for C++17's `std::in_place_index_t`.
|
||||
template <size_t I>
|
||||
struct in_place_index_t {};
|
||||
#endif // ABSL_HAVE_STD_VARIANT
|
||||
|
||||
// Constexpr move and forward
|
||||
|
||||
|
|
Loading…
Reference in a new issue