Skip to content

Commit 009ff7a

Browse files
authored
Merge pull request #12036 from kjbracey-arm/callback_fiddle
Callback extension and optimisation
2 parents 2736896 + d09d854 commit 009ff7a

File tree

12 files changed

+859
-285
lines changed

12 files changed

+859
-285
lines changed

TESTS/mbed_functional/callback/main.cpp

Lines changed: 202 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,27 @@
1818
#include "greentea-client/test_env.h"
1919
#include "unity.h"
2020
#include "utest.h"
21+
#include <mstd_functional>
2122

2223
using namespace utest::v1;
2324

25+
template <typename T>
26+
using func0_type = T();
27+
28+
template <typename T>
29+
using func1_type = T(T);
30+
31+
template <typename T>
32+
using func2_type = T(T, T);
33+
34+
template <typename T>
35+
using func3_type = T(T, T, T);
36+
37+
template <typename T>
38+
using func4_type = T(T, T, T, T);
39+
40+
template <typename T>
41+
using func5_type = T(T, T, T, T, T);
2442

2543
// static functions
2644
template <typename T>
@@ -523,13 +541,17 @@ void test_dispatch0()
523541
Verifier<T>::verify0(&const_volatile_void_func0<T>, (const volatile Thing<T> *)&thing);
524542
Verifier<T>::verify0(callback(static_func0<T>));
525543

526-
Callback<T()> cb(static_func0);
544+
Callback<T()> cb(static_func0<T>);
527545
Verifier<T>::verify0(cb);
528-
cb = static_func0;
546+
TEST_ASSERT_TRUE(cb);
547+
func0_type<T> *p = nullptr;
548+
cb = p;
549+
TEST_ASSERT_FALSE(cb);
550+
cb = static_func0<T>;
529551
Verifier<T>::verify0(cb);
530552
cb = {&bound_func0<T>, &thing};
531553
Verifier<T>::verify0(&cb, &Callback<T()>::call);
532-
Verifier<T>::verify0(&Callback<T()>::thunk, (void *)&cb);
554+
Verifier<T>::verify0(&Callback<T()>::thunk, &cb);
533555
}
534556

535557
template <typename T>
@@ -554,9 +576,13 @@ void test_dispatch1()
554576
Verifier<T>::verify1(&const_volatile_void_func1<T>, (const volatile Thing<T> *)&thing);
555577
Verifier<T>::verify1(callback(static_func1<T>));
556578

557-
Callback<T(T)> cb(static_func1);
579+
Callback<T(T)> cb(static_func1<T>);
558580
Verifier<T>::verify1(cb);
559-
cb = static_func1;
581+
TEST_ASSERT_TRUE(cb);
582+
func1_type<T> *p = nullptr;
583+
cb = p;
584+
TEST_ASSERT_FALSE(cb);
585+
cb = static_func1<T>;
560586
Verifier<T>::verify1(cb);
561587
cb = {&bound_func1<T>, &thing};
562588
Verifier<T>::verify1(&cb, &Callback<T(T)>::call);
@@ -585,9 +611,13 @@ void test_dispatch2()
585611
Verifier<T>::verify2(&const_volatile_void_func2<T>, (const volatile Thing<T> *)&thing);
586612
Verifier<T>::verify2(callback(static_func2<T>));
587613

588-
Callback<T(T, T)> cb(static_func2);
614+
Callback<T(T, T)> cb(static_func2<T>);
589615
Verifier<T>::verify2(cb);
590-
cb = static_func2;
616+
TEST_ASSERT_TRUE(cb);
617+
func2_type<T> *p = nullptr;
618+
cb = p;
619+
TEST_ASSERT_FALSE(cb);
620+
cb = static_func2<T>;
591621
Verifier<T>::verify2(cb);
592622
cb = {&bound_func2<T>, &thing};
593623
Verifier<T>::verify2(&cb, &Callback<T(T, T)>::call);
@@ -616,9 +646,13 @@ void test_dispatch3()
616646
Verifier<T>::verify3(&const_volatile_void_func3<T>, (const volatile Thing<T> *)&thing);
617647
Verifier<T>::verify3(callback(static_func3<T>));
618648

