Skip to content

Commit

Permalink
made queue_event default constructible to allow the usage of "static …
Browse files Browse the repository at this point in the history
…queues" (based on std::array)

added tests for sml::process_queue<> and sml::defer_queue<> with static queues
  • Loading branch information
devzeb authored and kris-jusiak committed Mar 8, 2024
1 parent 7581bc1 commit 57f2e3e
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 5 deletions.
11 changes: 9 additions & 2 deletions include/boost/sml.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<queue_event &&>(other));
}
constexpr queue_event &operator=(queue_event &&other) {
dtor(data);
if (dtor != nullptr) {
dtor(data);
}
id = other.id;
dtor = other.dtor;
move = other.move;
Expand All @@ -678,7 +681,11 @@ class queue_event {
move = &move_impl<T>;
new (&data) T(static_cast<T &&>(object));
}
~queue_event() { dtor(data); }
~queue_event() {
if (dtor) {
dtor(data);
}
}
alignas(alignment) aux::byte data[size];
int id = -1;

Expand Down
29 changes: 26 additions & 3 deletions test/ft/actions_defer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <string>
#include <vector>

#include "static_deque.h"

namespace sml = boost::sml;

struct event1 {};
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -340,4 +342,25 @@ test defer_multi = [] {
sml::sm<c, sml::defer_queue<std::deque>> sm{};
sm.process_event(event1());
expect(sm.is(sml::X));
};

template <typename T>
using MinimalStaticDeque10 = MinimalStaticDeque<T, 10>;

test defer_minimal_static_deque = [] {
const auto c = [] {
using namespace sml;
// clang-format off
return make_transition_table(
*state1 + event<event1> / defer,
state1 + event<event2> = state2,
state2 + event<event1> = X
);
// clang-format off
};

sml::sm<decltype(c), sml::defer_queue<MinimalStaticDeque10>> sm{c};
sm.process_event(event1());
sm.process_event(event2());
expect(sm.is(sml::X));
};
36 changes: 36 additions & 0 deletions test/ft/actions_process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <utility>
#include <vector>

#include "static_queue.h"

namespace sml = boost::sml;

struct e1 {};
Expand Down Expand Up @@ -332,3 +334,37 @@ test process_between_substates = [] {
expect(sm.is<decltype(sml::state<sub1>)>(sml::X));
expect(sm.is<decltype(sml::state<sub2>)>(sml::X));
};

template <typename T>
using MinimalStaticQueue10 = MinimalStaticQueue<T, 10>;

test queue_process_events_static_queue = [] {
struct c {
std::vector<int> 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<sml::initial> / (process(e1()), process(e2()), a0)
, idle + event<e1> / a1
, idle + event<e2> / a2 = X
);
// clang-format on
}
};

sml::sm<c, sml::process_queue<MinimalStaticQueue10>> 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]);
};
34 changes: 34 additions & 0 deletions test/ft/actions_process_n_defer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#include <queue>
#include <string>

#include "static_deque.h"
#include "static_queue.h"

namespace sml = boost::sml;

struct e1 {};
Expand Down Expand Up @@ -114,3 +117,34 @@ test process_n_defer_again = [] {
std::cout << calls << "\n";
expect(calls == "|s3_entry|e1|e1|e1");
};

template <typename T>
using MinimalStaticDeque10 = MinimalStaticDeque<T, 10>;

template <typename T>
using MinimalStaticQueue10 = MinimalStaticQueue<T, 10>;

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<sml::initial> / process(e1{})
, s1 + event<e1> / defer = s2
, s2 / defer = s3
, s3 + event<e1> / process(e2{})
, s3 + event<e2> / defer = s4
, s4 + event<e2> = s5
, s5 = s6
, s6 + on_entry<_> / process(e3{})
, s6 + event<e3> = s7
, s7 = X
);
// clang-format on
}
};

sml::sm<c, sml::process_queue<MinimalStaticQueue10>, sml::defer_queue<MinimalStaticDeque10>> sm{};
expect(sm.is(sml::X));
};
78 changes: 78 additions & 0 deletions test/ft/static_deque.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#ifndef STATIC_DEQUE_H
#define STATIC_DEQUE_H

#include <array>
#include <stdexcept>

template <typename T, std::size_t Size>
struct MinimalStaticDeque {
std::array<T, Size> 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
50 changes: 50 additions & 0 deletions test/ft/static_queue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef STATIC_QUEUE_H
#define STATIC_QUEUE_H

#include <array>
#include <stdexcept>

template <typename T, std::size_t Size>
struct MinimalStaticQueue {
std::array<T, Size> 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

0 comments on commit 57f2e3e

Please sign in to comment.