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 namespace pw { 20 namespace kvs { 21 namespace internal { 22 23 // This borrows the `make_span` function from Chromium and uses to see if a type 24 // can be represented as a span. See: 25 // https://chromium.googlesource.com/chromium/src/+/master/base/containers/span.h 26 27 // Simplified implementation of C++20's std::iter_reference_t. 28 // As opposed to std::iter_reference_t, this implementation does not restrict 29 // the type of `Iter`. 30 // 31 // Reference: https://wg21.link/iterator.synopsis#:~:text=iter_reference_t 32 template <typename Iter> 33 using iter_reference_t = decltype(*std::declval<Iter&>()); 34 35 template <typename T> 36 struct ExtentImpl : std::integral_constant<size_t, std::dynamic_extent> {}; 37 38 template <typename T, size_t N> 39 struct ExtentImpl<T[N]> : std::integral_constant<size_t, N> {}; 40 41 template <typename T, size_t N> 42 struct ExtentImpl<std::array<T, N>> : std::integral_constant<size_t, N> {}; 43 44 template <typename T, size_t N> 45 struct ExtentImpl<std::span<T, N>> : std::integral_constant<size_t, N> {}; 46 47 template <typename T> 48 using Extent = ExtentImpl<std::remove_cv_t<std::remove_reference_t<T>>>; 49 50 // Type-deducing helpers for constructing a span. 51 template <int&... ExplicitArgumentBarrier, typename It, typename EndOrSize> 52 constexpr auto make_span(It it, EndOrSize end_or_size) noexcept { 53 using T = std::remove_reference_t<iter_reference_t<It>>; 54 return std::span<T>(it, end_or_size); 55 } 56 57 // make_span utility function that deduces both the span's value_type and extent 58 // from the passed in argument. 59 // 60 // Usage: auto span = base::make_span(...); 61 template <int&... ExplicitArgumentBarrier, 62 typename Container, 63 typename T = std::remove_pointer_t< 64 decltype(std::data(std::declval<Container>()))>> 65 constexpr auto make_span(Container&& container) noexcept { 66 return std::span<T, Extent<Container>::value>( 67 std::forward<Container>(container)); 68 } 69 70 // The make_span functions above don't seem to work correctly with arrays of 71 // non-const values, so add const to the type. That is fine for KVS's Put 72 // method, since the values can be accepted as const. 73 template <typename T, 74 typename = decltype(make_span(std::declval<std::add_const_t<T>>()))> 75 constexpr bool ConvertsToSpan(int) { 76 return true; 77 } 78 79 // If the expression std::span(T) fails, then the type can't be converted to a 80 // std::span. 81 template <typename T> 82 constexpr bool ConvertsToSpan(...) { 83 return false; 84 } 85 86 } // namespace internal 87 88 // Traits class to detect if the type converts to a std::span. 89 template <typename T> 90 struct ConvertsToSpan 91 : public std::bool_constant< 92 internal::ConvertsToSpan<std::remove_reference_t<T>>(0)> {}; 93 94 } // namespace kvs 95 } // namespace pw 96