619-
Callback<T(T, T, T)> cb(static_func3);
649+
Callback<T(T, T, T)> cb(static_func3<T>);
620650
Verifier<T>::verify3(cb);
621-
cb = static_func3;
651+
TEST_ASSERT_TRUE(cb);
652+
func3_type<T> *p = nullptr;
653+
cb = p;
654+
TEST_ASSERT_FALSE(cb);
655+
cb = static_func3<T>;
622656
Verifier<T>::verify3(cb);
623657
cb = {&bound_func3<T>, &thing};
624658
Verifier<T>::verify3(&cb, &Callback<T(T, T, T)>::call);
@@ -647,9 +681,13 @@ void test_dispatch4()
647681
Verifier<T>::verify4(&const_volatile_void_func4<T>, (const volatile Thing<T> *)&thing);
648682
Verifier<T>::verify4(callback(static_func4<T>));
649683

650-
Callback<T(T, T, T, T)> cb(static_func4);
684+
Callback<T(T, T, T, T)> cb(static_func4<T>);
651685
Verifier<T>::verify4(cb);
652-
cb = static_func4;
686+
TEST_ASSERT_TRUE(cb);
687+
func4_type<T> *p = nullptr;
688+
cb = p;
689+
TEST_ASSERT_FALSE(cb);
690+
cb = static_func4<T>;
653691
Verifier<T>::verify4(cb);
654692
cb = {&bound_func4<T>, &thing};
655693
Verifier<T>::verify4(&cb, &Callback<T(T, T, T, T)>::call);
@@ -678,15 +716,159 @@ void test_dispatch5()
678716
Verifier<T>::verify5(&const_volatile_void_func5<T>, (const volatile Thing<T> *)&thing);
679717
Verifier<T>::verify5(callback(static_func5<T>));
680718

681-
Callback<T(T, T, T, T, T)> cb(static_func5);
719+
Callback<T(T, T, T, T, T)> cb(static_func5<T>);
682720
Verifier<T>::verify5(cb);
683-
cb = static_func5;
721+
TEST_ASSERT_TRUE(cb);
722+
func5_type<T> *p = nullptr;
723+
cb = p;
724+
TEST_ASSERT_FALSE(cb);
725+
cb = static_func5<T>;
684726
Verifier<T>::verify5(cb);
685727
cb = {&bound_func5<T>, &thing};
686728
Verifier<T>::verify5(&cb, &Callback<T(T, T, T, T, T)>::call);
729+
#if 0
687730
Verifier<T>::verify5(&Callback<T(T, T, T, T, T)>::thunk, (void *)&cb);
731+
#endif
688732
}
689733

