mirror of https://github.com/ARMmbed/mbed-os.git
338 lines
8.6 KiB
Plaintext
338 lines
8.6 KiB
Plaintext
/* mbed Microcontroller Library
|
|
* Copyright (c) 2019 ARM Limited
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#ifndef MSTD_UTILITY_
|
|
#define MSTD_UTILITY_
|
|
|
|
/* <mstd_utility>
|
|
*
|
|
* - includes toolchain's <utility>
|
|
* - For ARM C 5, standard C++11/14 features:
|
|
* - include <initializer_list>
|
|
* - std::move, std::forward, std::exchange
|
|
* - std::declval
|
|
* - std::integer_sequence
|
|
* - include <algorithm> to get default std::swap
|
|
* - mstd::swap - substitute for std::swap that can move
|
|
* - std::swap(array)
|
|
* - Swap assistance, to ensure moves happen on ARM C 5
|
|
* - mstd::swap - alias for std::swap, or a local moving implementation for ARM C 5
|
|
* - For all toolchains, C++17/20 backports:
|
|
* - mstd::as_const
|
|
*/
|
|
|
|
#include <utility>
|
|
|
|
#ifdef __CC_ARM
|
|
#include <_move.h>
|
|
#include <algorithm> // to get std::swap
|
|
#include <cstddef>
|
|
#include <initializer_list>
|
|
#include <cstdint> // uintmax_t
|
|
#include <mstd_type_traits>
|
|
#endif
|
|
|
|
|
|
namespace mstd {
|
|
// [utility.swap] - ARMC5's std::swap is not C++11, so make sure mstd::swap is
|
|
// So to get ADL-aware lookup with good default swap, users should do `using mstd::swap; swap(x, y);`.
|
|
#ifdef __CC_ARM
|
|
template <class _TypeT>
|
|
void swap(_TypeT &__a, _TypeT &__b)
|
|
noexcept(__is_nothrow_constructible(_TypeT, _TypeT &&) && __is_nothrow_assignable(_TypeT &, _TypeT &&))
|
|
{
|
|
_TypeT __tmp = std::move(__a);
|
|
__a = std::move(__b);
|
|
__b = std::move(__tmp);
|
|
}
|
|
|
|
template <class _TypeT, std::size_t _Size>
|
|
void swap(_TypeT (&__a)[_Size], _TypeT (&__b)[_Size])
|
|
noexcept(noexcept(swap(*__a, *__b)))
|
|
{
|
|
_TypeT *__ptr_a = __a, *__ptr_b = __b;
|
|
const _TypeT * const __end_a = __a + _Size;
|
|
for (; __ptr_a != __end_a; ++__ptr_a, ++__ptr_b) {
|
|
swap(*__ptr_a, *__ptr_b);
|
|
}
|
|
}
|
|
#else
|
|
using std::swap;
|
|
#endif
|
|
|
|
} // namespace mstd
|
|
|
|
|
|
#ifdef __CC_ARM
|
|
|
|
namespace std {
|
|
|
|
template <typename _TypeT>
|
|
constexpr conditional_t<!is_nothrow_move_constructible<_TypeT>::value && is_copy_constructible<_TypeT>::value,
|
|
const _TypeT &, _TypeT &&>
|
|
move_if_noexcept(_TypeT &__t) noexcept
|
|
{
|
|
return std::move(__t);
|
|
}
|
|
|
|
// [declval]
|
|
// is provided by mstd_type_traits, which we include
|
|
|
|
// [utility.swap] - ARMC5's basic swap in <algorithm> does not move, but
|
|
// we can add this std overload for arrays, and send it to our mstd moving version
|
|
template <class _TypeT, std::size_t _Size>
|
|
void swap(_TypeT (&__a)[_Size], _TypeT (&__b)[_Size])
|
|
noexcept(noexcept(mstd::swap(*__a, *__b)))
|
|
{
|
|
mstd::swap(__a, __b);
|
|
}
|
|
|
|
// [intseq.intseq]
|
|
template <typename T, T... I>
|
|
struct integer_sequence {
|
|
using value_type = T;
|
|
static constexpr size_t size() noexcept { return sizeof...(I); }
|
|
};
|
|
|
|
template <size_t... I>
|
|
using index_sequence = integer_sequence<size_t, I...>;
|
|
|
|
// [intseq.make]
|
|
namespace impl {
|
|
|
|
template <typename seq1, typename seq2>
|
|
struct combine_umax_sequences;
|
|
|
|
template <uintmax_t... seq1, uintmax_t... seq2>
|
|
struct combine_umax_sequences<integer_sequence<uintmax_t, seq1...>, integer_sequence<uintmax_t, seq2...>>
|
|
: mstd::type_identity<integer_sequence<uintmax_t, seq1..., sizeof...(seq1) + seq2...>> { };
|
|
|
|
template <uintmax_t N>
|
|
struct make_umax_sequence : combine_umax_sequences<typename make_umax_sequence<N / 2>::type,
|
|
typename make_umax_sequence<N - N / 2>::type> { };
|
|
|
|
template <>
|
|
struct make_umax_sequence<1> : mstd::type_identity<integer_sequence<uintmax_t, 0>> { };
|
|
|
|
template <>
|
|
struct make_umax_sequence<0> : mstd::type_identity<integer_sequence<uintmax_t>> { };
|
|
|
|
|
|
template <typename T, T N, typename useq = typename make_umax_sequence<N>::type>
|
|
struct make_integer_sequence;
|
|
|
|
template <typename T, T N, uintmax_t... I>
|
|
struct make_integer_sequence<T, N, integer_sequence<uintmax_t, I...>> {
|
|
static_assert(N >= 0, "negative integer sequence");
|
|
using type = integer_sequence<T, static_cast<T>(I)...>;
|
|
};
|
|
}
|
|
|
|
template <typename T, T N>
|
|
using make_integer_sequence = typename impl::make_integer_sequence<T, N>::type;
|
|
|
|
template <size_t N>
|
|
using make_index_sequence = make_integer_sequence<size_t, N>;
|
|
|
|
template <typename... T>
|
|
using index_sequence_for = make_index_sequence<sizeof...(T)>;
|
|
|
|
|
|
// [pair.astuple]
|
|
template <typename>
|
|
struct tuple_size;
|
|
|
|
template <size_t, typename>
|
|
struct tuple_element;
|
|
|
|
template <size_t I, typename T>
|
|
using tuple_element_t = typename tuple_element<I, T>::type;
|
|
|
|
template <typename T1, typename T2>
|
|
struct tuple_size<pair<T1, T2>> : integral_constant<size_t, 2> { };
|
|
|
|
template <typename T1, typename T2>
|
|
struct tuple_element<0, pair<T1, T2>> : mstd::type_identity<T1> { };
|
|
|
|
template <typename T1, typename T2>
|
|
struct tuple_element<1, pair<T1, T2>> : mstd::type_identity<T2> { };
|
|
|
|
namespace impl{
|
|
|
|
template <size_t I>
|
|
struct pair_getter;
|
|
|
|
template <>
|
|
struct pair_getter<0> {
|
|
template <typename T1, typename T2>
|
|
static T1 &get(pair<T1, T2> &p)
|
|
{
|
|
return p.first;
|
|
}
|
|
template <typename T1, typename T2>
|
|
static const T1 &cget(const pair<T1, T2> &p)
|
|
{
|
|
return p.first;
|
|
}
|
|
template <typename T1, typename T2>
|
|
static T1 &&get_move(pair<T1, T2> &&p)
|
|
{
|
|
return std::forward<T1>(p.first);
|
|
}
|
|
template <typename T1, typename T2>
|
|
static const T1 &&cget_move(const pair<T1, T2> &&p)
|
|
{
|
|
return std::forward<T1>(p.first);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct pair_getter<1> {
|
|
template <typename T1, typename T2>
|
|
static T2 &get(pair<T1, T2> &p)
|
|
{
|
|
return p.second;
|
|
}
|
|
template <typename T1, typename T2>
|
|
static const T2 &cget(const pair<T1, T2> &p)
|
|
{
|
|
return p.second;
|
|
}
|
|
template <typename T1, typename T2>
|
|
static T2 &&get_move(pair<T1, T2> &&p)
|
|
{
|
|
return std::forward<T2>(p.second);
|
|
}
|
|
template <typename T1, typename T2>
|
|
static const T2 &&cget_move(const pair<T1, T2> &&p)
|
|
{
|
|
return std::forward<T2>(p.second);
|
|
}
|
|
};
|
|
}
|
|
|
|
template <size_t I, typename T1, typename T2>
|
|
constexpr tuple_element_t<I, pair<T1, T2>> &get(pair<T1, T2> &p) noexcept
|
|
{
|
|
return impl::pair_getter<I>::get(p);
|
|
}
|
|
|
|
template <size_t I, typename T1, typename T2>
|
|
constexpr const tuple_element_t<I, pair<T1, T2>> &get(const pair<T1, T2> &p) noexcept
|
|
{
|
|
return impl::pair_getter<I>::cget(p);
|
|
}
|
|
|
|
template <size_t I, typename T1, typename T2>
|
|
constexpr tuple_element_t<I, pair<T1, T2>> &&get(pair<T1, T2> &&p) noexcept
|
|
{
|
|
return impl::pair_getter<I>::get_move(std::move(p));
|
|
}
|
|
|
|
template <size_t I, typename T1, typename T2>
|
|
constexpr const tuple_element_t<I, pair<T1, T2>> &&get(const pair<T1, T2> &&p) noexcept
|
|
{
|
|
return impl::pair_getter<I>::cget_move(std::move(p));
|
|
}
|
|
|
|
template <typename T1, typename T2>
|
|
constexpr T1 &get(pair<T1, T2> &p) noexcept
|
|
{
|
|
return p.first;
|
|
}
|
|
|
|
template <typename T1, typename T2>
|
|
constexpr const T1 &get(const pair<T1, T2> &p) noexcept
|
|
{
|
|
return p.first;
|
|
}
|
|
|
|
template <typename T1, typename T2>
|
|
constexpr T1 &&get(pair<T1, T2> &&p) noexcept
|
|
{
|
|
return p.first;
|
|
}
|
|
|
|
template <typename T1, typename T2>
|
|
constexpr const T1 &&get(const pair<T1, T2> &&p) noexcept
|
|
{
|
|
return p.first;
|
|
}
|
|
|
|
template <typename T2, typename T1>
|
|
constexpr T2 &get(pair<T1, T2> &p) noexcept
|
|
{
|
|
return p.second;
|
|
}
|
|
|
|
template <typename T2, typename T1>
|
|
constexpr const T2 &get(const pair<T1, T2> &p) noexcept
|
|
{
|
|
return p.second;
|
|
}
|
|
|
|
template <typename T2, typename T1>
|
|
constexpr T2 &&get(pair<T1, T2> &&p) noexcept
|
|
{
|
|
return p.second;
|
|
}
|
|
|
|
template <typename T2, typename T1>
|
|
constexpr const T2 &&get(const pair<T1, T2> &&p) noexcept
|
|
{
|
|
return p.second;
|
|
}
|
|
|
|
|
|
} // namespace std
|
|
#endif
|
|
|
|
namespace mstd {
|
|
namespace rel_ops { using namespace std::rel_ops; }
|
|
using std::initializer_list;
|
|
using std::exchange;
|
|
using std::forward;
|
|
using std::move;
|
|
// No exceptions in mbed OS
|
|
template <typename T>
|
|
T &&move_if_noexcept(T &t) noexcept
|
|
{
|
|
return mstd::move(t);
|
|
}
|
|
using std::declval;
|
|
using std::make_pair;
|
|
using std::get;
|
|
using std::pair;
|
|
using std::integer_sequence;
|
|
|
|
// C++17 [utility.as_const] */
|
|
#if __cpp_lib_as_const >= 201510
|
|
using std::as_const;
|
|
#else
|
|
template <typename _TypeT>
|
|
constexpr std::add_const_t<_TypeT> &as_const(_TypeT &__t) noexcept
|
|
{
|
|
return __t;
|
|
}
|
|
|
|
template <typename _TypeT>
|
|
void as_const(_TypeT &&) = delete;
|
|
#endif
|
|
|
|
} // namespace mstd
|
|
|
|
#endif // MSTD_UTILITY_
|