Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add <mstd_xxx> C++ headers #11039

Merged
merged 11 commits into from Jul 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .astyleignore
Expand Up @@ -20,6 +20,7 @@
^features/storage/filesystem/littlefs/littlefs/
^features/unsupported/
^hal/storage_abstraction
^platform/cxxsupport
^rtos/TARGET_CORTEX/rtx4
^rtos/TARGET_CORTEX/rtx5
^targets
Expand Down
18 changes: 11 additions & 7 deletions TESTS/mbed_platform/atomic/main.cpp
Expand Up @@ -18,6 +18,8 @@
#include "unity/unity.h"
#include "utest/utest.h"

#include <mstd_atomic>

#if !MBED_CONF_RTOS_PRESENT
#error [NOT_SUPPORTED] test not supported
#endif
Expand All @@ -28,6 +30,8 @@ using utest::v1::Case;

namespace {

using mstd::atomic;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mbed.h is included above, so there's using namespace std and using mstd:atomic that both brings atomic in the global namespace.

Copy link
Contributor Author

@kjbracey kjbracey Jul 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually pulling it into this unnamed namespace.

I previously claimed that a global-scope using mstd::atomic would override a more general using namespace std for atomic, and I'm sure I'd tested this, but seemed not to work here.

But putting it into an inner namespace like this does work - it searches innermost namespace first.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I somehow missed the anonymous namespace declaration. Good to know.


/* Lock-free operations will be much faster - keep runtime down */
#define ADD_UNLOCKED_ITERATIONS (SystemCoreClock / 1000)
#define ADD_LOCKED_ITERATIONS (SystemCoreClock / 8000)
Expand All @@ -53,7 +57,7 @@ struct add_release_incrementer {
static void op(A *ptr)
{
for (long i = add_iterations(*ptr); i > 0; i--) {
ptr->fetch_add(1, mbed::memory_order_release);
ptr->fetch_add(1, mstd::memory_order_release);
}
}
};
Expand Down Expand Up @@ -120,8 +124,8 @@ void test_atomic_add()
{
struct {
volatile T nonatomic1;
Atomic<T> atomic1;
volatile Atomic<T> atomic2; // use volatile just to exercise the templates' volatile methods
atomic<T> atomic1;
volatile atomic<T> atomic2; // use volatile just to exercise the templates' volatile methods
volatile T nonatomic2;
} data = { 0, { 0 }, { 1 }, 0 }; // test initialisation

Expand Down Expand Up @@ -201,17 +205,17 @@ void struct_incrementer_b(A *data)
template<typename T, size_t N>
void test_atomic_struct()
{
TEST_ASSERT_EQUAL(N, sizeof(Atomic<T>));
TEST_ASSERT_EQUAL(N, sizeof(atomic<T>));

// Small structures don't have value constructor implemented;
Atomic<T> data;
atomic<T> data;
atomic_init(&data, T{0, 0, 0});

Thread t1(osPriorityNormal, THREAD_STACK);
Thread t2(osPriorityNormal, THREAD_STACK);

TEST_ASSERT_EQUAL(osOK, t1.start(callback(struct_incrementer_a<Atomic<T> >, &data)));
TEST_ASSERT_EQUAL(osOK, t2.start(callback(struct_incrementer_b<Atomic<T> >, &data)));
TEST_ASSERT_EQUAL(osOK, t1.start(callback(struct_incrementer_a<atomic<T> >, &data)));
TEST_ASSERT_EQUAL(osOK, t2.start(callback(struct_incrementer_b<atomic<T> >, &data)));

for (long i = add_iterations(data); i > 0; i--) {
T curval = data, newval;
Expand Down
1 change: 1 addition & 0 deletions UNITTESTS/CMakeLists.txt
Expand Up @@ -95,6 +95,7 @@ set(unittest-includes-base
"${PROJECT_SOURCE_DIR}/target_h/events"
"${PROJECT_SOURCE_DIR}/target_h/events/equeue"
"${PROJECT_SOURCE_DIR}/target_h/platform"
"${PROJECT_SOURCE_DIR}/target_h/platform/cxxsupport"
"${PROJECT_SOURCE_DIR}/target_h/drivers"
"${PROJECT_SOURCE_DIR}/stubs"
"${PROJECT_SOURCE_DIR}/.."
Expand Down
110 changes: 110 additions & 0 deletions UNITTESTS/target_h/platform/cxxsupport/mstd_algorithm
@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not have <mstd_initializer_list> for initialiser list ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good general question - for consistency, it would indeed make sense to have mstd_xxx for all headers we think are good, to "approve" them, and to allow a single using namespace mstd, even if we currently don't need any adaptation, and it would just copy everything over. If you want to fill them in, I wouldn't object, at least for "not-too-bloaty-for-embedded" stuff.

* - 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we get constexpr replacement if std::min and std::max are directly imported ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mstd::min and mstd::max. For ARM C 5 those are these replacement implementations, rather than being aliased to std::min like for the other toolchains.

*/

#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_
58 changes: 58 additions & 0 deletions UNITTESTS/target_h/platform/cxxsupport/mstd_atomic
@@ -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
54 changes: 54 additions & 0 deletions UNITTESTS/target_h/platform/cxxsupport/mstd_cstddef
@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure to agree with that definition; in C++14 a constexpr object can invoke non const member function in a constexpr context. In C++11; constexpr equals const.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constexpr implies const method in a C++11, yes, but I don't think that's an issue here. That would be used as:

MSTD_CONSTEXPR_FN_14 int my_complicated_method() /* const or not */ {
      // some-multi-line thing
     return whatever;
}

Flipping from constexpr in C++14 to inline in C++11 seems right to me - either member or non-member.

Or were you misunderstanding OBJ - that was intended for a constexpr object:

static MSTD_CONSTEXPR_OBJ_14 int npos = -1;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of the following case:

struct Foo { 
    constexpr Foo() { }

    // not a const member function!
    MSTD_CONSTEXPR_FN_14 int get_something() { /* ... */ }
};

static MSTD_CONSTEXPR_OBJ_14 Foo foo;

void foo() { 
   // error call of a non const function on a const object
   auto v = foo.get_something();
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems fine to me? In C++14, the function is constexpr, not const, and it fails to compile.

In C++11, the function is inline, not const, and it fails to compile.

#endif

namespace mstd
{
using std::size_t;
using std::ptrdiff_t;
using std::nullptr_t;
using std::max_align_t;

}

#endif // MSTD_CSTDDEF_