Initial Commit
This commit is contained in:
commit
c2e7548296
238 changed files with 65475 additions and 0 deletions
178
absl/types/BUILD.bazel
Normal file
178
absl/types/BUILD.bazel
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
load(
|
||||
"//absl:copts.bzl",
|
||||
"ABSL_DEFAULT_COPTS",
|
||||
"ABSL_TEST_COPTS",
|
||||
"ABSL_EXCEPTIONS_FLAG",
|
||||
)
|
||||
load(
|
||||
"//absl:test_dependencies.bzl",
|
||||
"GUNIT_MAIN_DEPS_SELECTOR",
|
||||
)
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"]) # Apache 2.0
|
||||
|
||||
cc_library(
|
||||
name = "any",
|
||||
hdrs = ["any.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
deps = [
|
||||
":bad_any_cast",
|
||||
"//absl/base:config",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/utility",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "bad_any_cast",
|
||||
srcs = ["bad_any_cast.cc"],
|
||||
hdrs = ["bad_any_cast.h"],
|
||||
copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS,
|
||||
features = [
|
||||
"-use_header_modules", # b/33207452
|
||||
],
|
||||
deps = [
|
||||
"//absl/base",
|
||||
"//absl/base:config",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "any_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"any_test.cc",
|
||||
],
|
||||
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
|
||||
deps = [
|
||||
":any",
|
||||
"//absl/base",
|
||||
"//absl/base:config",
|
||||
"//absl/base:exception_testing",
|
||||
"//absl/container:test_instance_tracker",
|
||||
] + select(GUNIT_MAIN_DEPS_SELECTOR),
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "any_test_noexceptions",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"any_test.cc",
|
||||
],
|
||||
copts = ABSL_TEST_COPTS,
|
||||
deps = [
|
||||
":any",
|
||||
"//absl/base",
|
||||
"//absl/base:config",
|
||||
"//absl/base:exception_testing",
|
||||
"//absl/container:test_instance_tracker",
|
||||
] + select(GUNIT_MAIN_DEPS_SELECTOR),
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "span",
|
||||
hdrs = ["span.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
deps = [
|
||||
"//absl/algorithm",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:throw_delegate",
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "span_test",
|
||||
size = "small",
|
||||
srcs = ["span_test.cc"],
|
||||
copts = ABSL_TEST_COPTS + ["-fexceptions"],
|
||||
deps = [
|
||||
":span",
|
||||
"//absl/base:config",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:exception_testing",
|
||||
"//absl/container:fixed_array",
|
||||
"//absl/container:inlined_vector",
|
||||
"//absl/strings",
|
||||
] + select(GUNIT_MAIN_DEPS_SELECTOR),
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "span_test_noexceptions",
|
||||
size = "small",
|
||||
srcs = ["span_test.cc"],
|
||||
copts = ABSL_TEST_COPTS,
|
||||
deps = [
|
||||
":span",
|
||||
"//absl/base:config",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:exception_testing",
|
||||
"//absl/container:fixed_array",
|
||||
"//absl/container:inlined_vector",
|
||||
"//absl/strings",
|
||||
] + select(GUNIT_MAIN_DEPS_SELECTOR),
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "optional",
|
||||
srcs = ["optional.cc"],
|
||||
hdrs = ["optional.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
deps = [
|
||||
":bad_optional_access",
|
||||
"//absl/base:config",
|
||||
"//absl/memory",
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/utility",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "bad_optional_access",
|
||||
srcs = ["bad_optional_access.cc"],
|
||||
hdrs = ["bad_optional_access.h"],
|
||||
copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG,
|
||||
features = [
|
||||
"-use_header_modules", # b/33207452
|
||||
],
|
||||
deps = [
|
||||
"//absl/base",
|
||||
"//absl/base:config",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "optional_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"optional_test.cc",
|
||||
],
|
||||
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
|
||||
deps = [
|
||||
":optional",
|
||||
"//absl/base",
|
||||
"//absl/base:config",
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/strings",
|
||||
] + select(GUNIT_MAIN_DEPS_SELECTOR),
|
||||
)
|
||||
539
absl/types/any.h
Normal file
539
absl/types/any.h
Normal file
|
|
@ -0,0 +1,539 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// any.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file define the `absl::any` type for holding a type-safe value
|
||||
// of any type. The 'absl::any` type is useful for providing a way to hold
|
||||
// something that is, as yet, unspecified. Such unspecified types
|
||||
// traditionally are passed between API boundaries until they are later cast to
|
||||
// their "destination" types. To cast to such a destination type, use
|
||||
// `absl::any_cast()`. Note that when casting an `absl::any`, you must cast it
|
||||
// to an explicit type; implicit conversions will throw.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// auto a = absl::any(65);
|
||||
// absl::any_cast<int>(a); // 65
|
||||
// absl::any_cast<char>(a); // throws absl::bad_any_cast
|
||||
// absl::any_cast<std::string>(a); // throws absl::bad_any_cast
|
||||
//
|
||||
// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
|
||||
// and is designed to be a drop-in replacement for code compliant with C++17.
|
||||
//
|
||||
// Traditionally, the behavior of casting to a temporary unspecified type has
|
||||
// been accomplished with the `void *` paradigm, where the pointer was to some
|
||||
// other unspecified type. `absl::any` provides an "owning" version of `void *`
|
||||
// that avoids issues of pointer management.
|
||||
//
|
||||
// Note: just as in the case of `void *`, use of `absl::any` (and its C++17
|
||||
// version `std::any`) is a code smell indicating that your API might not be
|
||||
// constructed correctly. We have seen that most uses of `any` are unwarranted,
|
||||
// and `absl::any`, like `std::any`, is difficult to use properly. Before using
|
||||
// this abstraction, make sure that you should not instead be rewriting your
|
||||
// code to be more specific.
|
||||
//
|
||||
// Abseil expects to release an `absl::variant` type shortly (a C++11 compatible
|
||||
// version of the C++17 `std::variant), which is generally preferred for use
|
||||
// over `absl::any`.
|
||||
#ifndef ABSL_TYPES_ANY_H_
|
||||
#define ABSL_TYPES_ANY_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/utility/utility.h"
|
||||
|
||||
#ifdef ABSL_HAVE_STD_ANY
|
||||
|
||||
#include <any>
|
||||
|
||||
namespace absl {
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
using std::bad_any_cast;
|
||||
using std::make_any;
|
||||
} // namespace absl
|
||||
|
||||
#else // ABSL_HAVE_STD_ANY
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
#include "absl/types/bad_any_cast.h"
|
||||
|
||||
// NOTE: This macro is an implementation detail that is undefined at the bottom
|
||||
// of the file. It is not intended for expansion directly from user code.
|
||||
#ifdef ABSL_ANY_DETAIL_HAS_RTTI
|
||||
#error ABSL_ANY_DETAIL_HAS_RTTI cannot be directly set
|
||||
#elif !defined(__GNUC__) || defined(__GXX_RTTI)
|
||||
#define ABSL_ANY_DETAIL_HAS_RTTI 1
|
||||
#endif // !defined(__GNUC__) || defined(__GXX_RTTI)
|
||||
|
||||
namespace absl {
|
||||
|
||||
namespace any_internal {
|
||||
|
||||
// FastTypeId<Type>() evaluates at compile/link-time to a unique integer for the
|
||||
// passed in type. Their values are neither contiguous nor small, making them
|
||||
// unfit for using as an index into a vector, but a good match for keys into
|
||||
// maps or straight up comparisons.
|
||||
// Note that on 64-bit (unix) systems size_t is 64-bit while int is 32-bit and
|
||||
// the compiler will happily and quietly assign such a 64-bit value to a
|
||||
// 32-bit integer. While a client should never do that it SHOULD still be safe,
|
||||
// assuming the BSS segment doesn't span more than 4GiB.
|
||||
template<typename Type>
|
||||
inline size_t FastTypeId() {
|
||||
static_assert(sizeof(char*) <= sizeof(size_t),
|
||||
"ptr size too large for size_t");
|
||||
|
||||
// This static variable isn't actually used, only its address, so there are
|
||||
// no concurrency issues.
|
||||
static char dummy_var;
|
||||
return reinterpret_cast<size_t>(&dummy_var);
|
||||
}
|
||||
|
||||
} // namespace any_internal
|
||||
|
||||
class any;
|
||||
|
||||
// swap()
|
||||
//
|
||||
// Swaps two `absl::any` values. Equivalent to `x.swap(y) where `x` and `y` are
|
||||
// `absl::any` types.
|
||||
void swap(any& x, any& y) noexcept;
|
||||
|
||||
// make_any()
|
||||
//
|
||||
// Constructs an `absl::any` of type `T` with the given arguments.
|
||||
template <typename T, typename... Args>
|
||||
any make_any(Args&&... args);
|
||||
|
||||
// Overload of `absl::make_any()` for constructing an `absl::any` type from an
|
||||
// initializer list.
|
||||
template <typename T, typename U, typename... Args>
|
||||
any make_any(std::initializer_list<U> il, Args&&... args);
|
||||
|
||||
// any_cast()
|
||||
//
|
||||
// Statically casts the value of a `const absl::any` type to the given type.
|
||||
// This function will throw `absl::bad_any_cast` if the stored value type of the
|
||||
// `absl::any` does not match the cast.
|
||||
//
|
||||
// `any_cast()` can also be used to get a reference to the internal storage iff
|
||||
// a reference type is passed as its `ValueType`:
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::any my_any = std::vector<int>();
|
||||
// absl::any_cast<std::vector<int>&>(my_any).push_back(42);
|
||||
template <typename ValueType>
|
||||
ValueType any_cast(const any& operand);
|
||||
|
||||
// Overload of `any_cast()` to statically cast the value of a non-const
|
||||
// `absl::any` type to the given type. This function will throw
|
||||
// `absl::bad_any_cast` if the stored value type of the `absl::any` does not
|
||||
// match the cast.
|
||||
template <typename ValueType>
|
||||
ValueType any_cast(any& operand); // NOLINT(runtime/references)
|
||||
|
||||
// Overload of `any_cast()` to statically cast the rvalue of an `absl::any`
|
||||
// type. This function will throw `absl::bad_any_cast` if the stored value type
|
||||
// of the `absl::any` does not match the cast.
|
||||
template <typename ValueType>
|
||||
ValueType any_cast(any&& operand);
|
||||
|
||||
// Overload of `any_cast()` to statically cast the value of a const pointer
|
||||
// `absl::any` type to the given pointer type, or `nullptr` if the stored value
|
||||
// type of the `absl::any` does not match the cast.
|
||||
template <typename ValueType>
|
||||
const ValueType* any_cast(const any* operand) noexcept;
|
||||
|
||||
// Overload of `any_cast()` to statically cast the value of a pointer
|
||||
// `absl::any` type to the given pointer type, or `nullptr` if the stored value
|
||||
// type of the `absl::any` does not match the cast.
|
||||
template <typename ValueType>
|
||||
ValueType* any_cast(any* operand) noexcept;
|
||||
|
||||
// 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
|
||||
// store values of types that are unknown at compile time. The `absl::any`
|
||||
// object, when containing a value, must contain a value type; storing a
|
||||
// reference type is neither desired nor supported.
|
||||
//
|
||||
// An `absl::any` can only store a type that is copy-constructable; move-only
|
||||
// types are not allowed within an `any` object.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// auto a = absl::any(65); // Literal, copyable
|
||||
// auto b = absl::any(std::vector<int>()); // Default-initialized, copyable
|
||||
// std::unique_ptr<Foo> my_foo;
|
||||
// auto c = absl::any(std::move(my_foo)); // Error, not copy-constructable
|
||||
//
|
||||
// Note that `absl::any` makes use of decayed types (`absl::decay_t` in this
|
||||
// context) to remove const-volative qualifiers (known as "cv qualifiers"),
|
||||
// decay functions to function pointers, etc. We essentially "decay" a given
|
||||
// type into its essential type.
|
||||
//
|
||||
// `absl::any` makes use of decayed types when determing the basic type `T` of
|
||||
// the value to store in the any's contained object. In the documentation below,
|
||||
// we explcitly denote this by using the phrase "a decayed type of `T`".
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// const int a = 4;
|
||||
// absl::any foo(a); // Decay ensures we store an "int", not a "const int&".
|
||||
//
|
||||
// void my_function() {}
|
||||
// absl::any bar(my_function); // Decay ensures we store a function pointer.
|
||||
//
|
||||
// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
|
||||
// and is designed to be a drop-in replacement for code compliant with C++17.
|
||||
class any {
|
||||
private:
|
||||
template <typename T>
|
||||
struct IsInPlaceType;
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
|
||||
// Constructs an empty `absl::any` object (`any::has_value()` will return
|
||||
// `false`).
|
||||
constexpr any() noexcept;
|
||||
|
||||
// Copy constructs an `absl::any` object with a "contained object" of the
|
||||
// passed type of `other` (or an empty `absl::any` if `other.has_value()` is
|
||||
// `false`.
|
||||
any(const any& other)
|
||||
: obj_(other.has_value() ? other.obj_->Clone()
|
||||
: std::unique_ptr<ObjInterface>()) {}
|
||||
|
||||
// Move constructs an `absl::any` object with a "contained object" of the
|
||||
// passed type of `other` (or an empty `absl::any` if `other.has_value()` is
|
||||
// `false`).
|
||||
any(any&& other) noexcept = default;
|
||||
|
||||
// Constructs an `absl::any` object with a "contained object" of the decayed
|
||||
// type of `T`, which is initialized via `std::forward<T>(value)`.
|
||||
//
|
||||
// This constructor will not participate in overload resolution if the
|
||||
// decayed type of `T` is not copy-constructible.
|
||||
template <
|
||||
typename T, typename VT = absl::decay_t<T>,
|
||||
absl::enable_if_t<!absl::disjunction<
|
||||
std::is_same<any, VT>, IsInPlaceType<VT>,
|
||||
absl::negation<std::is_copy_constructible<VT> > >::value>* = nullptr>
|
||||
any(T&& value) : obj_(new Obj<VT>(in_place, std::forward<T>(value))) {}
|
||||
|
||||
// Constructs an `absl::any` object with a "contained object" of the decayed
|
||||
// type of `T`, which is initialized via `std::forward<T>(value)`.
|
||||
template <typename T, typename... Args, typename VT = absl::decay_t<T>,
|
||||
absl::enable_if_t<absl::conjunction<
|
||||
std::is_copy_constructible<VT>,
|
||||
std::is_constructible<VT, Args...>>::value>* = nullptr>
|
||||
explicit any(in_place_type_t<T> /*tag*/, Args&&... args)
|
||||
: obj_(new Obj<VT>(in_place, std::forward<Args>(args)...)) {}
|
||||
|
||||
// Constructs an `absl::any` object with a "contained object" of the passed
|
||||
// type `VT` as a decayed type of `T`. `VT` is initialized as if
|
||||
// direct-non-list-initializing an object of type `VT` with the arguments
|
||||
// `initializer_list, std::forward<Args>(args)...`.
|
||||
template <
|
||||
typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
|
||||
absl::enable_if_t<
|
||||
absl::conjunction<std::is_copy_constructible<VT>,
|
||||
std::is_constructible<VT, std::initializer_list<U>&,
|
||||
Args...>>::value>* = nullptr>
|
||||
explicit any(in_place_type_t<T> /*tag*/, std::initializer_list<U> ilist,
|
||||
Args&&... args)
|
||||
: obj_(new Obj<VT>(in_place, ilist, std::forward<Args>(args)...)) {}
|
||||
|
||||
// Assignment operators
|
||||
|
||||
// Copy assigns an `absl::any` object with a "contained object" of the
|
||||
// passed type.
|
||||
any& operator=(const any& rhs) {
|
||||
any(rhs).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Move assigns an `absl::any` object with a "contained object" of the
|
||||
// passed type. `rhs` is left in a valid but otherwise unspecified state.
|
||||
any& operator=(any&& rhs) noexcept {
|
||||
any(std::move(rhs)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Assigns an `absl::any` object with a "contained object" of the passed type.
|
||||
template <typename T, typename VT = absl::decay_t<T>,
|
||||
absl::enable_if_t<absl::conjunction<
|
||||
absl::negation<std::is_same<VT, any>>,
|
||||
std::is_copy_constructible<VT>>::value>* = nullptr>
|
||||
any& operator=(T&& rhs) {
|
||||
any tmp(in_place_type_t<VT>(), std::forward<T>(rhs));
|
||||
tmp.swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Modifiers
|
||||
|
||||
// any::emplace()
|
||||
//
|
||||
// Emplaces a value within an `absl::any` object by calling `any::reset()`,
|
||||
// initializing the contained value as if direct-non-list-initializing an
|
||||
// object of type `VT` with the arguments `std::forward<Args>(args)...`, and
|
||||
// returning a reference to the new contained value.
|
||||
//
|
||||
// Note: If an exception is thrown during the call to `VT`’s constructor,
|
||||
// `*this` does not contain a value, and any previously contained value has
|
||||
// been destroyed.
|
||||
template <
|
||||
typename T, typename... Args, typename VT = absl::decay_t<T>,
|
||||
absl::enable_if_t<std::is_copy_constructible<VT>::value &&
|
||||
std::is_constructible<VT, Args...>::value>* = nullptr>
|
||||
VT& emplace(Args&&... args) {
|
||||
reset(); // NOTE: reset() is required here even in the world of exceptions.
|
||||
Obj<VT>* const object_ptr =
|
||||
new Obj<VT>(in_place, std::forward<Args>(args)...);
|
||||
obj_ = std::unique_ptr<ObjInterface>(object_ptr);
|
||||
return object_ptr->value;
|
||||
}
|
||||
|
||||
// Overload of `any::emplace()` to emplace a value within an `absl::any`
|
||||
// object by calling `any::reset()`, initializing the contained value as if
|
||||
// direct-non-list-initializing an object of type `VT` with the arguments
|
||||
// `initilizer_list, std::forward<Args>(args)...`, and returning a reference
|
||||
// to the new contained value.
|
||||
//
|
||||
// Note: If an exception is thrown during the call to `VT`’s constructor,
|
||||
// `*this` does not contain a value, and any previously contained value has
|
||||
// been destroyed. The function shall not participate in overload resolution
|
||||
// unless `is_copy_constructible_v<VT>` is `true` and
|
||||
// `is_constructible_v<VT, initializer_list<U>&, Args...>` is `true`.
|
||||
template <
|
||||
typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
|
||||
absl::enable_if_t<std::is_copy_constructible<VT>::value &&
|
||||
std::is_constructible<VT, std::initializer_list<U>&,
|
||||
Args...>::value>* = nullptr>
|
||||
VT& emplace(std::initializer_list<U> ilist, Args&&... args) {
|
||||
reset(); // NOTE: reset() is required here even in the world of exceptions.
|
||||
Obj<VT>* const object_ptr =
|
||||
new Obj<VT>(in_place, ilist, std::forward<Args>(args)...);
|
||||
obj_ = std::unique_ptr<ObjInterface>(object_ptr);
|
||||
return object_ptr->value;
|
||||
}
|
||||
|
||||
// any::reset()
|
||||
//
|
||||
// Resets the state of the `absl::any` object, destroying the contained object
|
||||
// if present.
|
||||
void reset() noexcept { obj_ = nullptr; }
|
||||
|
||||
// any::swap()
|
||||
//
|
||||
// Swaps the passed value and the value of this `absl::any` object.
|
||||
void swap(any& other) noexcept { obj_.swap(other.obj_); }
|
||||
|
||||
// Observors
|
||||
|
||||
// any::has_value()
|
||||
//
|
||||
// Returns `true` if the `any` object has a contained value, otherwise
|
||||
// returns `false`.
|
||||
bool has_value() const noexcept { return obj_ != nullptr; }
|
||||
|
||||
#if ABSL_ANY_DETAIL_HAS_RTTI
|
||||
// Returns: typeid(T) if *this has a contained object of type T, otherwise
|
||||
// typeid(void).
|
||||
const std::type_info& type() const noexcept {
|
||||
if (has_value()) {
|
||||
return obj_->Type();
|
||||
}
|
||||
|
||||
return typeid(void);
|
||||
}
|
||||
#endif // ABSL_ANY_DETAIL_HAS_RTTI
|
||||
private:
|
||||
// Tagged type-erased abstraction for holding a cloneable object.
|
||||
class ObjInterface {
|
||||
public:
|
||||
virtual ~ObjInterface() = default;
|
||||
virtual std::unique_ptr<ObjInterface> Clone() const = 0;
|
||||
virtual size_t type_id() const noexcept = 0;
|
||||
#if ABSL_ANY_DETAIL_HAS_RTTI
|
||||
virtual const std::type_info& Type() const noexcept = 0;
|
||||
#endif // ABSL_ANY_DETAIL_HAS_RTTI
|
||||
};
|
||||
|
||||
// Hold a value of some queryable type, with an ability to Clone it.
|
||||
template <typename T>
|
||||
class Obj : public ObjInterface {
|
||||
public:
|
||||
template <typename... Args>
|
||||
explicit Obj(in_place_t /*tag*/, Args&&... args)
|
||||
: value(std::forward<Args>(args)...) {}
|
||||
|
||||
std::unique_ptr<ObjInterface> Clone() const final {
|
||||
return std::unique_ptr<ObjInterface>(new Obj(in_place, value));
|
||||
}
|
||||
|
||||
size_t type_id() const noexcept final { return IdForType<T>(); }
|
||||
|
||||
#if ABSL_ANY_DETAIL_HAS_RTTI
|
||||
const std::type_info& Type() const noexcept final { return typeid(T); }
|
||||
#endif // ABSL_ANY_DETAIL_HAS_RTTI
|
||||
|
||||
T value;
|
||||
};
|
||||
|
||||
std::unique_ptr<ObjInterface> CloneObj() const {
|
||||
if (!obj_) return nullptr;
|
||||
return obj_->Clone();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static size_t IdForType() {
|
||||
// Note: This type dance is to make the behavior consistent with typeid.
|
||||
using NormalizedType =
|
||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||
|
||||
return any_internal::FastTypeId<NormalizedType>();
|
||||
}
|
||||
|
||||
size_t GetObjTypeId() const {
|
||||
return obj_ == nullptr ? any_internal::FastTypeId<void>() : obj_->type_id();
|
||||
}
|
||||
|
||||
// `absl::any` nonmember functions //
|
||||
|
||||
// Description at the declaration site (top of file).
|
||||
template <typename ValueType>
|
||||
friend ValueType any_cast(const any& operand);
|
||||
|
||||
// Description at the declaration site (top of file).
|
||||
template <typename ValueType>
|
||||
friend ValueType any_cast(any& operand); // NOLINT(runtime/references)
|
||||
|
||||
// Description at the declaration site (top of file).
|
||||
template <typename T>
|
||||
friend const T* any_cast(const any* operand) noexcept;
|
||||
|
||||
// Description at the declaration site (top of file).
|
||||
template <typename T>
|
||||
friend T* any_cast(any* operand) noexcept;
|
||||
|
||||
std::unique_ptr<ObjInterface> obj_;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation Details
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
constexpr any::any() noexcept = default;
|
||||
|
||||
template <typename T>
|
||||
struct any::IsInPlaceType : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct any::IsInPlaceType<in_place_type_t<T>> : std::true_type {};
|
||||
|
||||
inline void swap(any& x, any& y) noexcept { x.swap(y); }
|
||||
|
||||
// Description at the declaration site (top of file).
|
||||
template <typename T, typename... Args>
|
||||
any make_any(Args&&... args) {
|
||||
return any(in_place_type_t<T>(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Description at the declaration site (top of file).
|
||||
template <typename T, typename U, typename... Args>
|
||||
any make_any(std::initializer_list<U> il, Args&&... args) {
|
||||
return any(in_place_type_t<T>(), il, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Description at the declaration site (top of file).
|
||||
template <typename ValueType>
|
||||
ValueType any_cast(const any& operand) {
|
||||
using U = typename std::remove_cv<
|
||||
typename std::remove_reference<ValueType>::type>::type;
|
||||
static_assert(std::is_constructible<ValueType, const U&>::value,
|
||||
"Invalid ValueType");
|
||||
auto* const result = (any_cast<U>)(&operand);
|
||||
if (result == nullptr) {
|
||||
any_internal::ThrowBadAnyCast();
|
||||
}
|
||||
return static_cast<ValueType>(*result);
|
||||
}
|
||||
|
||||
// Description at the declaration site (top of file).
|
||||
template <typename ValueType>
|
||||
ValueType any_cast(any& operand) { // NOLINT(runtime/references)
|
||||
using U = typename std::remove_cv<
|
||||
typename std::remove_reference<ValueType>::type>::type;
|
||||
static_assert(std::is_constructible<ValueType, U&>::value,
|
||||
"Invalid ValueType");
|
||||
auto* result = (any_cast<U>)(&operand);
|
||||
if (result == nullptr) {
|
||||
any_internal::ThrowBadAnyCast();
|
||||
}
|
||||
return static_cast<ValueType>(*result);
|
||||
}
|
||||
|
||||
// Description at the declaration site (top of file).
|
||||
template <typename ValueType>
|
||||
ValueType any_cast(any&& operand) {
|
||||
using U = typename std::remove_cv<
|
||||
typename std::remove_reference<ValueType>::type>::type;
|
||||
static_assert(std::is_constructible<ValueType, U>::value,
|
||||
"Invalid ValueType");
|
||||
return static_cast<ValueType>(std::move((any_cast<U&>)(operand)));
|
||||
}
|
||||
|
||||
// Description at the declaration site (top of file).
|
||||
template <typename T>
|
||||
const T* any_cast(const any* operand) noexcept {
|
||||
return operand && operand->GetObjTypeId() == any::IdForType<T>()
|
||||
? std::addressof(
|
||||
static_cast<const any::Obj<T>*>(operand->obj_.get())->value)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
// Description at the declaration site (top of file).
|
||||
template <typename T>
|
||||
T* any_cast(any* operand) noexcept {
|
||||
return operand && operand->GetObjTypeId() == any::IdForType<T>()
|
||||
? std::addressof(
|
||||
static_cast<any::Obj<T>*>(operand->obj_.get())->value)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
} // namespace absl
|
||||
|
||||
#undef ABSL_ANY_DETAIL_HAS_RTTI
|
||||
|
||||
#endif // ABSL_HAVE_STD_ANY
|
||||
|
||||
#endif // ABSL_TYPES_ANY_H_
|
||||
713
absl/types/any_test.cc
Normal file
713
absl/types/any_test.cc
Normal file
|
|
@ -0,0 +1,713 @@
|
|||
// 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/any.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/exception_testing.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/container/internal/test_instance_tracker.h"
|
||||
|
||||
namespace {
|
||||
using absl::test_internal::CopyableOnlyInstance;
|
||||
using absl::test_internal::InstanceTracker;
|
||||
|
||||
template <typename T>
|
||||
const T& AsConst(const T& t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
struct MoveOnly {
|
||||
MoveOnly() = default;
|
||||
explicit MoveOnly(int value) : value(value) {}
|
||||
MoveOnly(MoveOnly&&) = default;
|
||||
MoveOnly& operator=(MoveOnly&&) = default;
|
||||
|
||||
int value = 0;
|
||||
};
|
||||
|
||||
struct CopyOnly {
|
||||
CopyOnly() = default;
|
||||
explicit CopyOnly(int value) : value(value) {}
|
||||
CopyOnly(CopyOnly&&) = delete;
|
||||
CopyOnly& operator=(CopyOnly&&) = delete;
|
||||
CopyOnly(const CopyOnly&) = default;
|
||||
CopyOnly& operator=(const CopyOnly&) = default;
|
||||
|
||||
int value = 0;
|
||||
};
|
||||
|
||||
struct MoveOnlyWithListConstructor {
|
||||
MoveOnlyWithListConstructor() = default;
|
||||
explicit MoveOnlyWithListConstructor(std::initializer_list<int> /*ilist*/,
|
||||
int value)
|
||||
: value(value) {}
|
||||
MoveOnlyWithListConstructor(MoveOnlyWithListConstructor&&) = default;
|
||||
MoveOnlyWithListConstructor& operator=(MoveOnlyWithListConstructor&&) =
|
||||
default;
|
||||
|
||||
int value = 0;
|
||||
};
|
||||
|
||||
struct IntMoveOnlyCopyOnly {
|
||||
IntMoveOnlyCopyOnly(int value, MoveOnly /*move_only*/, CopyOnly /*copy_only*/)
|
||||
: value(value) {}
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
struct ListMoveOnlyCopyOnly {
|
||||
ListMoveOnlyCopyOnly(std::initializer_list<int> ilist, MoveOnly /*move_only*/,
|
||||
CopyOnly /*copy_only*/)
|
||||
: values(ilist) {}
|
||||
|
||||
std::vector<int> values;
|
||||
};
|
||||
|
||||
using FunctionType = void();
|
||||
void FunctionToEmplace() {}
|
||||
|
||||
using ArrayType = int[2];
|
||||
using DecayedArray = absl::decay_t<ArrayType>;
|
||||
|
||||
TEST(AnyTest, Noexcept) {
|
||||
static_assert(std::is_nothrow_default_constructible<absl::any>(), "");
|
||||
static_assert(std::is_nothrow_move_constructible<absl::any>(), "");
|
||||
static_assert(std::is_nothrow_move_assignable<absl::any>(), "");
|
||||
static_assert(noexcept(std::declval<absl::any&>().has_value()), "");
|
||||
static_assert(noexcept(std::declval<absl::any&>().type()), "");
|
||||
static_assert(noexcept(absl::any_cast<int>(std::declval<absl::any*>())), "");
|
||||
static_assert(
|
||||
noexcept(std::declval<absl::any&>().swap(std::declval<absl::any&>())),
|
||||
"");
|
||||
|
||||
using std::swap;
|
||||
static_assert(
|
||||
noexcept(swap(std::declval<absl::any&>(), std::declval<absl::any&>())),
|
||||
"");
|
||||
}
|
||||
|
||||
TEST(AnyTest, HasValue) {
|
||||
absl::any o;
|
||||
EXPECT_FALSE(o.has_value());
|
||||
o.emplace<int>();
|
||||
EXPECT_TRUE(o.has_value());
|
||||
o.reset();
|
||||
EXPECT_FALSE(o.has_value());
|
||||
}
|
||||
|
||||
TEST(AnyTest, Type) {
|
||||
absl::any o;
|
||||
EXPECT_EQ(typeid(void), o.type());
|
||||
o.emplace<int>(5);
|
||||
EXPECT_EQ(typeid(int), o.type());
|
||||
o.emplace<float>(5.f);
|
||||
EXPECT_EQ(typeid(float), o.type());
|
||||
o.reset();
|
||||
EXPECT_EQ(typeid(void), o.type());
|
||||
}
|
||||
|
||||
TEST(AnyTest, EmptyPointerCast) {
|
||||
// pointer-to-unqualified overload
|
||||
{
|
||||
absl::any o;
|
||||
EXPECT_EQ(nullptr, absl::any_cast<int>(&o));
|
||||
o.emplace<int>();
|
||||
EXPECT_NE(nullptr, absl::any_cast<int>(&o));
|
||||
o.reset();
|
||||
EXPECT_EQ(nullptr, absl::any_cast<int>(&o));
|
||||
}
|
||||
|
||||
// pointer-to-const overload
|
||||
{
|
||||
absl::any o;
|
||||
EXPECT_EQ(nullptr, absl::any_cast<int>(&AsConst(o)));
|
||||
o.emplace<int>();
|
||||
EXPECT_NE(nullptr, absl::any_cast<int>(&AsConst(o)));
|
||||
o.reset();
|
||||
EXPECT_EQ(nullptr, absl::any_cast<int>(&AsConst(o)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AnyTest, InPlaceConstruction) {
|
||||
const CopyOnly copy_only{};
|
||||
absl::any o(absl::in_place_type_t<IntMoveOnlyCopyOnly>(), 5, MoveOnly(),
|
||||
copy_only);
|
||||
IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
|
||||
EXPECT_EQ(5, v.value);
|
||||
}
|
||||
|
||||
TEST(AnyTest, InPlaceConstructionWithCV) {
|
||||
const CopyOnly copy_only{};
|
||||
absl::any o(absl::in_place_type_t<const volatile IntMoveOnlyCopyOnly>(), 5,
|
||||
MoveOnly(), copy_only);
|
||||
IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
|
||||
EXPECT_EQ(5, v.value);
|
||||
}
|
||||
|
||||
TEST(AnyTest, InPlaceConstructionWithFunction) {
|
||||
absl::any o(absl::in_place_type_t<FunctionType>(), FunctionToEmplace);
|
||||
FunctionType*& construction_result = absl::any_cast<FunctionType*&>(o);
|
||||
EXPECT_EQ(&FunctionToEmplace, construction_result);
|
||||
}
|
||||
|
||||
TEST(AnyTest, InPlaceConstructionWithArray) {
|
||||
ArrayType ar = {5, 42};
|
||||
absl::any o(absl::in_place_type_t<ArrayType>(), ar);
|
||||
DecayedArray& construction_result = absl::any_cast<DecayedArray&>(o);
|
||||
EXPECT_EQ(&ar[0], construction_result);
|
||||
}
|
||||
|
||||
TEST(AnyTest, InPlaceConstructionIlist) {
|
||||
const CopyOnly copy_only{};
|
||||
absl::any o(absl::in_place_type_t<ListMoveOnlyCopyOnly>(), {1, 2, 3, 4},
|
||||
MoveOnly(), copy_only);
|
||||
ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
|
||||
std::vector<int> expected_values = {1, 2, 3, 4};
|
||||
EXPECT_EQ(expected_values, v.values);
|
||||
}
|
||||
|
||||
TEST(AnyTest, InPlaceConstructionIlistWithCV) {
|
||||
const CopyOnly copy_only{};
|
||||
absl::any o(absl::in_place_type_t<const volatile ListMoveOnlyCopyOnly>(),
|
||||
{1, 2, 3, 4}, MoveOnly(), copy_only);
|
||||
ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
|
||||
std::vector<int> expected_values = {1, 2, 3, 4};
|
||||
EXPECT_EQ(expected_values, v.values);
|
||||
}
|
||||
|
||||
TEST(AnyTest, InPlaceNoArgs) {
|
||||
absl::any o(absl::in_place_type_t<int>{});
|
||||
EXPECT_EQ(0, absl::any_cast<int&>(o));
|
||||
}
|
||||
|
||||
template <typename Enabler, typename T, typename... Args>
|
||||
struct CanEmplaceAnyImpl : std::false_type {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct CanEmplaceAnyImpl<
|
||||
absl::void_t<decltype(
|
||||
std::declval<absl::any&>().emplace<T>(std::declval<Args>()...))>,
|
||||
T, Args...> : std::true_type {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
using CanEmplaceAny = CanEmplaceAnyImpl<void, T, Args...>;
|
||||
|
||||
TEST(AnyTest, Emplace) {
|
||||
const CopyOnly copy_only{};
|
||||
absl::any o;
|
||||
EXPECT_TRUE((std::is_same<decltype(o.emplace<IntMoveOnlyCopyOnly>(
|
||||
5, MoveOnly(), copy_only)),
|
||||
IntMoveOnlyCopyOnly&>::value));
|
||||
IntMoveOnlyCopyOnly& emplace_result =
|
||||
o.emplace<IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
|
||||
EXPECT_EQ(5, emplace_result.value);
|
||||
IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
|
||||
EXPECT_EQ(5, v.value);
|
||||
EXPECT_EQ(&emplace_result, &v);
|
||||
|
||||
static_assert(!CanEmplaceAny<int, int, int>::value, "");
|
||||
static_assert(!CanEmplaceAny<MoveOnly, MoveOnly>::value, "");
|
||||
}
|
||||
|
||||
TEST(AnyTest, EmplaceWithCV) {
|
||||
const CopyOnly copy_only{};
|
||||
absl::any o;
|
||||
EXPECT_TRUE(
|
||||
(std::is_same<decltype(o.emplace<const volatile IntMoveOnlyCopyOnly>(
|
||||
5, MoveOnly(), copy_only)),
|
||||
IntMoveOnlyCopyOnly&>::value));
|
||||
IntMoveOnlyCopyOnly& emplace_result =
|
||||
o.emplace<const volatile IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
|
||||
EXPECT_EQ(5, emplace_result.value);
|
||||
IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
|
||||
EXPECT_EQ(5, v.value);
|
||||
EXPECT_EQ(&emplace_result, &v);
|
||||
}
|
||||
|
||||
TEST(AnyTest, EmplaceWithFunction) {
|
||||
absl::any o;
|
||||
EXPECT_TRUE(
|
||||
(std::is_same<decltype(o.emplace<FunctionType>(FunctionToEmplace)),
|
||||
FunctionType*&>::value));
|
||||
FunctionType*& emplace_result = o.emplace<FunctionType>(FunctionToEmplace);
|
||||
EXPECT_EQ(&FunctionToEmplace, emplace_result);
|
||||
}
|
||||
|
||||
TEST(AnyTest, EmplaceWithArray) {
|
||||
absl::any o;
|
||||
ArrayType ar = {5, 42};
|
||||
EXPECT_TRUE(
|
||||
(std::is_same<decltype(o.emplace<ArrayType>(ar)), DecayedArray&>::value));
|
||||
DecayedArray& emplace_result = o.emplace<ArrayType>(ar);
|
||||
EXPECT_EQ(&ar[0], emplace_result);
|
||||
}
|
||||
|
||||
TEST(AnyTest, EmplaceIlist) {
|
||||
const CopyOnly copy_only{};
|
||||
absl::any o;
|
||||
EXPECT_TRUE((std::is_same<decltype(o.emplace<ListMoveOnlyCopyOnly>(
|
||||
{1, 2, 3, 4}, MoveOnly(), copy_only)),
|
||||
ListMoveOnlyCopyOnly&>::value));
|
||||
ListMoveOnlyCopyOnly& emplace_result =
|
||||
o.emplace<ListMoveOnlyCopyOnly>({1, 2, 3, 4}, MoveOnly(), copy_only);
|
||||
ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
|
||||
EXPECT_EQ(&v, &emplace_result);
|
||||
std::vector<int> expected_values = {1, 2, 3, 4};
|
||||
EXPECT_EQ(expected_values, v.values);
|
||||
|
||||
static_assert(!CanEmplaceAny<int, std::initializer_list<int>>::value, "");
|
||||
static_assert(!CanEmplaceAny<MoveOnlyWithListConstructor,
|
||||
std::initializer_list<int>, int>::value,
|
||||
"");
|
||||
}
|
||||
|
||||
TEST(AnyTest, EmplaceIlistWithCV) {
|
||||
const CopyOnly copy_only{};
|
||||
absl::any o;
|
||||
EXPECT_TRUE(
|
||||
(std::is_same<decltype(o.emplace<const volatile ListMoveOnlyCopyOnly>(
|
||||
{1, 2, 3, 4}, MoveOnly(), copy_only)),
|
||||
ListMoveOnlyCopyOnly&>::value));
|
||||
ListMoveOnlyCopyOnly& emplace_result =
|
||||
o.emplace<const volatile ListMoveOnlyCopyOnly>({1, 2, 3, 4}, MoveOnly(),
|
||||
copy_only);
|
||||
ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
|
||||
EXPECT_EQ(&v, &emplace_result);
|
||||
std::vector<int> expected_values = {1, 2, 3, 4};
|
||||
EXPECT_EQ(expected_values, v.values);
|
||||
}
|
||||
|
||||
TEST(AnyTest, EmplaceNoArgs) {
|
||||
absl::any o;
|
||||
o.emplace<int>();
|
||||
EXPECT_EQ(0, absl::any_cast<int>(o));
|
||||
}
|
||||
|
||||
TEST(AnyTest, ConversionConstruction) {
|
||||
{
|
||||
absl::any o = 5;
|
||||
EXPECT_EQ(5, absl::any_cast<int>(o));
|
||||
}
|
||||
|
||||
{
|
||||
const CopyOnly copy_only(5);
|
||||
absl::any o = copy_only;
|
||||
EXPECT_EQ(5, absl::any_cast<CopyOnly&>(o).value);
|
||||
}
|
||||
|
||||
static_assert(!std::is_convertible<MoveOnly, absl::any>::value, "");
|
||||
}
|
||||
|
||||
TEST(AnyTest, ConversionAssignment) {
|
||||
{
|
||||
absl::any o;
|
||||
o = 5;
|
||||
EXPECT_EQ(5, absl::any_cast<int>(o));
|
||||
}
|
||||
|
||||
{
|
||||
const CopyOnly copy_only(5);
|
||||
absl::any o;
|
||||
o = copy_only;
|
||||
EXPECT_EQ(5, absl::any_cast<CopyOnly&>(o).value);
|
||||
}
|
||||
|
||||
static_assert(!std::is_assignable<MoveOnly, absl::any>::value, "");
|
||||
}
|
||||
|
||||
// Suppress MSVC warnings.
|
||||
// 4521: multiple copy constructors specified
|
||||
// We wrote multiple of them to test that the correct overloads are selected.
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4521)
|
||||
#endif
|
||||
|
||||
// Weird type for testing, only used to make sure we "properly" perfect-forward
|
||||
// when being placed into an absl::any (use the l-value constructor if given an
|
||||
// l-value rather than use the copy constructor).
|
||||
struct WeirdConstructor42 {
|
||||
explicit WeirdConstructor42(int value) : value(value) {}
|
||||
|
||||
// Copy-constructor
|
||||
WeirdConstructor42(const WeirdConstructor42& other) : value(other.value) {}
|
||||
|
||||
// L-value "weird" constructor (used when given an l-value)
|
||||
WeirdConstructor42(
|
||||
WeirdConstructor42& /*other*/) // NOLINT(runtime/references)
|
||||
: value(42) {}
|
||||
|
||||
int value;
|
||||
};
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
||||
TEST(AnyTest, WeirdConversionConstruction) {
|
||||
{
|
||||
const WeirdConstructor42 source(5);
|
||||
absl::any o = source; // Actual copy
|
||||
EXPECT_EQ(5, absl::any_cast<WeirdConstructor42&>(o).value);
|
||||
}
|
||||
|
||||
{
|
||||
WeirdConstructor42 source(5);
|
||||
absl::any o = source; // Weird "conversion"
|
||||
EXPECT_EQ(42, absl::any_cast<WeirdConstructor42&>(o).value);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AnyTest, WeirdConversionAssignment) {
|
||||
{
|
||||
const WeirdConstructor42 source(5);
|
||||
absl::any o;
|
||||
o = source; // Actual copy
|
||||
EXPECT_EQ(5, absl::any_cast<WeirdConstructor42&>(o).value);
|
||||
}
|
||||
|
||||
{
|
||||
WeirdConstructor42 source(5);
|
||||
absl::any o;
|
||||
o = source; // Weird "conversion"
|
||||
EXPECT_EQ(42, absl::any_cast<WeirdConstructor42&>(o).value);
|
||||
}
|
||||
}
|
||||
|
||||
struct Value {};
|
||||
|
||||
TEST(AnyTest, AnyCastValue) {
|
||||
{
|
||||
absl::any o;
|
||||
o.emplace<int>(5);
|
||||
EXPECT_EQ(5, absl::any_cast<int>(o));
|
||||
EXPECT_EQ(5, absl::any_cast<int>(AsConst(o)));
|
||||
static_assert(
|
||||
std::is_same<decltype(absl::any_cast<Value>(o)), Value>::value, "");
|
||||
}
|
||||
|
||||
{
|
||||
absl::any o;
|
||||
o.emplace<int>(5);
|
||||
EXPECT_EQ(5, absl::any_cast<const int>(o));
|
||||
EXPECT_EQ(5, absl::any_cast<const int>(AsConst(o)));
|
||||
static_assert(std::is_same<decltype(absl::any_cast<const Value>(o)),
|
||||
const Value>::value,
|
||||
"");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AnyTest, AnyCastReference) {
|
||||
{
|
||||
absl::any o;
|
||||
o.emplace<int>(5);
|
||||
EXPECT_EQ(5, absl::any_cast<int&>(o));
|
||||
EXPECT_EQ(5, absl::any_cast<const int&>(AsConst(o)));
|
||||
static_assert(
|
||||
std::is_same<decltype(absl::any_cast<Value&>(o)), Value&>::value, "");
|
||||
}
|
||||
|
||||
{
|
||||
absl::any o;
|
||||
o.emplace<int>(5);
|
||||
EXPECT_EQ(5, absl::any_cast<const int>(o));
|
||||
EXPECT_EQ(5, absl::any_cast<const int>(AsConst(o)));
|
||||
static_assert(std::is_same<decltype(absl::any_cast<const Value&>(o)),
|
||||
const Value&>::value,
|
||||
"");
|
||||
}
|
||||
|
||||
{
|
||||
absl::any o;
|
||||
o.emplace<int>(5);
|
||||
EXPECT_EQ(5, absl::any_cast<int&&>(std::move(o)));
|
||||
static_assert(std::is_same<decltype(absl::any_cast<Value&&>(std::move(o))),
|
||||
Value&&>::value,
|
||||
"");
|
||||
}
|
||||
|
||||
{
|
||||
absl::any o;
|
||||
o.emplace<int>(5);
|
||||
EXPECT_EQ(5, absl::any_cast<const int>(std::move(o)));
|
||||
static_assert(
|
||||
std::is_same<decltype(absl::any_cast<const Value&&>(std::move(o))),
|
||||
const Value&&>::value,
|
||||
"");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AnyTest, AnyCastPointer) {
|
||||
{
|
||||
absl::any o;
|
||||
EXPECT_EQ(nullptr, absl::any_cast<char>(&o));
|
||||
o.emplace<int>(5);
|
||||
EXPECT_EQ(nullptr, absl::any_cast<char>(&o));
|
||||
o.emplace<char>('a');
|
||||
EXPECT_EQ('a', *absl::any_cast<char>(&o));
|
||||
static_assert(
|
||||
std::is_same<decltype(absl::any_cast<Value>(&o)), Value*>::value, "");
|
||||
}
|
||||
|
||||
{
|
||||
absl::any o;
|
||||
EXPECT_EQ(nullptr, absl::any_cast<const char>(&o));
|
||||
o.emplace<int>(5);
|
||||
EXPECT_EQ(nullptr, absl::any_cast<const char>(&o));
|
||||
o.emplace<char>('a');
|
||||
EXPECT_EQ('a', *absl::any_cast<const char>(&o));
|
||||
static_assert(std::is_same<decltype(absl::any_cast<const Value>(&o)),
|
||||
const Value*>::value,
|
||||
"");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AnyTest, MakeAny) {
|
||||
const CopyOnly copy_only{};
|
||||
auto o = absl::make_any<IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
|
||||
static_assert(std::is_same<decltype(o), absl::any>::value, "");
|
||||
EXPECT_EQ(5, absl::any_cast<IntMoveOnlyCopyOnly&>(o).value);
|
||||
}
|
||||
|
||||
TEST(AnyTest, MakeAnyIList) {
|
||||
const CopyOnly copy_only{};
|
||||
auto o =
|
||||
absl::make_any<ListMoveOnlyCopyOnly>({1, 2, 3}, MoveOnly(), copy_only);
|
||||
static_assert(std::is_same<decltype(o), absl::any>::value, "");
|
||||
ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
|
||||
std::vector<int> expected_values = {1, 2, 3};
|
||||
EXPECT_EQ(expected_values, v.values);
|
||||
}
|
||||
|
||||
// Test the use of copy constructor and operator=
|
||||
TEST(AnyTest, Copy) {
|
||||
InstanceTracker tracker_raii;
|
||||
|
||||
{
|
||||
absl::any o(absl::in_place_type_t<CopyableOnlyInstance>{}, 123);
|
||||
CopyableOnlyInstance* f1 = absl::any_cast<CopyableOnlyInstance>(&o);
|
||||
|
||||
absl::any o2(o);
|
||||
const CopyableOnlyInstance* f2 = absl::any_cast<CopyableOnlyInstance>(&o2);
|
||||
EXPECT_EQ(123, f2->value());
|
||||
EXPECT_NE(f1, f2);
|
||||
|
||||
absl::any o3;
|
||||
o3 = o2;
|
||||
const CopyableOnlyInstance* f3 = absl::any_cast<CopyableOnlyInstance>(&o3);
|
||||
EXPECT_EQ(123, f3->value());
|
||||
EXPECT_NE(f2, f3);
|
||||
|
||||
const absl::any o4(4);
|
||||
// copy construct from const lvalue ref.
|
||||
absl::any o5 = o4;
|
||||
EXPECT_EQ(4, absl::any_cast<int>(o4));
|
||||
EXPECT_EQ(4, absl::any_cast<int>(o5));
|
||||
|
||||
// Copy construct from const rvalue ref.
|
||||
absl::any o6 = std::move(o4); // NOLINT
|
||||
EXPECT_EQ(4, absl::any_cast<int>(o4));
|
||||
EXPECT_EQ(4, absl::any_cast<int>(o6));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AnyTest, Move) {
|
||||
InstanceTracker tracker_raii;
|
||||
|
||||
absl::any any1;
|
||||
any1.emplace<CopyableOnlyInstance>(5);
|
||||
|
||||
// This is a copy, so copy count increases to 1.
|
||||
absl::any any2 = any1;
|
||||
EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any1).value());
|
||||
EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any2).value());
|
||||
EXPECT_EQ(1, tracker_raii.copies());
|
||||
|
||||
// This isn't a copy, so copy count doesn't increase.
|
||||
absl::any any3 = std::move(any2);
|
||||
EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any3).value());
|
||||
EXPECT_EQ(1, tracker_raii.copies());
|
||||
|
||||
absl::any any4;
|
||||
any4 = std::move(any3);
|
||||
EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any4).value());
|
||||
EXPECT_EQ(1, tracker_raii.copies());
|
||||
|
||||
absl::any tmp4(4);
|
||||
absl::any o4(std::move(tmp4)); // move construct
|
||||
EXPECT_EQ(4, absl::any_cast<int>(o4));
|
||||
o4 = o4; // self assign
|
||||
EXPECT_EQ(4, absl::any_cast<int>(o4));
|
||||
EXPECT_TRUE(o4.has_value());
|
||||
|
||||
absl::any o5;
|
||||
absl::any tmp5(5);
|
||||
o5 = std::move(tmp5); // move assign
|
||||
EXPECT_EQ(5, absl::any_cast<int>(o5));
|
||||
}
|
||||
|
||||
// Reset the ObjectOwner with an object of a different type
|
||||
TEST(AnyTest, Reset) {
|
||||
absl::any o;
|
||||
o.emplace<int>();
|
||||
|
||||
o.reset();
|
||||
EXPECT_FALSE(o.has_value());
|
||||
|
||||
o.emplace<char>();
|
||||
EXPECT_TRUE(o.has_value());
|
||||
}
|
||||
|
||||
TEST(AnyTest, ConversionConstructionCausesOneCopy) {
|
||||
InstanceTracker tracker_raii;
|
||||
CopyableOnlyInstance counter(5);
|
||||
absl::any o(counter);
|
||||
EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(o).value());
|
||||
EXPECT_EQ(1, tracker_raii.copies());
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
// Tests for Exception Behavior //
|
||||
//////////////////////////////////
|
||||
|
||||
#define ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(...) \
|
||||
ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), absl::bad_any_cast, \
|
||||
"Bad any cast")
|
||||
|
||||
TEST(AnyTest, ThrowBadAlloc) {
|
||||
{
|
||||
absl::any a;
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int&>(a));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&>(a));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int&&>(absl::any{}));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&&>(absl::any{}));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(a));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(a));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(absl::any{}));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(absl::any{}));
|
||||
|
||||
// const absl::any operand
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&>(AsConst(a)));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(AsConst(a)));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(AsConst(a)));
|
||||
}
|
||||
|
||||
{
|
||||
absl::any a(absl::in_place_type_t<int>{});
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&>(a));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float&>(a));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&&>(absl::any{}));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(
|
||||
absl::any_cast<const float&&>(absl::any{}));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(a));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(a));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(absl::any{}));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(absl::any{}));
|
||||
|
||||
// const absl::any operand
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float&>(AsConst(a)));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(AsConst(a)));
|
||||
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(AsConst(a)));
|
||||
}
|
||||
}
|
||||
|
||||
class BadCopy {};
|
||||
|
||||
struct BadCopyable {
|
||||
BadCopyable() = default;
|
||||
BadCopyable(BadCopyable&&) = default;
|
||||
BadCopyable(const BadCopyable&) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
throw BadCopy();
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "Bad copy");
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#define ABSL_ANY_TEST_EXPECT_BAD_COPY(...) \
|
||||
ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), BadCopy, "Bad copy")
|
||||
|
||||
// Test the guarantees regarding exceptions in copy/assign.
|
||||
TEST(AnyTest, FailedCopy) {
|
||||
{
|
||||
const BadCopyable bad{};
|
||||
ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{bad});
|
||||
}
|
||||
|
||||
{
|
||||
absl::any src(absl::in_place_type_t<BadCopyable>{});
|
||||
ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{src});
|
||||
}
|
||||
|
||||
{
|
||||
BadCopyable bad;
|
||||
absl::any target;
|
||||
ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad);
|
||||
}
|
||||
|
||||
{
|
||||
BadCopyable bad;
|
||||
absl::any target(absl::in_place_type_t<BadCopyable>{});
|
||||
ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad);
|
||||
EXPECT_TRUE(target.has_value());
|
||||
}
|
||||
|
||||
{
|
||||
absl::any src(absl::in_place_type_t<BadCopyable>{});
|
||||
absl::any target;
|
||||
ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src);
|
||||
EXPECT_FALSE(target.has_value());
|
||||
}
|
||||
|
||||
{
|
||||
absl::any src(absl::in_place_type_t<BadCopyable>{});
|
||||
absl::any target(absl::in_place_type_t<BadCopyable>{});
|
||||
ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src);
|
||||
EXPECT_TRUE(target.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
// Test the guarantees regarding exceptions in emplace.
|
||||
TEST(AnyTest, FailedEmplace) {
|
||||
{
|
||||
BadCopyable bad;
|
||||
absl::any target;
|
||||
ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad));
|
||||
}
|
||||
|
||||
{
|
||||
BadCopyable bad;
|
||||
absl::any target(absl::in_place_type_t<int>{});
|
||||
ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad));
|
||||
#if defined(ABSL_HAVE_STD_ANY) && defined(__GLIBCXX__)
|
||||
// libstdc++ std::any::emplace() implementation (as of 7.2) has a bug: if an
|
||||
// exception is thrown, *this contains a value.
|
||||
#define ABSL_GLIBCXX_ANY_EMPLACE_EXCEPTION_BUG 1
|
||||
#endif
|
||||
#if defined(ABSL_HAVE_EXCEPTIONS) && \
|
||||
!defined(ABSL_GLIBCXX_ANY_EMPLACE_EXCEPTION_BUG)
|
||||
EXPECT_FALSE(target.has_value());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
40
absl/types/bad_any_cast.cc
Normal file
40
absl/types/bad_any_cast.cc
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// 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_any_cast.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
|
||||
namespace absl {
|
||||
|
||||
bad_any_cast::~bad_any_cast() = default;
|
||||
|
||||
const char* bad_any_cast::what() const noexcept { return "Bad any cast"; }
|
||||
|
||||
namespace any_internal {
|
||||
|
||||
void ThrowBadAnyCast() {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
throw bad_any_cast();
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "Bad any cast");
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace any_internal
|
||||
} // namespace absl
|
||||
44
absl/types/bad_any_cast.h
Normal file
44
absl/types/bad_any_cast.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// 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.
|
||||
|
||||
#ifndef ABSL_TYPES_BAD_ANY_CAST_H_
|
||||
#define ABSL_TYPES_BAD_ANY_CAST_H_
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
namespace absl {
|
||||
|
||||
////////////////////////
|
||||
// [any.bad_any_cast] //
|
||||
////////////////////////
|
||||
|
||||
// Objects of type bad_any_cast are thrown by a failed any_cast.
|
||||
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();
|
||||
|
||||
} // namespace any_internal
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TYPES_BAD_ANY_CAST_H_
|
||||
42
absl/types/bad_optional_access.cc
Normal file
42
absl/types/bad_optional_access.cc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// 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_optional_access.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
|
||||
namespace absl {
|
||||
|
||||
bad_optional_access::~bad_optional_access() = default;
|
||||
|
||||
const char* bad_optional_access::what() const noexcept {
|
||||
return "optional has no value";
|
||||
}
|
||||
|
||||
namespace optional_internal {
|
||||
|
||||
void throw_bad_optional_access() {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
throw bad_optional_access();
|
||||
#else
|
||||
ABSL_RAW_LOG(FATAL, "Bad optional access");
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace optional_internal
|
||||
} // namespace absl
|
||||
37
absl/types/bad_optional_access.h
Normal file
37
absl/types/bad_optional_access.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// 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.
|
||||
|
||||
#ifndef ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
|
||||
#define ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace absl {
|
||||
|
||||
class bad_optional_access : public std::exception {
|
||||
public:
|
||||
bad_optional_access() = default;
|
||||
~bad_optional_access() override;
|
||||
const char* what() const noexcept override;
|
||||
};
|
||||
|
||||
namespace optional_internal {
|
||||
|
||||
// throw delegator
|
||||
[[noreturn]] void throw_bad_optional_access();
|
||||
|
||||
} // namespace optional_internal
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
|
||||
24
absl/types/optional.cc
Normal file
24
absl/types/optional.cc
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// 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/optional.h"
|
||||
|
||||
#ifndef ABSL_HAVE_STD_OPTIONAL
|
||||
namespace absl {
|
||||
|
||||
nullopt_t::init_t nullopt_t::init;
|
||||
extern const nullopt_t nullopt{nullopt_t::init};
|
||||
|
||||
} // namespace absl
|
||||
#endif // ABSL_HAVE_STD_OPTIONAL
|
||||
1092
absl/types/optional.h
Normal file
1092
absl/types/optional.h
Normal file
File diff suppressed because it is too large
Load diff
1539
absl/types/optional_test.cc
Normal file
1539
absl/types/optional_test.cc
Normal file
File diff suppressed because it is too large
Load diff
738
absl/types/span.h
Normal file
738
absl/types/span.h
Normal file
|
|
@ -0,0 +1,738 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// span.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines a `Span<T>` type for holding a view of an existing
|
||||
// array of data. The `Span` object, much like the `absl::string_view` object,
|
||||
// does not own such data itself. A span provides a lightweight way to pass
|
||||
// around view of such data.
|
||||
//
|
||||
// Additionally, this header file defines `MakeSpan()` and `MakeConstSpan()`
|
||||
// factory functions, for clearly creating spans of type `Span<T>` or read-only
|
||||
// `Span<const T>` when such types may be difficult to identify due to issues
|
||||
// with implicit conversion.
|
||||
//
|
||||
// The C++ standards committee currently has a proposal for a `std::span` type,
|
||||
// (http://wg21.link/p0122), which is not yet part of the standard (though may
|
||||
// become part of C++20). As of August 2017, the differences between
|
||||
// `absl::Span` and this proposal are:
|
||||
// * `absl::Span` uses `size_t` for `size_type`
|
||||
// * `absl::Span` has no `operator()`
|
||||
// * `absl::Span` has no constructors for `std::unique_ptr` or
|
||||
// `std::shared_ptr`
|
||||
// * `absl::span` has the factory functions `MakeSpan()` and
|
||||
// `MakeConstSpan()`
|
||||
// * `absl::Span` has `front()` and `back()` methods
|
||||
// * bounds-checked access to `absl::Span` is accomplished with `at()`
|
||||
// * `absl::Span` has compiler-provided move and copy constructors and
|
||||
// assignment. This is due to them being specified as `constexpr`, but that
|
||||
// implies const in C++11.
|
||||
// * `absl::Span` has no `element_type` or `index_type` typedefs
|
||||
// * A read-only `absl::Span<const T>` can be implicitly constructed from an
|
||||
// initializer list.
|
||||
// * `absl::Span` has no `bytes()`, `size_bytes()`, `as_bytes()`, or
|
||||
// `as_mutable_bytes()` methods
|
||||
// * `absl::Span` has no static extent template parameter, nor constructors
|
||||
// which exist only because of the static extent parameter.
|
||||
// * `absl::Span` has an explicit mutable-reference constructor
|
||||
//
|
||||
// For more information, see the class comments below.
|
||||
#ifndef ABSL_TYPES_SPAN_H_
|
||||
#define ABSL_TYPES_SPAN_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/algorithm/algorithm.h"
|
||||
#include "absl/base/internal/throw_delegate.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/optimization.h"
|
||||
#include "absl/base/port.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
|
||||
namespace absl {
|
||||
|
||||
template <typename T>
|
||||
class Span;
|
||||
|
||||
namespace span_internal {
|
||||
// A constexpr min function
|
||||
constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; }
|
||||
|
||||
// Wrappers for access to container data pointers.
|
||||
template <typename C>
|
||||
constexpr auto GetDataImpl(C& c, char) noexcept // NOLINT(runtime/references)
|
||||
-> decltype(c.data()) {
|
||||
return c.data();
|
||||
}
|
||||
|
||||
// Before C++17, std::string::data returns a const char* in all cases.
|
||||
inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references)
|
||||
int) noexcept {
|
||||
return &s[0];
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
constexpr auto GetData(C& c) noexcept // NOLINT(runtime/references)
|
||||
-> decltype(GetDataImpl(c, 0)) {
|
||||
return GetDataImpl(c, 0);
|
||||
}
|
||||
|
||||
// Detection idioms for size() and data().
|
||||
template <typename C>
|
||||
using HasSize =
|
||||
std::is_integral<absl::decay_t<decltype(std::declval<C&>().size())>>;
|
||||
|
||||
// We want to enable conversion from vector<T*> to Span<const T* const> but
|
||||
// disable conversion from vector<Derived> to Span<Base>. Here we use
|
||||
// the fact that U** is convertible to Q* const* if and only if Q is the same
|
||||
// type or a more cv-qualified version of U. We also decay the result type of
|
||||
// data() to avoid problems with classes which have a member function data()
|
||||
// which returns a reference.
|
||||
template <typename T, typename C>
|
||||
using HasData =
|
||||
std::is_convertible<absl::decay_t<decltype(GetData(std::declval<C&>()))>*,
|
||||
T* const*>;
|
||||
|
||||
// Extracts value type from a Container
|
||||
template <typename C>
|
||||
struct ElementType {
|
||||
using type = typename absl::remove_reference_t<C>::value_type;
|
||||
};
|
||||
|
||||
template <typename T, size_t N>
|
||||
struct ElementType<T (&)[N]> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
using ElementT = typename ElementType<C>::type;
|
||||
|
||||
template <typename T>
|
||||
using EnableIfMutable =
|
||||
typename std::enable_if<!std::is_const<T>::value, int>::type;
|
||||
|
||||
template <typename T>
|
||||
bool EqualImpl(Span<T> a, Span<T> b) {
|
||||
static_assert(std::is_const<T>::value, "");
|
||||
return absl::equal(a.begin(), a.end(), b.begin(), b.end());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool LessThanImpl(Span<T> a, Span<T> b) {
|
||||
static_assert(std::is_const<T>::value, "");
|
||||
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
|
||||
}
|
||||
|
||||
// The `IsConvertible` classes here are needed because of the
|
||||
// `std::is_convertible` bug in libcxx when compiled with GCC. This build
|
||||
// configuration is used by Android NDK toolchain. Reference link:
|
||||
// https://bugs.llvm.org/show_bug.cgi?id=27538.
|
||||
template <typename From, typename To>
|
||||
struct IsConvertibleHelper {
|
||||
private:
|
||||
static std::true_type test(To);
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
using type = decltype(test(std::declval<From>()));
|
||||
};
|
||||
|
||||
template <typename From, typename To>
|
||||
struct IsConvertible : IsConvertibleHelper<From, To>::type {};
|
||||
|
||||
// TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the
|
||||
// older version of libcxx is not supported.
|
||||
template <typename From, typename To>
|
||||
using EnableIfConvertibleToSpanConst =
|
||||
typename std::enable_if<IsConvertible<From, Span<const To>>::value>::type;
|
||||
} // namespace span_internal
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Span
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// A `Span` is an "array view" type for holding a view of a contiguous data
|
||||
// array; the `Span` object does not and cannot own such data itself. A span
|
||||
// provides an easy way to provide overloads for anything operating on
|
||||
// contiguous sequences without needing to manage pointers and array lengths
|
||||
// manually.
|
||||
|
||||
// A span is conceptually a pointer (ptr) and a length (size) into an already
|
||||
// existing array of contiguous memory; the array it represents references the
|
||||
// elements "ptr[0] .. ptr[size-1]". Passing a properly-constructed `Span`
|
||||
// instead of raw pointers avoids many issues related to index out of bounds
|
||||
// errors.
|
||||
//
|
||||
// Spans may also be constructed from containers holding contiguous sequences.
|
||||
// Such containers must supply `data()` and `size() const` methods (e.g
|
||||
// `std::vector<T>`, `absl::InlinedVector<T, N>`). All implicit conversions to
|
||||
// `absl::Span` from such containers will create spans of type `const T`;
|
||||
// spans which can mutate their values (of type `T`) must use explicit
|
||||
// constructors.
|
||||
//
|
||||
// A `Span<T>` is somewhat analogous to an `absl::string_view`, but for an array
|
||||
// of elements of type `T`. A user of `Span` must ensure that the data being
|
||||
// pointed to outlives the `Span` itself.
|
||||
//
|
||||
// You can construct a `Span<T>` in several ways:
|
||||
//
|
||||
// * Explicitly from a reference to a container type
|
||||
// * Explicitly from a pointer and size
|
||||
// * Implicitly from a container type (but only for spans of type `const T`)
|
||||
// * Using the `MakeSpan()` or `MakeConstSpan()` factory functions.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// // Construct a Span explicitly from a container:
|
||||
// std::vector<int> v = {1, 2, 3, 4, 5};
|
||||
// auto span = absl::Span<const int>(v);
|
||||
//
|
||||
// // Construct a Span explicitly from a C-style array:
|
||||
// int a[5] = {1, 2, 3, 4, 5};
|
||||
// auto span = absl::Span<const int>(a);
|
||||
//
|
||||
// // Construct a Span implicitly from a container
|
||||
// void MyRoutine(absl::Span<const int> a) {
|
||||
// ...
|
||||
// };
|
||||
// std::vector v = {1,2,3,4,5};
|
||||
// MyRoutine(v) // convert to Span<const T>
|
||||
//
|
||||
// Note that `Span` objects, in addition to requiring that the memory they
|
||||
// point to remains alive, must also ensure that such memory does not get
|
||||
// reallocated. Therefore, to avoid undefined behavior, containers with
|
||||
// associated span views should not invoke operations that may reallocate memory
|
||||
// (such as resizing) or invalidate iterarors into the container.
|
||||
//
|
||||
// One common use for a `Span` is when passing arguments to a routine that can
|
||||
// accept a variety of array types (e.g. a `std::vector`, `absl::InlinedVector`,
|
||||
// a C-style array, etc.). Instead of creating overloads for each case, you
|
||||
// can simply specify a `Span` as the argument to such a routine.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// void MyRoutine(absl::Span<const int> a) {
|
||||
// ...
|
||||
// };
|
||||
//
|
||||
// std::vector v = {1,2,3,4,5};
|
||||
// MyRoutine(v);
|
||||
//
|
||||
// absl::InlinedVector<int, 4> my_inline_vector;
|
||||
// MyRoutine(my_inline_vector);
|
||||
//
|
||||
// // Explicit constructor from pointer,size
|
||||
// int* my_array = new int[10];
|
||||
// MyRoutine(absl::Span<const int>(my_array, 10));
|
||||
template <typename T>
|
||||
class Span {
|
||||
private:
|
||||
// Used to determine whether a Span can be constructed from a container of
|
||||
// type C.
|
||||
template <typename C>
|
||||
using EnableIfConvertibleFrom =
|
||||
typename std::enable_if<span_internal::HasData<T, C>::value &&
|
||||
span_internal::HasSize<C>::value>::type;
|
||||
|
||||
// Used to SFINAE-enable a function when the slice elements are const.
|
||||
template <typename U>
|
||||
using EnableIfConstView =
|
||||
typename std::enable_if<std::is_const<T>::value, U>::type;
|
||||
|
||||
// Used to SFINAE-enable a function when the slice elements are mutable.
|
||||
template <typename U>
|
||||
using EnableIfMutableView =
|
||||
typename std::enable_if<!std::is_const<T>::value, U>::type;
|
||||
|
||||
public:
|
||||
using value_type = absl::remove_cv_t<T>;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
static const size_type npos = -1;
|
||||
|
||||
constexpr Span() noexcept : Span(nullptr, 0) {}
|
||||
constexpr Span(pointer array, size_type length) noexcept
|
||||
: ptr_(array), len_(length) {}
|
||||
|
||||
// Implicit conversion constructors
|
||||
template <size_t N>
|
||||
constexpr Span(T (&a)[N]) noexcept // NOLINT(runtime/explicit)
|
||||
: Span(a, N) {}
|
||||
|
||||
// Explicit reference constructor for a mutable `Span<T>` type
|
||||
template <typename V, typename = EnableIfConvertibleFrom<V>,
|
||||
typename = EnableIfMutableView<V>>
|
||||
explicit Span(V& v) noexcept // NOLINT(runtime/references)
|
||||
: Span(span_internal::GetData(v), v.size()) {}
|
||||
|
||||
// Implicit reference constructor for a read-only `Span<const T>` type
|
||||
template <typename V, typename = EnableIfConvertibleFrom<V>,
|
||||
typename = EnableIfConstView<V>>
|
||||
constexpr Span(const V& v) noexcept // NOLINT(runtime/explicit)
|
||||
: Span(span_internal::GetData(v), v.size()) {}
|
||||
|
||||
// Implicit constructor from an initializer list, making it possible to pass a
|
||||
// brace-enclosed initializer list to a function expecting a `Span`. Such
|
||||
// spans constructed from an initializer list must be of type `Span<const T>`.
|
||||
//
|
||||
// void Process(absl::Span<const int> x);
|
||||
// Process({1, 2, 3});
|
||||
//
|
||||
// Note that as always the array referenced by the span must outlive the span.
|
||||
// Since an initializer list constructor acts as if it is fed a temporary
|
||||
// array (cf. C++ standard [dcl.init.list]/5), it's safe to use this
|
||||
// constructor only when the `std::initializer_list` itself outlives the span.
|
||||
// In order to meet this requirement it's sufficient to ensure that neither
|
||||
// the span nor a copy of it is used outside of the expression in which it's
|
||||
// created:
|
||||
//
|
||||
// // Assume that this function uses the array directly, not retaining any
|
||||
// // copy of the span or pointer to any of its elements.
|
||||
// void Process(absl::Span<const int> ints);
|
||||
//
|
||||
// // Okay: the std::initializer_list<int> will reference a temporary array
|
||||
// // that isn't destroyed until after the call to Process returns.
|
||||
// Process({ 17, 19 });
|
||||
//
|
||||
// // Not okay: the storage used by the std::initializer_list<int> is not
|
||||
// // allowed to be referenced after the first line.
|
||||
// absl::Span<const int> ints = { 17, 19 };
|
||||
// Process(ints);
|
||||
//
|
||||
// // Not okay for the same reason as above: even when the elements of the
|
||||
// // initializer list expression are not temporaries the underlying array
|
||||
// // is, so the initializer list must still outlive the span.
|
||||
// const int foo = 17;
|
||||
// absl::Span<const int> ints = { foo };
|
||||
// Process(ints);
|
||||
//
|
||||
template <typename LazyT = T,
|
||||
typename = EnableIfConstView<LazyT>>
|
||||
Span(
|
||||
std::initializer_list<value_type> v) noexcept // NOLINT(runtime/explicit)
|
||||
: Span(v.begin(), v.size()) {}
|
||||
|
||||
// Accessors
|
||||
|
||||
// Span::data()
|
||||
//
|
||||
// Returns a pointer to the span's underlying array of data (which is held
|
||||
// outside the span).
|
||||
constexpr pointer data() const noexcept { return ptr_; }
|
||||
|
||||
// Span::size()
|
||||
//
|
||||
// Returns the size of this span.
|
||||
constexpr size_type size() const noexcept { return len_; }
|
||||
|
||||
// Span::length()
|
||||
//
|
||||
// Returns the length (size) of this span.
|
||||
constexpr size_type length() const noexcept { return size(); }
|
||||
|
||||
// Span::empty()
|
||||
//
|
||||
// Returns a boolean indicating whether or not this span is considered empty.
|
||||
constexpr bool empty() const noexcept { return size() == 0; }
|
||||
|
||||
// Span::operator[]
|
||||
//
|
||||
// Returns a reference to the i'th element of this span.
|
||||
constexpr reference operator[](size_type i) const noexcept {
|
||||
// MSVC 2015 accepts this as constexpr, but not ptr_[i]
|
||||
return *(data() + i);
|
||||
}
|
||||
|
||||
// Span::at()
|
||||
//
|
||||
// Returns a reference to the i'th element of this span.
|
||||
constexpr reference at(size_type i) const {
|
||||
return ABSL_PREDICT_FALSE(i < size())
|
||||
? ptr_[i]
|
||||
: (base_internal::ThrowStdOutOfRange(
|
||||
"Span::at failed bounds check"),
|
||||
ptr_[i]);
|
||||
}
|
||||
|
||||
// Span::front()
|
||||
//
|
||||
// Returns a reference to the first element of this span.
|
||||
reference front() const noexcept { return ABSL_ASSERT(size() > 0), ptr_[0]; }
|
||||
|
||||
// Span::back()
|
||||
//
|
||||
// Returns a reference to the last element of this span.
|
||||
reference back() const noexcept {
|
||||
return ABSL_ASSERT(size() > 0), ptr_[size() - 1];
|
||||
}
|
||||
|
||||
// Span::begin()
|
||||
//
|
||||
// Returns an iterator to the first element of this span.
|
||||
constexpr iterator begin() const noexcept { return ptr_; }
|
||||
|
||||
// Span::cbegin()
|
||||
//
|
||||
// Returns a const iterator to the first element of this span.
|
||||
constexpr const_iterator cbegin() const noexcept { return ptr_; }
|
||||
|
||||
// Span::end()
|
||||
//
|
||||
// Returns an iterator to the last element of this span.
|
||||
iterator end() const noexcept { return ptr_ + len_; }
|
||||
|
||||
// Span::cend()
|
||||
//
|
||||
// Returns a const iterator to the last element of this span.
|
||||
const_iterator cend() const noexcept { return end(); }
|
||||
|
||||
// Span::rbegin()
|
||||
//
|
||||
// Returns a reverse iterator starting at the last element of this span.
|
||||
reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
|
||||
|
||||
// Span::crbegin()
|
||||
//
|
||||
// Returns a reverse const iterator starting at the last element of this span.
|
||||
const_reverse_iterator crbegin() const noexcept { return rbegin(); }
|
||||
|
||||
// Span::rend()
|
||||
//
|
||||
// Returns a reverse iterator starting at the first element of this span.
|
||||
reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
|
||||
|
||||
// Span::crend()
|
||||
//
|
||||
// Returns a reverse iterator starting at the first element of this span.
|
||||
const_reverse_iterator crend() const noexcept { return rend(); }
|
||||
|
||||
// Span mutations
|
||||
|
||||
// Span::remove_prefix()
|
||||
//
|
||||
// Removes the first `n` elements from the span.
|
||||
void remove_prefix(size_type n) noexcept {
|
||||
assert(len_ >= n);
|
||||
ptr_ += n;
|
||||
len_ -= n;
|
||||
}
|
||||
|
||||
// Span::remove_suffix()
|
||||
//
|
||||
// Removes the last `n` elements from the span.
|
||||
void remove_suffix(size_type n) noexcept {
|
||||
assert(len_ >= n);
|
||||
len_ -= n;
|
||||
}
|
||||
|
||||
// Span::subspan()
|
||||
//
|
||||
// Returns a `Span` starting at element `pos` and of length `len`, with
|
||||
// proper bounds checking to ensure `len` does not exceed the ptr+size of the
|
||||
// original array. (Spans whose `len` would point past the end of the array
|
||||
// will throw a `std::out_of_range`.)
|
||||
constexpr Span subspan(size_type pos = 0, size_type len = npos) const {
|
||||
return (pos <= len_)
|
||||
? Span(ptr_ + pos, span_internal::Min(len_ - pos, len))
|
||||
: (base_internal::ThrowStdOutOfRange("pos > size()"), Span());
|
||||
}
|
||||
|
||||
private:
|
||||
pointer ptr_;
|
||||
size_type len_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const typename Span<T>::size_type Span<T>::npos;
|
||||
|
||||
// Span relationals
|
||||
|
||||
// Equality is compared element-by-element, while ordering is lexicographical.
|
||||
// We provide three overloads for each operator to cover any combination on the
|
||||
// left or right hand side of mutable Span<T>, read-only Span<const T>, and
|
||||
// convertible-to-read-only Span<T>.
|
||||
// TODO(zhangxy): Due to MSVC overload resolution bug with partial ordering
|
||||
// template functions, 5 overloads per operator is needed as a workaround. We
|
||||
// should update them to 3 overloads per operator using non-deduced context like
|
||||
// string_view, i.e.
|
||||
// - (Span<T>, Span<T>)
|
||||
// - (Span<T>, non_deduced<Span<const T>>)
|
||||
// - (non_deduced<Span<const T>>, Span<T>)
|
||||
|
||||
// operator==
|
||||
template <typename T>
|
||||
bool operator==(Span<T> a, Span<T> b) {
|
||||
return span_internal::EqualImpl<const T>(a, b);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator==(Span<const T> a, Span<T> b) {
|
||||
return span_internal::EqualImpl<const T>(a, b);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator==(Span<T> a, Span<const T> b) {
|
||||
return span_internal::EqualImpl<const T>(a, b);
|
||||
}
|
||||
template <typename T, typename U,
|
||||
typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
|
||||
bool operator==(const U& a, Span<T> b) {
|
||||
return span_internal::EqualImpl<const T>(a, b);
|
||||
}
|
||||
template <typename T, typename U,
|
||||
typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
|
||||
bool operator==(Span<T> a, const U& b) {
|
||||
return span_internal::EqualImpl<const T>(a, b);
|
||||
}
|
||||
|
||||
// operator!=
|
||||
template <typename T>
|
||||
bool operator!=(Span<T> a, Span<T> b) {
|
||||
return !(a == b);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator!=(Span<const T> a, Span<T> b) {
|
||||
return !(a == b);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator!=(Span<T> a, Span<const T> b) {
|
||||
return !(a == b);
|
||||
}
|
||||
template <typename T, typename U,
|
||||
typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
|
||||
bool operator!=(const U& a, Span<T> b) {
|
||||
return !(a == b);
|
||||
}
|
||||
template <typename T, typename U,
|
||||
typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
|
||||
bool operator!=(Span<T> a, const U& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
// operator<
|
||||
template <typename T>
|
||||
bool operator<(Span<T> a, Span<T> b) {
|
||||
return span_internal::LessThanImpl<const T>(a, b);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator<(Span<const T> a, Span<T> b) {
|
||||
return span_internal::LessThanImpl<const T>(a, b);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator<(Span<T> a, Span<const T> b) {
|
||||
return span_internal::LessThanImpl<const T>(a, b);
|
||||
}
|
||||
template <typename T, typename U,
|
||||
typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
|
||||
bool operator<(const U& a, Span<T> b) {
|
||||
return span_internal::LessThanImpl<const T>(a, b);
|
||||
}
|
||||
template <typename T, typename U,
|
||||
typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
|
||||
bool operator<(Span<T> a, const U& b) {
|
||||
return span_internal::LessThanImpl<const T>(a, b);
|
||||
}
|
||||
|
||||
// operator>
|
||||
template <typename T>
|
||||
bool operator>(Span<T> a, Span<T> b) {
|
||||
return b < a;
|
||||
}
|
||||
template <typename T>
|
||||
bool operator>(Span<const T> a, Span<T> b) {
|
||||
return b < a;
|
||||
}
|
||||
template <typename T>
|
||||
bool operator>(Span<T> a, Span<const T> b) {
|
||||
return b < a;
|
||||
}
|
||||
template <typename T, typename U,
|
||||
typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
|
||||
bool operator>(const U& a, Span<T> b) {
|
||||
return b < a;
|
||||
}
|
||||
template <typename T, typename U,
|
||||
typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
|
||||
bool operator>(Span<T> a, const U& b) {
|
||||
return b < a;
|
||||
}
|
||||
|
||||
// operator<=
|
||||
template <typename T>
|
||||
bool operator<=(Span<T> a, Span<T> b) {
|
||||
return !(b < a);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator<=(Span<const T> a, Span<T> b) {
|
||||
return !(b < a);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator<=(Span<T> a, Span<const T> b) {
|
||||
return !(b < a);
|
||||
}
|
||||
template <typename T, typename U,
|
||||
typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
|
||||
bool operator<=(const U& a, Span<T> b) {
|
||||
return !(b < a);
|
||||
}
|
||||
template <typename T, typename U,
|
||||
typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
|
||||
bool operator<=(Span<T> a, const U& b) {
|
||||
return !(b < a);
|
||||
}
|
||||
|
||||
// operator>=
|
||||
template <typename T>
|
||||
bool operator>=(Span<T> a, Span<T> b) {
|
||||
return !(a < b);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator>=(Span<const T> a, Span<T> b) {
|
||||
return !(a < b);
|
||||
}
|
||||
template <typename T>
|
||||
bool operator>=(Span<T> a, Span<const T> b) {
|
||||
return !(a < b);
|
||||
}
|
||||
template <typename T, typename U,
|
||||
typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
|
||||
bool operator>=(const U& a, Span<T> b) {
|
||||
return !(a < b);
|
||||
}
|
||||
template <typename T, typename U,
|
||||
typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
|
||||
bool operator>=(Span<T> a, const U& b) {
|
||||
return !(a < b);
|
||||
}
|
||||
|
||||
// MakeSpan()
|
||||
//
|
||||
// Constructs a mutable `Span<T>`, deducing `T` automatically from either a
|
||||
// container or pointer+size.
|
||||
//
|
||||
// Because a read-only `Span<const T>` is implicitly constructed from container
|
||||
// types regardless of whether the container itself is a const container,
|
||||
// constructing mutable spans of type `Span<T>` from containers requires
|
||||
// explicit constructors. The container-accepting version of `MakeSpan()`
|
||||
// deduces the type of `T` by the constness of the pointer received from the
|
||||
// container's `data()` member. Similarly, the pointer-accepting version returns
|
||||
// a `Span<const T>` if `T` is `const`, and a `Span<T>` otherwise.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// void MyRoutine(absl::Span<MyComplicatedType> a) {
|
||||
// ...
|
||||
// };
|
||||
// // my_vector is a container of non-const types
|
||||
// std::vector<MyComplicatedType> my_vector;
|
||||
//
|
||||
// // Constructing a Span implicitly attempts to create a Span of type
|
||||
// // `Span<const T>`
|
||||
// MyRoutine(my_vector); // error, type mismatch
|
||||
//
|
||||
// // Explicitly constructing the Span is verbose
|
||||
// MyRoutine(absl::Span<MyComplicatedType>(my_vector);
|
||||
//
|
||||
// // Use MakeSpan() to make an absl::Span<T>
|
||||
// MyRoutine(absl::MakeSpan(my_vector));
|
||||
//
|
||||
// // Construct a span from an array ptr+size
|
||||
// absl::Span<T> my_span() {
|
||||
// return absl::MakeSpan(&array[0], num_elements_);
|
||||
// }
|
||||
//
|
||||
template <int&... ExplicitArgumentBarrier, typename T>
|
||||
constexpr Span<T> MakeSpan(T* ptr, size_t size) noexcept {
|
||||
return Span<T>(ptr, size);
|
||||
}
|
||||
|
||||
template <int&... ExplicitArgumentBarrier, typename T>
|
||||
Span<T> MakeSpan(T* begin, T* end) noexcept {
|
||||
return ABSL_ASSERT(begin <= end), Span<T>(begin, end - begin);
|
||||
}
|
||||
|
||||
template <int&... ExplicitArgumentBarrier, typename C>
|
||||
constexpr auto MakeSpan(C& c) noexcept // NOLINT(runtime/references)
|
||||
-> decltype(absl::MakeSpan(span_internal::GetData(c), c.size())) {
|
||||
return MakeSpan(span_internal::GetData(c), c.size());
|
||||
}
|
||||
|
||||
template <int&... ExplicitArgumentBarrier, typename T, size_t N>
|
||||
constexpr Span<T> MakeSpan(T (&array)[N]) noexcept {
|
||||
return Span<T>(array, N);
|
||||
}
|
||||
|
||||
// MakeConstSpan()
|
||||
//
|
||||
// Constructs a `Span<const T>` as with `MakeSpan`, deducing `T` automatically,
|
||||
// but always returning a `Span<const T>`.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// void ProcessInts(absl::Span<const int> some_ints);
|
||||
//
|
||||
// // Call with a pointer and size.
|
||||
// int array[3] = { 0, 0, 0 };
|
||||
// ProcessInts(absl::MakeConstSpan(&array[0], 3));
|
||||
//
|
||||
// // Call with a [begin, end) pair.
|
||||
// ProcessInts(absl::MakeConstSpan(&array[0], &array[3]));
|
||||
//
|
||||
// // Call directly with an array.
|
||||
// ProcessInts(absl::MakeConstSpan(array));
|
||||
//
|
||||
// // Call with a contiguous container.
|
||||
// std::vector<int> some_ints = ...;
|
||||
// ProcessInts(absl::MakeConstSpan(some_ints));
|
||||
// ProcessInts(absl::MakeConstSpan(std::vector<int>{ 0, 0, 0 }));
|
||||
//
|
||||
template <int&... ExplicitArgumentBarrier, typename T>
|
||||
constexpr Span<const T> MakeConstSpan(T* ptr, size_t size) noexcept {
|
||||
return Span<const T>(ptr, size);
|
||||
}
|
||||
|
||||
template <int&... ExplicitArgumentBarrier, typename T>
|
||||
Span<const T> MakeConstSpan(T* begin, T* end) noexcept {
|
||||
return ABSL_ASSERT(begin <= end), Span<const T>(begin, end - begin);
|
||||
}
|
||||
|
||||
template <int&... ExplicitArgumentBarrier, typename C>
|
||||
constexpr auto MakeConstSpan(const C& c) noexcept -> decltype(MakeSpan(c)) {
|
||||
return MakeSpan(c);
|
||||
}
|
||||
|
||||
template <int&... ExplicitArgumentBarrier, typename T, size_t N>
|
||||
constexpr Span<const T> MakeConstSpan(const T (&array)[N]) noexcept {
|
||||
return Span<const T>(array, N);
|
||||
}
|
||||
} // namespace absl
|
||||
#endif // ABSL_TYPES_SPAN_H_
|
||||
783
absl/types/span_test.cc
Normal file
783
absl/types/span_test.cc
Normal file
|
|
@ -0,0 +1,783 @@
|
|||
// 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/span.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <initializer_list>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/exception_testing.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/port.h"
|
||||
#include "absl/container/fixed_array.h"
|
||||
#include "absl/container/inlined_vector.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
|
||||
namespace {
|
||||
|
||||
MATCHER_P(DataIs, data,
|
||||
absl::StrCat("data() is ", negation ? "is " : "isn't ",
|
||||
testing::PrintToString(data))) {
|
||||
return arg.data() == data;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto SpanIs(T data, size_t size)
|
||||
-> decltype(testing::AllOf(DataIs(data), testing::SizeIs(size))) {
|
||||
return testing::AllOf(DataIs(data), testing::SizeIs(size));
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
auto SpanIs(const Container& c) -> decltype(SpanIs(c.data(), c.size())) {
|
||||
return SpanIs(c.data(), c.size());
|
||||
}
|
||||
|
||||
std::vector<int> MakeRamp(int len, int offset = 0) {
|
||||
std::vector<int> v(len);
|
||||
std::iota(v.begin(), v.end(), offset);
|
||||
return v;
|
||||
}
|
||||
|
||||
TEST(IntSpan, EmptyCtors) {
|
||||
absl::Span<int> s;
|
||||
EXPECT_THAT(s, SpanIs(nullptr, 0));
|
||||
}
|
||||
|
||||
TEST(IntSpan, PtrLenCtor) {
|
||||
int a[] = {1, 2, 3};
|
||||
absl::Span<int> s(&a[0], 2);
|
||||
EXPECT_THAT(s, SpanIs(a, 2));
|
||||
}
|
||||
|
||||
TEST(IntSpan, ArrayCtor) {
|
||||
int a[] = {1, 2, 3};
|
||||
absl::Span<int> s(a);
|
||||
EXPECT_THAT(s, SpanIs(a, 3));
|
||||
|
||||
EXPECT_TRUE((std::is_constructible<absl::Span<const int>, int[3]>::value));
|
||||
EXPECT_TRUE(
|
||||
(std::is_constructible<absl::Span<const int>, const int[3]>::value));
|
||||
EXPECT_FALSE((std::is_constructible<absl::Span<int>, const int[3]>::value));
|
||||
EXPECT_TRUE((std::is_convertible<int[3], absl::Span<const int>>::value));
|
||||
EXPECT_TRUE(
|
||||
(std::is_convertible<const int[3], absl::Span<const int>>::value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void TakesGenericSpan(absl::Span<T>) {}
|
||||
|
||||
TEST(IntSpan, ContainerCtor) {
|
||||
std::vector<int> empty;
|
||||
absl::Span<int> s_empty(empty);
|
||||
EXPECT_THAT(s_empty, SpanIs(empty));
|
||||
|
||||
std::vector<int> filled{1, 2, 3};
|
||||
absl::Span<int> s_filled(filled);
|
||||
EXPECT_THAT(s_filled, SpanIs(filled));
|
||||
|
||||
absl::Span<int> s_from_span(filled);
|
||||
EXPECT_THAT(s_from_span, SpanIs(s_filled));
|
||||
|
||||
absl::Span<const int> const_filled = filled;
|
||||
EXPECT_THAT(const_filled, SpanIs(filled));
|
||||
|
||||
absl::Span<const int> const_from_span = s_filled;
|
||||
EXPECT_THAT(const_from_span, SpanIs(s_filled));
|
||||
|
||||
EXPECT_TRUE(
|
||||
(std::is_convertible<std::vector<int>&, absl::Span<const int>>::value));
|
||||
EXPECT_TRUE(
|
||||
(std::is_convertible<absl::Span<int>&, absl::Span<const int>>::value));
|
||||
|
||||
TakesGenericSpan(absl::Span<int>(filled));
|
||||
}
|
||||
|
||||
// A struct supplying shallow data() const.
|
||||
struct ContainerWithShallowConstData {
|
||||
std::vector<int> storage;
|
||||
int* data() const { return const_cast<int*>(storage.data()); }
|
||||
int size() const { return storage.size(); }
|
||||
};
|
||||
|
||||
TEST(IntSpan, ShallowConstness) {
|
||||
const ContainerWithShallowConstData c{MakeRamp(20)};
|
||||
absl::Span<int> s(
|
||||
c); // We should be able to do this even though data() is const.
|
||||
s[0] = -1;
|
||||
EXPECT_EQ(c.storage[0], -1);
|
||||
}
|
||||
|
||||
TEST(CharSpan, StringCtor) {
|
||||
std::string empty = "";
|
||||
absl::Span<char> s_empty(empty);
|
||||
EXPECT_THAT(s_empty, SpanIs(empty));
|
||||
|
||||
std::string abc = "abc";
|
||||
absl::Span<char> s_abc(abc);
|
||||
EXPECT_THAT(s_abc, SpanIs(abc));
|
||||
|
||||
absl::Span<const char> s_const_abc = abc;
|
||||
EXPECT_THAT(s_const_abc, SpanIs(abc));
|
||||
|
||||
EXPECT_FALSE((std::is_constructible<absl::Span<int>, std::string>::value));
|
||||
EXPECT_FALSE((std::is_constructible<absl::Span<const int>, std::string>::value));
|
||||
EXPECT_TRUE((std::is_convertible<std::string, absl::Span<const char>>::value));
|
||||
}
|
||||
|
||||
TEST(IntSpan, FromConstPointer) {
|
||||
EXPECT_TRUE((std::is_constructible<absl::Span<const int* const>,
|
||||
std::vector<int*>>::value));
|
||||
EXPECT_TRUE((std::is_constructible<absl::Span<const int* const>,
|
||||
std::vector<const int*>>::value));
|
||||
EXPECT_FALSE((
|
||||
std::is_constructible<absl::Span<const int*>, std::vector<int*>>::value));
|
||||
EXPECT_FALSE((
|
||||
std::is_constructible<absl::Span<int*>, std::vector<const int*>>::value));
|
||||
}
|
||||
|
||||
struct TypeWithMisleadingData {
|
||||
int& data() { return i; }
|
||||
int size() { return 1; }
|
||||
int i;
|
||||
};
|
||||
|
||||
struct TypeWithMisleadingSize {
|
||||
int* data() { return &i; }
|
||||
const char* size() { return "1"; }
|
||||
int i;
|
||||
};
|
||||
|
||||
TEST(IntSpan, EvilTypes) {
|
||||
EXPECT_FALSE(
|
||||
(std::is_constructible<absl::Span<int>, TypeWithMisleadingData&>::value));
|
||||
EXPECT_FALSE(
|
||||
(std::is_constructible<absl::Span<int>, TypeWithMisleadingSize&>::value));
|
||||
}
|
||||
|
||||
struct Base {
|
||||
int* data() { return &i; }
|
||||
int size() { return 1; }
|
||||
int i;
|
||||
};
|
||||
struct Derived : Base {};
|
||||
|
||||
TEST(IntSpan, SpanOfDerived) {
|
||||
EXPECT_TRUE((std::is_constructible<absl::Span<int>, Base&>::value));
|
||||
EXPECT_TRUE((std::is_constructible<absl::Span<int>, Derived&>::value));
|
||||
EXPECT_FALSE(
|
||||
(std::is_constructible<absl::Span<Base>, std::vector<Derived>>::value));
|
||||
}
|
||||
|
||||
void TestInitializerList(absl::Span<const int> s, const std::vector<int>& v) {
|
||||
EXPECT_TRUE(absl::equal(s.begin(), s.end(), v.begin(), v.end()));
|
||||
}
|
||||
|
||||
TEST(ConstIntSpan, InitializerListConversion) {
|
||||
TestInitializerList({}, {});
|
||||
TestInitializerList({1}, {1});
|
||||
TestInitializerList({1, 2, 3}, {1, 2, 3});
|
||||
|
||||
EXPECT_FALSE((std::is_constructible<absl::Span<int>,
|
||||
std::initializer_list<int>>::value));
|
||||
EXPECT_FALSE((
|
||||
std::is_convertible<absl::Span<int>, std::initializer_list<int>>::value));
|
||||
}
|
||||
|
||||
TEST(IntSpan, Data) {
|
||||
int i;
|
||||
absl::Span<int> s(&i, 1);
|
||||
EXPECT_EQ(&i, s.data());
|
||||
}
|
||||
|
||||
TEST(IntSpan, SizeLengthEmpty) {
|
||||
absl::Span<int> empty;
|
||||
EXPECT_EQ(empty.size(), 0);
|
||||
EXPECT_TRUE(empty.empty());
|
||||
EXPECT_EQ(empty.size(), empty.length());
|
||||
|
||||
auto v = MakeRamp(10);
|
||||
absl::Span<int> s(v);
|
||||
EXPECT_EQ(s.size(), 10);
|
||||
EXPECT_FALSE(s.empty());
|
||||
EXPECT_EQ(s.size(), s.length());
|
||||
}
|
||||
|
||||
TEST(IntSpan, ElementAccess) {
|
||||
auto v = MakeRamp(10);
|
||||
absl::Span<int> s(v);
|
||||
for (int i = 0; i < s.size(); ++i) {
|
||||
EXPECT_EQ(s[i], s.at(i));
|
||||
}
|
||||
|
||||
EXPECT_EQ(s.front(), s[0]);
|
||||
EXPECT_EQ(s.back(), s[9]);
|
||||
}
|
||||
|
||||
TEST(IntSpan, AtThrows) {
|
||||
auto v = MakeRamp(10);
|
||||
absl::Span<int> s(v);
|
||||
|
||||
EXPECT_EQ(s.at(9), 9);
|
||||
ABSL_BASE_INTERNAL_EXPECT_FAIL(s.at(10), std::out_of_range,
|
||||
"failed bounds check");
|
||||
}
|
||||
|
||||
TEST(IntSpan, RemovePrefixAndSuffix) {
|
||||
auto v = MakeRamp(20, 1);
|
||||
absl::Span<int> s(v);
|
||||
EXPECT_EQ(s.size(), 20);
|
||||
|
||||
s.remove_suffix(0);
|
||||
s.remove_prefix(0);
|
||||
EXPECT_EQ(s.size(), 20);
|
||||
|
||||
s.remove_prefix(1);
|
||||
EXPECT_EQ(s.size(), 19);
|
||||
EXPECT_EQ(s[0], 2);
|
||||
|
||||
s.remove_suffix(1);
|
||||
EXPECT_EQ(s.size(), 18);
|
||||
EXPECT_EQ(s.back(), 19);
|
||||
|
||||
s.remove_prefix(7);
|
||||
EXPECT_EQ(s.size(), 11);
|
||||
EXPECT_EQ(s[0], 9);
|
||||
|
||||
s.remove_suffix(11);
|
||||
EXPECT_EQ(s.size(), 0);
|
||||
|
||||
EXPECT_EQ(v, MakeRamp(20, 1));
|
||||
}
|
||||
|
||||
TEST(IntSpan, Subspan) {
|
||||
std::vector<int> empty;
|
||||
EXPECT_EQ(absl::MakeSpan(empty).subspan(), empty);
|
||||
EXPECT_THAT(absl::MakeSpan(empty).subspan(0, 0), SpanIs(empty));
|
||||
EXPECT_THAT(absl::MakeSpan(empty).subspan(0, absl::Span<const int>::npos),
|
||||
SpanIs(empty));
|
||||
|
||||
auto ramp = MakeRamp(10);
|
||||
EXPECT_THAT(absl::MakeSpan(ramp).subspan(), SpanIs(ramp));
|
||||
EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, 10), SpanIs(ramp));
|
||||
EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, absl::Span<const int>::npos),
|
||||
SpanIs(ramp));
|
||||
EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, 3), SpanIs(ramp.data(), 3));
|
||||
EXPECT_THAT(absl::MakeSpan(ramp).subspan(5, absl::Span<const int>::npos),
|
||||
SpanIs(ramp.data() + 5, 5));
|
||||
EXPECT_THAT(absl::MakeSpan(ramp).subspan(3, 3), SpanIs(ramp.data() + 3, 3));
|
||||
EXPECT_THAT(absl::MakeSpan(ramp).subspan(10, 5), SpanIs(ramp.data() + 10, 0));
|
||||
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
EXPECT_THROW(absl::MakeSpan(ramp).subspan(11, 5), std::out_of_range);
|
||||
#else
|
||||
EXPECT_DEATH(absl::MakeSpan(ramp).subspan(11, 5), "");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(IntSpan, MakeSpanPtrLength) {
|
||||
std::vector<int> empty;
|
||||
auto s_empty = absl::MakeSpan(empty.data(), empty.size());
|
||||
EXPECT_THAT(s_empty, SpanIs(empty));
|
||||
|
||||
std::array<int, 3> a{{1, 2, 3}};
|
||||
auto s = absl::MakeSpan(a.data(), a.size());
|
||||
EXPECT_THAT(s, SpanIs(a));
|
||||
|
||||
EXPECT_THAT(absl::MakeConstSpan(empty.data(), empty.size()), SpanIs(s_empty));
|
||||
EXPECT_THAT(absl::MakeConstSpan(a.data(), a.size()), SpanIs(s));
|
||||
}
|
||||
|
||||
TEST(IntSpan, MakeSpanTwoPtrs) {
|
||||
std::vector<int> empty;
|
||||
auto s_empty = absl::MakeSpan(empty.data(), empty.data());
|
||||
EXPECT_THAT(s_empty, SpanIs(empty));
|
||||
|
||||
std::vector<int> v{1, 2, 3};
|
||||
auto s = absl::MakeSpan(v.data(), v.data() + 1);
|
||||
EXPECT_THAT(s, SpanIs(v.data(), 1));
|
||||
|
||||
EXPECT_THAT(absl::MakeConstSpan(empty.data(), empty.data()), SpanIs(s_empty));
|
||||
EXPECT_THAT(absl::MakeConstSpan(v.data(), v.data() + 1), SpanIs(s));
|
||||
}
|
||||
|
||||
TEST(IntSpan, MakeSpanContainer) {
|
||||
std::vector<int> empty;
|
||||
auto s_empty = absl::MakeSpan(empty);
|
||||
EXPECT_THAT(s_empty, SpanIs(empty));
|
||||
|
||||
std::vector<int> v{1, 2, 3};
|
||||
auto s = absl::MakeSpan(v);
|
||||
EXPECT_THAT(s, SpanIs(v));
|
||||
|
||||
EXPECT_THAT(absl::MakeConstSpan(empty), SpanIs(s_empty));
|
||||
EXPECT_THAT(absl::MakeConstSpan(v), SpanIs(s));
|
||||
|
||||
EXPECT_THAT(absl::MakeSpan(s), SpanIs(s));
|
||||
EXPECT_THAT(absl::MakeConstSpan(s), SpanIs(s));
|
||||
}
|
||||
|
||||
TEST(CharSpan, MakeSpanString) {
|
||||
std::string empty = "";
|
||||
auto s_empty = absl::MakeSpan(empty);
|
||||
EXPECT_THAT(s_empty, SpanIs(empty));
|
||||
|
||||
std::string str = "abc";
|
||||
auto s_str = absl::MakeSpan(str);
|
||||
EXPECT_THAT(s_str, SpanIs(str));
|
||||
|
||||
EXPECT_THAT(absl::MakeConstSpan(empty), SpanIs(s_empty));
|
||||
EXPECT_THAT(absl::MakeConstSpan(str), SpanIs(s_str));
|
||||
}
|
||||
|
||||
TEST(IntSpan, MakeSpanArray) {
|
||||
int a[] = {1, 2, 3};
|
||||
auto s = absl::MakeSpan(a);
|
||||
EXPECT_THAT(s, SpanIs(a, 3));
|
||||
|
||||
const int ca[] = {1, 2, 3};
|
||||
auto s_ca = absl::MakeSpan(ca);
|
||||
EXPECT_THAT(s_ca, SpanIs(ca, 3));
|
||||
|
||||
EXPECT_THAT(absl::MakeConstSpan(a), SpanIs(s));
|
||||
EXPECT_THAT(absl::MakeConstSpan(ca), SpanIs(s_ca));
|
||||
}
|
||||
|
||||
// Compile-asserts that the argument has the expected decayed type.
|
||||
template <typename Expected, typename T>
|
||||
void CheckType(const T& /* value */) {
|
||||
testing::StaticAssertTypeEq<Expected, T>();
|
||||
}
|
||||
|
||||
TEST(IntSpan, MakeSpanTypes) {
|
||||
std::vector<int> vec;
|
||||
const std::vector<int> cvec;
|
||||
int a[1];
|
||||
const int ca[] = {1};
|
||||
int* ip = a;
|
||||
const int* cip = ca;
|
||||
std::string s = "";
|
||||
const std::string cs = "";
|
||||
CheckType<absl::Span<int>>(absl::MakeSpan(vec));
|
||||
CheckType<absl::Span<const int>>(absl::MakeSpan(cvec));
|
||||
CheckType<absl::Span<int>>(absl::MakeSpan(ip, ip + 1));
|
||||
CheckType<absl::Span<int>>(absl::MakeSpan(ip, 1));
|
||||
CheckType<absl::Span<const int>>(absl::MakeSpan(cip, cip + 1));
|
||||
CheckType<absl::Span<const int>>(absl::MakeSpan(cip, 1));
|
||||
CheckType<absl::Span<int>>(absl::MakeSpan(a));
|
||||
CheckType<absl::Span<int>>(absl::MakeSpan(a, a + 1));
|
||||
CheckType<absl::Span<int>>(absl::MakeSpan(a, 1));
|
||||
CheckType<absl::Span<const int>>(absl::MakeSpan(ca));
|
||||
CheckType<absl::Span<const int>>(absl::MakeSpan(ca, ca + 1));
|
||||
CheckType<absl::Span<const int>>(absl::MakeSpan(ca, 1));
|
||||
CheckType<absl::Span<char>>(absl::MakeSpan(s));
|
||||
CheckType<absl::Span<const char>>(absl::MakeSpan(cs));
|
||||
}
|
||||
|
||||
TEST(ConstIntSpan, MakeConstSpanTypes) {
|
||||
std::vector<int> vec;
|
||||
const std::vector<int> cvec;
|
||||
int array[1];
|
||||
const int carray[] = {0};
|
||||
int* ptr = array;
|
||||
const int* cptr = carray;
|
||||
std::string s = "";
|
||||
std::string cs = "";
|
||||
CheckType<absl::Span<const int>>(absl::MakeConstSpan(vec));
|
||||
CheckType<absl::Span<const int>>(absl::MakeConstSpan(cvec));
|
||||
CheckType<absl::Span<const int>>(absl::MakeConstSpan(ptr, ptr + 1));
|
||||
CheckType<absl::Span<const int>>(absl::MakeConstSpan(ptr, 1));
|
||||
CheckType<absl::Span<const int>>(absl::MakeConstSpan(cptr, cptr + 1));
|
||||
CheckType<absl::Span<const int>>(absl::MakeConstSpan(cptr, 1));
|
||||
CheckType<absl::Span<const int>>(absl::MakeConstSpan(array));
|
||||
CheckType<absl::Span<const int>>(absl::MakeConstSpan(carray));
|
||||
CheckType<absl::Span<const char>>(absl::MakeConstSpan(s));
|
||||
CheckType<absl::Span<const char>>(absl::MakeConstSpan(cs));
|
||||
}
|
||||
|
||||
TEST(IntSpan, Equality) {
|
||||
const int arr1[] = {1, 2, 3, 4, 5};
|
||||
int arr2[] = {1, 2, 3, 4, 5};
|
||||
std::vector<int> vec1(std::begin(arr1), std::end(arr1));
|
||||
std::vector<int> vec2 = vec1;
|
||||
std::vector<int> other_vec = {2, 4, 6, 8, 10};
|
||||
// These two slices are from different vectors, but have the same size and
|
||||
// have the same elements (right now). They should compare equal. Test both
|
||||
// == and !=.
|
||||
const absl::Span<const int> from1 = vec1;
|
||||
const absl::Span<const int> from2 = vec2;
|
||||
EXPECT_EQ(from1, from1);
|
||||
EXPECT_FALSE(from1 != from1);
|
||||
EXPECT_EQ(from1, from2);
|
||||
EXPECT_FALSE(from1 != from2);
|
||||
|
||||
// These two slices have different underlying vector values. They should be
|
||||
// considered not equal. Test both == and !=.
|
||||
const absl::Span<const int> from_other = other_vec;
|
||||
EXPECT_NE(from1, from_other);
|
||||
EXPECT_FALSE(from1 == from_other);
|
||||
|
||||
// Comparison between a vector and its slice should be equal. And vice-versa.
|
||||
// This ensures implicit conversion to Span works on both sides of ==.
|
||||
EXPECT_EQ(vec1, from1);
|
||||
EXPECT_FALSE(vec1 != from1);
|
||||
EXPECT_EQ(from1, vec1);
|
||||
EXPECT_FALSE(from1 != vec1);
|
||||
|
||||
// This verifies that absl::Span<T> can be compared freely with
|
||||
// absl::Span<const T>.
|
||||
const absl::Span<int> mutable_from1(vec1);
|
||||
const absl::Span<int> mutable_from2(vec2);
|
||||
EXPECT_EQ(from1, mutable_from1);
|
||||
EXPECT_EQ(mutable_from1, from1);
|
||||
EXPECT_EQ(mutable_from1, mutable_from2);
|
||||
EXPECT_EQ(mutable_from2, mutable_from1);
|
||||
|
||||
// Comparison between a vector and its slice should be equal for mutable
|
||||
// Spans as well.
|
||||
EXPECT_EQ(vec1, mutable_from1);
|
||||
EXPECT_FALSE(vec1 != mutable_from1);
|
||||
EXPECT_EQ(mutable_from1, vec1);
|
||||
EXPECT_FALSE(mutable_from1 != vec1);
|
||||
|
||||
// Comparison between convertible-to-Span-of-const and Span-of-mutable. Arrays
|
||||
// are used because they're the only value type which converts to a
|
||||
// Span-of-mutable. EXPECT_TRUE is used instead of EXPECT_EQ to avoid
|
||||
// array-to-pointer decay.
|
||||
EXPECT_TRUE(arr1 == mutable_from1);
|
||||
EXPECT_FALSE(arr1 != mutable_from1);
|
||||
EXPECT_TRUE(mutable_from1 == arr1);
|
||||
EXPECT_FALSE(mutable_from1 != arr1);
|
||||
|
||||
// Comparison between convertible-to-Span-of-mutable and Span-of-const
|
||||
EXPECT_TRUE(arr2 == from1);
|
||||
EXPECT_FALSE(arr2 != from1);
|
||||
EXPECT_TRUE(from1 == arr2);
|
||||
EXPECT_FALSE(from1 != arr2);
|
||||
|
||||
// With a different size, the array slices should not be equal.
|
||||
EXPECT_NE(from1, absl::Span<const int>(from1).subspan(0, from1.size() - 1));
|
||||
|
||||
// With different contents, the array slices should not be equal.
|
||||
++vec2.back();
|
||||
EXPECT_NE(from1, from2);
|
||||
}
|
||||
|
||||
class IntSpanOrderComparisonTest : public testing::Test {
|
||||
public:
|
||||
IntSpanOrderComparisonTest()
|
||||
: arr_before_{1, 2, 3},
|
||||
arr_after_{1, 2, 4},
|
||||
carr_after_{1, 2, 4},
|
||||
vec_before_(std::begin(arr_before_), std::end(arr_before_)),
|
||||
vec_after_(std::begin(arr_after_), std::end(arr_after_)),
|
||||
before_(vec_before_),
|
||||
after_(vec_after_),
|
||||
cbefore_(vec_before_),
|
||||
cafter_(vec_after_) {}
|
||||
|
||||
protected:
|
||||
int arr_before_[3], arr_after_[3];
|
||||
const int carr_after_[3];
|
||||
std::vector<int> vec_before_, vec_after_;
|
||||
absl::Span<int> before_, after_;
|
||||
absl::Span<const int> cbefore_, cafter_;
|
||||
};
|
||||
|
||||
TEST_F(IntSpanOrderComparisonTest, CompareSpans) {
|
||||
EXPECT_TRUE(cbefore_ < cafter_);
|
||||
EXPECT_TRUE(cbefore_ <= cafter_);
|
||||
EXPECT_TRUE(cafter_ > cbefore_);
|
||||
EXPECT_TRUE(cafter_ >= cbefore_);
|
||||
|
||||
EXPECT_FALSE(cbefore_ > cafter_);
|
||||
EXPECT_FALSE(cafter_ < cbefore_);
|
||||
|
||||
EXPECT_TRUE(before_ < after_);
|
||||
EXPECT_TRUE(before_ <= after_);
|
||||
EXPECT_TRUE(after_ > before_);
|
||||
EXPECT_TRUE(after_ >= before_);
|
||||
|
||||
EXPECT_FALSE(before_ > after_);
|
||||
EXPECT_FALSE(after_ < before_);
|
||||
|
||||
EXPECT_TRUE(cbefore_ < after_);
|
||||
EXPECT_TRUE(cbefore_ <= after_);
|
||||
EXPECT_TRUE(after_ > cbefore_);
|
||||
EXPECT_TRUE(after_ >= cbefore_);
|
||||
|
||||
EXPECT_FALSE(cbefore_ > after_);
|
||||
EXPECT_FALSE(after_ < cbefore_);
|
||||
}
|
||||
|
||||
TEST_F(IntSpanOrderComparisonTest, SpanOfConstAndContainer) {
|
||||
EXPECT_TRUE(cbefore_ < vec_after_);
|
||||
EXPECT_TRUE(cbefore_ <= vec_after_);
|
||||
EXPECT_TRUE(vec_after_ > cbefore_);
|
||||
EXPECT_TRUE(vec_after_ >= cbefore_);
|
||||
|
||||
EXPECT_FALSE(cbefore_ > vec_after_);
|
||||
EXPECT_FALSE(vec_after_ < cbefore_);
|
||||
|
||||
EXPECT_TRUE(arr_before_ < cafter_);
|
||||
EXPECT_TRUE(arr_before_ <= cafter_);
|
||||
EXPECT_TRUE(cafter_ > arr_before_);
|
||||
EXPECT_TRUE(cafter_ >= arr_before_);
|
||||
|
||||
EXPECT_FALSE(arr_before_ > cafter_);
|
||||
EXPECT_FALSE(cafter_ < arr_before_);
|
||||
}
|
||||
|
||||
TEST_F(IntSpanOrderComparisonTest, SpanOfMutableAndContainer) {
|
||||
EXPECT_TRUE(vec_before_ < after_);
|
||||
EXPECT_TRUE(vec_before_ <= after_);
|
||||
EXPECT_TRUE(after_ > vec_before_);
|
||||
EXPECT_TRUE(after_ >= vec_before_);
|
||||
|
||||
EXPECT_FALSE(vec_before_ > after_);
|
||||
EXPECT_FALSE(after_ < vec_before_);
|
||||
|
||||
EXPECT_TRUE(before_ < carr_after_);
|
||||
EXPECT_TRUE(before_ <= carr_after_);
|
||||
EXPECT_TRUE(carr_after_ > before_);
|
||||
EXPECT_TRUE(carr_after_ >= before_);
|
||||
|
||||
EXPECT_FALSE(before_ > carr_after_);
|
||||
EXPECT_FALSE(carr_after_ < before_);
|
||||
}
|
||||
|
||||
TEST_F(IntSpanOrderComparisonTest, EqualSpans) {
|
||||
EXPECT_FALSE(before_ < before_);
|
||||
EXPECT_TRUE(before_ <= before_);
|
||||
EXPECT_FALSE(before_ > before_);
|
||||
EXPECT_TRUE(before_ >= before_);
|
||||
}
|
||||
|
||||
TEST_F(IntSpanOrderComparisonTest, Subspans) {
|
||||
auto subspan = before_.subspan(0, 1);
|
||||
EXPECT_TRUE(subspan < before_);
|
||||
EXPECT_TRUE(subspan <= before_);
|
||||
EXPECT_TRUE(before_ > subspan);
|
||||
EXPECT_TRUE(before_ >= subspan);
|
||||
|
||||
EXPECT_FALSE(subspan > before_);
|
||||
EXPECT_FALSE(before_ < subspan);
|
||||
}
|
||||
|
||||
TEST_F(IntSpanOrderComparisonTest, EmptySpans) {
|
||||
absl::Span<int> empty;
|
||||
EXPECT_FALSE(empty < empty);
|
||||
EXPECT_TRUE(empty <= empty);
|
||||
EXPECT_FALSE(empty > empty);
|
||||
EXPECT_TRUE(empty >= empty);
|
||||
|
||||
EXPECT_TRUE(empty < before_);
|
||||
EXPECT_TRUE(empty <= before_);
|
||||
EXPECT_TRUE(before_ > empty);
|
||||
EXPECT_TRUE(before_ >= empty);
|
||||
|
||||
EXPECT_FALSE(empty > before_);
|
||||
EXPECT_FALSE(before_ < empty);
|
||||
}
|
||||
|
||||
TEST(IntSpan, ExposesContainerTypesAndConsts) {
|
||||
absl::Span<int> slice;
|
||||
CheckType<absl::Span<int>::iterator>(slice.begin());
|
||||
EXPECT_TRUE((std::is_convertible<decltype(slice.begin()),
|
||||
absl::Span<int>::const_iterator>::value));
|
||||
CheckType<absl::Span<int>::const_iterator>(slice.cbegin());
|
||||
EXPECT_TRUE((std::is_convertible<decltype(slice.end()),
|
||||
absl::Span<int>::const_iterator>::value));
|
||||
CheckType<absl::Span<int>::const_iterator>(slice.cend());
|
||||
CheckType<absl::Span<int>::reverse_iterator>(slice.rend());
|
||||
EXPECT_TRUE(
|
||||
(std::is_convertible<decltype(slice.rend()),
|
||||
absl::Span<int>::const_reverse_iterator>::value));
|
||||
CheckType<absl::Span<int>::const_reverse_iterator>(slice.crend());
|
||||
testing::StaticAssertTypeEq<int, absl::Span<int>::value_type>();
|
||||
testing::StaticAssertTypeEq<int, absl::Span<const int>::value_type>();
|
||||
testing::StaticAssertTypeEq<int*, absl::Span<int>::pointer>();
|
||||
testing::StaticAssertTypeEq<const int*, absl::Span<const int>::pointer>();
|
||||
testing::StaticAssertTypeEq<int&, absl::Span<int>::reference>();
|
||||
testing::StaticAssertTypeEq<const int&, absl::Span<const int>::reference>();
|
||||
testing::StaticAssertTypeEq<const int&, absl::Span<int>::const_reference>();
|
||||
testing::StaticAssertTypeEq<const int&,
|
||||
absl::Span<const int>::const_reference>();
|
||||
EXPECT_EQ(static_cast<absl::Span<int>::size_type>(-1), absl::Span<int>::npos);
|
||||
}
|
||||
|
||||
TEST(IntSpan, IteratorsAndReferences) {
|
||||
auto accept_pointer = [](int*) {};
|
||||
auto accept_reference = [](int&) {};
|
||||
auto accept_iterator = [](absl::Span<int>::iterator) {};
|
||||
auto accept_const_iterator = [](absl::Span<int>::const_iterator) {};
|
||||
auto accept_reverse_iterator = [](absl::Span<int>::reverse_iterator) {};
|
||||
auto accept_const_reverse_iterator =
|
||||
[](absl::Span<int>::const_reverse_iterator) {};
|
||||
|
||||
int a[1];
|
||||
absl::Span<int> s = a;
|
||||
|
||||
accept_pointer(s.data());
|
||||
accept_iterator(s.begin());
|
||||
accept_const_iterator(s.begin());
|
||||
accept_const_iterator(s.cbegin());
|
||||
accept_iterator(s.end());
|
||||
accept_const_iterator(s.end());
|
||||
accept_const_iterator(s.cend());
|
||||
accept_reverse_iterator(s.rbegin());
|
||||
accept_const_reverse_iterator(s.rbegin());
|
||||
accept_const_reverse_iterator(s.crbegin());
|
||||
accept_reverse_iterator(s.rend());
|
||||
accept_const_reverse_iterator(s.rend());
|
||||
accept_const_reverse_iterator(s.crend());
|
||||
|
||||
accept_reference(s[0]);
|
||||
accept_reference(s.at(0));
|
||||
accept_reference(s.front());
|
||||
accept_reference(s.back());
|
||||
}
|
||||
|
||||
TEST(IntSpan, IteratorsAndReferences_Const) {
|
||||
auto accept_pointer = [](int*) {};
|
||||
auto accept_reference = [](int&) {};
|
||||
auto accept_iterator = [](absl::Span<int>::iterator) {};
|
||||
auto accept_const_iterator = [](absl::Span<int>::const_iterator) {};
|
||||
auto accept_reverse_iterator = [](absl::Span<int>::reverse_iterator) {};
|
||||
auto accept_const_reverse_iterator =
|
||||
[](absl::Span<int>::const_reverse_iterator) {};
|
||||
|
||||
int a[1];
|
||||
const absl::Span<int> s = a;
|
||||
|
||||
accept_pointer(s.data());
|
||||
accept_iterator(s.begin());
|
||||
accept_const_iterator(s.begin());
|
||||
accept_const_iterator(s.cbegin());
|
||||
accept_iterator(s.end());
|
||||
accept_const_iterator(s.end());
|
||||
accept_const_iterator(s.cend());
|
||||
accept_reverse_iterator(s.rbegin());
|
||||
accept_const_reverse_iterator(s.rbegin());
|
||||
accept_const_reverse_iterator(s.crbegin());
|
||||
accept_reverse_iterator(s.rend());
|
||||
accept_const_reverse_iterator(s.rend());
|
||||
accept_const_reverse_iterator(s.crend());
|
||||
|
||||
accept_reference(s[0]);
|
||||
accept_reference(s.at(0));
|
||||
accept_reference(s.front());
|
||||
accept_reference(s.back());
|
||||
}
|
||||
|
||||
TEST(IntSpan, NoexceptTest) {
|
||||
int a[] = {1, 2, 3};
|
||||
std::vector<int> v;
|
||||
EXPECT_TRUE(noexcept(absl::Span<const int>()));
|
||||
EXPECT_TRUE(noexcept(absl::Span<const int>(a, 2)));
|
||||
EXPECT_TRUE(noexcept(absl::Span<const int>(a)));
|
||||
EXPECT_TRUE(noexcept(absl::Span<const int>(v)));
|
||||
EXPECT_TRUE(noexcept(absl::Span<int>(v)));
|
||||
EXPECT_TRUE(noexcept(absl::Span<const int>({1, 2, 3})));
|
||||
EXPECT_TRUE(noexcept(absl::MakeSpan(v)));
|
||||
EXPECT_TRUE(noexcept(absl::MakeSpan(a)));
|
||||
EXPECT_TRUE(noexcept(absl::MakeSpan(a, 2)));
|
||||
EXPECT_TRUE(noexcept(absl::MakeSpan(a, a + 1)));
|
||||
EXPECT_TRUE(noexcept(absl::MakeConstSpan(v)));
|
||||
EXPECT_TRUE(noexcept(absl::MakeConstSpan(a)));
|
||||
EXPECT_TRUE(noexcept(absl::MakeConstSpan(a, 2)));
|
||||
EXPECT_TRUE(noexcept(absl::MakeConstSpan(a, a + 1)));
|
||||
|
||||
absl::Span<int> s(v);
|
||||
EXPECT_TRUE(noexcept(s.data()));
|
||||
EXPECT_TRUE(noexcept(s.size()));
|
||||
EXPECT_TRUE(noexcept(s.length()));
|
||||
EXPECT_TRUE(noexcept(s.empty()));
|
||||
EXPECT_TRUE(noexcept(s[0]));
|
||||
EXPECT_TRUE(noexcept(s.front()));
|
||||
EXPECT_TRUE(noexcept(s.back()));
|
||||
EXPECT_TRUE(noexcept(s.begin()));
|
||||
EXPECT_TRUE(noexcept(s.cbegin()));
|
||||
EXPECT_TRUE(noexcept(s.end()));
|
||||
EXPECT_TRUE(noexcept(s.cend()));
|
||||
EXPECT_TRUE(noexcept(s.rbegin()));
|
||||
EXPECT_TRUE(noexcept(s.crbegin()));
|
||||
EXPECT_TRUE(noexcept(s.rend()));
|
||||
EXPECT_TRUE(noexcept(s.crend()));
|
||||
EXPECT_TRUE(noexcept(s.remove_prefix(0)));
|
||||
EXPECT_TRUE(noexcept(s.remove_suffix(0)));
|
||||
}
|
||||
|
||||
// ConstexprTester exercises expressions in a constexpr context. Simply placing
|
||||
// the expression in a constexpr function is not enough, as some compilers will
|
||||
// simply compile the constexpr function as runtime code. Using template
|
||||
// parameters forces compile-time execution.
|
||||
template <int i>
|
||||
struct ConstexprTester {};
|
||||
|
||||
#define ABSL_TEST_CONSTEXPR(expr) \
|
||||
do { \
|
||||
ABSL_ATTRIBUTE_UNUSED ConstexprTester<(expr, 1)> t; \
|
||||
} while (0)
|
||||
|
||||
struct ContainerWithConstexprMethods {
|
||||
constexpr int size() const { return 1; }
|
||||
constexpr const int* data() const { return &i; }
|
||||
const int i;
|
||||
};
|
||||
|
||||
TEST(ConstIntSpan, ConstexprTest) {
|
||||
static constexpr int a[] = {1, 2, 3};
|
||||
static constexpr int sized_arr[2] = {1, 2};
|
||||
static constexpr ContainerWithConstexprMethods c{1};
|
||||
ABSL_TEST_CONSTEXPR(absl::Span<const int>());
|
||||
ABSL_TEST_CONSTEXPR(absl::Span<const int>(a, 2));
|
||||
ABSL_TEST_CONSTEXPR(absl::Span<const int>(sized_arr));
|
||||
ABSL_TEST_CONSTEXPR(absl::Span<const int>(c));
|
||||
ABSL_TEST_CONSTEXPR(absl::MakeSpan(&a[0], 1));
|
||||
ABSL_TEST_CONSTEXPR(absl::MakeSpan(c));
|
||||
ABSL_TEST_CONSTEXPR(absl::MakeSpan(a));
|
||||
ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(&a[0], 1));
|
||||
ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(c));
|
||||
ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(a));
|
||||
|
||||
constexpr absl::Span<const int> span = c;
|
||||
ABSL_TEST_CONSTEXPR(span.data());
|
||||
ABSL_TEST_CONSTEXPR(span.size());
|
||||
ABSL_TEST_CONSTEXPR(span.length());
|
||||
ABSL_TEST_CONSTEXPR(span.empty());
|
||||
ABSL_TEST_CONSTEXPR(span.begin());
|
||||
ABSL_TEST_CONSTEXPR(span.cbegin());
|
||||
ABSL_TEST_CONSTEXPR(span.subspan(0, 0));
|
||||
ABSL_TEST_CONSTEXPR(span[0]);
|
||||
}
|
||||
|
||||
struct BigStruct {
|
||||
char bytes[10000];
|
||||
};
|
||||
|
||||
TEST(Span, SpanSize) {
|
||||
EXPECT_LE(sizeof(absl::Span<int>), 2 * sizeof(void*));
|
||||
EXPECT_LE(sizeof(absl::Span<BigStruct>), 2 * sizeof(void*));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
Loading…
Add table
Add a link
Reference in a new issue