1//
2// Copyright 2019 The Abseil Authors.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// https://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16#ifndef ABSL_TYPES_INTERNAL_SPAN_H_
17#define ABSL_TYPES_INTERNAL_SPAN_H_
18
19#include <algorithm>
20#include <cstddef>
21#include <string>
22#include <type_traits>
23
24#include "absl/algorithm/algorithm.h"
25#include "absl/base/internal/throw_delegate.h"
26#include "absl/meta/type_traits.h"
27
28namespace absl {
29
30namespace span_internal {
31// A constexpr min function
32constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; }
33
34// Wrappers for access to container data pointers.
35template <typename C>
36constexpr auto GetDataImpl(C& c, char) noexcept // NOLINT(runtime/references)
37 -> decltype(c.data()) {
38 return c.data();
39}
40
41// Before C++17, std::string::data returns a const char* in all cases.
42inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references)
43 int) noexcept {
44 return &s[0];
45}
46
47template <typename C>
48constexpr auto GetData(C& c) noexcept // NOLINT(runtime/references)
49 -> decltype(GetDataImpl(c, 0)) {
50 return GetDataImpl(c, 0);
51}
52
53// Detection idioms for size() and data().
54template <typename C>
55using HasSize =
56 std::is_integral<absl::decay_t<decltype(std::declval<C&>().size())>>;
57
58// We want to enable conversion from vector<T*> to Span<const T* const> but
59// disable conversion from vector<Derived> to Span<Base>. Here we use
60// the fact that U** is convertible to Q* const* if and only if Q is the same
61// type or a more cv-qualified version of U. We also decay the result type of
62// data() to avoid problems with classes which have a member function data()
63// which returns a reference.
64template <typename T, typename C>
65using HasData =
66 std::is_convertible<absl::decay_t<decltype(GetData(std::declval<C&>()))>*,
67 T* const*>;
68
69// Extracts value type from a Container
70template <typename C>
71struct ElementType {
72 using type = typename absl::remove_reference_t<C>::value_type;
73};
74
75template <typename T, size_t N>
76struct ElementType<T (&)[N]> {
77 using type = T;
78};
79
80template <typename C>
81using ElementT = typename ElementType<C>::type;
82
83template <typename T>
84using EnableIfMutable =
85 typename std::enable_if<!std::is_const<T>::value, int>::type;
86
87template <template <typename> class SpanT, typename T>
88bool EqualImpl(SpanT<T> a, SpanT<T> b) {
89 static_assert(std::is_const<T>::value, "");
90 return absl::equal(a.begin(), a.end(), b.begin(), b.end());
91}
92
93template <template <typename> class SpanT, typename T>
94bool LessThanImpl(SpanT<T> a, SpanT<T> b) {
95 // We can't use value_type since that is remove_cv_t<T>, so we go the long way
96 // around.
97 static_assert(std::is_const<T>::value, "");
98 return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
99}
100
101// The `IsConvertible` classes here are needed because of the
102// `std::is_convertible` bug in libcxx when compiled with GCC. This build
103// configuration is used by Android NDK toolchain. Reference link:
104// https://bugs.llvm.org/show_bug.cgi?id=27538.
105template <typename From, typename To>
106struct IsConvertibleHelper {
107 private:
108 static std::true_type testval(To);
109 static std::false_type testval(...);
110
111 public:
112 using type = decltype(testval(std::declval<From>()));
113};
114
115template <typename From, typename To>
116struct IsConvertible : IsConvertibleHelper<From, To>::type {};
117
118// TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the
119// older version of libcxx is not supported.
120template <typename From, typename To>
121using EnableIfConvertibleTo =
122 typename std::enable_if<IsConvertible<From, To>::value>::type;
123} // namespace span_internal
124} // namespace absl
125
126#endif // ABSL_TYPES_INTERNAL_SPAN_H_
127