| // Copyright 2020 The Pigweed 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. |
| #pragma once |
| |
| #include <iterator> |
| #include <type_traits> |
| |
| namespace pw::kvs { |
| namespace internal { |
| |
| // This borrows the `make_span` function from Chromium and uses to see if a type |
| // can be represented as a span. See: |
| // https://chromium.googlesource.com/chromium/src/+/master/base/containers/span.h |
| |
| // Simplified implementation of C++20's std::iter_reference_t. |
| // As opposed to std::iter_reference_t, this implementation does not restrict |
| // the type of `Iter`. |
| // |
| // Reference: https://wg21.link/iterator.synopsis#:~:text=iter_reference_t |
| template <typename Iter> |
| using iter_reference_t = decltype(*std::declval<Iter&>()); |
| |
| template <typename T> |
| struct ExtentImpl : std::integral_constant<size_t, std::dynamic_extent> {}; |
| |
| template <typename T, size_t N> |
| struct ExtentImpl<T[N]> : std::integral_constant<size_t, N> {}; |
| |
| template <typename T, size_t N> |
| struct ExtentImpl<std::array<T, N>> : std::integral_constant<size_t, N> {}; |
| |
| template <typename T, size_t N> |
| struct ExtentImpl<std::span<T, N>> : std::integral_constant<size_t, N> {}; |
| |
| template <typename T> |
| using Extent = ExtentImpl<std::remove_cv_t<std::remove_reference_t<T>>>; |
| |
| // Type-deducing helpers for constructing a span. |
| template <int&... ExplicitArgumentBarrier, typename It, typename EndOrSize> |
| constexpr auto make_span(It it, EndOrSize end_or_size) noexcept { |
| using T = std::remove_reference_t<iter_reference_t<It>>; |
| return std::span<T>(it, end_or_size); |
| } |
| |
| // make_span utility function that deduces both the span's value_type and extent |
| // from the passed in argument. |
| // |
| // Usage: auto span = base::make_span(...); |
| template <int&... ExplicitArgumentBarrier, |
| typename Container, |
| typename T = std::remove_pointer_t< |
| decltype(std::data(std::declval<Container>()))>> |
| constexpr auto make_span(Container&& container) noexcept { |
| return std::span<T, Extent<Container>::value>( |
| std::forward<Container>(container)); |
| } |
| |
| // The make_span functions above don't seem to work correctly with arrays of |
| // non-const values, so add const to the type. That is fine for KVS's Put |
| // method, since the values can be accepted as const. |
| template <typename T, |
| typename = decltype(make_span(std::declval<std::add_const_t<T>>()))> |
| constexpr bool ConvertsToSpan(int) { |
| return true; |
| } |
| |
| // If the expression std::span(T) fails, then the type can't be converted to a |
| // std::span. |
| template <typename T> |
| constexpr bool ConvertsToSpan(...) { |
| return false; |
| } |
| |
| } // namespace internal |
| |
| // Traits class to detect if the type converts to a std::span. |
| template <typename T> |
| struct ConvertsToSpan |
| : public std::bool_constant< |
| internal::ConvertsToSpan<std::remove_reference_t<T>>(0)> {}; |
| |
| } // namespace pw::kvs |