Initial Commit

This commit is contained in:
misterg 2017-09-19 16:54:40 -04:00
commit c2e7548296
238 changed files with 65475 additions and 0 deletions

178
absl/types/BUILD.bazel Normal file
View 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
View 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
View 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

View 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
View 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_

View 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

View 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
View 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

File diff suppressed because it is too large Load diff

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
View 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
View 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