mirror of https://github.com/ARMmbed/mbed-os.git
1229 lines
35 KiB
C++
1229 lines
35 KiB
C++
/* 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 <typename T, T V>
|
|
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<typename T, T V>
|
|
constexpr T integral_constant<T, V>::value;
|
|
|
|
/* true_type, false_type */
|
|
using true_type = integral_constant<bool, true>;
|
|
using false_type = integral_constant<bool, false>;
|
|
|
|
} // namespace std
|
|
#else
|
|
#include <cstddef>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#endif
|
|
|
|
/* Add some foundational stuff from C++17 or later or TS into namespace mbed */
|
|
namespace mbed {
|
|
|
|
/* C++20 type identity */
|
|
template<typename T>
|
|
struct type_identity {
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T>
|
|
using type_identity_t = typename type_identity<T>::type;
|
|
|
|
/* C++17 void_t (foundation for detection idiom) */
|
|
/* void_t<Args...> 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 <typename...>
|
|
struct void_helper : type_identity<void> { };
|
|
}
|
|
template <typename... Ts>
|
|
using void_t = typename impl::void_helper<Ts...>::type;
|
|
#else
|
|
template <typename...>
|
|
using void_t = void;
|
|
#endif
|
|
|
|
/* C++17 bool_constant */
|
|
#if __cplusplus >= 201703 || __cpp_lib_bool_constant >= 201505
|
|
using std::bool_constant;
|
|
#else
|
|
template <bool B>
|
|
using bool_constant = std::integral_constant<bool, B>;
|
|
#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 <typename, typename>
|
|
struct is_same : false_type { };
|
|
|
|
template <typename T>
|
|
struct is_same<T, T> : true_type { };
|
|
|
|
/* conditional */
|
|
template <bool B, typename T, typename F>
|
|
struct conditional : mbed::type_identity<F> { };
|
|
|
|
template <typename T, typename F>
|
|
struct conditional<true, T, F> : mbed::type_identity<T> { };
|
|
|
|
template <bool B, typename T, typename F>
|
|
using conditional_t = typename conditional<B, T, F>::type;
|
|
|
|
/* enable_if */
|
|
template <bool B, typename T = void>
|
|
struct enable_if { };
|
|
|
|
template <typename T>
|
|
struct enable_if<true, T> : mbed::type_identity<T> { };
|
|
|
|
template <bool B, typename T = void>
|
|
using enable_if_t = typename enable_if<B, T>::type;
|
|
|
|
/* Forward declarations */
|
|
template <typename From, typename To>
|
|
struct is_convertible;
|
|
|
|
template <typename T>
|
|
struct is_object;
|
|
|
|
template <typename T>
|
|
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<class...>
|
|
struct conjunction : std::true_type { };
|
|
template<class B1>
|
|
struct conjunction<B1> : B1 { };
|
|
template<class B1, class... BN>
|
|
struct conjunction<B1, BN...> : std::conditional_t<bool(B1::value), conjunction<BN...>, B1> { };
|
|
|
|
template<class...>
|
|
struct disjunction : std::false_type { };
|
|
template<class B1>
|
|
struct disjunction<B1> : B1 { };
|
|
template<class B1, class... BN>
|
|
struct disjunction<B1, BN...> : std::conditional_t<bool(B1::value), B1, disjunction<BN...>> { };
|
|
|
|
template<class B>
|
|
struct negation : bool_constant<!bool(B::value)> { };
|
|
#endif
|
|
|
|
/* C++ detection idiom from Library fundamentals v2 TS */
|
|
/* Place into mbed::experimental to match their std::experimental */
|
|
namespace experimental {
|
|
|
|
namespace impl {
|
|
template <class Default, class Void, template<class...> class Op, class... Args>
|
|
struct detector {
|
|
using value_t = std::false_type;
|
|
using type = Default;
|
|
};
|
|
|
|
template <class Default, template<class...> class Op, class... Args>
|
|
struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
|
|
using value_t = std::true_type;
|
|
using type = Op<Args...>;
|
|
};
|
|
|
|
} // 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<template<class...> class Op, class... Args>
|
|
using is_detected = typename impl::detector<nonesuch, void, Op, Args...>::value_t;
|
|
|
|
template<template<class...> class Op, class... Args>
|
|
using detected_t = typename impl::detector<nonesuch, void, Op, Args...>::type;
|
|
|
|
template<class Default, template<class...> class Op, class... Args>
|
|
using detected_or = typename impl::detector<Default, void, Op, Args...>;
|
|
|
|
template<class Default, template<class...> class Op, class... Args>
|
|
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
|
|
|
|
template<class Expected, template<class...> class Op, class... Args>
|
|
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
|
|
|
|
template<class To, template<class...> class Op, class... Args>
|
|
using is_detected_convertible = std::is_convertible<detected_t<Op, Args...>, 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 <iterator>
|
|
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 <typename T>
|
|
struct remove_const : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
struct remove_const<const T> : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
using remove_const_t = typename remove_const<T>::type;
|
|
|
|
template <typename T>
|
|
struct remove_volatile : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
struct remove_volatile<volatile T> : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
using remove_volatile_t = typename remove_volatile<T>::type;
|
|
|
|
template <typename T>
|
|
struct remove_cv : remove_volatile<remove_const_t<T>> { };
|
|
|
|
template <typename T>
|
|
using remove_cv_t = typename remove_cv<T>::type;
|
|
|
|
/* add_const/volatile/cv */
|
|
template <typename T>
|
|
struct add_const : mbed::type_identity<const T> { };
|
|
|
|
template <typename T>
|
|
using add_const_t = typename add_const<T>::type;
|
|
|
|
template <typename T>
|
|
struct add_volatile : mbed::type_identity<volatile T> { };
|
|
|
|
template <typename T>
|
|
using add_volatile_t = typename add_volatile<T>::type;
|
|
|
|
template <typename T>
|
|
struct add_cv : mbed::type_identity<const volatile T> { };
|
|
|
|
template <typename T>
|
|
using add_cv_t = typename add_cv<T>::type;
|
|
|
|
/* remove_reference */
|
|
template <typename T>
|
|
struct remove_reference : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
struct remove_reference<T &> : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
struct remove_reference<T &&> : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
using remove_reference_t = typename remove_reference<T>::type;
|
|
|
|
/* add_lvalue_reference / add_value_reference */
|
|
namespace impl {
|
|
template <typename T> // Base test - objects and references
|
|
struct is_referenceable : mbed::disjunction<is_object<T>, is_reference<T>> { };
|
|
template <typename R, typename... Args> // Specialisation - unqualified functions (non-variadic)
|
|
struct is_referenceable<R(Args...)> : true_type { };
|
|
template <typename R, typename... Args> // Specialisation - unqualified functions (variadic)
|
|
struct is_referenceable<R(Args... ...)> : true_type { };
|
|
|
|
template <typename T, bool = is_referenceable<T>::value>
|
|
struct add_lvalue_reference : mbed::type_identity<T> { };
|
|
template <typename T>
|
|
struct add_lvalue_reference<T, true> : mbed::type_identity<T &> { };
|
|
|
|
template <typename T, bool = is_referenceable<T>::value>
|
|
struct add_rvalue_reference : mbed::type_identity<T> { };
|
|
template <typename T>
|
|
struct add_rvalue_reference<T, true> : mbed::type_identity<T &&> { };
|
|
} // namespace impl
|
|
|
|
template <typename T>
|
|
struct add_lvalue_reference : impl::add_lvalue_reference<T> { };
|
|
template <typename T>
|
|
using add_lvalue_reference_t = typename add_lvalue_reference<T>::type;
|
|
|
|
template <typename T>
|
|
struct add_rvalue_reference : impl::add_rvalue_reference<T> { };
|
|
template <typename T>
|
|
using add_rvalue_reference_t = typename add_rvalue_reference<T>::type;
|
|
|
|
/* declval */
|
|
template <class T>
|
|
add_rvalue_reference_t<T> declval() noexcept;
|
|
|
|
/* is_void */
|
|
template <typename T>
|
|
struct is_void : is_same<void, remove_cv_t<T>> { };
|
|
|
|
/* is_null_pointer */
|
|
template <typename T>
|
|
struct is_null_pointer : is_same<nullptr_t, remove_cv_t<T>> { };
|
|
|
|
/* is_integral */
|
|
template <typename T>
|
|
struct is_integral :
|
|
mbed::disjunction<
|
|
is_same<bool, remove_cv_t<T>>,
|
|
is_same<char, remove_cv_t<T>>,
|
|
is_same<signed char, remove_cv_t<T>>,
|
|
is_same<unsigned char, remove_cv_t<T>>,
|
|
is_same<char16_t, remove_cv_t<T>>,
|
|
is_same<char32_t, remove_cv_t<T>>,
|
|
is_same<wchar_t, remove_cv_t<T>>,
|
|
is_same<short, remove_cv_t<T>>,
|
|
is_same<unsigned short, remove_cv_t<T>>,
|
|
is_same<int, remove_cv_t<T>>,
|
|
is_same<unsigned int, remove_cv_t<T>>,
|
|
is_same<long, remove_cv_t<T>>,
|
|
is_same<unsigned long, remove_cv_t<T>>,
|
|
is_same<long long, remove_cv_t<T>>,
|
|
is_same<unsigned long long, remove_cv_t<T>>> { };
|
|
|
|
/* is_floating_point */
|
|
template <typename T>
|
|
struct is_floating_point :
|
|
mbed::disjunction<
|
|
is_same<float, remove_cv_t<T>>,
|
|
is_same<double, remove_cv_t<T>>,
|
|
is_same<long double, remove_cv_t<T>>> { };
|
|
|
|
/* is_array */
|
|
template <typename T>
|
|
struct is_array : false_type { };
|
|
|
|
template <typename T>
|
|
struct is_array<T[]> : true_type { };
|
|
|
|
template <typename T, size_t N>
|
|
struct is_array<T[N]> : true_type { };
|
|
|
|
/* is_pointer */
|
|
namespace impl {
|
|
template <typename T>
|
|
struct is_unqualified_pointer : false_type { };
|
|
template <typename T>
|
|
struct is_unqualified_pointer<T *> : true_type { };
|
|
} // namespace impl
|
|
|
|
template <typename T>
|
|
struct is_pointer : impl::is_unqualified_pointer<remove_cv_t<T>> { };
|
|
|
|
/* is_lvalue_reference */
|
|
template <typename T>
|
|
struct is_lvalue_reference : false_type { };
|
|
|
|
template <typename T>
|
|
struct is_lvalue_reference<T &> : true_type { };
|
|
|
|
/* is_rvalue_reference */
|
|
template <typename T>
|
|
struct is_rvalue_reference : false_type { };
|
|
|
|
template <typename T>
|
|
struct is_rvalue_reference<T &&> : true_type { };
|
|
|
|
/* is_enum */
|
|
template <typename T>
|
|
struct is_enum : mbed::bool_constant<__is_enum(T)> { };
|
|
|
|
/* is_union */
|
|
template <typename T>
|
|
struct is_union : mbed::bool_constant<__is_union(T)> { };
|
|
|
|
/* is_class */
|
|
template <typename T>
|
|
struct is_class : mbed::bool_constant<__is_class(T)> { };
|
|
|
|
/* is_function */
|
|
template <typename T>
|
|
struct is_function : false_type { };
|
|
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args...)> : true_type { }; // 0 or more named arguments
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args... ...)> : true_type { }; // 0 or more named arguments and variadic
|
|
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args...) &> : true_type { };
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args... ...) &> : true_type { };
|
|
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args...) &&> : true_type { };
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args... ...) &&> : true_type { };
|
|
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args...) const> : true_type { };
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args... ...) const> : true_type { };
|
|
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args...) const &> : true_type { };
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args... ...) const &> : true_type { };
|
|
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args...) const &&> : true_type { };
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args... ...) const &&> : true_type { };
|
|
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args...) volatile> : true_type { };
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args... ...) volatile> : true_type { };
|
|
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args...) volatile &> : true_type { };
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args... ...) volatile &> : true_type { };
|
|
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args...) volatile &&> : true_type { };
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args... ...) volatile &&> : true_type { };
|
|
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args...) const volatile> : true_type { };
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args... ...) const volatile> : true_type { };
|
|
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args...) const volatile &> : true_type { };
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args... ...) const volatile &> : true_type { };
|
|
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args...) const volatile &&> : true_type { };
|
|
template <typename R, typename... Args>
|
|
struct is_function<R(Args... ...) const volatile &&> : true_type { };
|
|
|
|
/* is_member_function_pointer */
|
|
namespace impl {
|
|
/* Two helper filters to complement is_function */
|
|
template <typename>
|
|
using always_true = true_type;
|
|
template <typename T>
|
|
using is_not_function = mbed::negation<is_function<T>>;
|
|
|
|
template <typename T, template<typename> class Filter = always_true>
|
|
struct is_unqualified_member_pointer : false_type { };
|
|
template <typename T, template<typename> class Filter, typename U>
|
|
struct is_unqualified_member_pointer<T U::*, Filter> : Filter<T> { };
|
|
|
|
} // namespace impl
|
|
|
|
template <typename T>
|
|
struct is_member_function_pointer : impl::is_unqualified_member_pointer<remove_cv_t<T>, is_function> { };
|
|
|
|
/* is_member_object_pointer */
|
|
template <typename T>
|
|
struct is_member_object_pointer : impl::is_unqualified_member_pointer<remove_cv_t<T>, impl::is_not_function> { };
|
|
|
|
/* is_reference = (is_lvalue_reference || is_rvalue_reference) */
|
|
template <typename T>
|
|
struct is_reference : false_type { };
|
|
|
|
template <typename T>
|
|
struct is_reference<T &> : true_type { };
|
|
|
|
template <typename T>
|
|
struct is_reference<T &&> : true_type { };
|
|
|
|
/* is_arithmetic */
|
|
template <typename T>
|
|
struct is_arithmetic : mbed::disjunction<is_integral<T>, is_floating_point<T>> { };
|
|
|
|
/* is_fundamental */
|
|
template <typename T>
|
|
struct is_fundamental : mbed::disjunction<is_arithmetic<T>, is_void<T>, is_null_pointer<T>> { };
|
|
|
|
/* is_compound */
|
|
template <typename T>
|
|
struct is_compound : mbed::negation<is_fundamental<T>> { };
|
|
|
|
/* is_member_pointer */
|
|
template <typename T>
|
|
struct is_member_pointer : impl::is_unqualified_member_pointer<remove_cv_t<T>> { };
|
|
|
|
/* is_scalar */
|
|
template <typename T>
|
|
struct is_scalar : mbed::disjunction<is_arithmetic<T>, is_enum<T>, is_pointer<T>, is_member_pointer<T>, is_null_pointer<T>> { };
|
|
|
|
/* is_object */
|
|
template <typename T>
|
|
struct is_object : mbed::disjunction<is_scalar<T>, is_array<T>, is_union<T>, is_class<T>> { };
|
|
|
|
/* is_const */
|
|
template <typename T>
|
|
struct is_const : false_type { };
|
|
|
|
template <typename T>
|
|
struct is_const<const T> : true_type { };
|
|
|
|
/* is_volatile */
|
|
template <typename T>
|
|
struct is_volatile : false_type { };
|
|
|
|
template <typename T>
|
|
struct is_volatile<volatile T> : true_type { };
|
|
|
|
/* is_trivial */
|
|
template <typename T>
|
|
struct is_trivial : mbed::bool_constant<__is_trivial(T)> { };
|
|
|
|
/* is_trivially_copyable */
|
|
template <typename T>
|
|
struct is_trivially_copyable : mbed::bool_constant<__is_trivially_copyable(T)> { };
|
|
|
|
/* is_standard_layout */
|
|
template <typename T>
|
|
struct is_standard_layout : mbed::bool_constant<__is_standard_layout(T)> { };
|
|
|
|
/* is_pod */
|
|
template <typename T>
|
|
struct is_pod : mbed::bool_constant<__is_pod(T)> { };
|
|
|
|
/* is_literal_type */
|
|
template <typename T>
|
|
struct is_literal_type : mbed::bool_constant<__is_literal_type(T)> { };
|
|
|
|
/* is_empty */
|
|
template <typename T>
|
|
struct is_empty : mbed::bool_constant<__is_empty(T)> { };
|
|
|
|
/* is_polymorphic */
|
|
template <typename T>
|
|
struct is_polymorphic : mbed::bool_constant<__is_polymorphic(T)> { };
|
|
|
|
/* is_abstract */
|
|
template <typename T>
|
|
struct is_abstract : mbed::bool_constant<__is_abstract(T)> { };
|
|
|
|
/* is_final (C++14) not supported */
|
|
|
|
/* is_signed */
|
|
namespace impl {
|
|
template <typename T, bool = is_arithmetic<T>::value >
|
|
struct is_signed : false_type { };
|
|
template <typename T>
|
|
struct is_signed<T, true> : mbed::bool_constant<T(-1) < T(0)> { };
|
|
} // namespace impl
|
|
|
|
template <typename T>
|
|
struct is_signed : impl::is_signed<T> { };
|
|
|
|
/* is_unsigned */
|
|
namespace impl {
|
|
template <typename T, bool = is_arithmetic<T>::value >
|
|
struct is_unsigned : false_type { };
|
|
template <typename T>
|
|
struct is_unsigned<T, true> : mbed::bool_constant<T(0) < T(-1)> { };
|
|
}
|
|
|
|
template <typename T>
|
|
struct is_unsigned : impl::is_unsigned<T> { };
|
|
|
|
/* is_constructible */
|
|
template <typename T, typename... Args>
|
|
struct is_constructible : mbed::bool_constant<__is_constructible(T, Args...)> { };
|
|
|
|
/* is_default_constructible */
|
|
template <typename T>
|
|
struct is_default_constructible : is_constructible<T> { };
|
|
|
|
/* is_copy_constructible */
|
|
template <typename T>
|
|
struct is_copy_constructible : is_constructible<T, add_lvalue_reference_t<add_const_t<T>>> { };
|
|
|
|
/* is_move_constructible */
|
|
template <typename T>
|
|
struct is_move_constructible : is_constructible<T, add_rvalue_reference_t<T>> { };
|
|
|
|
/* is_assignable */
|
|
namespace impl {
|
|
template <typename To, typename From, typename = void>
|
|
struct is_assignable : std::false_type { };
|
|
|
|
template <typename To, typename From>
|
|
struct is_assignable<To, From, mbed::void_t<decltype(std::declval<To>() = std::declval<From>())>> : std::true_type { };
|
|
} // namespace impl
|
|
|
|
template <typename To, typename From>
|
|
struct is_assignable : impl::is_assignable<To, From> { };
|
|
|
|
/* is_copy_assignable */
|
|
template <typename T>
|
|
struct is_copy_assignable : is_assignable<add_lvalue_reference_t<T>,
|
|
add_lvalue_reference_t<add_const_t<T>>> { };
|
|
|
|
/* is_move_assignable */
|
|
template <typename T>
|
|
struct is_move_assignable : is_assignable<add_lvalue_reference_t<T>,
|
|
add_rvalue_reference_t<T>> { };
|
|
|
|
/* is_destructible */
|
|
template <typename T>
|
|
struct is_destructible : mbed::bool_constant<__is_destructible(T)> { };
|
|
|
|
/* is_trivially_constructible */
|
|
template <typename T, typename... Args>
|
|
struct is_trivially_constructible : mbed::bool_constant<__is_trivially_constructible(T, Args...)> { };
|
|
|
|
/* is_trivially_default_constructible */
|
|
template <typename T>
|
|
struct is_trivially_default_constructible : is_trivially_constructible<T> { };
|
|
|
|
/* is_trivially_copy_constructible */
|
|
template <typename T>
|
|
struct is_trivially_copy_constructible : is_trivially_constructible<T, add_lvalue_reference_t<add_const_t<T>>> { };
|
|
|
|
/* is_trivially_move_constructible */
|
|
template <typename T>
|
|
struct is_trivially_move_constructible : is_trivially_constructible<T, add_rvalue_reference_t<T>> { };
|
|
|
|
/* is_trivially_assignable */
|
|
template <typename To, typename From>
|
|
struct is_trivially_assignable : mbed::bool_constant<__is_trivially_assignable(To, From)> { };
|
|
|
|
/* is_trivially_copy_assignable */
|
|
template <typename T>
|
|
struct is_trivially_copy_assignable : is_trivially_assignable<add_lvalue_reference_t<T>,
|
|
add_lvalue_reference_t<add_const_t<T>>> { };
|
|
|
|
/* is_trivially_move_assignable */
|
|
template <typename T>
|
|
struct is_trivially_move_assignable : is_trivially_assignable<add_lvalue_reference_t<T>,
|
|
add_rvalue_reference_t<T>> { };
|
|
|
|
/* is_trivially_destructible */
|
|
template <typename T>
|
|
struct is_trivially_destructible : mbed::bool_constant<__is_trivially_destructible(T)> { };
|
|
|
|
/* is_nothrow_constructible */
|
|
template <typename T, typename... Args>
|
|
struct is_nothrow_constructible : mbed::bool_constant<__is_nothrow_constructible(T, Args...)> { };
|
|
|
|
/* is_nothrow_default_constructible */
|
|
template <typename T>
|
|
struct is_nothrow_default_constructible : is_nothrow_constructible<T> { };
|
|
|
|
/* is_nothrow_copy_constructible */
|
|
template <typename T>
|
|
struct is_nothrow_copy_constructible : is_nothrow_constructible<T, add_lvalue_reference_t<add_const_t<T>>> { };
|
|
|
|
/* is_nothrow_move_constructible */
|
|
template <typename T>
|
|
struct is_nothrow_move_constructible : is_nothrow_constructible<T, add_rvalue_reference_t<T>> { };
|
|
|
|
/* is_nothrow_assignable */
|
|
template <typename To, typename From>
|
|
struct is_nothrow_assignable : mbed::bool_constant<__is_nothrow_assignable(To, From)> { };
|
|
|
|
/* is_copy_assignable */
|
|
template <typename T>
|
|
struct is_nothrow_copy_assignable : is_nothrow_assignable<add_lvalue_reference_t<T>,
|
|
add_lvalue_reference_t<add_const_t<T>>> { };
|
|
|
|
/* is_move_assignable */
|
|
template <typename T>
|
|
struct is_nothrow_move_assignable : is_nothrow_assignable<add_lvalue_reference_t<T>,
|
|
add_rvalue_reference_t<T>> { };
|
|
|
|
/* is_nothrow_destructible */
|
|
template <typename T>
|
|
struct is_nothrow_destructible : mbed::bool_constant<__is_nothrow_destructible(T)> { };
|
|
|
|
/* has_virtual_destructor */
|
|
template <typename T>
|
|
struct has_virtual_destructor : mbed::bool_constant<__has_virtual_destructor(T)> { };
|
|
|
|
/* alignment_of */
|
|
template <typename T>
|
|
struct alignment_of : integral_constant<size_t, alignof(T)> { };
|
|
|
|
/* rank */
|
|
template <typename T>
|
|
struct rank : integral_constant<size_t, 0> { };
|
|
|
|
template <typename T>
|
|
struct rank<T[]> : integral_constant<size_t, rank<T>::value + 1u> { };
|
|
|
|
template <typename T, size_t N>
|
|
struct rank<T[N]> : integral_constant<size_t, rank<T>::value + 1u> { };
|
|
|
|
/* extent */
|
|
template <typename T, unsigned I = 0>
|
|
struct extent : integral_constant<size_t, 0> { };
|
|
|
|
template <typename T>
|
|
struct extent<T[], 0> : integral_constant<size_t, 0> { };
|
|
|
|
template <typename T, unsigned I>
|
|
struct extent<T[], I> : extent<T, I - 1> { };
|
|
|
|
template <typename T, size_t N>
|
|
struct extent<T[N], 0> : integral_constant<size_t, N> { };
|
|
|
|
template <typename T, size_t N, unsigned I>
|
|
struct extent<T[N], I> : extent<T, I - 1> { };
|
|
|
|
/* is_convertible */
|
|
/* __is_convertible_to apparently returns true for any From if To is void */
|
|
template <typename From, typename To>
|
|
struct is_convertible : conditional_t<is_void<To>::value,
|
|
is_void<From>,
|
|
mbed::bool_constant<__is_convertible_to(From, To)>> { };
|
|
|
|
/* is_base_of */
|
|
template <typename Base, typename Derived>
|
|
struct is_base_of : mbed::bool_constant<__is_base_of(Base, Derived) && __is_class(Derived)> { };
|
|
|
|
/* remove_extent */
|
|
template <typename T>
|
|
struct remove_extent : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
struct remove_extent<T[]> : mbed::type_identity<T> { };
|
|
|
|
template <typename T, size_t N>
|
|
struct remove_extent<T[N]> : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
using remove_extent_t = typename remove_extent<T>::type;
|
|
|
|
/* remove_all_extents */
|
|
template <typename T>
|
|
struct remove_all_extents : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
using remove_all_extents_t = typename remove_all_extents<T>::type;
|
|
|
|
template <typename T>
|
|
struct remove_all_extents<T[]> : mbed::type_identity<remove_all_extents_t<T>> { };
|
|
|
|
template <typename T, size_t N>
|
|
struct remove_all_extents<T[N]> : mbed::type_identity<remove_all_extents_t<T>> { };
|
|
|
|
/* remove_pointer */
|
|
template <typename T>
|
|
struct remove_pointer : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
struct remove_pointer<T *> : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
struct remove_pointer<T * const> : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
struct remove_pointer<T * volatile> : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
struct remove_pointer<T * const volatile> : mbed::type_identity<T> { };
|
|
|
|
template <typename T>
|
|
using remove_pointer_t = typename remove_pointer<T>::type;
|
|
|
|
/* add_pointer */
|
|
namespace impl {
|
|
template <typename T, bool = mbed::disjunction<is_referenceable<T>, is_void<T>>::value>
|
|
struct add_pointer : mbed::type_identity<T> { };
|
|
template <typename T>
|
|
struct add_pointer<T, true> : mbed::type_identity<remove_reference_t<T> *> { };
|
|
} // namespace impl
|
|
|
|
template <typename T>
|
|
struct add_pointer : impl::add_pointer<T> { };
|
|
|
|
template <typename T>
|
|
using add_pointer_t = typename add_pointer<T>::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 <size_t Len, size_t Align = impl::possible_alignment_requirement(Len)>
|
|
struct aligned_storage {
|
|
struct type {
|
|
__attribute__((aligned(Align))) unsigned char data[Len];
|
|
};
|
|
};
|
|
|
|
template <size_t Len, size_t Align = impl::possible_alignment_requirement(Len)>
|
|
using aligned_storage_t = typename aligned_storage<Len, Align>::type;
|
|
|
|
/* decay */
|
|
namespace impl {
|
|
template <typename T>
|
|
struct decay : mbed::type_identity<
|
|
conditional_t<is_array<T>::value,
|
|
remove_extent_t<T>,
|
|
conditional_t<is_function<T>::value,
|
|
add_pointer_t<T>,
|
|
remove_cv_t<T>
|
|
>
|
|
>
|
|
> { };
|
|
} // namespace impl
|
|
|
|
template <typename T>
|
|
struct decay : impl::decay<remove_reference_t<T>> { };
|
|
|
|
template <typename T>
|
|
using decay_t = typename decay<T>::type;
|
|
|
|
/* common_type (0 types) */
|
|
template <typename...>
|
|
struct common_type { };
|
|
|
|
template <typename... T>
|
|
using common_type_t = typename common_type<T...>::type;
|
|
|
|
namespace impl {
|
|
template <typename T1, typename T2>
|
|
using ternary_t = decltype(false ? declval<T1>() : declval<T2>());
|
|
|
|
template <typename T1, typename T2, typename=void>
|
|
struct ct2_default { };
|
|
|
|
template <typename T1, typename T2>
|
|
struct ct2_default<T1, T2, mbed::void_t<ternary_t<T1, T2>>> : mbed::type_identity<decay_t<ternary_t<T1, T2>>> { };
|
|
|
|
template <typename T1, typename T2, typename D1 = decay_t<T1>, typename D2 = decay_t<T2>>
|
|
struct ct2 : common_type<D1, D2> { };
|
|
|
|
template <typename D1, typename D2>
|
|
struct ct2<D1, D2, D1, D2> : ct2_default<D1, D2> { };
|
|
|
|
template <typename Void, typename T1, typename T2, typename... TN>
|
|
struct ct_multi { };
|
|
|
|
template <typename T1, typename T2, typename... TN>
|
|
struct ct_multi<mbed::void_t<common_type<T1, T2>>, T1, T2, TN...> : common_type<common_type_t<T1, T2>, TN...> { };
|
|
} // namespace impl
|
|
|
|
/* common_type (1 type) */
|
|
template <typename T>
|
|
struct common_type<T> : common_type<T, T> { };
|
|
|
|
/* common_type (2 types) - applications can add extra 2-type specializations */
|
|
template <typename T1, typename T2>
|
|
struct common_type<T1, T2> : impl::ct2<T1, T2> { };
|
|
|
|
/* common_type (3+ types) */
|
|
template <typename T1, typename T2, typename... TN>
|
|
struct common_type<T1, T2, TN...> : impl::ct_multi<void, T1, T2, TN...> { };
|
|
|
|
/* underlying_type */
|
|
template <typename T>
|
|
struct underlying_type : mbed::type_identity<__underlying_type(T)> { };
|
|
|
|
template <typename T>
|
|
using underlying_type_t = typename underlying_type<T>::type;
|
|
|
|
/* result_of not implemented */
|
|
|
|
/* addressof */
|
|
template <typename T>
|
|
T *addressof(T &arg) noexcept
|
|
{
|
|
return reinterpret_cast<T *>(const_cast<char *>(&reinterpret_cast<const volatile char &>(arg)));
|
|
}
|
|
|
|
/* move */
|
|
template <typename T>
|
|
constexpr remove_reference_t<T> &&move(T &&a) noexcept
|
|
{
|
|
return static_cast<remove_reference_t<T> &&>(a);
|
|
}
|
|
|
|
/* forward */
|
|
template <typename T>
|
|
constexpr T &&forward(remove_reference_t<T> &a) noexcept
|
|
{
|
|
return static_cast<T &&>(a);
|
|
}
|
|
|
|
template <typename T>
|
|
constexpr T &&forward(remove_reference_t<T> &&a) noexcept
|
|
{
|
|
return static_cast<T &&>(a);
|
|
}
|
|
|
|
/* std::array is pretty useful */
|
|
template <class T, size_t N>
|
|
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<iterator>;
|
|
using const_reverse_iterator = std::reverse_iterator<const_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 <class T>
|
|
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 <class C>
|
|
auto begin(C &c) -> decltype(c.begin())
|
|
{
|
|
return c.begin();
|
|
}
|
|
|
|
template <class C>
|
|
auto begin(const C &c) -> decltype(c.begin())
|
|
{
|
|
return c.begin();
|
|
}
|
|
|
|
template <class T, size_t N>
|
|
T *begin(T (&array)[N]) noexcept
|
|
{
|
|
return &array[0];
|
|
}
|
|
|
|
template <class C>
|
|
auto cbegin(const C &c) noexcept(noexcept(begin(c))) -> decltype(begin(c))
|
|
{
|
|
return begin(c);
|
|
}
|
|
|
|
/* begin(initializer_list<E>) */
|
|
template <class E>
|
|
const E begin(initializer_list<E> il) noexcept
|
|
{
|
|
return il.begin();
|
|
}
|
|
|
|
/* end */
|
|
template <class C>
|
|
auto end(C &c) -> decltype(c.end())
|
|
{
|
|
return c.end();
|
|
}
|
|
|
|
template <class C>
|
|
auto end(const C &c) -> decltype(c.end())
|
|
{
|
|
return c.end();
|
|
}
|
|
|
|
template <class T, size_t N>
|
|
T *end(T (&array)[N]) noexcept
|
|
{
|
|
return &array[N];
|
|
}
|
|
|
|
template <class C>
|
|
auto cend(const C &c) noexcept(noexcept(end(c))) -> decltype(end(c))
|
|
{
|
|
return end(c);
|
|
}
|
|
|
|
/* end(initializer_list<E>) */
|
|
template <class E>
|
|
const E end(initializer_list<E> 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<uintptr_t>(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<void *>(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 <typename T>
|
|
constexpr std::add_const_t<T> &as_const(T &t) noexcept
|
|
{
|
|
return t;
|
|
}
|
|
|
|
template <typename T>
|
|
void as_const(T &&) = delete;
|
|
#endif
|
|
|
|
/* C++20 remove_cvref */
|
|
template <typename T>
|
|
struct remove_cvref : type_identity<std::remove_cv_t<std::remove_reference_t<T>>> { };
|
|
|
|
template <typename T>
|
|
using remove_cvref_t = typename remove_cvref<T>::type;
|
|
|
|
} // namespace mbed
|
|
|
|
#endif // MBED_CXXSUPPORT_H
|