mbed-os5 only for TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

platform/cxxsupport/mstd_utility

Committer:
kenjiArai
Date:
2019-12-31
Revision:
1:9db0e321a9f4

File content as of revision 1:9db0e321a9f4:

/* 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;
using std::index_sequence;
using std::make_integer_sequence;
using std::make_index_sequence;
using std::index_sequence_for;

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