734+
#include <mstd_functional>
735+
736+
struct TrivialFunctionObject {
737+
TrivialFunctionObject(int n) : val(n)
738+
{
739+
}
740+
741+
int operator()(int x) const
742+
{
743+
return x + val;
744+
}
745+
private:
746+
int val;
747+
};
748+
749+
/* Exact count of copy, construction and destruction may vary depending on
750+
* copy elision by compiler, but the derived live count can be relied upon.
751+
*/
752+
static int construct_count;
753+
static int destruct_count;
754+
static int copy_count;
755+
756+
static int live_count()
757+
{
758+
return construct_count - destruct_count;
759+
}
760+
761+
struct FunctionObject {
762+
FunctionObject(int n) : val(n)
763+
{
764+
construct_count++;
765+
}
766+
767+
FunctionObject(const FunctionObject &other) : val(other.val)
768+
{
769+
construct_count++;
770+
copy_count++;
771+
}
772+
773+
~FunctionObject()
774+
{
775+
destruct_count++;
776+
destroyed = true;
777+
}
778+
779+
int operator()(int x) const
780+
{
781+
return destroyed ? -1000 : x + val;
782+
}
783+
private:
784+
const int val;
785+
bool destroyed = false;
786+
};
787+
788+
void test_trivial()
789+
{
790+
TrivialFunctionObject fn(1);
791+
TEST_ASSERT_EQUAL(2, fn(1));
792+
Callback<int(int)> cb(fn);
793+
TEST_ASSERT_TRUE(cb);
794+
TEST_ASSERT_EQUAL(2, cb(1));
795+
fn = 5;
796+
TEST_ASSERT_EQUAL(6, fn(1));
797+
TEST_ASSERT_EQUAL(2, cb(1));
798+
cb = std::ref(fn);
799+
fn = 10;
800+
TEST_ASSERT_EQUAL(11, fn(1));
801+
TEST_ASSERT_EQUAL(11, cb(1));
802+
cb = TrivialFunctionObject(3);
803+
TEST_ASSERT_EQUAL(7, cb(4));
804+
cb = nullptr;
805+
TEST_ASSERT_FALSE(cb);
806+
cb = TrivialFunctionObject(7);
807+
Callback<int(int)> cb2(cb);
808+
TEST_ASSERT_EQUAL(8, cb(1));
809+
TEST_ASSERT_EQUAL(9, cb2(2));
810+
cb2 = cb;
811+
TEST_ASSERT_EQUAL(6, cb2(-1));
812+
cb = cb;
813+
TEST_ASSERT_EQUAL(8, cb(1));
814+
cb = std::negate<int>();
815+
TEST_ASSERT_EQUAL(-4, cb(4));
816+
cb = [](int x) {
817+
return x - 7;
818+
};
819+
TEST_ASSERT_EQUAL(1, cb(8));
820+
cb = cb2 = nullptr;
821+
TEST_ASSERT_FALSE(cb);
822+
}
823+
824+
#if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
825+
void test_nontrivial()
826+
{
827+
{
828+
FunctionObject fn(1);
829+
TEST_ASSERT_EQUAL(1, construct_count);
830+
TEST_ASSERT_EQUAL(0, destruct_count);
831+
TEST_ASSERT_EQUAL(2, fn(1));
832+
Callback<int(int)> cb(fn);
833+
TEST_ASSERT_TRUE(cb);
834+
TEST_ASSERT_EQUAL(2, live_count());
835+
TEST_ASSERT_EQUAL(2, cb(1));
836+
cb = std::ref(fn);
837+
TEST_ASSERT_EQUAL(1, live_count());
838+
TEST_ASSERT_EQUAL(5, cb(4));
839+
cb = FunctionObject(3);
840+
TEST_ASSERT_EQUAL(2, live_count());
841+
TEST_ASSERT_EQUAL(7, cb(4));
842+
cb = nullptr;
843+
TEST_ASSERT_FALSE(cb);
844+
TEST_ASSERT_EQUAL(1, live_count());
845+
cb = FunctionObject(7);
846+
TEST_ASSERT_EQUAL(2, live_count());
847+
int old_copy_count = copy_count;
848+
Callback<int(int)> cb2(cb);
849+
TEST_ASSERT_EQUAL(old_copy_count + 1, copy_count);
850+
TEST_ASSERT_EQUAL(3, live_count());
851+
TEST_ASSERT_EQUAL(8, cb(1));
852+
TEST_ASSERT_EQUAL(9, cb2(2));
853+
old_copy_count = copy_count;
854+
cb2 = cb;
855+
TEST_ASSERT_EQUAL(old_copy_count + 1, copy_count);
856+
TEST_ASSERT_EQUAL(3, live_count());
857+
TEST_ASSERT_EQUAL(6, cb2(-1));
858+
int old_construct_count = construct_count;
859+
old_copy_count = copy_count;
860+
cb = cb;
861+
TEST_ASSERT_EQUAL(3, live_count());
862+
TEST_ASSERT_EQUAL(old_construct_count, construct_count);
863+
TEST_ASSERT_EQUAL(old_copy_count, copy_count);
864+
cb = cb2 = nullptr;
865+
TEST_ASSERT_FALSE(cb);
866+
TEST_ASSERT_EQUAL(1, live_count());
867+
}
868+
TEST_ASSERT_EQUAL(0, live_count());
869+
}
870+
#endif
871+
690872

