From 80afc3a169507c23397371e9308c17351e36a645 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Wed, 19 Jun 2019 16:23:54 +0300 Subject: [PATCH] Add C++11/14 support utility file As we start trying to use new facilities, we're likely to need some more helpers. In particular, ARM C 5 has no C++11 support in its library at all, so to avoid totally breaking it we need some backup. For the other toolchains, we can add a few C++17/C++20/TS extensions into namespace mbed to make life a little easier. * For ARM C 5: C++14 type_traits subset, std::move, std::forward, std::array, std::initializer_list, std::begin, std::end, std::align, std::maxalign_t, std::aligned_storage, alignof + alignas macro replacements. * For ARM C 5: MBED_CONSTEXPR_FN_14 and MBED_CONSTEXPR_OBJ_14 to mark things that can only be constexpr in C++14 or later. * For other compilers: mbed::void_t, mbed::type_identity, mbed::conjunction, mbed::disjunction, mbed::negation, mbed::experimental::nonesuch, mbed::experimental::is_detected family, mbed::remove_cvref, mbed::as_const. --- platform/mbed_cxxsupport.h | 1228 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1228 insertions(+) create mode 100644 platform/mbed_cxxsupport.h diff --git a/platform/mbed_cxxsupport.h b/platform/mbed_cxxsupport.h new file mode 100644 index 0000000000..ed1c394c4b --- /dev/null +++ b/platform/mbed_cxxsupport.h @@ -0,0 +1,1228 @@ +/* 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 MBED_CXXSUPPORT_H +#define MBED_CXXSUPPORT_H + +#include "mbed_toolchain.h" + +/* Mbed OS code is expected to work as C++14 or later, but + * we currently also want to not totally break ARM Compiler 5, which has a + * subset of C++11 language and no C++11 library. + * + * This adaptation file fills out missing namespace std functionality for + * ARM Compiler 5, and backports some post-C++14 features into namespace mbed. + */ + +/* Macros that can be used to mark functions and objects that are + * constexpr in C++14 or later, but not in earlier versions. + */ +#if __cplusplus >= 201402 +#define MBED_CONSTEXPR_FN_14 constexpr +#define MBED_CONSTEXPR_OBJ_14 constexpr +#else +#define MBED_CONSTEXPR_FN_14 inline +#define MBED_CONSTEXPR_OBJ_14 const +#endif + +// The template stuff in here is too confusing for astyle +// *INDENT-OFF* + +/* Start with some core C++11 type trait building blocks for ARMC5 */ +#ifdef __CC_ARM + +/* ARMC5 lacks alignof and alignas keyword - do the best we can */ + +/* alignof */ +#define alignof(T) __alignof__(T) + +/* alignas(N) */ +/* Types not supported - workaround is to use alignas(alignof(T)), which is legal anyway */ +#ifndef __alignas_is_defined +#define __alignas_is_defined +#define alignas(N) __attribute__((aligned(N))) +#endif + +namespace std { + +/* integral_constant */ +template +struct integral_constant { + using value_type = T; + using type = integral_constant; + static constexpr T value = V; + constexpr operator T() const noexcept + { + return V; + } + constexpr T operator()() const noexcept + { + return V; + } +}; + +template +constexpr T integral_constant::value; + +/* true_type, false_type */ +using true_type = integral_constant; +using false_type = integral_constant; + +} // namespace std +#else +#include +#include +#include +#endif + +/* Add some foundational stuff from C++17 or later or TS into namespace mbed */ +namespace mbed { + +/* C++20 type identity */ +template +struct type_identity { + using type = T; +}; + +template +using type_identity_t = typename type_identity::type; + +/* C++17 void_t (foundation for detection idiom) */ +/* void_t is void if args are valid, else a substitution failure */ +#if __cplusplus >= 201703 || __cpp_lib_void_t >= 201411 +using std::void_t; +#elif defined __CC_ARM +namespace impl { +template +struct void_helper : type_identity { }; +} +template +using void_t = typename impl::void_helper::type; +#else +template +using void_t = void; +#endif + +/* C++17 bool_constant */ +#if __cplusplus >= 201703 || __cpp_lib_bool_constant >= 201505 +using std::bool_constant; +#else +template +using bool_constant = std::integral_constant; +#endif + +} // namespace mbed + +#ifdef __CC_ARM +/* Fill in core missing C++11/C++14 functionality for ARM C 5 into namespace std */ +/* First, the things needed to support the detector idiom. */ +namespace std { + +/* is_same */ +template +struct is_same : false_type { }; + +template +struct is_same : true_type { }; + +/* conditional */ +template +struct conditional : mbed::type_identity { }; + +template +struct conditional : mbed::type_identity { }; + +template +using conditional_t = typename conditional::type; + +/* enable_if */ +template +struct enable_if { }; + +template +struct enable_if : mbed::type_identity { }; + +template +using enable_if_t = typename enable_if::type; + +/* Forward declarations */ +template +struct is_convertible; + +template +struct is_object; + +template +struct is_reference; + +} // namespace std +#endif // __CC_ARM + +/* Reinvent or pull in good stuff not in C++14 into namespace mbed */ +namespace mbed { + +/* C++17 logical operations on traits */ +#if __cplusplus >= 201703 || __cpp_lib_logical_traits >= 201510 +using std::conjunction; +using std::disjunction; +using std::negation; +#else +template +struct conjunction : std::true_type { }; +template +struct conjunction : B1 { }; +template +struct conjunction : std::conditional_t, B1> { }; + +template +struct disjunction : std::false_type { }; +template +struct disjunction : B1 { }; +template +struct disjunction : std::conditional_t> { }; + +template +struct negation : bool_constant { }; +#endif + +/* C++ detection idiom from Library fundamentals v2 TS */ +/* Place into mbed::experimental to match their std::experimental */ +namespace experimental { + +namespace impl { +template class Op, class... Args> +struct detector { + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> { + using value_t = std::true_type; + using type = Op; +}; + +} // namespace impl + +struct nonesuch { + ~nonesuch() = delete; + nonesuch(nonesuch const &) = delete; + void operator=(nonesuch const &) = delete; +}; + +#if 0 +/* Deactivated because impl::detector appears to not work on ARM C 5; it seems to produce + * hard errors in the template template parameter expansion. You can use void_t directly instead. + * + * Reactivate if working ARM C 5 implementation discovered, or ARM C 5 support + * dropped. + */ + +template class Op, class... Args> +using is_detected = typename impl::detector::value_t; + +template class Op, class... Args> +using detected_t = typename impl::detector::type; + +template class Op, class... Args> +using detected_or = typename impl::detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = std::is_convertible, To>; +#endif // if 0 - deactivated detector idiom +} // namespace experimental +} // namespace mbed + +#ifdef __CC_ARM +/* More missing C++11/C++14 functionality for ARM C 5 */ +#include +namespace std { + +/* nullptr_t */ +using nullptr_t = decltype(nullptr); + +/* maxalign_t */ +union maxalign_t { long double ld; long long ll; }; + +/* remove_const/volatile/cv */ +template +struct remove_const : mbed::type_identity { }; + +template +struct remove_const : mbed::type_identity { }; + +template +using remove_const_t = typename remove_const::type; + +template +struct remove_volatile : mbed::type_identity { }; + +template +struct remove_volatile : mbed::type_identity { }; + +template +using remove_volatile_t = typename remove_volatile::type; + +template +struct remove_cv : remove_volatile> { }; + +template +using remove_cv_t = typename remove_cv::type; + +/* add_const/volatile/cv */ +template +struct add_const : mbed::type_identity { }; + +template +using add_const_t = typename add_const::type; + +template +struct add_volatile : mbed::type_identity { }; + +template +using add_volatile_t = typename add_volatile::type; + +template +struct add_cv : mbed::type_identity { }; + +template +using add_cv_t = typename add_cv::type; + +/* remove_reference */ +template +struct remove_reference : mbed::type_identity { }; + +template +struct remove_reference : mbed::type_identity { }; + +template +struct remove_reference : mbed::type_identity { }; + +template +using remove_reference_t = typename remove_reference::type; + +/* add_lvalue_reference / add_value_reference */ +namespace impl { +template // Base test - objects and references +struct is_referenceable : mbed::disjunction, is_reference> { }; +template // Specialisation - unqualified functions (non-variadic) +struct is_referenceable : true_type { }; +template // Specialisation - unqualified functions (variadic) +struct is_referenceable : true_type { }; + +template ::value> +struct add_lvalue_reference : mbed::type_identity { }; +template +struct add_lvalue_reference : mbed::type_identity { }; + +template ::value> +struct add_rvalue_reference : mbed::type_identity { }; +template +struct add_rvalue_reference : mbed::type_identity { }; +} // namespace impl + +template +struct add_lvalue_reference : impl::add_lvalue_reference { }; +template +using add_lvalue_reference_t = typename add_lvalue_reference::type; + +template +struct add_rvalue_reference : impl::add_rvalue_reference { }; +template +using add_rvalue_reference_t = typename add_rvalue_reference::type; + +/* declval */ +template +add_rvalue_reference_t declval() noexcept; + +/* is_void */ +template +struct is_void : is_same> { }; + +/* is_null_pointer */ +template +struct is_null_pointer : is_same> { }; + +/* is_integral */ +template +struct is_integral : + mbed::disjunction< + is_same>, + is_same>, + is_same>, + is_same>, + is_same>, + is_same>, + is_same>, + is_same>, + is_same>, + is_same>, + is_same>, + is_same>, + is_same>, + is_same>, + is_same>> { }; + +/* is_floating_point */ +template +struct is_floating_point : + mbed::disjunction< + is_same>, + is_same>, + is_same>> { }; + +/* is_array */ +template +struct is_array : false_type { }; + +template +struct is_array : true_type { }; + +template +struct is_array : true_type { }; + +/* is_pointer */ +namespace impl { +template +struct is_unqualified_pointer : false_type { }; +template +struct is_unqualified_pointer : true_type { }; +} // namespace impl + +template +struct is_pointer : impl::is_unqualified_pointer> { }; + +/* is_lvalue_reference */ +template +struct is_lvalue_reference : false_type { }; + +template +struct is_lvalue_reference : true_type { }; + +/* is_rvalue_reference */ +template +struct is_rvalue_reference : false_type { }; + +template +struct is_rvalue_reference : true_type { }; + +/* is_enum */ +template +struct is_enum : mbed::bool_constant<__is_enum(T)> { }; + +/* is_union */ +template +struct is_union : mbed::bool_constant<__is_union(T)> { }; + +/* is_class */ +template +struct is_class : mbed::bool_constant<__is_class(T)> { }; + +/* is_function */ +template +struct is_function : false_type { }; + +template +struct is_function : true_type { }; // 0 or more named arguments +template +struct is_function : true_type { }; // 0 or more named arguments and variadic + +template +struct is_function : true_type { }; +template +struct is_function : true_type { }; + +template +struct is_function : true_type { }; +template +struct is_function : true_type { }; + +template +struct is_function : true_type { }; +template +struct is_function : true_type { }; + +template +struct is_function : true_type { }; +template +struct is_function : true_type { }; + +template +struct is_function : true_type { }; +template +struct is_function : true_type { }; + +template +struct is_function : true_type { }; +template +struct is_function : true_type { }; + +template +struct is_function : true_type { }; +template +struct is_function : true_type { }; + +template +struct is_function : true_type { }; +template +struct is_function : true_type { }; + +template +struct is_function : true_type { }; +template +struct is_function : true_type { }; + +template +struct is_function : true_type { }; +template +struct is_function : true_type { }; + +template +struct is_function : true_type { }; +template +struct is_function : true_type { }; + +/* is_member_function_pointer */ +namespace impl { +/* Two helper filters to complement is_function */ +template +using always_true = true_type; +template +using is_not_function = mbed::negation>; + +template class Filter = always_true> +struct is_unqualified_member_pointer : false_type { }; +template class Filter, typename U> +struct is_unqualified_member_pointer : Filter { }; + +} // namespace impl + +template +struct is_member_function_pointer : impl::is_unqualified_member_pointer, is_function> { }; + +/* is_member_object_pointer */ +template +struct is_member_object_pointer : impl::is_unqualified_member_pointer, impl::is_not_function> { }; + +/* is_reference = (is_lvalue_reference || is_rvalue_reference) */ +template +struct is_reference : false_type { }; + +template +struct is_reference : true_type { }; + +template +struct is_reference : true_type { }; + +/* is_arithmetic */ +template +struct is_arithmetic : mbed::disjunction, is_floating_point> { }; + +/* is_fundamental */ +template +struct is_fundamental : mbed::disjunction, is_void, is_null_pointer> { }; + +/* is_compound */ +template +struct is_compound : mbed::negation> { }; + +/* is_member_pointer */ +template +struct is_member_pointer : impl::is_unqualified_member_pointer> { }; + +/* is_scalar */ +template +struct is_scalar : mbed::disjunction, is_enum, is_pointer, is_member_pointer, is_null_pointer> { }; + +/* is_object */ +template +struct is_object : mbed::disjunction, is_array, is_union, is_class> { }; + +/* is_const */ +template +struct is_const : false_type { }; + +template +struct is_const : true_type { }; + +/* is_volatile */ +template +struct is_volatile : false_type { }; + +template +struct is_volatile : true_type { }; + +/* is_trivial */ +template +struct is_trivial : mbed::bool_constant<__is_trivial(T)> { }; + +/* is_trivially_copyable */ +template +struct is_trivially_copyable : mbed::bool_constant<__is_trivially_copyable(T)> { }; + +/* is_standard_layout */ +template +struct is_standard_layout : mbed::bool_constant<__is_standard_layout(T)> { }; + +/* is_pod */ +template +struct is_pod : mbed::bool_constant<__is_pod(T)> { }; + +/* is_literal_type */ +template +struct is_literal_type : mbed::bool_constant<__is_literal_type(T)> { }; + +/* is_empty */ +template +struct is_empty : mbed::bool_constant<__is_empty(T)> { }; + +/* is_polymorphic */ +template +struct is_polymorphic : mbed::bool_constant<__is_polymorphic(T)> { }; + +/* is_abstract */ +template +struct is_abstract : mbed::bool_constant<__is_abstract(T)> { }; + +/* is_final (C++14) not supported */ + +/* is_signed */ +namespace impl { +template ::value > +struct is_signed : false_type { }; +template +struct is_signed : mbed::bool_constant { }; +} // namespace impl + +template +struct is_signed : impl::is_signed { }; + +/* is_unsigned */ +namespace impl { + template ::value > + struct is_unsigned : false_type { }; + template + struct is_unsigned : mbed::bool_constant { }; +} + +template +struct is_unsigned : impl::is_unsigned { }; + +/* is_constructible */ +template +struct is_constructible : mbed::bool_constant<__is_constructible(T, Args...)> { }; + +/* is_default_constructible */ +template +struct is_default_constructible : is_constructible { }; + +/* is_copy_constructible */ +template +struct is_copy_constructible : is_constructible>> { }; + +/* is_move_constructible */ +template +struct is_move_constructible : is_constructible> { }; + +/* is_assignable */ +namespace impl { +template +struct is_assignable : std::false_type { }; + +template +struct is_assignable() = std::declval())>> : std::true_type { }; +} // namespace impl + +template +struct is_assignable : impl::is_assignable { }; + +/* is_copy_assignable */ +template +struct is_copy_assignable : is_assignable, + add_lvalue_reference_t>> { }; + +/* is_move_assignable */ +template +struct is_move_assignable : is_assignable, + add_rvalue_reference_t> { }; + +/* is_destructible */ +template +struct is_destructible : mbed::bool_constant<__is_destructible(T)> { }; + +/* is_trivially_constructible */ +template +struct is_trivially_constructible : mbed::bool_constant<__is_trivially_constructible(T, Args...)> { }; + +/* is_trivially_default_constructible */ +template +struct is_trivially_default_constructible : is_trivially_constructible { }; + +/* is_trivially_copy_constructible */ +template +struct is_trivially_copy_constructible : is_trivially_constructible>> { }; + +/* is_trivially_move_constructible */ +template +struct is_trivially_move_constructible : is_trivially_constructible> { }; + +/* is_trivially_assignable */ +template +struct is_trivially_assignable : mbed::bool_constant<__is_trivially_assignable(To, From)> { }; + +/* is_trivially_copy_assignable */ +template +struct is_trivially_copy_assignable : is_trivially_assignable, + add_lvalue_reference_t>> { }; + +/* is_trivially_move_assignable */ +template +struct is_trivially_move_assignable : is_trivially_assignable, + add_rvalue_reference_t> { }; + +/* is_trivially_destructible */ +template +struct is_trivially_destructible : mbed::bool_constant<__is_trivially_destructible(T)> { }; + +/* is_nothrow_constructible */ +template +struct is_nothrow_constructible : mbed::bool_constant<__is_nothrow_constructible(T, Args...)> { }; + +/* is_nothrow_default_constructible */ +template +struct is_nothrow_default_constructible : is_nothrow_constructible { }; + +/* is_nothrow_copy_constructible */ +template +struct is_nothrow_copy_constructible : is_nothrow_constructible>> { }; + +/* is_nothrow_move_constructible */ +template +struct is_nothrow_move_constructible : is_nothrow_constructible> { }; + +/* is_nothrow_assignable */ +template +struct is_nothrow_assignable : mbed::bool_constant<__is_nothrow_assignable(To, From)> { }; + +/* is_copy_assignable */ +template +struct is_nothrow_copy_assignable : is_nothrow_assignable, + add_lvalue_reference_t>> { }; + +/* is_move_assignable */ +template +struct is_nothrow_move_assignable : is_nothrow_assignable, + add_rvalue_reference_t> { }; + +/* is_nothrow_destructible */ +template +struct is_nothrow_destructible : mbed::bool_constant<__is_nothrow_destructible(T)> { }; + +/* has_virtual_destructor */ +template +struct has_virtual_destructor : mbed::bool_constant<__has_virtual_destructor(T)> { }; + +/* alignment_of */ +template +struct alignment_of : integral_constant { }; + +/* rank */ +template +struct rank : integral_constant { }; + +template +struct rank : integral_constant::value + 1u> { }; + +template +struct rank : integral_constant::value + 1u> { }; + +/* extent */ +template +struct extent : integral_constant { }; + +template +struct extent : integral_constant { }; + +template +struct extent : extent { }; + +template +struct extent : integral_constant { }; + +template +struct extent : extent { }; + +/* is_convertible */ +/* __is_convertible_to apparently returns true for any From if To is void */ +template +struct is_convertible : conditional_t::value, + is_void, + mbed::bool_constant<__is_convertible_to(From, To)>> { }; + +/* is_base_of */ +template +struct is_base_of : mbed::bool_constant<__is_base_of(Base, Derived) && __is_class(Derived)> { }; + +/* remove_extent */ +template +struct remove_extent : mbed::type_identity { }; + +template +struct remove_extent : mbed::type_identity { }; + +template +struct remove_extent : mbed::type_identity { }; + +template +using remove_extent_t = typename remove_extent::type; + +/* remove_all_extents */ +template +struct remove_all_extents : mbed::type_identity { }; + +template +using remove_all_extents_t = typename remove_all_extents::type; + +template +struct remove_all_extents : mbed::type_identity> { }; + +template +struct remove_all_extents : mbed::type_identity> { }; + +/* remove_pointer */ +template +struct remove_pointer : mbed::type_identity { }; + +template +struct remove_pointer : mbed::type_identity { }; + +template +struct remove_pointer : mbed::type_identity { }; + +template +struct remove_pointer : mbed::type_identity { }; + +template +struct remove_pointer : mbed::type_identity { }; + +template +using remove_pointer_t = typename remove_pointer::type; + +/* add_pointer */ +namespace impl { +template , is_void>::value> +struct add_pointer : mbed::type_identity { }; +template +struct add_pointer : mbed::type_identity *> { }; +} // namespace impl + +template +struct add_pointer : impl::add_pointer { }; + +template +using add_pointer_t = typename add_pointer::type; + +/* aligned_storage */ +namespace impl { +constexpr size_t possible_alignment_requirement(size_t n) +{ + return n <= 1 ? 1 : + n <= 2 ? 2 : + n <= 4 ? 4 : 8; +} +} + +template +struct aligned_storage { + struct type { + __attribute__((aligned(Align))) unsigned char data[Len]; + }; +}; + +template +using aligned_storage_t = typename aligned_storage::type; + +/* decay */ +namespace impl { +template +struct decay : mbed::type_identity< + conditional_t::value, + remove_extent_t, + conditional_t::value, + add_pointer_t, + remove_cv_t + > + > + > { }; +} // namespace impl + +template +struct decay : impl::decay> { }; + +template +using decay_t = typename decay::type; + +/* common_type (0 types) */ +template +struct common_type { }; + +template +using common_type_t = typename common_type::type; + +namespace impl { +template +using ternary_t = decltype(false ? declval() : declval()); + +template +struct ct2_default { }; + +template +struct ct2_default>> : mbed::type_identity>> { }; + +template , typename D2 = decay_t> +struct ct2 : common_type { }; + +template +struct ct2 : ct2_default { }; + +template +struct ct_multi { }; + +template +struct ct_multi>, T1, T2, TN...> : common_type, TN...> { }; +} // namespace impl + +/* common_type (1 type) */ +template +struct common_type : common_type { }; + +/* common_type (2 types) - applications can add extra 2-type specializations */ +template +struct common_type : impl::ct2 { }; + +/* common_type (3+ types) */ +template +struct common_type : impl::ct_multi { }; + +/* underlying_type */ +template +struct underlying_type : mbed::type_identity<__underlying_type(T)> { }; + +template +using underlying_type_t = typename underlying_type::type; + +/* result_of not implemented */ + +/* addressof */ +template +T *addressof(T &arg) noexcept +{ + return reinterpret_cast(const_cast(&reinterpret_cast(arg))); +} + +/* move */ +template +constexpr remove_reference_t &&move(T &&a) noexcept +{ + return static_cast &&>(a); +} + +/* forward */ +template +constexpr T &&forward(remove_reference_t &a) noexcept +{ + return static_cast(a); +} + +template +constexpr T &&forward(remove_reference_t &&a) noexcept +{ + return static_cast(a); +} + +/* std::array is pretty useful */ +template +struct array { + T _elem[N]; + + using value_type = T; + using size_type = size_t; + using difference_type = ptrdiff_t; + using reference = T &; + using const_reference = const T &; + using pointer = T *; + using const_pointer = const T *; + using iterator = T *; + using const_iterator = const T *; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + T &at(size_t pos) + { + MBED_ASSERT(pos < size()); + return _elem[pos]; + } + const T &at(size_t pos) const + { + MBED_ASSERT(pos < size()); + return _elem[pos]; + } + T &operator[](size_t pos) + { + return _elem[pos]; + } + const T &operator[](size_t pos) const + { + return _elem[pos]; + } + T &front() + { + return _elem[0]; + } + const T &front() const + { + return _elem[0]; + } + T &back() + { + return _elem[N - 1]; + } + const T &back() const + { + return _elem[N - 1]; + } + T *data() noexcept + { + return _elem; + } + const T *data() const noexcept + { + return _elem; + } + constexpr bool empty() const noexcept + { + return false; + } + constexpr size_t size() const noexcept + { + return N; + } + constexpr size_t max_size() const noexcept + { + return N; + } + void fill(const T &value) + { + std::fill(begin(), end(), value); + } + iterator begin() noexcept + { + return _elem; + } + const_iterator begin() const noexcept + { + return _elem; + } + const_iterator cbegin() const noexcept + { + return _elem; + } + iterator end() noexcept + { + return _elem + N; + } + const_iterator end() const noexcept + { + return _elem + N; + } + const_iterator cend() const noexcept + { + return _elem + N; + } + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } + const_reverse_iterator rbegin() const noexcept + { + return const_reverse_iterator(end()); + } + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(end()); + } + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } + const_reverse_iterator rend() const noexcept + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(begin()); + } +}; + +/* ARM Compiler 5 supports initializer lists, but is missing std::initializer_list */ +/* Implementation deduced experimentally */ +template +struct initializer_list { + using value_type = T; + using reference = const T &; + using const_reference = const T &; + using size_type = size_t; + using iterator = const T *; + using const_iterator = const T *; + constexpr initializer_list() noexcept : _ptr(nullptr), _count(0) + { + } + constexpr initializer_list(const T *p, size_t n) noexcept : _ptr(p), _count(n) + { + } + constexpr size_t size() const noexcept + { + return _count; + } + const T *begin() const noexcept + { + return _ptr; + } + const T *end() const noexcept + { + return _ptr + _count; + } +private: + const T *_ptr; + size_t _count; +}; + +/* begin */ +template +auto begin(C &c) -> decltype(c.begin()) +{ + return c.begin(); +} + +template +auto begin(const C &c) -> decltype(c.begin()) +{ + return c.begin(); +} + +template +T *begin(T (&array)[N]) noexcept +{ + return &array[0]; +} + +template +auto cbegin(const C &c) noexcept(noexcept(begin(c))) -> decltype(begin(c)) +{ + return begin(c); +} + +/* begin(initializer_list) */ +template +const E begin(initializer_list il) noexcept +{ + return il.begin(); +} + +/* end */ +template +auto end(C &c) -> decltype(c.end()) +{ + return c.end(); +} + +template +auto end(const C &c) -> decltype(c.end()) +{ + return c.end(); +} + +template +T *end(T (&array)[N]) noexcept +{ + return &array[N]; +} + +template +auto cend(const C &c) noexcept(noexcept(end(c))) -> decltype(end(c)) +{ + return end(c); +} + +/* end(initializer_list) */ +template +const E end(initializer_list il) noexcept +{ + return il.end(); +} + +/* align */ +inline void *align(size_t alignment, size_t size, void *&ptr, size_t &space) noexcept +{ + /* Behavior is undefined if alignment is not a power of 2 */ + uintptr_t addr = reinterpret_cast(ptr); + uintptr_t new_addr = (addr + (alignment - 1)) & ~(alignment - 1); + uintptr_t pad = new_addr - addr; + if (pad + size <= space) { + space -= pad; + ptr = reinterpret_cast(new_addr); + return ptr; + } else { + return nullptr; + } +} + +} // namespace std +#endif // __CC_ARM + +/* More post-C++14 stuff */ +namespace mbed { + +/* C++17 as_const */ +#if __cplusplus >= 201703 || __cpp_lib_as_const >= 201510 +using std::as_const; +#else +template +constexpr std::add_const_t &as_const(T &t) noexcept +{ + return t; +} + +template +void as_const(T &&) = delete; +#endif + +/* C++20 remove_cvref */ +template +struct remove_cvref : type_identity>> { }; + +template +using remove_cvref_t = typename remove_cvref::type; + +} // namespace mbed + +#endif // MBED_CXXSUPPORT_H