Import Mbed OS hard-float snapshot
This commit is contained in:
65
platform/cxxsupport/README.md
Normal file
65
platform/cxxsupport/README.md
Normal file
@@ -0,0 +1,65 @@
|
||||
## C++ support ##
|
||||
|
||||
Mbed OS supports a number of toolchains, and the files here provide support
|
||||
to smooth over C++ library differences.
|
||||
|
||||
The current baseline version is C++14, so we hope for full C++14 library
|
||||
support.
|
||||
|
||||
Omissions are:
|
||||
* areas like chrono and threads, which depend on OS support, where
|
||||
retargeting is not complete.
|
||||
* atomics and shared pointers, as atomic implementations for ARMv6-M
|
||||
are not provided by all toolchains, and the ARMv7-M implementations include
|
||||
DMB instructions we do not want/need for non-SMP.
|
||||
|
||||
User code should normally be able to include C++14 headers and get
|
||||
most expected functionality. (But bear in mind that many C++ library
|
||||
features like streams and STL containers are quite heavy and may
|
||||
not be appropriate for small embedded use).
|
||||
|
||||
However, ARM C 5 has only C++11 language support (at least a large subset), and
|
||||
no C++11/14 library. For the headers that are totally new in C++11,
|
||||
they are provided here in TOOLCHAIN_ARMC5 under their standard C++11 name.
|
||||
(Eg `<array>`, `<cinttypes>`, `<initializer_list>`, `<type_traits>`).
|
||||
But for headers that already exist in C++03, extensions are required.
|
||||
|
||||
So, to support ARM C 5, use `#include <mstd_utility>`, rather than
|
||||
`#include <utility>` if you need C++11 or later features from that header.
|
||||
|
||||
Each `mstd_` file includes the toolchain's corresponding header file,
|
||||
which will provide its facilities in `namespace std`. Any missing
|
||||
C++11/C++14 facilities for ARM C 5 are also provided in `namespace std`.
|
||||
|
||||
Then APIs from `namespace std` are added to `namespace mstd`, with adjustment
|
||||
if necessary, and APIs being omitted if not suitable for embedded use.
|
||||
For example:
|
||||
|
||||
* `std::size_t` (`<cstddef>`) - toolchain's `std::size_t`
|
||||
* `mstd::size_t` (`<mstd_cstddef>`) - alias for `std::size_t`
|
||||
* `std::swap` (`<utility>`) - toolchain's `std::swap` (not move-capable for ARM C 5)
|
||||
* `mstd::swap` (`<mstd_utility>`) - alias for `std::swap` or move-capable ARM C 5 replacement.
|
||||
* `std::atomic` (`<atomic>`) - toolchain's `std::atomic` (not implemented for IAR ARMv6)
|
||||
* `mstd::atomic` (`<mstd_atomic>`) - custom `mstd::atomic` for all toolchains
|
||||
* `std::void_t` (`<type_traits>`) - toolchain's `std::void_t` if available (it's C++17 so likely not)
|
||||
* `mstd::void_t` (`<mstd_type_traits>`) - alias for `std::void_t` if available, else local implementation
|
||||
* `std::thread` (`<thread>`) - toolchain's `std::thread` - not available or ported
|
||||
* `mstd::thread` - doesn't exist - `mstd` APIs only exist if available on all toolchains
|
||||
|
||||
Using `std::xxx` will generally work, but may suffer from toolchain variance. `mstd::xxx` should always be better - it will either be an alias to `std::xxx`, or work better for Mbed OS.
|
||||
|
||||
In portable code, when compiling for non-Mbed OS, the directive `namespace mstd == std` can be used
|
||||
to cover the difference:
|
||||
|
||||
```C++
|
||||
// my_code.c
|
||||
#if TARGET_LIKE_MBED
|
||||
#include <mstd_atomic>
|
||||
#else
|
||||
#include <atomic>
|
||||
namespace mstd = std;
|
||||
#endif
|
||||
|
||||
mstd::atomic my_atomic;
|
||||
```
|
||||
|
||||
99
platform/cxxsupport/mstd_algorithm
Normal file
99
platform/cxxsupport/mstd_algorithm
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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_
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace mstd
|
||||
{
|
||||
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;
|
||||
using std::min;
|
||||
using std::max;
|
||||
using std::minmax;
|
||||
}
|
||||
|
||||
#endif // MSTD_ALGORITHM_
|
||||
1225
platform/cxxsupport/mstd_atomic
Normal file
1225
platform/cxxsupport/mstd_atomic
Normal file
File diff suppressed because it is too large
Load Diff
69
platform/cxxsupport/mstd_cstddef
Normal file
69
platform/cxxsupport/mstd_cstddef
Normal file
@@ -0,0 +1,69 @@
|
||||
/* 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.
|
||||
* - - MSTD_CONSTEXPR_XX_11 macros that can be used to permit
|
||||
* constexpr alternatives for C.
|
||||
*/
|
||||
|
||||
#if __cplusplus
|
||||
|
||||
#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
|
||||
|
||||
#define MSTD_CONSTEXPR_FN_11 constexpr
|
||||
#define MSTD_CONSTEXPR_OBJ_11 constexpr
|
||||
|
||||
namespace mstd {
|
||||
using std::size_t;
|
||||
using std::ptrdiff_t;
|
||||
using std::nullptr_t;
|
||||
using std::max_align_t;
|
||||
|
||||
}
|
||||
|
||||
#else // __cplusplus
|
||||
|
||||
#define MSTD_CONSTEXPR_FN_14 inline
|
||||
#define MSTD_CONSTEXPR_OBJ_14 const
|
||||
#define MSTD_CONSTEXPR_FN_11 inline
|
||||
#define MSTD_CONSTEXPR_OBJ_11 const
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // MSTD_CSTDDEF_
|
||||
136
platform/cxxsupport/mstd_functional
Normal file
136
platform/cxxsupport/mstd_functional
Normal file
@@ -0,0 +1,136 @@
|
||||
/* 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 all toolchains, C++17/20 backports:
|
||||
* - mstd::not_fn (C++17)
|
||||
* - mstd::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(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_
|
||||
150
platform/cxxsupport/mstd_iterator
Normal file
150
platform/cxxsupport/mstd_iterator
Normal file
@@ -0,0 +1,150 @@
|
||||
/* 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::make_reverse_iterator
|
||||
* - std::move_iterator, std::make_move_iterator
|
||||
* - For all toolchains, C++17/20 backports:
|
||||
* - mstd::size
|
||||
* - mstd::ssize
|
||||
* - mstd::empty
|
||||
* - mstd::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_
|
||||
138
platform/cxxsupport/mstd_memory
Normal file
138
platform/cxxsupport/mstd_memory
Normal 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_
|
||||
419
platform/cxxsupport/mstd_mutex
Normal file
419
platform/cxxsupport/mstd_mutex
Normal file
@@ -0,0 +1,419 @@
|
||||
/* 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_
|
||||
|
||||
/* <mstd_mutex>
|
||||
*
|
||||
* - includes toolchain's <mutex> (if any)
|
||||
* - For toolchains not providing them, local implementation of C++11/14 equivalent features:
|
||||
* - mstd::defer_lock etc
|
||||
* - mstd::lock_guard
|
||||
* - mstd::unique_lock
|
||||
* - mstd::lock
|
||||
* - mstd::try_lock
|
||||
* - If not available, local version of:
|
||||
* - mstd::scoped_lock (C++17)
|
||||
* - For all toolchains, local implementations:
|
||||
* - mstd::call_once, mstd::once_flag
|
||||
* - mstd::mutex, mstd::recursive_mutex
|
||||
*
|
||||
* Toolchains will vary greatly in how much is in namespace std, depending on retargetting.
|
||||
*/
|
||||
|
||||
#if !defined __IAR_SYSTEMS_ICC__
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
#if MBED_CONF_RTOS_PRESENT
|
||||
#include "platform/SingletonPtr.h"
|
||||
#include "rtos/Mutex.h"
|
||||
#endif
|
||||
|
||||
#include <mstd_utility>
|
||||
#include <mstd_functional>
|
||||
#include <mstd_tuple>
|
||||
#include <chrono>
|
||||
|
||||
#include "mbed_atomic.h"
|
||||
#include "mbed_assert.h"
|
||||
|
||||
extern "C" int __cxa_guard_acquire(int *guard_object_p);
|
||||
extern "C" void __cxa_guard_release(int *guard_object_p);
|
||||
|
||||
// IAR does not provide <mutex> at all - it errors on inclusion
|
||||
// ARMC6 provides it, but it is empty unless _ARM_LIBCPP_EXTERNAL_THREADS is defined
|
||||
// GCC has it, and only the actual `mutex` types are conditional on _GLIBCXX_HAS_GTHREADS
|
||||
// So pick up std stuff, unless ICC, or ARMC6-without-threads
|
||||
namespace mstd {
|
||||
#if !defined __IAR_SYSTEMS_ICC__ && !defined _LIBCPP_HAS_NO_THREADS
|
||||
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;
|
||||
#else
|
||||
// [thread.lock]
|
||||
struct defer_lock_t { };
|
||||
struct try_to_lock_t { };
|
||||
struct adopt_lock_t { };
|
||||
constexpr defer_lock_t defer_lock;
|
||||
constexpr try_to_lock_t try_to_lock;
|
||||
constexpr adopt_lock_t adopt_lock;
|
||||
|
||||
// [thread.lock.guard]
|
||||
template <class Mutex>
|
||||
class lock_guard {
|
||||
Mutex ±
|
||||
public:
|
||||
using mutex_type = Mutex;
|
||||
explicit lock_guard(Mutex &m) : pm(m) { m.lock(); }
|
||||
lock_guard(Mutex &m, adopt_lock_t) noexcept : pm(m) { }
|
||||
~lock_guard() { pm.unlock(); }
|
||||
|
||||
lock_guard(const lock_guard &) = delete;
|
||||
lock_guard &operator=(const lock_guard &) = delete;
|
||||
};
|
||||
|
||||
|
||||
// [thread.lock.unique]
|
||||
template<class Mutex>
|
||||
class unique_lock {
|
||||
public:
|
||||
using mutex_type = Mutex;
|
||||
|
||||
unique_lock() noexcept : pm(nullptr), owns(false) { }
|
||||
explicit unique_lock(mutex_type &m) : pm(&m), owns(true) { m.lock(); }
|
||||
unique_lock(mutex_type &m, defer_lock_t) noexcept : pm(&m), owns(false) { }
|
||||
unique_lock(mutex_type &m, try_to_lock_t) : pm(&m), owns(m.try_lock()) { }
|
||||
unique_lock(mutex_type &m, adopt_lock_t) : pm(&m), owns(true) { }
|
||||
template <class Clock, class Duration>
|
||||
unique_lock(mutex_type &m, const std::chrono::time_point<Clock, Duration> &abs_time) : pm(&m), owns(m.try_lock_until(abs_time)) { }
|
||||
template <class Rep, class Period>
|
||||
unique_lock(mutex_type &m, const std::chrono::duration<Rep, Period> &rel_time) : pm(&m), owns(m.try_lock_for(rel_time)) { }
|
||||
~unique_lock() { if (owns) pm->unlock(); }
|
||||
|
||||
unique_lock(const unique_lock &) = delete;
|
||||
unique_lock &operator=(const unique_lock &) = delete;
|
||||
|
||||
unique_lock(unique_lock &&u) noexcept : pm(u.pm), owns(u.owns) {
|
||||
u.pm = nullptr;
|
||||
u.owns = false;
|
||||
}
|
||||
|
||||
unique_lock &operator=(unique_lock &&u) noexcept {
|
||||
if (owns) {
|
||||
pm->unlock();
|
||||
}
|
||||
pm = mstd::exchange(u.pm, nullptr);
|
||||
owns = mstd::exchange(u.owns, false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void lock() {
|
||||
MBED_ASSERT(!owns);
|
||||
pm->lock();
|
||||
owns = true;
|
||||
}
|
||||
|
||||
bool try_lock() {
|
||||
MBED_ASSERT(!owns);
|
||||
return owns = pm->try_lock();
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const std::chrono::time_point<Clock, Duration> &abs_time) {
|
||||
MBED_ASSERT(!owns);
|
||||
return owns = pm->try_lock_until(abs_time);
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const std::chrono::duration<Rep, Period> &rel_time) {
|
||||
MBED_ASSERT(!owns);
|
||||
return owns = pm->try_lock_for(rel_time);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
MBED_ASSERT(owns);
|
||||
pm->unlock();
|
||||
owns = false;
|
||||
}
|
||||
|
||||
void swap(unique_lock &u) noexcept {
|
||||
mstd::swap(pm, u.pm);
|
||||
mstd::swap(owns, u.owns);
|
||||
}
|
||||
|
||||
mutex_type *release() noexcept {
|
||||
owns = false;
|
||||
return mstd::exchange(pm, nullptr);
|
||||
}
|
||||
|
||||
bool owns_lock() const noexcept {
|
||||
return owns;
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return owns;
|
||||
}
|
||||
|
||||
mutex_type *mutex() const noexcept {
|
||||
return pm;
|
||||
}
|
||||
|
||||
private:
|
||||
mutex_type *pm;
|
||||
bool owns;
|
||||
};
|
||||
|
||||
template<class Mutex>
|
||||
void swap(unique_lock<Mutex> &x, unique_lock<Mutex> &y) noexcept
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
// [thread.lock.algorithm]
|
||||
template <class L1, class L2>
|
||||
int try_lock(L1 &l1, L2 &l2)
|
||||
{
|
||||
unique_lock<L1> u1(l1, try_to_lock);
|
||||
if (!u1) {
|
||||
return 0;
|
||||
}
|
||||
if (l2.try_lock()) {
|
||||
u1.release();
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class L1, class L2, class L3, class... LN>
|
||||
int try_lock(L1 &l1, L2 &l2, L3 &l3, LN &... ln)
|
||||
{
|
||||
unique_lock<L1> u1(l1, try_to_lock);
|
||||
if (!u1) {
|
||||
return 0;
|
||||
}
|
||||
int result = mstd::try_lock(l2, l3, ln...);
|
||||
if (result == -1) {
|
||||
u1.release(); // make u1 release l1 so it remains locked when we return
|
||||
return -1;
|
||||
} else {
|
||||
return result + 1; // u1 unlocks l1 when we return
|
||||
}
|
||||
}
|
||||
|
||||
// Howard Hinnant's "smart" algorithm from
|
||||
// http://howardhinnant.github.io/dining_philosophers.html
|
||||
//
|
||||
// 1) Lock a mutex
|
||||
// 2) Try-lock all the rest
|
||||
// 3) If try-lock fails, retry, but starting with the mutex whose try-lock failed
|
||||
// (so we expect to block on that lock)
|
||||
//
|
||||
// Do not bother with the "polite" yield, as it adds an OS dependency and we
|
||||
// want to optimise for space, not speed.
|
||||
// Use of unique_lock is necessary to make the code correct in case of exceptions;
|
||||
// we don't strictly require this, but stick with the RAII form nevertheless -
|
||||
// overhead of unique_lock should be minimal with optimisation enabled.
|
||||
template <class L1, class L2>
|
||||
void lock(L1 &l1, L2 &l2)
|
||||
{
|
||||
for (;;) {
|
||||
{
|
||||
unique_lock<L1> u1(l1);
|
||||
if (l2.try_lock()) {
|
||||
u1.release(); // make u1 release l1 so it remains locked when we return
|
||||
return;
|
||||
}
|
||||
} // u1 unlocks l1 when we leave scope
|
||||
{
|
||||
unique_lock<L2> u2(l2);
|
||||
if (l1.try_lock()) {
|
||||
u2.release();
|
||||
return;
|
||||
}
|
||||
} // u2 unlocks l2 when we leave scope
|
||||
}
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
template <class L1, class L2, class L3, class... LN>
|
||||
void lock_from(int first, L1 &l1, L2 &l2, L3 &l3, LN &... ln)
|
||||
{
|
||||
for (;;) {
|
||||
switch (first) {
|
||||
case 1:
|
||||
{
|
||||
unique_lock<L1> u1(l1);
|
||||
first = mstd::try_lock(l2, l3, ln...);
|
||||
if (first == -1) {
|
||||
u1.release();
|
||||
return;
|
||||
}
|
||||
}
|
||||
first += 2;
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
unique_lock<L2> u2(l2);
|
||||
first = mstd::try_lock(l3, ln..., l1);
|
||||
if (first == -1) {
|
||||
u2.release();
|
||||
return;
|
||||
}
|
||||
}
|
||||
first += 3;
|
||||
if (first > 3 + sizeof...(LN)) {
|
||||
first = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return impl::lock_from(first - 2, l3, ln..., l1, l2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class L1, class L2, class L3, class... LN>
|
||||
void lock(L1 &l1, L2 &l2, L3 &l3, LN &... ln)
|
||||
{
|
||||
impl::lock_from(1, l1, l2, l3, ln...);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#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 {
|
||||
mstd::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;
|
||||
};
|
||||
|
||||
// 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 ±
|
||||
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
|
||||
|
||||
// [thread.once.onceflag]
|
||||
// Always local implementation - need to investigate GCC + ARMC6 retargetting
|
||||
struct once_flag {
|
||||
constexpr once_flag() noexcept : __guard() { }
|
||||
once_flag(const once_flag &) = delete;
|
||||
once_flag &operator=(const once_flag &) = delete;
|
||||
~once_flag() = default;
|
||||
private:
|
||||
template <class Callable, class... Args>
|
||||
friend void call_once(once_flag &flag, Callable&& f, Args&&... args);
|
||||
int __guard;
|
||||
};
|
||||
|
||||
// [thread.once.callonce]
|
||||
template <class Callable, class... Args>
|
||||
void call_once(once_flag &flag, Callable&& f, Args&&... args)
|
||||
{
|
||||
if (!(core_util_atomic_load_explicit((uint8_t *)&flag.__guard, mbed_memory_order_acquire) & 1)) {
|
||||
if (__cxa_guard_acquire(&flag.__guard)) {
|
||||
mstd::invoke(mstd::forward<Callable>(f), mstd::forward<Args>(args)...);
|
||||
__cxa_guard_release(&flag.__guard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [thread.mutex.class]
|
||||
// Always local implementation - need to investigate GCC + ARMC6 retargetting
|
||||
#if MBED_CONF_RTOS_PRESENT
|
||||
class _Mutex_base {
|
||||
// Constructor must be constexpr - we are required to initialise on first use
|
||||
// not in our constructor. (So that mutex use in static constructors is safe).
|
||||
SingletonPtr<rtos::Mutex> _pm;
|
||||
public:
|
||||
constexpr _Mutex_base() noexcept = default;
|
||||
~_Mutex_base();
|
||||
_Mutex_base(const _Mutex_base &) = delete;
|
||||
_Mutex_base &operator=(const _Mutex_base &) = delete;
|
||||
void lock();
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
};
|
||||
#else
|
||||
class _Mutex_base {
|
||||
public:
|
||||
constexpr _Mutex_base() noexcept = default;
|
||||
~_Mutex_base() = default;
|
||||
_Mutex_base(const _Mutex_base &) = delete;
|
||||
_Mutex_base &operator=(const _Mutex_base &) = delete;
|
||||
void lock() { }
|
||||
bool try_lock() { return true; }
|
||||
void unlock() { }
|
||||
};
|
||||
#endif
|
||||
|
||||
// We don't currently distinguish implementations (and aren't required to -
|
||||
// current thread not owning a non-recursive one is a precondition, we don't
|
||||
// have to take any special action).
|
||||
class mutex : public _Mutex_base {
|
||||
};
|
||||
|
||||
// [thread.mutex.recursive]
|
||||
class recursive_mutex : public _Mutex_base {
|
||||
};
|
||||
|
||||
} // namespace mstd
|
||||
|
||||
#endif // MSTD_MUTEX_
|
||||
50
platform/cxxsupport/mstd_mutex.cpp
Normal file
50
platform/cxxsupport/mstd_mutex.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#include <mstd_mutex>
|
||||
|
||||
#if MBED_CONF_RTOS_PRESENT
|
||||
|
||||
/* SharedPointer<Mutex> lazy-init kerfuffle will generate code - don't inline it */
|
||||
namespace mstd {
|
||||
|
||||
// Lock and try lock use SingletonPtr::get() to lazy-init
|
||||
void _Mutex_base::lock()
|
||||
{
|
||||
_pm.get()->lock();
|
||||
}
|
||||
|
||||
bool _Mutex_base::try_lock()
|
||||
{
|
||||
return _pm.get()->trylock();
|
||||
}
|
||||
|
||||
// Unlock knows it must have been initted, so optimise with get_no_init()
|
||||
void _Mutex_base::unlock()
|
||||
{
|
||||
_pm.get_no_init()->unlock();
|
||||
}
|
||||
|
||||
// And don't forget to destroy - SingletonPtr doesn't do it automatically
|
||||
_Mutex_base::~_Mutex_base()
|
||||
{
|
||||
_pm.destroy();
|
||||
}
|
||||
|
||||
} // namespace mstd
|
||||
|
||||
#endif
|
||||
56
platform/cxxsupport/mstd_new
Normal file
56
platform/cxxsupport/mstd_new
Normal file
@@ -0,0 +1,56 @@
|
||||
/* 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_NEW_
|
||||
#define MSTD_NEW_
|
||||
|
||||
/* <mstd_new>
|
||||
*
|
||||
* - includes toolchain's <new>
|
||||
* - For all toolchains, C++17 backports:
|
||||
* - mstd::launder
|
||||
*/
|
||||
|
||||
#include <new>
|
||||
#if __cpp_lib_launder < 201606
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
namespace mstd
|
||||
{
|
||||
using std::nothrow_t;
|
||||
using std::nothrow;
|
||||
using std::new_handler;
|
||||
using std::set_new_handler;
|
||||
|
||||
#if __cpp_lib_launder >= 201606
|
||||
using std::launder;
|
||||
#else
|
||||
template <typename T>
|
||||
constexpr T *launder(T *p) noexcept
|
||||
{
|
||||
static_assert(!std::is_function<T>::value && !std::is_void<T>::value, "Can only launder complete object types");
|
||||
#if defined __clang__ || __GNUC__ >= 9
|
||||
return __builtin_launder(p);
|
||||
#else
|
||||
return p;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace mstd
|
||||
|
||||
#endif // MSTD_NEW_
|
||||
93
platform/cxxsupport/mstd_tuple
Normal file
93
platform/cxxsupport/mstd_tuple
Normal file
@@ -0,0 +1,93 @@
|
||||
/* 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 LEOR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef MSTD_TUPLE_
|
||||
#define MSTD_TUPLE_
|
||||
|
||||
/* <mstd_tuple>
|
||||
*
|
||||
* - includes toolchain's <tuple>
|
||||
* - For all toolchains, C++17 backports:
|
||||
* - mstd::apply
|
||||
* - mstd::make_from_tuple
|
||||
*/
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#if __cpp_lib_apply < 201603 || __cpp_lib_make_from_tuple < 201606
|
||||
#include <mstd_utility> // integer_sequence
|
||||
#endif
|
||||
#if __cpp_lib_apply < 201603
|
||||
#include <mstd_functional> // invoke
|
||||
#endif
|
||||
|
||||
namespace mstd {
|
||||
using std::tuple;
|
||||
using std::ignore;
|
||||
using std::make_tuple;
|
||||
using std::forward_as_tuple;
|
||||
using std::tie;
|
||||
using std::tuple_cat;
|
||||
using std::tuple_size;
|
||||
using std::tuple_element;
|
||||
using std::tuple_element_t;
|
||||
using std::get;
|
||||
|
||||
// [tuple.apply]
|
||||
#if __cpp_lib_apply >= 201603
|
||||
using std::apply;
|
||||
#else
|
||||
namespace impl {
|
||||
template <class F, class Tuple, size_t... I>
|
||||
invoke_result_t<F, tuple_element_t<I, Tuple>...> apply(F&& f, Tuple&& t, std::index_sequence<I...>)
|
||||
{
|
||||
return mstd::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...);
|
||||
}
|
||||
}
|
||||
|
||||
// apply<F, Tuple> - works also for tuple-like objects such as array or pair
|
||||
// user-defined types can specialize std::get and std::tuple_size to make this work
|
||||
template <class F, class Tuple>
|
||||
auto apply(F&& f, Tuple&& t) ->
|
||||
decltype(impl::apply(std::forward<F>(f), std::forward<Tuple>(t), std::make_index_sequence<tuple_size<remove_reference_t<Tuple>>::value>{}))
|
||||
{
|
||||
return impl::apply(std::forward<F>(f), std::forward<Tuple>(t),
|
||||
std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __cpp_lib_make_from_tuple >= 201606
|
||||
using std::make_from_tuple;
|
||||
#else
|
||||
namespace impl {
|
||||
template <class T, class Tuple, size_t... I>
|
||||
T make_from_tuple(Tuple&& t, std::index_sequence<I...>)
|
||||
{
|
||||
return T(std::get<I>(std::forward<Tuple>(t))...);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class Tuple>
|
||||
T make_from_tuple(Tuple&& t)
|
||||
{
|
||||
return impl::make_from_tuple<T>(std::forward<Tuple>(t),
|
||||
std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace mstd
|
||||
|
||||
#endif // MSTD_TUPLE_
|
||||
475
platform/cxxsupport/mstd_type_traits
Normal file
475
platform/cxxsupport/mstd_type_traits
Normal file
@@ -0,0 +1,475 @@
|
||||
/* 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 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)
|
||||
* - mstd::is_constant_evaluated
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
} // namespace mstd
|
||||
|
||||
namespace mstd {
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
/* C++20 is_constant_evaluated */
|
||||
constexpr bool is_constant_evaluated() noexcept
|
||||
{
|
||||
#ifdef __clang__
|
||||
#if __has_builtin(__builtin_is_constant_evaluated)
|
||||
#define MSTD_HAS_IS_CONSTANT_EVALUATED 1
|
||||
return __builtin_is_constant_evaluated();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
#elif __GNUC__ >= 9
|
||||
#define MSTD_HAS_IS_CONSTANT_EVALUATED 1
|
||||
return __builtin_is_constant_evaluated();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MSTD_HAS_IS_CONSTANT_EVALUATED
|
||||
#define MSTD_CONSTEXPR_IF_HAS_IS_CONSTANT_EVALUATED constexpr
|
||||
#else
|
||||
#define MSTD_CONSTEXPR_IF_HAS_IS_CONSTANT_EVALUATED
|
||||
#endif
|
||||
|
||||
} // namespace mstd
|
||||
|
||||
#endif /* MSTD_TYPE_TRAITS_ */
|
||||
77
platform/cxxsupport/mstd_utility
Normal file
77
platform/cxxsupport/mstd_utility
Normal file
@@ -0,0 +1,77 @@
|
||||
/* 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 {
|
||||
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;
|
||||
using std::swap;
|
||||
// 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_
|
||||
Reference in New Issue
Block a user