diff --git a/include/boost/sml.hpp b/include/boost/sml.hpp index a493433c..783d344e 100644 --- a/include/boost/sml.hpp +++ b/include/boost/sml.hpp @@ -658,11 +658,14 @@ class queue_event { } public: + constexpr queue_event() : dtor(nullptr) {} constexpr queue_event(queue_event &&other) : id(other.id), dtor(other.dtor), move(other.move) { move(data, static_cast(other)); } constexpr queue_event &operator=(queue_event &&other) { - dtor(data); + if (dtor != nullptr) { + dtor(data); + } id = other.id; dtor = other.dtor; move = other.move; @@ -678,7 +681,11 @@ class queue_event { move = &move_impl; new (&data) T(static_cast(object)); } - ~queue_event() { dtor(data); } + ~queue_event() { + if (dtor) { + dtor(data); + } + } alignas(alignment) aux::byte data[size]; int id = -1; diff --git a/test/ft/actions_defer.cpp b/test/ft/actions_defer.cpp index 8e294b67..84202724 100644 --- a/test/ft/actions_defer.cpp +++ b/test/ft/actions_defer.cpp @@ -11,6 +11,8 @@ #include #include +#include "static_deque.h" + namespace sml = boost::sml; struct event1 {}; @@ -294,9 +296,9 @@ test defer_and_action = [] { struct c { auto operator()() { using namespace sml; - auto action1 = [this]{ calls += "a1|"; }; - auto action2 = [this]{ calls += "a2|"; }; - auto action3 = [this]{ calls += "a3|"; }; + auto action1 = [this] { calls += "a1|"; }; + auto action2 = [this] { calls += "a2|"; }; + auto action3 = [this] { calls += "a3|"; }; // clang-format off return make_transition_table( @@ -340,4 +342,25 @@ test defer_multi = [] { sml::sm> sm{}; sm.process_event(event1()); expect(sm.is(sml::X)); +}; + +template +using MinimalStaticDeque10 = MinimalStaticDeque; + +test defer_minimal_static_deque = [] { + const auto c = [] { + using namespace sml; + // clang-format off + return make_transition_table( + *state1 + event / defer, + state1 + event = state2, + state2 + event = X + ); + // clang-format off + }; + + sml::sm> sm{c}; + sm.process_event(event1()); + sm.process_event(event2()); + expect(sm.is(sml::X)); }; \ No newline at end of file diff --git a/test/ft/actions_process.cpp b/test/ft/actions_process.cpp index 31d9c642..3a9331dd 100644 --- a/test/ft/actions_process.cpp +++ b/test/ft/actions_process.cpp @@ -11,6 +11,8 @@ #include #include +#include "static_queue.h" + namespace sml = boost::sml; struct e1 {}; @@ -332,3 +334,37 @@ test process_between_substates = [] { expect(sm.is)>(sml::X)); expect(sm.is)>(sml::X)); }; + +template +using MinimalStaticQueue10 = MinimalStaticQueue; + +test queue_process_events_static_queue = [] { + struct c { + std::vector calls; + + auto operator()() { + using namespace sml; + + const auto a0 = [this] { calls.push_back(0); }; + const auto a1 = [this] { calls.push_back(1); }; + const auto a2 = [this] { calls.push_back(2); }; + + // clang-format off + return make_transition_table( + * idle + on_entry / (process(e1()), process(e2()), a0) + , idle + event / a1 + , idle + event / a2 = X + ); + // clang-format on + } + }; + + sml::sm> sm{}; + expect(sm.is(sml::X)); + + const c& c_ = sm; + expect(3u == c_.calls.size()); + expect(0 == c_.calls[0]); + expect(1 == c_.calls[1]); + expect(2 == c_.calls[2]); +}; \ No newline at end of file diff --git a/test/ft/actions_process_n_defer.cpp b/test/ft/actions_process_n_defer.cpp index 387fcb65..53cf62f5 100644 --- a/test/ft/actions_process_n_defer.cpp +++ b/test/ft/actions_process_n_defer.cpp @@ -11,6 +11,9 @@ #include #include +#include "static_deque.h" +#include "static_queue.h" + namespace sml = boost::sml; struct e1 {}; @@ -114,3 +117,34 @@ test process_n_defer_again = [] { std::cout << calls << "\n"; expect(calls == "|s3_entry|e1|e1|e1"); }; + +template +using MinimalStaticDeque10 = MinimalStaticDeque; + +template +using MinimalStaticQueue10 = MinimalStaticQueue; + +test mix_process_n_defer_at_init_static_queue = [] { + struct c { + auto operator()() { + using namespace sml; + // clang-format off + return make_transition_table( + * s1 + on_entry / process(e1{}) + , s1 + event / defer = s2 + , s2 / defer = s3 + , s3 + event / process(e2{}) + , s3 + event / defer = s4 + , s4 + event = s5 + , s5 = s6 + , s6 + on_entry<_> / process(e3{}) + , s6 + event = s7 + , s7 = X + ); + // clang-format on + } + }; + + sml::sm, sml::defer_queue> sm{}; + expect(sm.is(sml::X)); +}; \ No newline at end of file diff --git a/test/ft/static_deque.h b/test/ft/static_deque.h new file mode 100644 index 00000000..e4eb7471 --- /dev/null +++ b/test/ft/static_deque.h @@ -0,0 +1,78 @@ +#ifndef STATIC_DEQUE_H +#define STATIC_DEQUE_H + +#include +#include + +template +struct MinimalStaticDeque { + std::array queue_data{}; + std::size_t current_index = 0; + + using value_type = typename decltype(queue_data)::value_type; + using reference = typename decltype(queue_data)::reference; + using const_reference = typename decltype(queue_data)::const_reference; + using size_type = typename decltype(queue_data)::size_type; + using difference_type = typename decltype(queue_data)::difference_type; + using pointer = typename decltype(queue_data)::pointer; + using const_pointer = typename decltype(queue_data)::const_pointer; + using iterator = typename decltype(queue_data)::iterator; + using const_iterator = typename decltype(queue_data)::const_iterator; + using reverse_iterator = typename decltype(queue_data)::reverse_iterator; + using const_reverse_iterator = typename decltype(queue_data)::const_reverse_iterator; + + void push_back(T&& t) { queue_data[current_index++] = std::move(t); } + T& front() { + if (current_index == 0) { + throw std::out_of_range("queue is empty"); + } + return queue_data[0]; + } + T& back() { + if (current_index == 0) { + throw std::out_of_range("queue is empty"); + } + return queue_data[current_index - 1]; + } + void pop_front() { + if (current_index == 0) { + throw std::out_of_range("queue is empty"); + } + std::move(std::next(queue_data.begin()), queue_data.end(), queue_data.begin()); + current_index--; + } + void pop_back() { // removes the last element + if (current_index == 0) { + throw std::out_of_range("queue is empty"); + } + current_index--; + } + void push_front(T&& value) { + if (current_index == Size) { + throw std::runtime_error("queue is full"); + } + std::move_backward(begin(), end(), std::next(end())); + queue_data[0] = std::move(value); + current_index++; + } + bool empty() const { return current_index == 0; } + + iterator begin() { return queue_data.begin(); } + const_iterator cbegin() const { return queue_data.cbegin(); } + + iterator end() { return std::next(queue_data.begin(), current_index); } + const_iterator cend() const { return std::next(queue_data.begin(), current_index); } + + iterator erase(const_iterator pos) { + if (pos == end()) { + throw std::out_of_range("queue is empty"); + } + const auto position = std::distance(cbegin(), pos); + auto start = queue_data.begin() + position; + std::move(std::next(start), end(), start); + current_index--; + return start; + } +}; + +#endif // STATIC_DEQUE_H diff --git a/test/ft/static_queue.h b/test/ft/static_queue.h new file mode 100644 index 00000000..4e738148 --- /dev/null +++ b/test/ft/static_queue.h @@ -0,0 +1,50 @@ +#ifndef STATIC_QUEUE_H +#define STATIC_QUEUE_H + +#include +#include + +template +struct MinimalStaticQueue { + std::array queue_data{}; + std::size_t current_index = 0; + + using value_type = typename decltype(queue_data)::value_type; + using reference = typename decltype(queue_data)::reference; + using const_reference = typename decltype(queue_data)::const_reference; + using size_type = typename decltype(queue_data)::size_type; + using difference_type = typename decltype(queue_data)::difference_type; + using pointer = typename decltype(queue_data)::pointer; + using const_pointer = typename decltype(queue_data)::const_pointer; + using iterator = typename decltype(queue_data)::iterator; + using const_iterator = typename decltype(queue_data)::const_iterator; + using reverse_iterator = typename decltype(queue_data)::reverse_iterator; + using const_reverse_iterator = typename decltype(queue_data)::const_reverse_iterator; + + void push(T&& t) { queue_data[current_index++] = std::move(t); } + T& front() { + if (current_index == 0) { + throw std::out_of_range("queue is empty"); + } + return queue_data[0]; + } + T& back() { + if (current_index == 0) { + throw std::out_of_range("queue is empty"); + } + return queue_data[current_index - 1]; + } + iterator begin() { return queue_data.begin(); } + iterator end() { return std::next(queue_data.begin(), current_index); } + + void pop() { // removes the first element + if (current_index == 0) { + throw std::out_of_range("queue is empty"); + } + std::move(std::next(begin()), end(), begin()); + current_index--; + } + bool empty() const { return current_index == 0; } +}; + +#endif // STATIC_QUEUE_H