Open-source absl::AnySpan

PiperOrigin-RevId: 883174961
Change-Id: Iea8fe182d759350f2b84e78892243867cd9f4be8
This commit is contained in:
Abseil Team
2026-03-13 08:19:35 -07:00
committed by Copybara-Service
parent efcd129252
commit 522a5a8b51
7 changed files with 3085 additions and 0 deletions

View File

@@ -450,7 +450,9 @@ set(ABSL_INTERNAL_DLL_FILES
"time/time.cc"
"time/time.h"
"types/any.h"
"types/any_span.h"
"types/compare.h"
"types/internal/any_span.h"
"types/internal/span.h"
"types/optional.h"
"types/optional_ref.h"

View File

@@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load(
@@ -119,6 +120,61 @@ cc_test(
],
)
cc_library(
name = "any_span",
srcs = ["internal/any_span.h"],
hdrs = [
"any_span.h",
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:nullability",
"//absl/base:raw_logging_internal",
"//absl/base:throw_delegate",
"//absl/meta:type_traits",
],
)
cc_test(
name = "any_span_test",
size = "small",
srcs = ["any_span_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":any_span",
":span",
"//absl/base:config",
"//absl/base:exception_testing",
"//absl/base:raw_logging_internal",
"//absl/hash:hash_testing",
"//absl/meta:type_traits",
"//absl/strings",
"@googletest//:gtest",
"@googletest//:gtest_main",
],
)
cc_binary(
name = "any_span_benchmark",
testonly = True,
srcs = ["any_span_benchmark.cc"],
tags = ["benchmark"],
deps = [
":any_span",
":span",
"//absl/base:config",
"//absl/base:raw_logging_internal",
"//absl/flags:flag",
"//absl/strings",
"//absl/strings:string_view",
"@google_benchmark//:benchmark_main",
],
)
cc_library(
name = "optional",
hdrs = ["optional.h"],

View File

@@ -27,6 +27,43 @@ absl_cc_library(
PUBLIC
)
absl_cc_library(
NAME
any_span
HDRS
"any_span.h"
SRCS
"internal/any_span.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
absl::config
absl::core_headers
absl::nullability
absl::raw_logging_internal
absl::throw_delegate
absl::type_traits
PUBLIC
)
absl_cc_test(
NAME
any_span_test
SRCS
"any_span_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::config
absl::exception_testing
absl::hash_testing
absl::raw_logging_internal
absl::span
absl::strings
absl::type_traits
GTest::gmock_main
)
absl_cc_library(
NAME
span

1083
absl/types/any_span.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,258 @@
// Copyright 2026 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
//
// https://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 <cstddef>
#include <cstdint>
#include <deque>
#include <string>
#include <type_traits>
#include <vector>
#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/flags/flag.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/any_span.h"
#include "absl/types/span.h"
#include "benchmark/benchmark.h"
ABSL_FLAG(uint64_t, benchmark_container_size, 2000,
"The size of the containers to use for benchmarking.");
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace {
//
// Benchmarks and supporting code follows.
//
template <typename T>
T MakeElement(int) {
ABSL_RAW_LOG(FATAL, "Not implemented.");
}
template <>
std::string MakeElement<std::string>(int i) {
return absl::StrCat(i, i, i);
}
template <>
int MakeElement<int>(int i) {
return i;
}
template <typename Container>
Container MakeContainer() {
const size_t container_size = absl::GetFlag(FLAGS_benchmark_container_size);
Container c;
for (size_t i = 0; i < container_size; ++i) {
c.push_back(
MakeElement<typename Container::value_type>(static_cast<int>(i)));
}
return c;
}
template <typename Container, typename SourceContainer>
Container MakePointerContainer(SourceContainer* source) {
Container c;
for (auto& value : *source) {
c.push_back(&value);
}
return c;
}
//
// Sequential Access Benchmarks
//
// Control run, iterating original container.
template <typename Container>
void BM_Sequential(benchmark::State& state) {
auto a = MakeContainer<Container>();
benchmark::DoNotOptimize(a);
for (auto _ : state) {
for (auto& v : a) {
benchmark::DoNotOptimize(v);
}
}
}
// Wraps the container with a Span.
template <typename Container>
void BM_Sequential_Span(benchmark::State& state) {
auto container = MakeContainer<Container>();
absl::Span<typename Container::value_type> array_span(container);
benchmark::DoNotOptimize(array_span);
for (auto _ : state) {
for (auto& v : array_span) {
benchmark::DoNotOptimize(v);
}
}
}
// Same as BM_Sequential_Span, but uses a container of pointers and
// dereferences it.
template <typename Container>
void BM_Sequential_DerefSpan(benchmark::State& state) {
using T = typename std::remove_pointer<typename Container::value_type>::type;
auto values = MakeContainer<std::vector<T>>();
const auto container = MakePointerContainer<Container>(&values);
absl::Span<T* const> array_span(container);
benchmark::DoNotOptimize(array_span);
for (auto _ : state) {
for (const auto& v : array_span) {
benchmark::DoNotOptimize(*v);
}
}
}
// Wraps a AnySpan<const T> around a Container. Sequentially reads the
// entire span.
template <typename Container>
void BM_Sequential_AnySpan(benchmark::State& state) {
using T = typename Container::value_type;
auto container = MakeContainer<Container>();
AnySpan<T> span(container);
benchmark::DoNotOptimize(span);
for (auto _ : state) {
for (T& s : span) {
benchmark::DoNotOptimize(s);
}
}
}
// Same as BM_Sequential_AnySpan, but dereferences the elements.
template <typename Container>
void BM_Sequential_AnySpanDeref(benchmark::State& state) {
using T = typename std::remove_pointer<typename Container::value_type>::type;
auto values = MakeContainer<std::vector<T>>();
auto container = MakePointerContainer<Container>(&values);
AnySpan<T> span(container, any_span_transform::Deref());
benchmark::DoNotOptimize(span);
for (auto _ : state) {
for (auto& s : span) {
benchmark::DoNotOptimize(s);
}
}
}
//
// Random Access Benchmarks
//
// Control run, accessing the original container.
template <typename Container>
void BM_Random(benchmark::State& state) {
auto a = MakeContainer<Container>();
auto* b = &a;
benchmark::DoNotOptimize(a);
benchmark::DoNotOptimize(b);
for (auto _ : state) {
uint64_t index_seed = 0;
for (size_t j = 0; j < a.size(); ++j) {
index_seed += 5623;
const uint64_t index = index_seed % a.size();
benchmark::DoNotOptimize((*b)[index]);
}
}
}
// Wraps a Span around a Container. Randomly reads the span.
template <typename Container>
void BM_Random_Span(benchmark::State& state) {
using T = typename Container::value_type;
auto v = MakeContainer<Container>();
absl::Span<T> array_span(v);
benchmark::DoNotOptimize(array_span);
for (auto _ : state) {
uint64_t index_seed = 0;
for (size_t j = 0; j < v.size(); ++j) {
index_seed += 5623;
const uint64_t index = index_seed % v.size();
benchmark::DoNotOptimize(array_span[index]);
}
}
}
// Wraps a AnySpan around a Container. Randomly reads the span.
template <typename Container>
void BM_Random_AnySpan(benchmark::State& state) {
using T = typename Container::value_type;
auto container = MakeContainer<Container>();
AnySpan<T> span(container);
benchmark::DoNotOptimize(span);
for (auto _ : state) {
uint64_t index_seed = 0;
for (size_t j = 0; j < container.size(); ++j) {
index_seed += 5623;
const uint64_t index = index_seed % span.size();
benchmark::DoNotOptimize(span[index]);
}
}
}
// Same as BM_Random_AnySpan, but dereferences elements.
template <typename Container>
void BM_Random_AnySpanDeref(benchmark::State& state) {
using T = typename std::remove_pointer<typename Container::value_type>::type;
auto values = MakeContainer<std::vector<T>>();
auto container = MakePointerContainer<Container>(&values);
AnySpan<T> span(container, any_span_transform::Deref());
benchmark::DoNotOptimize(span);
for (auto _ : state) {
uint64_t index_seed = 0;
for (size_t j = 0; j < container.size(); ++j) {
index_seed += 5623;
const uint64_t index = index_seed % span.size();
benchmark::DoNotOptimize(span[index]);
}
}
}
// Sequential access int.
BENCHMARK_TEMPLATE(BM_Sequential, std::vector<int>);
BENCHMARK_TEMPLATE(BM_Sequential, std::deque<int>);
BENCHMARK_TEMPLATE(BM_Sequential_Span, std::vector<int>);
BENCHMARK_TEMPLATE(BM_Sequential_AnySpan, std::vector<int>);
BENCHMARK_TEMPLATE(BM_Sequential_AnySpan, std::deque<int>);
// Sequential access string.
BENCHMARK_TEMPLATE(BM_Sequential, std::vector<std::string>);
BENCHMARK_TEMPLATE(BM_Sequential, std::deque<std::string>);
BENCHMARK_TEMPLATE(BM_Sequential_Span, std::vector<std::string>);
BENCHMARK_TEMPLATE(BM_Sequential_AnySpan, std::vector<std::string>);
BENCHMARK_TEMPLATE(BM_Sequential_AnySpan, std::deque<std::string>);
BENCHMARK_TEMPLATE(BM_Sequential_DerefSpan, std::vector<std::string*>);
BENCHMARK_TEMPLATE(BM_Sequential_AnySpanDeref, std::vector<std::string*>);
// Random access int.
BENCHMARK_TEMPLATE(BM_Random, std::vector<int>);
BENCHMARK_TEMPLATE(BM_Random, std::deque<int>);
BENCHMARK_TEMPLATE(BM_Random_Span, std::vector<int>);
BENCHMARK_TEMPLATE(BM_Random_AnySpan, std::vector<int>);
BENCHMARK_TEMPLATE(BM_Random_AnySpan, std::deque<int>);
// Random access string.
BENCHMARK_TEMPLATE(BM_Random, std::vector<std::string>);
BENCHMARK_TEMPLATE(BM_Random, std::deque<std::string>);
BENCHMARK_TEMPLATE(BM_Random_Span, std::vector<std::string>);
BENCHMARK_TEMPLATE(BM_Random_AnySpan, std::vector<std::string>);
BENCHMARK_TEMPLATE(BM_Random_AnySpan, std::deque<std::string>);
BENCHMARK_TEMPLATE(BM_Random_AnySpanDeref, std::vector<std::string*>);
} // namespace
ABSL_NAMESPACE_END
} // namespace absl

1172
absl/types/any_span_test.cc Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,477 @@
// Copyright 2026 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
//
// https://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.
//
// -----------------------------------------------------------------------------
// File: internal/any_span.h
// -----------------------------------------------------------------------------
//
// Helper types and functions used by AnySpan. This file should only be
// included by any_span.h.
#ifndef ABSL_TYPES_INTERNAL_ANY_SPAN_H_
#define ABSL_TYPES_INTERNAL_ANY_SPAN_H_
#include <algorithm>
#include <cstddef>
#include <functional>
#include <type_traits>
#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/optimization.h"
#include "absl/meta/type_traits.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
template <typename T>
class AnySpan;
namespace any_span_transform {
struct IdentityT;
struct DerefT;
} // namespace any_span_transform
namespace any_span_internal {
//
// IsAnySpan inherits from true_type if T is an instance of AnySpan.
//
template <typename T>
struct IsAnySpan : public std::false_type {};
template <typename T>
struct IsAnySpan<AnySpan<T>> : public std::true_type {};
// A type suitable for storing any function pointer. The standard allows
// function pointers to round-trip through other function pointers, but void* is
// implementation defined.
using FunPtr = void (*)();
// Whether a transform will be copied and therefore does not have to outlive
// the AnySpan.
template <typename Transform>
constexpr bool kIsTransformCopied =
std::is_function_v<std::remove_pointer_t<Transform>>;
// Type to pass as extra argument to TransformPtr to ensure that our
// assumption about Transform copyability is valid.
template <typename Transform>
using IsTransformCopied =
std::integral_constant<bool, kIsTransformCopied<Transform>>;
// A pointer to the transform function or functor that should be applied to
// elements of the container.
class TransformPtr {
public:
TransformPtr() = default;
// Construct from ptr to function.
template <typename R, typename... Args, typename CopiedTransform>
explicit TransformPtr(R (*f)(Args...),
CopiedTransform copied_transform [[maybe_unused]])
: fun_ptr_(reinterpret_cast<FunPtr>(f)) {
static_assert(CopiedTransform::value);
}
// Construct from any other invokable object.
template <typename T, typename CopiedTransform>
explicit TransformPtr(const T& t,
CopiedTransform copied_transform [[maybe_unused]])
: ptr_(&t) {
static_assert(!CopiedTransform::value);
}
// Casts the pointer to the given type.
template <typename Transform>
auto get() const {
if constexpr (std::is_function_v<Transform>) {
return reinterpret_cast<const Transform*>(fun_ptr_);
} else if constexpr (std::is_function_v<std::remove_pointer_t<Transform>>) {
return reinterpret_cast<const Transform>(fun_ptr_);
} else {
return static_cast<const Transform*>(ptr_);
}
}
private:
union {
const void* ptr_ = nullptr;
FunPtr fun_ptr_;
};
};
// A void* pointer to the container and transform functor. These are always cast
// to the correct type since we create this object and the GetterFunction at the
// same time (from one of the Make*Getter functions below).
struct TransformedContainer {
// The container or array.
void* ptr;
// The transform being applied to the container.
TransformPtr transform;
};
// Applies transform (at the correct type) to the argument and returns the
// result. Does some validity checking to make sure the result is not a
// temporary (proxy containers are not allowed).
template <typename T, typename Transform, typename U>
T& ApplyTransform(TransformPtr transform, U& u) { // NOLINT(runtime/references)
const auto t = transform.get<Transform>();
ABSL_RAW_DCHECK(t != nullptr, "pointer cannot be null");
// If compilation fails here due to dropping a const qualifier, it usually
// means you tried to wrap a const container with a non-const AnySpan.
//
// If compilation fails here due to a reference to a temporary, it usually
// means that the container or transform cannot be converted to a reference to
// T. AnySpan requires that a valid instance of T exists, conversion to a
// value type (such as string -> StringPiece or int -> float) is not
// supported.
//
// If compilation fails here due to taking the address of a temporary object,
// it means that the transform is returning a temporary. This is disallowed.
// Transforms must return a reference to T, or a reference to an object that
// can be safely converted to a reference to T (such as a reference_wrapper or
// a class that inherits from T).
return *&std::invoke(*t, u); // Failed compilation? See above.
}
// The return type of GetterFunction<T>. GetterFunctions return non-const
// references to support mutable -> const conversion of spans without additional
// indirection.
template <typename T>
using GetterFunctionResult = absl::remove_const_t<T>&;
// A type of function pointer that can return an element of a
// TransformedContainer. This is used so that we can type-erase with a simple
// function pointer instead of a vtable. Doing things this way has less pointer
// indirection.
template <typename T>
using GetterFunction = GetterFunctionResult<T> (*)(const TransformedContainer&,
std::size_t);
// A GetterFunction that works on arrays.
template <typename T, typename Element, typename Transform>
GetterFunctionResult<T> GetFromArray(const TransformedContainer& container,
std::size_t i) {
ABSL_RAW_DCHECK(container.ptr != nullptr, "cannot dereference null pointer");
auto* array = static_cast<Element*>(container.ptr);
return const_cast<GetterFunctionResult<T>>(
ApplyTransform<T, Transform>(container.transform, array[i]));
}
// A GetterFunction that works on containers.
template <typename T, typename Container, typename Transform>
GetterFunctionResult<T> GetFromContainer(const TransformedContainer& container,
std::size_t i) {
ABSL_RAW_DCHECK(container.ptr != nullptr, "cannot dereference null pointer");
Container& c = *static_cast<Container*>(container.ptr);
return const_cast<GetterFunctionResult<T>>(
ApplyTransform<T, Transform>(container.transform, c[i]));
}
// A GetterFunction that crashes, indicating an invalid AnySpan has been
// accessed..
template <typename T>
GetterFunctionResult<T> GetFromUninitialized(const TransformedContainer&,
std::size_t) {
ABSL_RAW_LOG(FATAL, "Uninitialized AnySpan access.");
}
//
// ArrayTag and PtrArrayTag are GetterFunctions that are never called. They are
// used as a tag so Getter::Get can access flat arrays without a function
// pointer.
//
template <typename T>
GetterFunctionResult<T> ArrayTag(const TransformedContainer&, std::size_t) {
ABSL_RAW_LOG(FATAL, "ArrayTag should never be called.");
}
template <typename T>
GetterFunctionResult<T> PtrArrayTag(const TransformedContainer&, std::size_t) {
ABSL_RAW_LOG(FATAL, "PtrArrayTag should never be called.");
}
//
// HasSize<Container> inherets from true_type if Container has a size() member.
// false_type otherwise.
//
template <typename, typename = void>
struct HasSize : public std::false_type {};
template <class Container>
struct HasSize<Container,
absl::void_t<decltype(std::declval<Container&>().size())>>
: public std::true_type {};
//
// TypeOfData<Container>::type is the return type of data() if Container has a
// data() member. It is NoData otherwise.
//
struct NoData {};
template <typename, typename = void>
struct TypeOfData {
using type = NoData;
};
template <class Container>
struct TypeOfData<Container,
absl::void_t<decltype(std::declval<Container&>().data())>> {
using type = decltype(std::declval<Container&>().data());
};
// Element type of container based on operator[].
template <class Container>
using ElementType = typename std::remove_reference<
decltype(std::declval<Container&>()[0])>::type;
// Element type of container when elements are dereferenced.
template <class Container>
using DerefElementType = typename std::remove_reference<
decltype(*std::declval<ElementType<Container>>())>::type;
// DataIsValid is true_type if Container has a data() member that returns a
// pointer to the type returned by operator[], false_type if there is no data()
// member or if the types disagree.
template <class Container>
using DataIsValid =
std::is_same<ElementType<Container>*, typename TypeOfData<Container>::type>;
// Used to access elements of a container or array.
template <typename T>
struct Getter {
Getter() {}
// Handle mutable -> const conversion.
template <typename LazyT = T, typename = typename std::enable_if<
std::is_const<LazyT>::value>::type>
explicit Getter(const Getter<absl::remove_const_t<T>>& other) {
using MutableT = absl::remove_const_t<T>;
if (other.fun == &ArrayTag<MutableT>) {
ABSL_RAW_DCHECK(other.offset == 0u, "offset must be zero");
fun = &ArrayTag<T>;
array = other.array;
offset = 0;
} else if (other.fun == &PtrArrayTag<MutableT>) {
ABSL_RAW_DCHECK(other.offset == 0u, "offset must be zero");
fun = &PtrArrayTag<T>;
ptr_array = other.ptr_array;
offset = 0;
} else {
fun = other.fun;
container = other.container;
offset = other.offset;
}
}
// Returns the element at the given index.
T& Get(std::size_t index) const {
ABSL_RAW_DCHECK(fun != nullptr, "pointer cannot be null");
if (ABSL_PREDICT_TRUE(fun == &ArrayTag<T>)) {
ABSL_RAW_DCHECK(array != nullptr, "pointer cannot be null");
return array[index];
}
if (fun == &PtrArrayTag<T>) {
ABSL_RAW_DCHECK(ptr_array != nullptr, "pointer cannot be null");
return *ptr_array[index];
}
return fun(container, index + offset);
}
// Returns a Getter offset into this one by pos.
Getter Offset(std::size_t pos) const {
// Special case when offset is zero. This safely handles empty spans and
// empty containers where data() can be null.
if (pos == 0) {
return *this;
}
ABSL_RAW_DCHECK(fun != nullptr, "pointer cannot be null");
Getter result;
result.fun = fun;
if (fun == &ArrayTag<T>) {
ABSL_RAW_DCHECK(array != nullptr, "pointer cannot be null");
ABSL_RAW_DCHECK(offset == 0u, "offset must be zero");
result.array = array + pos;
result.offset = 0;
} else if (fun == &PtrArrayTag<T>) {
ABSL_RAW_DCHECK(ptr_array != nullptr, "pointer cannot be null");
ABSL_RAW_DCHECK(offset == 0u, "offset must be zero");
result.ptr_array = ptr_array + pos;
result.offset = 0;
} else {
ABSL_RAW_DCHECK(container.ptr != nullptr, "pointer cannot be null");
result.container = container;
result.offset = offset + pos;
}
return result;
}
// A pointer to a function (or tag function) that specifies how to get an
// element from the array or container.
GetterFunction<T> fun = &GetFromUninitialized<T>;
union {
T* array; // Active if fun == ArrayTag<T>.
T* const* ptr_array; // Active if fun == PtrArrayTag<T>.
TransformedContainer container; // Active for all other fun.
};
// Offset into container. Always 0 for array or ptr_array.
std::size_t offset = 0;
};
//
// MakeArrayGetter returns a Getter for an array.
//
// MakeArrayGetterImpl is specialised to use ArrayTag<T> when Element == T and
// Transform == IdentityT, and to use PtrArrayTag<T> when Element == T* and
// Transform == DerefT.
//
template <typename SpanElement, typename ArrayElement, typename Transform>
struct MakeArrayGetterImpl {
template <typename U>
static Getter<U> Make(ArrayElement* array, const Transform& transform) {
Getter<U> result;
result.fun = &GetFromArray<U, ArrayElement, Transform>;
result.container.ptr = const_cast<void*>(static_cast<const void*>(array));
result.container.transform =
TransformPtr(transform, IsTransformCopied<Transform>{});
return result;
}
};
// When the span and the array are the same type.
template <typename T>
struct MakeArrayGetterImpl<T, T, any_span_transform::IdentityT> {
template <typename U>
static Getter<U> Make(T* array, const any_span_transform::IdentityT&) {
Getter<U> result;
result.fun = &ArrayTag<U>;
result.array = array;
return result;
}
};
// If we are dereferencing an array of mutable elements (T*), it is safe to add
// constness (const T*).
template <typename T>
struct MakeArrayGetterImpl<const T, T, any_span_transform::IdentityT>
: public MakeArrayGetterImpl<const T, const T,
any_span_transform::IdentityT> {};
// When the array is of pointers to elements of the same type as the span.
template <typename T>
struct MakeArrayGetterImpl<T, T*, any_span_transform::DerefT> {
template <typename U>
static Getter<U> Make(T* const* ptr_array,
const any_span_transform::DerefT&) {
Getter<U> result;
result.fun = &PtrArrayTag<U>;
result.ptr_array = ptr_array;
return result;
}
};
// If we are dereferencing an array that is mutable along any extent, it is safe
// to add constness.
template <typename T>
struct MakeArrayGetterImpl<const T, T*, any_span_transform::DerefT>
: public MakeArrayGetterImpl<const T, const T*,
any_span_transform::DerefT> {};
template <typename T>
struct MakeArrayGetterImpl<const T, T* const, any_span_transform::DerefT>
: public MakeArrayGetterImpl<const T, const T*,
any_span_transform::DerefT> {};
template <typename T>
struct MakeArrayGetterImpl<const T, const T* const, any_span_transform::DerefT>
: public MakeArrayGetterImpl<const T, const T*,
any_span_transform::DerefT> {};
template <typename T, typename Element, typename Transform>
Getter<T> MakeArrayGetter(Element* array, const Transform& transform) {
return MakeArrayGetterImpl<T, Element, Transform>::template Make<T>(
array, transform);
}
//
// MakeContainerGetter returns a Getter for a given container. It will pass
// container.data() to MakeArrayGetter if possible, which allows element access
// to be inline.
//
// The first argument to MakeArrayGetterImpl is expected to be of type
// DataIsValid<container>.
//
template <typename T, typename Container, typename Transform>
Getter<T> MakeContainerGetterImpl(
std::true_type /* DataIsValid<Container> */,
Container& container, // NOLINT(runtime/references)
const Transform& transform) {
return MakeArrayGetter<T, ElementType<Container>, Transform>(container.data(),
transform);
}
template <typename T, typename Container, typename Transform>
Getter<T> MakeContainerGetterImpl(
std::false_type /* DataIsValid<Container> */,
Container& container, // NOLINT(runtime/references)
const Transform& transform) {
Getter<T> result;
result.fun = &GetFromContainer<T, Container, Transform>;
result.container.ptr =
const_cast<void*>(static_cast<const void*>(&container));
result.container.transform =
TransformPtr(transform, IsTransformCopied<Transform>{});
return result;
}
template <typename T, typename Container, typename Transform>
Getter<T> MakeContainerGetter(
Container& container, // NOLINT(runtime/references)
const Transform& transform) {
static_assert(std::is_reference<decltype(container[0])>::value,
"AnySpan only works with containers that return a reference "
"(no vector<bool>, or containers that return by value).");
return MakeContainerGetterImpl<T>(DataIsValid<Container>(), container,
transform);
}
// Used for testing. Returns true if the given AnySpan performs inline element
// access.
template <typename T>
bool IsCheap(AnySpan<T> s) {
return s.getter_.fun == &ArrayTag<T> || s.getter_.fun == &PtrArrayTag<T>;
}
template <typename T>
bool EqualImpl(AnySpan<T> a, AnySpan<T> b) {
static_assert(std::is_const<T>::value, "");
return std::equal(a.begin(), a.end(), b.begin(), b.end());
}
} // namespace any_span_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TYPES_INTERNAL_ANY_SPAN_H_