mbed-os/platform/cxxsupport/mstd_utility

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_