diff --git a/platform/cxxsupport/mstd_iterator b/platform/cxxsupport/mstd_iterator index 52c2092e50..9082702347 100644 --- a/platform/cxxsupport/mstd_iterator +++ b/platform/cxxsupport/mstd_iterator @@ -29,6 +29,7 @@ * - mstd::ssize * - mstd::empty * - mstd::data + * - mstd::iter_reference_t */ #include @@ -144,6 +145,9 @@ constexpr ptrdiff_t ssize(const T (&)[N]) noexcept return N; } +template +using iter_reference_t = decltype(*std::declval()); + } diff --git a/platform/cxxsupport/mstd_span b/platform/cxxsupport/mstd_span new file mode 100644 index 0000000000..184f14ee32 --- /dev/null +++ b/platform/cxxsupport/mstd_span @@ -0,0 +1,418 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * 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 + * + * http://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. + */ +#ifndef MSTD_SPAN_ +#define MSTD_SPAN_ + +/* + * + * - Includes toolchain's if available + * - Otherwise provides an implementation of a C++20 equivalent std::span + * - deduction guides available from C++17 and on + * - Provides nonstandard mstd::make_span functions to allow deduction pre C++17 + * - mstd::make_span functions stay available after C++17 for backwards compatibility + */ + +#if __cplusplus >= 201703L && __has_include() +#include +#endif + +#if __cpp_lib_span >= 202002L +#include + +namespace mstd { + using std::span; + using std::dynamic_extent; +} + +#else //__cpp_lib_span >= 202002L + +#include +#include +#include +#include "mbed_assert.h" + +namespace mstd { + +constexpr size_t dynamic_extent = -1; + +template +class span; + +namespace detail { + +template +struct storage { + constexpr storage() noexcept = default; + + constexpr storage(ElementType *ptr, size_t) noexcept : + _data(ptr) + {} + + ElementType *_data = nullptr; + static constexpr size_t _size = Extent; +}; +template +constexpr size_t storage::_size; + +template +struct storage { + constexpr storage() noexcept = default; + + constexpr storage(ElementType *ptr, size_t size) noexcept : + _data(ptr), _size(size) + {} + + ElementType *_data = nullptr; + size_t _size = 0; +}; + +template +struct is_span: std::false_type {}; + +template +struct is_span>: std::true_type {}; + +template +struct is_std_array: std::false_type {}; + +template +struct is_std_array>: std::true_type {}; + +template +struct has_size : std::false_type {}; + +template +struct has_size()))>>: + std::true_type {}; + +template +struct has_data : std::false_type {}; + +template +struct has_data()))>>: + std::true_type {}; + +template> +struct is_container{ + static constexpr bool value = + !is_span::value && !is_std_array::value && + !std::is_array::value && has_size::value && + has_data::value; +}; + +template +using iterator_t = decltype(mstd::begin(std::declval())); + +template +using range_reference_t = mstd::iter_reference_t>; + +template +struct is_compatible : std::false_type {}; + +template +struct is_compatible())) + >, void>::value>>: +mstd::is_convertible()))> (*)[], E (*)[]>{}; + +} // namespace detail + +template +class span { +public: + using element_type = ElementType; + using value_type = typename mstd::remove_cv_t; + using index_type = size_t; + using difference_type = ptrdiff_t; + using pointer = element_type *; + using const_pointer = const element_type *; + using reference = element_type &; + using const_reference = const element_type &; + using iterator = pointer; + using reverse_iterator = std::reverse_iterator; + + static constexpr index_type extent = Extent; + + // Constructors, copy and assignment + template = 0> + constexpr span() noexcept + {} + + template>(*)[], + ElementType(*)[]>::value, int> = 0> + constexpr span(It ptr, index_type count) : + _storage(ptr, count) + { + MBED_ASSERT(extent == dynamic_extent || extent == count); + } + + template>(*)[], + ElementType(*)[]>::value, int> = 0> + constexpr span(It first, It last) : + _storage(first, last - first) + { + MBED_ASSERT(first <= last); + MBED_ASSERT(extent == dynamic_extent || extent == last - first); + MBED_ASSERT(extent == 0 || nullptr != first); + } + + template + constexpr span(type_identity_t(&arr)[N], + typename mstd::enable_if_t<(Extent == dynamic_extent || Extent == N) && + mstd::is_convertible(*)[], + ElementType(*)[]>::value, int> = 0) noexcept: + _storage(arr, N) + {} + + template + constexpr span(std::array &arr, + typename mstd::enable_if_t<(Extent == dynamic_extent || Extent == N) && + mstd::is_convertible(*)[], + ElementType(*)[]>::value, int> = 0) noexcept: + _storage(arr.data(), N) + {} + + template + constexpr span(const std::array &arr, + typename mstd::enable_if_t<(Extent == dynamic_extent || Extent == N) && + mstd::is_convertible(*)[], + ElementType(*)[]>::value, int> = 0) noexcept: + _storage(arr.data(), N) + {} + + template::value && + detail::is_compatible::value, int> = 0> + constexpr span(R &&r) : + _storage(mstd::data(r), mstd::size(r)) + { + MBED_ASSERT(extent == dynamic_extent || extent == mstd::size(r)); + } + + constexpr span(const span &other) noexcept = default; + + template::value, int> = 0> + constexpr span(const span& s) noexcept: + _storage(s.data(), s.size()) + {} + + ~span() noexcept = default; + + constexpr span& operator=(const span &other) noexcept = default; + + // Subviews + template + constexpr span first() const + { + static_assert(Count <= extent); + MBED_ASSERT(Count <= size()); + return {data(), Count}; + } + + template + constexpr span last() const + { + static_assert(Count <= extent); + MBED_ASSERT(Count <= size()); + return {data() + (size() - Count), Count}; + } + + template + constexpr span subspan() const + { + static_assert(Offset <= extent && (Count == dynamic_extent || Count <= extent - Offset)); + // Only check against Offset == 0 to prevent a warning for subspan<0, N> + MBED_ASSERT((Offset == 0 || Offset <= size()) + && (Count == dynamic_extent || Count <= size() - Offset)); + return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset}; + } + + constexpr span first(index_type count) const + { + MBED_ASSERT(count <= size()); + return {data(), count}; + } + + constexpr span last(index_type count) const + { + MBED_ASSERT(count <= size()); + return {data() + (size() - count), count}; + } + + constexpr span + subspan(index_type offset, index_type count = dynamic_extent) const + { + MBED_ASSERT(offset <= size() && (count == dynamic_extent || count <= size() - offset)); + return {data() + offset, count == dynamic_extent ? size() - offset : count }; + } + + // Observers + constexpr index_type size() const noexcept + { + return _storage._size; + } + + constexpr index_type size_bytes() const noexcept + { + return size() * sizeof(element_type); + } + + constexpr bool empty() const noexcept + { + return size() == 0; + } + + // Element access + constexpr reference operator[](index_type idx) const + { + MBED_ASSERT(idx < size()); + return *(data() + idx); + } + + constexpr reference front() const + { + MBED_ASSERT(!empty()); + return *data(); + } + + constexpr reference back() const + { + MBED_ASSERT(!empty()); + return *(data() + (size() - 1)); + } + + constexpr pointer data() const noexcept + { + return _storage._data; + } + + // Iterators + constexpr iterator begin() const noexcept + { + return data(); + } + + constexpr iterator end() const noexcept + { + return data() + size(); + } + + constexpr reverse_iterator rbegin() const noexcept + { + return reverse_iterator(end()); + } + + constexpr reverse_iterator rend() const noexcept + { + return reverse_iterator(begin()); + } + +private: + detail::storage _storage; +}; + +template +constexpr span::index_type span::extent; + +#if __cplusplus >= 201703L || __cpp_deduction_guides >= 201703L +// Deduction guides +template +span(It, EndOrSize) -> span>>; + +template +span(T (&)[N]) -> span; + +template +span(std::array&) -> span; + +template +span(const std::array&) -> span; + +template +span(R&&) -> span>>; +#endif //__cplusplus >= 201703L || __cpp_deduction_guides >= 201703L + +} // namespace mstd + +#endif //__cpp_lib_span >= 202002L + +namespace mstd { + +/** Create a span class with type and size inferred from the argument + * + * @param arr Reference to a c-style array + * @return Span with inferred type and size Extent + */ +template +constexpr span make_span(ElementType (&arr)[Extent]) +{ + return arr; +} + +template +constexpr span make_span(const ElementType (&arr)[Extent]) +{ + return arr; +} + +/** Create a span class with type and size inferred from the argument + * + * @param arr Reference to an std::array + * @return Span with inferred type and size Extent + */ +template +constexpr span make_span(std::array &arr) +{ + return arr; +} + +template +constexpr span make_span(const std::array &arr) +{ + return arr; +} + +/** Create a span class with type inferred from the argument + * + * @param cont Reference to a container + * @return Span with inferred type and dynamic size + */ +template +constexpr span make_span(R &cont) +{ + return cont; +} + +template +constexpr span make_span(const R &cont) +{ + return cont; +} + +} // namespace mstd + +#endif // MSTD_SPAN_