Add mstd_xxx headers to unit tests

Stripped down headers that route through to `std` forms more - eg
no local implementation of `atomic` or `mutex`.
pull/11039/head
Kevin Bracey 2019-07-16 17:50:31 +03:00
parent 85cd3cd9cc
commit 852a626399
10 changed files with 1301 additions and 0 deletions

View File

@ -95,6 +95,7 @@ set(unittest-includes-base
"${PROJECT_SOURCE_DIR}/target_h/events" "${PROJECT_SOURCE_DIR}/target_h/events"
"${PROJECT_SOURCE_DIR}/target_h/events/equeue" "${PROJECT_SOURCE_DIR}/target_h/events/equeue"
"${PROJECT_SOURCE_DIR}/target_h/platform" "${PROJECT_SOURCE_DIR}/target_h/platform"
"${PROJECT_SOURCE_DIR}/target_h/platform/cxxsupport"
"${PROJECT_SOURCE_DIR}/target_h/drivers" "${PROJECT_SOURCE_DIR}/target_h/drivers"
"${PROJECT_SOURCE_DIR}/stubs" "${PROJECT_SOURCE_DIR}/stubs"
"${PROJECT_SOURCE_DIR}/.." "${PROJECT_SOURCE_DIR}/.."

View File

@ -0,0 +1,110 @@
/* 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_ALGORITHM_
#define MSTD_ALGORITHM_
/* <mstd_algorithm>
*
* - provides <algorithm>
* - For ARM C 5, standard C++11/14 features:
* - std::min, std::max for std::initializer_list
* - std::all_of, std::any_of, std::none_of
* - std::find_if_not
* - std::equal (2-range forms)
* - std::copy_n, std::move, std::move_backward
* - mstd::min, mstd::max constexpr replacements
*/
#include <algorithm>
namespace mstd {
using std::min;
using std::max;
using std::minmax;
using std::initializer_list;
using std::all_of;
using std::any_of;
using std::none_of;
using std::for_each;
using std::find;
using std::find_if;
using std::find_if_not;
using std::find_end;
using std::find_first_of;
using std::adjacent_find;
using std::count;
using std::count_if;
using std::mismatch;
using std::equal;
using std::search;
using std::search_n;
using std::copy;
using std::copy_n;
using std::copy_if;
using std::move;
using std::move_backward;
using std::swap_ranges;
using std::iter_swap;
using std::transform;
using std::replace;
using std::replace_if;
using std::replace_copy;
using std::replace_copy_if;
using std::fill;
using std::fill_n;
using std::generate;
using std::generate_n;
using std::remove;
using std::remove_if;
using std::remove_copy;
using std::remove_copy_if;
using std::unique;
using std::unique_copy;
using std::reverse;
using std::reverse_copy;
using std::rotate;
using std::rotate_copy;
using std::partition;
using std::stable_partition;
using std::sort;
using std::stable_sort;
using std::partial_sort;
using std::partial_sort_copy;
using std::nth_element;
using std::lower_bound;
using std::upper_bound;
using std::equal_range;
using std::binary_search;
using std::merge;
using std::inplace_merge;
using std::includes;
using std::set_union;
using std::set_intersection;
using std::set_difference;
using std::set_symmetric_difference;
using std::push_heap;
using std::pop_heap;
using std::make_heap;
using std::sort_heap;
using std::min_element;
using std::max_element;
using std::lexicographical_compare;
using std::next_permutation;
using std::prev_permutation;
}
#endif // MSTD_ALGORITHM_

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2017 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_ATOMIC_
#define MSTD_ATOMIC_
#include <atomic>
namespace mstd {
using std::atomic;
using std::atomic_is_lock_free;
using std::atomic_store;
using std::atomic_store_explicit;
using std::atomic_load;
using std::atomic_load_explicit;
using std::atomic_exchange;
using std::atomic_exchange_explicit;
using std::atomic_compare_exchange_weak;
using std::atomic_compare_exchange_weak_explicit;
using std::atomic_compare_exchange_strong;
using std::atomic_compare_exchange_strong_explicit;
using std::atomic_fetch_add;
using std::atomic_fetch_add_explicit;
using std::atomic_fetch_sub;
using std::atomic_fetch_sub_explicit;
using std::atomic_fetch_and;
using std::atomic_fetch_and_explicit;
using std::atomic_fetch_or;
using std::atomic_fetch_or_explicit;
using std::atomic_fetch_xor;
using std::atomic_fetch_xor_explicit;
using std::atomic_flag;
using std::atomic_flag_test_and_set;
using std::atomic_flag_test_and_set_explicit;
using std::atomic_flag_clear;
using std::atomic_flag_clear_explicit;
using std::atomic_init;
using std::memory_order;
using std::kill_dependency;
using std::atomic_thread_fence;
using std::atomic_signal_fence;
}
#endif

View File

@ -0,0 +1,54 @@
/* 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_CSTDDEF_
#define MSTD_CSTDDEF_
/* <mstd_cstddef>
*
* - provides <cstddef>
* - For ARM C 5, standard C++11/14 features:
* - - adds macro replacements for alignof and alignas keywords
* - - adds missing std::nullptr_t
* - For all toolchains:
* - - MSTD_CONSTEXPR_XX_14 macros that can be used to mark
* things that are valid as constexpr only for C++14 or later,
* permitting constexpr use where ARM C 5 would reject it.
*/
#include <cstddef>
/* 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 MSTD_CONSTEXPR_FN_14 constexpr
#define MSTD_CONSTEXPR_OBJ_14 constexpr
#else
#define MSTD_CONSTEXPR_FN_14 inline
#define MSTD_CONSTEXPR_OBJ_14 const
#endif
namespace mstd
{
using std::size_t;
using std::ptrdiff_t;
using std::nullptr_t;
using std::max_align_t;
}
#endif // MSTD_CSTDDEF_

View File

@ -0,0 +1,141 @@
/* 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 tUNChe License.
*/
#ifndef MSTD_FUNCTIONAL_
#define MSTD_FUNCTIONAL_
/* <mstd_functional>
*
* - includes toolchain's <functional>
* - For ARM C 5, standard C++11/14 features:
* - std::mem_fn,
* - std::reference_wrapper, std::ref, std::cref
* - transparent std::plus<> etc
* - std::bit_and, std::bit_or, std::bit_xor, std::bit_not
* - For all toolchains, C++17/20 backports:
* - mbed::not_fn (C++17)
* - mbed::invoke (C++17)
* - mstd::unwrap_reference, mstd::unwrap_ref_decay (C++20)
*/
#include <functional>
#include <mstd_memory> // addressof
#include <mstd_utility> // forward
#include <mstd_type_traits>
namespace mstd {
// [func.invoke]
#if __cpp_lib_invoke >= 201411
using std::invoke;
#else
template <typename F, typename... Args>
invoke_result_t<F, Args...> invoke(F&& f, Args&&... args)
{
return impl::INVOKE(std::forward<F>(f), std::forward<Args>(args)...);
}
#endif // __cpp_lib_invoke
} // namespace mstd
namespace mstd {
using std::reference_wrapper;
using std::ref;
using std::cref;
using std::plus;
using std::minus;
using std::multiplies;
using std::divides;
using std::modulus;
using std::negate;
using std::equal_to;
using std::not_equal_to;
using std::greater;
using std::less;
using std::greater_equal;
using std::less_equal;
using std::logical_and;
using std::logical_or;
using std::logical_not;
using std::bit_and;
using std::bit_or;
using std::bit_xor;
using std::bit_not;
#if __cpp_lib_not_fn >= 201603
using std::not_fn;
#else
namespace impl {
// [func.not_fn]
template <typename F>
class not_fn_t {
std::decay_t<F> fn;
public:
explicit not_fn_t(F&& f) : fn(std::forward<F>(f)) { }
not_fn_t(const not_fn_t &other) = default;
not_fn_t(not_fn_t &&other) = default;
template<typename... Args>
auto operator()(Args&&... args) & -> decltype(!std::declval<invoke_result_t<std::decay_t<F> &, Args...>>())
{
return !mstd::invoke(fn, std::forward<Args>(args)...);
}
template<typename... Args>
auto operator()(Args&&... args) const & -> decltype(!std::declval<invoke_result_t<std::decay_t<F> const &, Args...>>())
{
return !mstd::invoke(fn, std::forward<Args>(args)...);
}
template<typename... Args>
auto operator()(Args&&... args) && -> decltype(!std::declval<invoke_result_t<std::decay_t<F>, Args...>>())
{
return !mstd::invoke(std::move(fn), std::forward<Args>(args)...);
}
template<typename... Args>
auto operator()(Args&&... args) const && -> decltype(!std::declval<invoke_result_t<std::decay_t<F> const, Args...>>())
{
return !mstd::invoke(std::move(fn), std::forward<Args>(args)...);
}
};
}
template <typename F>
impl::not_fn_t<F> not_fn_t(F&& f)
{
return impl::not_fn_t<F>(std::forward<F>(f));
}
#endif
/* C++20 unwrap_reference */
template <typename T>
struct unwrap_reference : type_identity<T> { };
template <typename T>
struct unwrap_reference<std::reference_wrapper<T>> : type_identity<T &> { };
template <typename T>
using unwrap_reference_t = typename unwrap_reference<T>::type;
/* C++20 unwrap_ref_decay */
template <typename T>
struct unwrap_ref_decay : unwrap_reference<std::decay_t<T>> { };
template <typename T>
using unwrap_ref_decay_t = typename unwrap_ref_decay<T>::type;
}
#endif // MSTD_FUNCTIONAL_

View File

@ -0,0 +1,149 @@
/* 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_ITERATOR_
#define MSTD_ITERATOR_
/* <mstd_iterator>
*
* - includes toolchain's <iterator>
* - For ARM C 5, C++11/14 features:
* - std::begin, std::end, etc
* - std::move_iterator, std::make_move_iterator
* - For all toolchains, C++17/20 backports:
* - mbed::size
* - mbed::ssize
* - mbed::empty
* - mbed::data
*/
#include <iterator>
#include <mstd_type_traits>
namespace mstd {
using std::initializer_list;
using std::iterator_traits;
// omitting deprecated std::iterator
using std::input_iterator_tag;
using std::output_iterator_tag;
using std::forward_iterator_tag;
using std::bidirectional_iterator_tag;
using std::random_access_iterator_tag;
using std::advance;
using std::distance;
using std::next;
using std::prev;
using std::reverse_iterator;
using std::make_reverse_iterator;
using std::back_insert_iterator;
using std::back_inserter;
using std::front_insert_iterator;
using std::front_inserter;
using std::insert_iterator;
using std::inserter;
using std::move_iterator;
using std::make_move_iterator;
using std::istream_iterator;
using std::ostream_iterator;
using std::istreambuf_iterator;
using std::ostreambuf_iterator;
using std::begin;
using std::end;
using std::cbegin;
using std::cend;
using std::rbegin;
using std::rend;
using std::crbegin;
using std::crend;
#if __cpp_lib_nonmember_container_access >= 201411
using std::size;
using std::empty;
using std::data;
#else
// [iterator.container]
template <class C>
constexpr auto size(const C &c) -> decltype(c.size())
{
return c.size();
}
template <class T, size_t N>
constexpr size_t size(const T (&)[N]) noexcept
{
return N;
}
template <class C>
constexpr auto empty(const C &c) -> decltype(c.empty())
{
return c.empty();
}
template <class T, size_t N>
constexpr bool empty(T (&)[N]) noexcept
{
return false;
}
template <class E>
constexpr bool empty(initializer_list<E> il)
{
return il.size() == 0;
}
template <class C>
constexpr auto data(C &c) -> decltype(c.data())
{
return c.data();
}
template <class C>
constexpr auto data(const C &c) -> decltype(c.data())
{
return c.data();
}
template <class T, size_t N>
constexpr T *data(T (&array)[N]) noexcept
{
return array;
}
template <class E>
constexpr const E *data(initializer_list<E> il)
{
return il.begin();
}
#endif
// C++20
template <class C>
constexpr auto ssize(const C &c) -> common_type_t<ptrdiff_t, make_signed_t<decltype(c.size())>>
{
return static_cast<common_type_t<ptrdiff_t, make_signed_t<decltype(c.size())>>>(c.size());
}
template <class T, ptrdiff_t N>
constexpr ptrdiff_t ssize(const T (&)[N]) noexcept
{
return N;
}
}
#endif // MSTD_ITERATOR_

View File

@ -0,0 +1,138 @@
/* 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_MEMORY_
#define MSTD_MEMORY_
/* <mstd_memory>
*
* - includes toolchain's <memory>
* - For ARM C 5, C++11/14 features:
* - std::align
* - std::addressof
* - std::uninitialized_copy_n
* - std::unique_ptr, std::make_unique, std::default_delete
* - For all toolchains, C++17 backports:
* - mstd::uninitialized_default_construct, mstd::uninitialized_value_construct
* - mstd::uninitialized_move, mstd::uninitialized_move_n
* - mstd::destroy_at, mstd::destroy, mstd::destroy_n
*/
#include <memory>
#include <mstd_type_traits>
#include <mstd_utility> // std::pair
#include <mstd_iterator> // std::iterator_traits
namespace mstd {
using std::align;
using std::allocator;
using std::addressof;
// [uninitialized.construct.default] (C++17)
template <class ForwardIterator, class Size>
void uninitialized_default_construct(ForwardIterator first, ForwardIterator last) {
for (; first != last; ++first) {
::new (static_cast<void*>(addressof(*first)))
typename std::iterator_traits<ForwardIterator>::value_type;
}
}
template <class ForwardIterator, class Size>
ForwardIterator uninitialized_default_construct_n(ForwardIterator first, Size n) {
for (; n; ++first, --n) {
::new (static_cast<void*>(addressof(*first)))
typename std::iterator_traits<ForwardIterator>::value_type;
}
return first;
}
// [uninitialized.construct.value] (C++17)
template <class ForwardIterator, class Size>
void uninitialized_value_construct(ForwardIterator first, ForwardIterator last) {
for (; first != last; ++first) {
::new (static_cast<void*>(addressof(*first)))
typename std::iterator_traits<ForwardIterator>::value_type();
}
}
template <class ForwardIterator, class Size>
ForwardIterator uninitialized_value_construct_n(ForwardIterator first, Size n) {
for (; n; ++first, --n) {
::new (static_cast<void*>(addressof(*first)))
typename std::iterator_traits<ForwardIterator>::value_type();
}
return first;
}
// [uninitialized.move] (C++17)
template <class InputIterator, class ForwardIterator>
ForwardIterator uninitialized_move(InputIterator first, InputIterator last, ForwardIterator result) {
for (; first != last; ++result, (void) ++first) {
::new (static_cast<void*>(addressof(*result)))
typename std::iterator_traits<ForwardIterator>::value_type(move(*first));
}
return result;
}
template <class InputIterator, class Size, class ForwardIterator>
std::pair<InputIterator, ForwardIterator> uninitialized_move_n(InputIterator first, Size n, ForwardIterator result) {
for ( ; n > 0; ++result, (void) ++first, --n) {
::new (static_cast<void*>(addressof(*result)))
typename std::iterator_traits<ForwardIterator>::value_type(std::move(*first));
}
return { first, result };
}
using std::uninitialized_copy;
using std::uninitialized_copy_n;
using std::uninitialized_fill;
using std::uninitialized_fill_n;
// [specialized.destroy] (C++17)
template <class T>
void destroy_at(T *location)
{
location->~T();
}
template <class ForwardIterator>
void destroy(ForwardIterator first, ForwardIterator last)
{
for (; first != last; ++first) {
destroy_at(addressof(*first));
}
}
template <class ForwardIterator, class Size>
ForwardIterator destroy_n(ForwardIterator first, Size n)
{
for (; n > 0; (void)++first, --n) {
destroy_at(addressof(*first));
}
return first;
}
using std::default_delete;
using std::unique_ptr;
using std::make_unique;
}
#endif // MSTD_MEMORY_

View File

@ -0,0 +1,92 @@
/* 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_MUTEX_
#define MSTD_MUTEX_
#include <mutex>
namespace mstd {
using std::defer_lock;
using std::defer_lock_t;
using std::try_to_lock;
using std::try_to_lock_t;
using std::adopt_lock;
using std::adopt_lock_t;
using std::lock_guard;
using std::unique_lock;
using std::try_lock;
using std::lock;
#if __cpp_lib_scoped_lock >= 201703
using std::scoped_lock;
#else
// [thread.lock.scoped]
// 2+ locks - use std::lock
template <class... MutexTypes>
class scoped_lock
#if 0 // no definition yet - needs tuple
tuple<MutexTypes &...> pm;
static void ignore(...) { }
public:
explicit scoped_lock(MutexTypes &... m) : pm(tie(m...)) { mstd::lock(m...); }
explicit scoped_lock(adopt_lock_t, MutexTypes &... m) noexcept : pm(mstd::tie(m...)) { }
~scoped_lock() { mstd::apply([](MutexTypes &... m) { ignore( (void(m.unlock()),0) ...); }, pm); }
scoped_lock(const scoped_lock &) = delete;
scoped_lock &operator=(const scoped_lock &) = delete;
}
#else
;
#endif
// 0 locks - no-op
template <>
class scoped_lock<> {
public:
explicit scoped_lock() = default;
explicit scoped_lock(adopt_lock_t) noexcept { }
~scoped_lock() = default;
scoped_lock(const scoped_lock &) = delete;
scoped_lock &operator=(const scoped_lock &) = delete;
};
// 1 lock - simple lock, equivalent to lock_guard<Mutex>
template <class Mutex>
class scoped_lock<Mutex> {
Mutex &pm;
public:
using mutex_type = Mutex;
explicit scoped_lock(Mutex &m) : pm(m) { m.lock(); }
explicit scoped_lock(adopt_lock_t, Mutex &m) noexcept : pm(m) { }
~scoped_lock() { pm.unlock(); }
scoped_lock(const scoped_lock &) = delete;
scoped_lock &operator=(const scoped_lock &) = delete;
};
#endif
using std::once_flag;
using std::call_once;
using std::mutex;
using std::recursive_mutex;
}
#endif // MSTD_MUTEX_

View File

@ -0,0 +1,483 @@
/* 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_TYPE_TRAITS_
#define MSTD_TYPE_TRAITS_
/* <mstd_type_traits>
*
* - includes toolchain's <type_traits>
* - For ARM C 5, standard C++11/14 features:
* - std::integral_constant, std::true_type, std::false_type
* - primary type categories (std::is_void, std::is_integral etc)
* - composite type categories (std::is_reference etc)
* - type properties (std::is_const, std::is_constructible etc), except std::is_final
* - type property queries (std::alignment_of, std::rank, std::extent)
* - type relations (std::is_same, std::is_base_of, std::is_convertible)
* - const-volatile modifications (std::remove_cv, std::add_const etc)
* - reference modifications (std::remove_reference, std::add_lvalue_reference etc)
* - sign modifications (std::make_signed, std::make_unsigned)
* - array modifications (std::remove_extent, std::remove_all_extents)
* - pointer modifications (std::remove_pointer, std::add_pointer)
* - other modifications:
* - std::aligned_storage
* - std::decay
* - std::enable_if
* - std::conditional
* - std::common_type
* - std::underlying_type
* - std::result_of
* - For all toolchains, C++17/20 backports:
* - mstd::type_identity
* - mstd::bool_constant
* - mstd::void_t
* - mstd::is_invocable, mbed::is_invocable_r, etc
* - mstd::invoke_result
* - logical operator traits (mstd::conjunction, mstd::disjunction, mstd::negation)
*/
#include <mstd_cstddef>
#include <type_traits>
// The template stuff in here is too confusing for astyle
// *INDENT-OFF*
namespace mstd {
/* 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 __cpp_lib_void_t >= 201411
using std::void_t;
#else
template <typename...>
using void_t = void;
#endif
/* C++17 bool_constant */
#if __cpp_lib_bool_constant >= 201505
using std::bool_constant;
#else
template <bool B>
using bool_constant = std::integral_constant<bool, B>;
#endif
/* Forward declarations */
#if __cpp_lib_is_invocable >= 201703
using std::invoke_result;
#else
template <typename F, typename... Args>
struct invoke_result;
#endif
using std::is_same;
using std::conditional;
using std::conditional_t;
using std::enable_if;
using std::enable_if_t;
using std::is_convertible;
using std::is_object;
using std::is_reference;
/* Reinvent or pull in good stuff not in C++14 into namespace mstd */
/* C++17 logical operations on traits */
#if __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 mstd::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 mstd
/* More post-C++14 stuff */
namespace mstd {
using std::remove_const;
using std::remove_const_t;
using std::remove_volatile;
using std::remove_volatile_t;
using std::remove_cv;
using std::remove_cv_t;
using std::add_const;
using std::add_const_t;
using std::add_volatile;
using std::add_volatile_t;
using std::add_cv;
using std::add_cv_t;
using std::remove_reference;
using std::remove_reference_t;
using std::add_lvalue_reference;
using std::add_rvalue_reference;
using std::is_void;
using std::is_null_pointer;
using std::is_integral;
using std::is_floating_point;
using std::is_array;
using std::is_pointer;
using std::is_lvalue_reference;
using std::is_rvalue_reference;
using std::is_enum;
using std::is_union;
using std::is_class;
using std::is_function;
using std::is_member_function_pointer;
using std::is_member_object_pointer;
using std::is_reference;
using std::is_arithmetic;
using std::is_fundamental;
using std::is_compound;
using std::is_member_pointer;
using std::is_scalar;
using std::is_object;
using std::is_const;
using std::is_volatile;
using std::is_trivial;
using std::is_trivially_copyable;
using std::is_standard_layout;
using std::is_pod;
using std::is_literal_type;
using std::is_empty;
using std::is_polymorphic;
using std::is_abstract;
using std::is_signed;
using std::is_unsigned;
using std::is_constructible;
using std::is_default_constructible;
using std::is_copy_constructible;
using std::is_move_constructible;
using std::is_assignable;
using std::is_copy_assignable;
using std::is_move_assignable;
using std::is_destructible;
using std::is_trivially_constructible;
using std::is_trivially_default_constructible;
using std::is_trivially_copy_constructible;
using std::is_trivially_move_constructible;
using std::is_trivially_assignable;
using std::is_trivially_copy_assignable;
using std::is_trivially_move_assignable;
using std::is_trivially_destructible;
// Exceptions are disabled in mbed, so short-circuit nothrow tests
// (Compilers don't make noexcept() return false with exceptions
// disabled, presumably to preserve binary compatibility, so the
// std versions of these are unduly pessimistic).
template <typename T, typename... Args>
struct is_nothrow_constructible : is_constructible<T, Args...> { };
template <typename T>
struct is_nothrow_default_constructible : is_default_constructible<T> { };
template <typename T>
struct is_nothrow_copy_constructible : is_copy_constructible<T> { };
template <typename T>
struct is_nothrow_move_constructible : is_move_constructible<T> { };
template <typename To, typename From>
struct is_nothrow_assignable: is_assignable<To, From> { };
template <typename T>
struct is_nothrow_copy_assignable : is_copy_assignable<T> { };
template <typename T>
struct is_nothrow_move_assignable : is_move_assignable<T> { };
using std::has_virtual_destructor;
using std::alignment_of;
using std::rank;
using std::extent;
using std::is_convertible;
using std::is_base_of;
using std::make_signed;
using std::make_signed_t;
using std::make_unsigned;
using std::make_unsigned_t;
using std::remove_extent;
using std::remove_extent_t;
using std::remove_all_extents;
using std::remove_all_extents_t;
using std::remove_pointer;
using std::remove_pointer_t;
using std::add_pointer;
using std::add_pointer_t;
using std::aligned_storage;
using std::aligned_storage_t;
using std::decay;
using std::decay_t;
using std::common_type;
using std::common_type_t;
using std::result_of;
using std::result_of_t;
/* 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;
/* C++20 unwrap_reference */
template <typename T>
struct unwrap_reference : type_identity<T> { };
template <typename T>
struct unwrap_reference<std::reference_wrapper<T>> : type_identity<T &> { };
template <typename T>
using unwrap_reference_t = typename unwrap_reference<T>::type;
/* C++20 unwrap_ref_decay */
template <typename T>
struct unwrap_ref_decay : unwrap_reference<std::decay_t<T>> { };
template <typename T>
using unwrap_ref_decay_t = typename unwrap_ref_decay<T>::type;
}
#if __cpp_lib_invoke < 201411
#include <utility> // want std::forward
#include <functional> // want std::reference_wrapper
#elif __cpp_lib_is_invocable < 201703
#include <functional> // want std::invoke
#endif
namespace mstd {
/* C++17 invoke_result, is_invocable, invoke */
#if __cpp_lib_is_invocable >= 201703
/* Library has complete suite - pull it into mstd */
using std::invoke_result;
using std::invoke_result_t;
using std::is_invocable;
using std::is_nothrow_invocable;
using std::is_invocable_r;
using std::is_nothrow_invocable_r;
#else // __cpp_lib_is_invocable
namespace impl {
#if __cpp_lib_invoke >= 201411
/* Library has just invoke - make it our impl::INVOKE so we can create invoke_result */
template <typename F, typename... Args>
using INVOKE = std::invoke<F, Args...>;
#else // __cpp_lib_invoke
/* Define our own INVOKE */
template <typename T>
struct is_reference_wrapper : std::false_type { };
template <typename T>
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type { };
/* F is pointer to member function, and 1st arg decays to matching class */
template<typename Base, typename F, typename T1, class... Args>
auto INVOKE(F Base::* fn, T1 &&target, Args &&...args)
// Noexcept specifications generate compiler errors unpacking args
//noexcept(noexcept((std::forward<T1>(target).*fn)(std::forward<Args>(args)...)))
-> std::enable_if_t<std::is_function<F>::value &&
std::is_base_of<Base, std::decay_t<T1>>::value,
decltype((std::forward<T1>(target).*fn)(std::forward<Args>(args)...))>
{
return (std::forward<T1>(target).*fn)(std::forward<Args>(args)...);
}
/* F is pointer to member function, and 1st arg is a reference wrapper */
template<typename Base, typename F, typename T1, class... Args>
auto INVOKE(F Base::* fn, T1 &&target, Args &&...args)
//noexcept(noexcept((std::forward<T1>(target).get().*fn)(std::forward<Args>(args)...)))
-> std::enable_if_t<std::is_function<F>::value &&
is_reference_wrapper<std::decay_t<T1>>::value,
decltype((std::forward<T1>(target).get().*fn)(std::forward<Args>(args)...))>
{
return (std::forward<T1>(target).get().*fn)(std::forward<Args>(args)...);
}
/* F is pointer to member function, and 1st arg doesn't match class and isn't reference wrapper - assume pointer */
template<typename Base, typename F, typename T1, class... Args>
auto INVOKE(F Base::* fn, T1 &&target, Args &&...args)
//noexcept(noexcept(((*std::forward<T1>(target)).*fn)(std::forward<Args>(args)...)))
-> std::enable_if_t<std::is_function<F>::value &&
!std::is_base_of<Base, std::decay_t<T1>>::value &&
!is_reference_wrapper<std::decay_t<T1>>::value,
decltype(((*std::forward<T1>(target)).*fn)(std::forward<Args>(args)...))>
{
return ((*std::forward<T1>(target)).*fn)(std::forward<Args>(args)...);
}
/* F is pointer to member object, and only arg decays to matching class */
template<typename Base, typename F, typename T1>
auto INVOKE(F Base::* obj, T1 &&target)
//noexcept(noexcept(std::forward<T1>(target).*obj))
-> std::enable_if_t<!std::is_function<F>::value &&
std::is_base_of<Base, std::decay_t<T1>>::value,
decltype(std::forward<T1>(target).*obj)>
{
return std::forward<T1>(target).*obj;
}
/* F is pointer to member object, and only arg is a reference wrapper */
template<typename Base, typename F, typename T1>
auto INVOKE(F Base::* obj, T1 &&target)
//noexcept(noexcept(std::forward<T1>(target).get().*obj))
-> std::enable_if_t<!std::is_function<F>::value &&
is_reference_wrapper<std::decay_t<T1>>::value,
decltype(std::forward<T1>(target).get().*obj)>
{
return std::forward<T1>(target).get().*obj;
}
/* F is pointer to member object, and only arg doesn't match class and isn't reference wrapper - assume pointer */
template<typename Base, typename F, typename T1>
auto INVOKE(F Base::* obj, T1 &&target)
//noexcept(noexcept((*std::forward<T1>(target)).*obj))
-> std::enable_if_t<!std::is_function<F>::value &&
!std::is_base_of<Base, std::decay_t<T1>>::value &&
!is_reference_wrapper<std::decay_t<T1>>::value,
decltype((*std::forward<T1>(target)).*obj)>
{
return (*std::forward<T1>(target)).*obj;
}
/* F is not a pointer to member */
template<typename F, typename... Args>
auto INVOKE(F&& f, Args&&... args)
//noexcept(noexcept(std::forward<F>(f)(std::forward<Args>(args)...)))
-> std::enable_if_t<!std::is_member_pointer<std::decay_t<F>>::value ||
(std::is_member_object_pointer<std::decay_t<F>>::value && sizeof...(args) != 1),
decltype(std::forward<F>(f)(std::forward<Args>(args)...))>
{
return std::forward<F>(f)(std::forward<Args>(args)...);
}
#endif // __cpp_lib_invoke
template <typename Void, typename F, typename... Args>
struct invoke_result { };
template <typename F, typename... Args> // void_t<decltype(INVOKE)> appears not to work here - why?
struct invoke_result<decltype(void(INVOKE(std::declval<F>(), std::declval<Args>()...))), F, Args...> :
type_identity<decltype(INVOKE(std::declval<F>(), std::declval<Args>()...))> { };
// This would be a lot shorter if we could get the detector idiom to work and use it
template <typename R, typename InvokeResult, typename = void>
struct is_invocable_r : std::false_type { };
template <typename R, typename InvokeResult>
struct is_invocable_r <R, InvokeResult, void_t<typename InvokeResult::type>> :
disjunction<std::is_void<R>, std::is_convertible<typename InvokeResult::type, R>> { };
template <typename R, typename InvokeResult, typename = void>
struct is_nothrow_invocable_r : std::false_type { };
template <typename R, typename InvokeResult>
struct is_nothrow_invocable_r<R, InvokeResult, void_t<typename InvokeResult::type>> :
disjunction<std::is_void<R>,
conjunction<std::is_convertible<typename InvokeResult::type, R>,
std::is_nothrow_constructible<R, typename InvokeResult::type>>> { };
} //namespace impl
template <class F, class... Args>
struct invoke_result : impl::invoke_result<void, F, Args...> { };
template <class F, class... Args>
using invoke_result_t = typename invoke_result<F, Args...>::type;
template <class F, class... Args>
struct is_invocable : impl::is_invocable_r<void, invoke_result<F, Args...>> { };
#if 0 // No exceptions in mbed OS
template <class F, class... Args>
struct is_nothrow_invocable : impl::is_nothrow_invocable_r<void, invoke_result<F, Args...>> { };
#else
template <class F, class... Args>
struct is_nothrow_invocable : impl::is_invocable_r<void, invoke_result<F, Args...>> { };
#endif
template <typename R, typename F, typename... Args>
struct is_invocable_r : impl::is_invocable_r<R, invoke_result<F, Args...>> { };
#if 0 // No exceptions in mbed OS
template <typename R, typename F, typename... Args>
struct is_nothrow_invocable_r : conjunction<impl::is_nothrow_invocable_r<R, invoke_result<F>>,
std::is_convertible<invoke_result_t<F, Args...>, R>> { };
#else
template <typename R, typename F, typename... Args>
struct is_nothrow_invocable_r : impl::is_invocable_r<R, invoke_result<F, Args...>> { };
#endif
#endif // __cpp_lib_is_invocable
} // namespace mstd
#endif /* MSTD_TYPE_TRAITS_ */

View File

@ -0,0 +1,75 @@
/* 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>
namespace mstd {
using std::swap;
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_