xref: /aosp_15_r20/external/pigweed/pw_kvs/public/pw_kvs/internal/span_traits.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <iterator>
17 #include <type_traits>
18 
19 #include "pw_span/span.h"
20 
21 namespace pw {
22 namespace kvs {
23 namespace internal {
24 
25 // This borrows the `make_span` function from Chromium and uses to see if a type
26 // can be represented as a span. See:
27 // https://chromium.googlesource.com/chromium/src/+/main/base/containers/span.h
28 
29 // Simplified implementation of C++20's std::iter_reference_t.
30 // As opposed to std::iter_reference_t, this implementation does not restrict
31 // the type of `Iter`.
32 //
33 // Reference: https://wg21.link/iterator.synopsis#:~:text=iter_reference_t
34 template <typename Iter>
35 using iter_reference_t = decltype(*std::declval<Iter&>());
36 
37 template <typename T>
38 struct ExtentImpl : std::integral_constant<size_t, dynamic_extent> {};
39 
40 template <typename T, size_t N>
41 struct ExtentImpl<T[N]> : std::integral_constant<size_t, N> {};
42 
43 template <typename T, size_t N>
44 struct ExtentImpl<std::array<T, N>> : std::integral_constant<size_t, N> {};
45 
46 template <typename T, size_t N>
47 struct ExtentImpl<span<T, N>> : std::integral_constant<size_t, N> {};
48 
49 template <typename T>
50 using Extent = ExtentImpl<std::remove_cv_t<std::remove_reference_t<T>>>;
51 
52 // Type-deducing helpers for constructing a span.
53 template <int&... ExplicitArgumentBarrier, typename It, typename EndOrSize>
54 constexpr auto make_span(It it, EndOrSize end_or_size) noexcept {
55   using T = std::remove_reference_t<iter_reference_t<It>>;
56   return span<T>(it, end_or_size);
57 }
58 
59 // make_span utility function that deduces both the span's value_type and extent
60 // from the passed in argument.
61 //
62 // Usage: auto span = base::make_span(...);
63 template <int&... ExplicitArgumentBarrier,
64           typename Container,
65           typename T = std::remove_pointer_t<
66               decltype(std::data(std::declval<Container>()))>>
67 constexpr auto make_span(Container&& container) noexcept {
68   return span<T, Extent<Container>::value>(std::forward<Container>(container));
69 }
70 
71 // The make_span functions above don't seem to work correctly with arrays of
72 // non-const values, so add const to the type. That is fine for KVS's Put
73 // method, since the values can be accepted as const.
74 template <typename T,
75           typename = decltype(make_span(std::declval<std::add_const_t<T>>()))>
76 constexpr bool ConvertsToSpan(int) {
77   return true;
78 }
79 
80 // If the expression span(T) fails, then the type can't be converted to a
81 // span.
82 template <typename T>
83 constexpr bool ConvertsToSpan(...) {
84   return false;
85 }
86 
87 }  // namespace internal
88 
89 // Traits class to detect if the type converts to a span.
90 template <typename T>
91 struct ConvertsToSpan
92     : public std::bool_constant<
93           internal::ConvertsToSpan<std::remove_reference_t<T>>(0)> {};
94 
95 }  // namespace kvs
96 }  // namespace pw
97