Skip to content

Commit 7a625c6

Browse files
authored
v2.1 (#17)
* v2.1 * add event reference * update only on real changes
1 parent 527420d commit 7a625c6

File tree

6 files changed

+89
-28
lines changed

6 files changed

+89
-28
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
33
# ---- Project ----
44

55
project(LarsEvent
6-
VERSION 2.0.3
6+
VERSION 2.1
77
LANGUAGES CXX
88
)
99

include/lars/event.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,11 @@ namespace lars{
6464
data->observers.emplace_back(StoredHandler{data->IDCounter,std::make_shared<Handler>(h)});
6565
return data->IDCounter++;
6666
}
67-
67+
68+
protected:
69+
Event(const Event &) = default;
70+
Event &operator=(const Event &) = default;
71+
6872
public:
6973

7074
struct Observer:public lars::Observer::Base{
@@ -100,9 +104,7 @@ namespace lars{
100104
Event():data(std::make_shared<Data>()){
101105
}
102106

103-
Event(const Event &) = delete;
104107
Event(Event &&other):Event(){ *this = std::move(other); }
105-
Event &operator=(const Event &) = delete;
106108
Event &operator=(Event &&other){
107109
std::swap(data, other.data);
108110
return *this;
@@ -142,5 +144,19 @@ namespace lars{
142144
}
143145

144146
};
147+
148+
template <typename ... Args> class EventReference: public Event<Args...> {
149+
protected:
150+
using Base = Event<Args...>;
151+
152+
public:
153+
EventReference(const Base &other):Base(other){}
154+
155+
EventReference &operator=(const Base &other){
156+
Base::operator=(other);
157+
return *this;
158+
}
159+
};
160+
145161

146162
}

include/lars/observable_value.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@
77

88
namespace lars {
99

10+
namespace observable_value_detail {
11+
// source: https://stackoverflow.com/questions/6534041/how-to-check-whether-operator-exists
12+
struct No {};
13+
template<typename T, typename Arg> No operator== (const T&, const Arg&);
14+
template<typename T, typename Arg = T> struct HasEqual {
15+
enum { value = !std::is_same<decltype(*(T*)(0) == *(Arg*)(0)), No>::value };
16+
};
17+
}
18+
1019
template <class T> class ObservableValue {
1120
protected:
1221
T value;
@@ -21,9 +30,17 @@ namespace lars {
2130
ObservableValue(ObservableValue &&) = delete;
2231
ObservableValue &operator=(ObservableValue &&) = delete;
2332

24-
template <typename ... Args> void set(Args ... args){
25-
value = T(std::forward<Args>(args)...);
26-
onChange.emit(value);
33+
template <typename ... Args> void set(Args && ... args){
34+
if constexpr (observable_value_detail::HasEqual<T>::value) {
35+
T newValue(std::forward<Args>(args)...);
36+
if (value != newValue) {
37+
value = std::move(newValue);
38+
onChange.emit(value);
39+
}
40+
} else {
41+
value = T(std::forward<Args>(args)...);
42+
onChange.emit(value);
43+
}
2744
}
2845

2946
template <typename ... Args> void setSilently(Args ... args){

tests/CMakeLists.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,18 @@ FetchContent_MakeAvailable(Catch2)
2323
# ---- Create binary ----
2424

2525
file(GLOB tests_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
26-
add_executable(lars-event-tests ${tests_sources})
27-
target_link_libraries(lars-event-tests PUBLIC Catch2 LarsEvent)
28-
set_target_properties(lars-event-tests PROPERTIES CXX_STANDARD 17 COMPILE_FLAGS "-Wall -pedantic -Wextra -Werror")
26+
add_executable(LarsEventTests ${tests_sources})
27+
target_link_libraries(LarsEventTests PUBLIC Catch2 LarsEvent)
28+
set_target_properties(LarsEventTests PROPERTIES CXX_STANDARD 17 COMPILE_FLAGS "-Wall -pedantic -Wextra -Werror")
2929

3030
# ---- Add tests ----
3131

3232
ENABLE_TESTING()
33-
ADD_TEST(lars-event-tests lars-event-tests)
33+
ADD_TEST(LarsEventTests LarsEventTests)
3434

3535
# ---- code coverage ----
3636

3737
if (${ENABLE_TEST_COVERAGE})
38-
set_target_properties(lars-event-tests PROPERTIES CXX_STANDARD 17 COMPILE_FLAGS "-O0 -g -fprofile-arcs -ftest-coverage --coverage")
39-
target_link_options(lars-event-tests PUBLIC "--coverage")
38+
set_target_properties(LarsEventTests PROPERTIES CXX_STANDARD 17 COMPILE_FLAGS "-O0 -g -fprofile-arcs -ftest-coverage --coverage")
39+
target_link_options(LarsEventTests PUBLIC "--coverage")
4040
endif()

tests/event.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ using namespace lars;
77
// instantiate template for coverage
88
template class lars::Event<>;
99

10-
TEST_CASE("Event"){
10+
TEST_CASE("Event", "[event]"){
1111

1212
SECTION("connect and observe"){
1313
lars::Event<> event;
@@ -117,3 +117,15 @@ TEST_CASE("Event"){
117117

118118
}
119119

120+
TEST_CASE("EventReference", "[event]"){
121+
lars::Event<> onA, onB;
122+
lars::EventReference<> onR(onA);
123+
unsigned aCount = 0, bCount = 0;
124+
onR.connect([&](){ aCount++; });
125+
onA.emit();
126+
onR = onB;
127+
onR.connect([&](){ bCount++; });
128+
onB.emit();
129+
REQUIRE(aCount == 1);
130+
REQUIRE(bCount == 1);
131+
}

tests/observable_value.cpp

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,44 @@
22

33
#include <lars/observable_value.h>
44

5+
using namespace lars;
6+
57
// instantiate templates for coverage
68
template class lars::ObservableValue<int>;
79
template class lars::DependentObservableValue<int,int,int>;
810

9-
TEST_CASE("Observable Value") {
10-
using namespace lars;
11-
12-
ObservableValue value(0);
13-
14-
unsigned total = 0;
15-
value.onChange.connect([&](auto &v){ total+=v; });
11+
TEST_CASE("ObservableValue", "[observable_value]") {
12+
int current = 0;
13+
ObservableValue value(current);
14+
unsigned changes = 0;
15+
value.onChange.connect([&](auto &v){
16+
REQUIRE(current == v);
17+
changes++;
18+
});
1619
REQUIRE(*value == 0);
17-
value.set(1);
18-
value.set(2);
19-
REQUIRE(total == 3);
20+
current++;
21+
value.set(current);
22+
value.set(current);
23+
value.set(current);
24+
current++;
25+
value.set(current);
26+
value.set(current);
27+
REQUIRE(changes == 2);
2028
REQUIRE(*value == 2);
2129
}
2230

23-
TEST_CASE("Dependent Observable Value") {
24-
using namespace lars;
31+
TEST_CASE("ObservableValue without comparison operator", "[observable_value]") {
32+
struct A{ };
33+
ObservableValue<A> value;
34+
unsigned changes = 0;
35+
value.onChange.connect([&](auto &){ changes++; });
36+
value.set();
37+
value.set();
38+
value.set();
39+
REQUIRE(changes == 3);
40+
}
2541

42+
TEST_CASE("Dependent Observable Value", "[observable_value]") {
2643
ObservableValue a(1);
2744
ObservableValue b(1);
2845
DependentObservableValue sum([](auto a, auto b){ return a+b; },a,b);
@@ -48,9 +65,8 @@ TEST_CASE("Dependent Observable Value") {
4865
REQUIRE(*prod == 10);
4966
}
5067

51-
TEST_CASE("Operators") {
68+
TEST_CASE("Operators", "[observable_value]") {
5269
using namespace lars;
53-
5470
struct A { int a = 0; };
5571
ObservableValue<A> value;
5672
REQUIRE(value->a == 0);

0 commit comments

Comments
 (0)