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