691873
// Test setup
692874
utest::v1::status_t test_setup(const size_t number_of_cases)
@@ -702,7 +884,10 @@ Case cases[] = {
702884
Case("Testing callbacks with 2 uint64s", test_dispatch2<uint64_t>),
703885
Case("Testing callbacks with 3 uint64s", test_dispatch3<uint64_t>),
704886
Case("Testing callbacks with 4 uint64s", test_dispatch4<uint64_t>),
887+
// IAR currently crashes at link time with this test - skip it as it's well beyond anything needed by real code
888+
#ifndef __ICCARM__
705889
Case("Testing callbacks with 5 uint64s", test_dispatch5<uint64_t>),
890+
#endif
706891
#elif DO_SMALL_TEST
707892
Case("Testing callbacks with 0 uchars", test_dispatch0<unsigned char>),
708893
Case("Testing callbacks with 1 uchars", test_dispatch1<unsigned char>),
@@ -717,6 +902,10 @@ Case cases[] = {
717902
Case("Testing callbacks with 3 ints", test_dispatch3<int>),
718903
Case("Testing callbacks with 4 ints", test_dispatch4<int>),
719904
Case("Testing callbacks with 5 ints", test_dispatch5<int>),
905+
Case("Testing trivial function object", test_trivial),
906+
#if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
907+
Case("Testing non-trivial function object", test_nontrivial),
908+
#endif
720909
#endif
721910
};
722911

TESTS/mbed_platform/Transaction/main.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@ void test_Transaction_init()
5858
TEST_ASSERT_EQUAL(rx_buffer_size, test_transaction.get_transaction()->rx_length);
5959
TEST_ASSERT_EQUAL(event_id, test_transaction.get_transaction()->event);
6060
TEST_ASSERT_EQUAL(word_width, test_transaction.get_transaction()->width);
61-
TEST_ASSERT_EQUAL(callback, test_transaction.get_transaction()->callback);
61+
#if MBED_CONF_PLATFORM_CALLBACK_COMPARABLE
62+
TEST_ASSERT_TRUE(callback == test_transaction.get_transaction()->callback);
63+
#else
64+
TEST_ASSERT_FALSE(nullptr == test_transaction.get_transaction()->callback)
65+
#endif
6266
}
6367

6468
/** Test Transaction class - creation without initialisation

TESTS/network/emac/emac_util.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,6 @@ char emac_if_get_trace_level();
102102

103103
void emac_if_trace_to_ascii_hex_dump(const char *prefix, int len, char *data);
104104

105-
void emac_if_link_state_change_cb(void *data, bool up);
106-
107105
unsigned char *emac_if_get_own_addr(void);
108106

109107
int emac_if_get_mtu_size();

UNITTESTS/features/netsocket/NetworkInterface/unittest.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
# UNIT TESTS
44
####################
55

6+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_PLATFORM_CALLBACK_COMPARABLE")
7+
68
# Source files
79
set(unittest-sources
810
../features/netsocket/SocketAddress.cpp
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2019 ARM Limited
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#ifndef MSTD_NEW_
18+
#define MSTD_NEW_
19+
20+
/* <mstd_new>
21+
*
22+
* - includes toolchain's <new>
23+
* - For all toolchains, C++17 backports:
24+
* - mstd::launder
25+
*/
26+
27+
#include <new>
28+
#if __cpp_lib_launder < 201606
29+
#include <type_traits>
30+
#endif
31+
32+
namespace mstd
33+
{
34+
using std::nothrow_t;
35+
using std::nothrow;
36+
using std::new_handler;
37+
using std::set_new_handler;
38+
39+
#if __cpp_lib_launder >= 201606
40+
using std::launder;
41+
#else
42+
template <typename T>
43+
constexpr T *launder(T *p) noexcept
44+
{
45+
static_assert(!std::is_function<T>::value && !std::is_void<T>::value, "Can only launder complete object types");
46+
#if defined __clang__ || __GNUC__ >= 9
47+
return __builtin_launder(p);
48+
#else
49+
return p;
50+
#endif
51+
}
52+
#endif
53+
54+
} // namespace mstd
55+
56+
#endif // MSTD_NEW_

0 commit comments

Comments
 (0)