/* 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