diff --git a/solutions/01-user-defined-types/src/Alarm.cpp b/solutions/01-user-defined-types/src/Alarm.cpp new file mode 100644 index 0000000..2b5ab1e --- /dev/null +++ b/solutions/01-user-defined-types/src/Alarm.cpp @@ -0,0 +1,40 @@ +// Alarm.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include + +Alarm::Alarm() { + std::clog << "Alarm default ctor " << this << '\n'; +} + +Alarm::Alarm(Type alarm_init) : value{alarm_init} { + std::clog << "Alarm non-default ctor " << this << '\n'; +} + +Alarm::~Alarm() { + std::clog << "Alarm dtor" << this << '\n'; +} + +const char* Alarm::to_string() const { + switch (value) { + case advisory: + return "advisory"; + case caution: + return "caution"; + case warning: + return "warning"; + default: + return "invalid"; + } +} + +Alarm::Type Alarm::type() const { + return value; +} + +std::ostream& operator<<(std::ostream& os, Alarm const& alarm) { + os << alarm.to_string(); + return os; +} diff --git a/solutions/01-user-defined-types/src/Alarm.h b/solutions/01-user-defined-types/src/Alarm.h new file mode 100644 index 0000000..b802a52 --- /dev/null +++ b/solutions/01-user-defined-types/src/Alarm.h @@ -0,0 +1,29 @@ +// Alarm.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_H +#define ALARM_H + +#include + +class Alarm { +public: + enum Type { invalid, advisory, caution, warning }; + + Alarm(); + ~Alarm(); + explicit Alarm(Type alarm_init); + + Type type() const; + + const char* to_string() const; + +private: + Type value{Type::invalid}; +}; + +std::ostream& operator<<(std::ostream& os, Alarm const& alarm); + +#endif diff --git a/solutions/01-user-defined-types/src/main.cpp b/solutions/01-user-defined-types/src/main.cpp new file mode 100644 index 0000000..2ac0db4 --- /dev/null +++ b/solutions/01-user-defined-types/src/main.cpp @@ -0,0 +1,18 @@ +// main.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include + +int main() { + Alarm a1; // + Alarm a2{}; // Value-initialised + Alarm a3{Alarm::warning}; // Explicitly initialised + + std::cout << static_cast(a1.type()) << '\n'; + std::cout << a2.to_string() << '\n'; + std::cout << a3 << '\n'; + + std::cout << "\nCompleted OK\n"; +} diff --git a/solutions/01-user-defined-types/tests/CMakeLists.txt b/solutions/01-user-defined-types/tests/CMakeLists.txt new file mode 100644 index 0000000..54b2766 --- /dev/null +++ b/solutions/01-user-defined-types/tests/CMakeLists.txt @@ -0,0 +1,12 @@ +find_package(GTest REQUIRED) +include(GoogleTest) + +add_executable(AlarmTest alarm_tests.cpp ${CMAKE_SOURCE_DIR}/src/Alarm.cpp) + +target_include_directories(AlarmTest PRIVATE + ${CMAKE_SOURCE_DIR}/src + ) + +target_link_libraries(AlarmTest GTest::gtest GTest::gtest_main) + +gtest_discover_tests(AlarmTest) \ No newline at end of file diff --git a/solutions/01-user-defined-types/tests/alarm_tests.cpp b/solutions/01-user-defined-types/tests/alarm_tests.cpp new file mode 100644 index 0000000..0ef6d80 --- /dev/null +++ b/solutions/01-user-defined-types/tests/alarm_tests.cpp @@ -0,0 +1,78 @@ +// alarm_tests.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include "gtest/gtest.h" + +namespace { +class AlarmTest : public ::testing::Test { +protected: + AlarmTest() = default; + std::stringstream ss{}; +}; +} // namespace + +TEST_F(AlarmTest, type_invalid) { + Alarm a{}; + ASSERT_EQ(Alarm::invalid, a.type()); +} + +TEST_F(AlarmTest, type_advisory) { + Alarm a{Alarm::advisory}; + ASSERT_EQ(Alarm::advisory, a.type()); +} + +TEST_F(AlarmTest, type_caution) { + Alarm a{Alarm::caution}; + ASSERT_EQ(Alarm::caution, a.type()); +} + +TEST_F(AlarmTest, type_warning) { + Alarm a{Alarm::warning}; + ASSERT_EQ(Alarm::warning, a.type()); +} + +TEST_F(AlarmTest, string_invalid) { + Alarm a{}; + ASSERT_EQ("invalid", a.to_string()); +} + +TEST_F(AlarmTest, string_advisory) { + Alarm a{Alarm::advisory}; + ASSERT_EQ("advisory", a.to_string()); +} + +TEST_F(AlarmTest, string_caution) { + Alarm a{Alarm::caution}; + ASSERT_EQ("caution", a.to_string()); +} + +TEST_F(AlarmTest, string_warning) { + Alarm a{Alarm::warning}; + ASSERT_EQ("warning", a.to_string()); +} + +TEST_F(AlarmTest, ostream_invalid) { + Alarm a{}; + ss << a; + ASSERT_EQ("invalid", ss.str()); +} + +TEST_F(AlarmTest, ostream_advisory) { + Alarm a{Alarm::advisory}; + ss << a; + ASSERT_EQ("advisory", ss.str()); +} + +TEST_F(AlarmTest, ostream_caution) { + Alarm a{Alarm::caution}; + ss << a; + ASSERT_EQ("caution", ss.str()); +} + +TEST_F(AlarmTest, ostream_warning) { + Alarm a{Alarm::warning}; + ss << a; + ASSERT_EQ("warning", ss.str()); +} diff --git a/solutions/01_object_model/src/main.cpp b/solutions/01_object_model/src/main.cpp deleted file mode 100644 index 6cd7930..0000000 --- a/solutions/01_object_model/src/main.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// main.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include - -int main(void) -{ - std::cout << "Hello world!" << '\n'; -} - diff --git a/solutions/02-functions-constants/src/Alarm.cpp b/solutions/02-functions-constants/src/Alarm.cpp new file mode 100644 index 0000000..71036be --- /dev/null +++ b/solutions/02-functions-constants/src/Alarm.cpp @@ -0,0 +1,43 @@ +// Alarm.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include + +Alarm::Alarm(Type alarm_init) : value{ alarm_init } +{} + +const char* Alarm::to_string() const { + switch (value) { + case Type::advisory: + return "advisory"; + case Type::caution: + return "caution"; + case Type::warning: + return "warning"; + default: + return "invalid"; + } +} + +Alarm::Type Alarm::type() const { + return value; +} + +std::ostream& operator<<(std::ostream& os, Alarm const& alarm) { + os << alarm.to_string(); + return os; +} + +Alarm make_alarm(Alarm::Type type) +{ + return Alarm{ type }; +} + +void print_alarm(Alarm const& alarm) +{ + std::cout << static_cast(alarm.type()) << ':' + << alarm.to_string() + << '\n'; +} diff --git a/solutions/02-functions-constants/src/Alarm.h b/solutions/02-functions-constants/src/Alarm.h new file mode 100644 index 0000000..dac824c --- /dev/null +++ b/solutions/02-functions-constants/src/Alarm.h @@ -0,0 +1,30 @@ +// Alarm.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_H +#define ALARM_H + +#include + +class Alarm { +public: + enum class Type { invalid, advisory, caution, warning }; + + Alarm() = default; + explicit Alarm(Type alarm_init); + + const char* to_string() const; + Type type() const; + +private: + Type value{ Type::invalid }; +}; + +std::ostream& operator<<(std::ostream& os, const Alarm& alarm); + +void print_alarm(Alarm const& alarm); +Alarm make_alarm(Alarm::Type type); + +#endif diff --git a/solutions/02-functions-constants/src/main.cpp b/solutions/02-functions-constants/src/main.cpp new file mode 100644 index 0000000..310ba25 --- /dev/null +++ b/solutions/02-functions-constants/src/main.cpp @@ -0,0 +1,27 @@ +// main.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include + +int main() +{ + Alarm a1; // + Alarm a2{}; // Value-initialised + Alarm a3{ Alarm::Type::warning }; // Explicitly initialised + auto a4 = make_alarm(Alarm::Type::caution); // factory-function + print_alarm(a2); + print_alarm(a3); + print_alarm(a4); + + // std::cout << static_cast(a1.type()) << '\n'; + // std::cout << a2.to_string() << '\n'; + // std::cout << a1 << '\n'; + // std::cout << a2 << '\n'; + // std::cout << a3 << '\n'; + // std::cout << a4 << '\n'; + a1 = make_alarm(Alarm::Type::advisory); // RVO + print_alarm(a1); + std::cout << "\nCompleted OK\n"; +} diff --git a/solutions/02_user_defined_types/src/Event.cpp b/solutions/02_user_defined_types/src/Event.cpp deleted file mode 100644 index 4d34a2e..0000000 --- a/solutions/02_user_defined_types/src/Event.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// Event.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Event.h" - -static char const* strings[]{ "unknown ", - "advisory ", - "caution ", - "warning " }; - -Event::Event(Alarm init) : event_type{ init } {} - -Alarm Event::type() const -{ - return event_type; -} - -char const* Event::as_string() const -{ - return strings[static_cast(event_type)]; -} diff --git a/solutions/02_user_defined_types/src/Event.h b/solutions/02_user_defined_types/src/Event.h deleted file mode 100644 index a79b8dd..0000000 --- a/solutions/02_user_defined_types/src/Event.h +++ /dev/null @@ -1,23 +0,0 @@ -// Event.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef EVENT_H -#define EVENT_H - -enum class Alarm { unknown, advisory, caution, warning }; - -class Event { -public: - Event() = default; - Event(Alarm init); - - Alarm type() const; - char const* as_string() const; - -private: - Alarm event_type{ Alarm::unknown }; -}; - -#endif diff --git a/solutions/02_user_defined_types/src/main.cpp b/solutions/02_user_defined_types/src/main.cpp deleted file mode 100644 index 6f7660b..0000000 --- a/solutions/02_user_defined_types/src/main.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// main.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Event.h" -#include - -int main() -{ - Event event1{}; - Event event2{ Alarm::warning }; - - std::cout << event1.as_string() << '\n'; - std::cout << event2.as_string() << '\n'; -} diff --git a/solutions/03-circular-buffer/src/Alarm.cpp b/solutions/03-circular-buffer/src/Alarm.cpp new file mode 100644 index 0000000..71036be --- /dev/null +++ b/solutions/03-circular-buffer/src/Alarm.cpp @@ -0,0 +1,43 @@ +// Alarm.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include + +Alarm::Alarm(Type alarm_init) : value{ alarm_init } +{} + +const char* Alarm::to_string() const { + switch (value) { + case Type::advisory: + return "advisory"; + case Type::caution: + return "caution"; + case Type::warning: + return "warning"; + default: + return "invalid"; + } +} + +Alarm::Type Alarm::type() const { + return value; +} + +std::ostream& operator<<(std::ostream& os, Alarm const& alarm) { + os << alarm.to_string(); + return os; +} + +Alarm make_alarm(Alarm::Type type) +{ + return Alarm{ type }; +} + +void print_alarm(Alarm const& alarm) +{ + std::cout << static_cast(alarm.type()) << ':' + << alarm.to_string() + << '\n'; +} diff --git a/solutions/03-circular-buffer/src/Alarm.h b/solutions/03-circular-buffer/src/Alarm.h new file mode 100644 index 0000000..dac824c --- /dev/null +++ b/solutions/03-circular-buffer/src/Alarm.h @@ -0,0 +1,30 @@ +// Alarm.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_H +#define ALARM_H + +#include + +class Alarm { +public: + enum class Type { invalid, advisory, caution, warning }; + + Alarm() = default; + explicit Alarm(Type alarm_init); + + const char* to_string() const; + Type type() const; + +private: + Type value{ Type::invalid }; +}; + +std::ostream& operator<<(std::ostream& os, const Alarm& alarm); + +void print_alarm(Alarm const& alarm); +Alarm make_alarm(Alarm::Type type); + +#endif diff --git a/solutions/03-circular-buffer/src/Buffer.cpp b/solutions/03-circular-buffer/src/Buffer.cpp new file mode 100644 index 0000000..865366d --- /dev/null +++ b/solutions/03-circular-buffer/src/Buffer.cpp @@ -0,0 +1,39 @@ +// Buffer.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Buffer.h" + +bool Buffer::add(Alarm const& in) +{ + if (num_elems == sz) return false; + + *write_pos = in; + ++num_elems; + ++write_pos; + if (write_pos == std::end(elems)) write_pos = std::begin(elems); + + return true; +} + +bool Buffer::get(Alarm& out) +{ + if (num_elems == 0) return false; + + out = *read_pos; + --num_elems; + ++read_pos; + if (read_pos == std::end(elems)) read_pos = std::begin(elems); + + return true; +} + +bool Buffer::is_empty() const +{ + return (num_elems == 0); +} + +bool Buffer::is_full() const +{ + return (num_elems == sz); +} \ No newline at end of file diff --git a/solutions/03-circular-buffer/src/Buffer.h b/solutions/03-circular-buffer/src/Buffer.h new file mode 100644 index 0000000..6872fdf --- /dev/null +++ b/solutions/03-circular-buffer/src/Buffer.h @@ -0,0 +1,35 @@ +// Buffer.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef BUFFER_H +#define BUFFER_H + +#include "Alarm.h" +#include +#include + +class Buffer { +public: + Buffer() = default; + + bool add(Alarm const& in); + bool get(Alarm& out); + + bool is_empty() const; + bool is_full() const; + + constexpr auto capacity() const -> std::size_t { return sz; } + +private: + static constexpr std::size_t sz{ 8 }; + using Container = std::array; + + Container elems {}; + Container::iterator write_pos{std::begin(elems)}; + Container::iterator read_pos{std::begin(elems)}; + size_t num_elems {}; +}; + +#endif diff --git a/solutions/03-circular-buffer/src/main.cpp b/solutions/03-circular-buffer/src/main.cpp new file mode 100644 index 0000000..042082e --- /dev/null +++ b/solutions/03-circular-buffer/src/main.cpp @@ -0,0 +1,67 @@ +// main.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include "Buffer.h" +#include +#include + +int main() +{ + Alarm a1; // + Alarm a2{}; // Value-initialised + Alarm a3{ Alarm::Type::warning }; // Explicitly initialised + + Buffer pipe{}; + + { // Test initial condition + assert(pipe.is_empty()); + } + + { // Test read from empty + assert(!pipe.get(a1)); + } + + { // Test add one + assert(pipe.add(a3)); + assert(!pipe.is_empty()); + assert(pipe.get(a1)); + assert(a1.type() == a3.type()); + assert(pipe.is_empty()); + } + + { // Test add to full + for (std::size_t count = 0; count < pipe.capacity(); ++count) { + assert(pipe.add(Alarm{ static_cast(count % 3 + 1) })); + } + assert(!pipe.add(Alarm{})); + } + { // Test wrap-around behaviour + // Read 2 + for (std::size_t count = 0; count < 2; ++count) { + assert(pipe.get(a1)); + assert(a1.type() == Alarm::Type(count+1)); + } + + // write to full again + assert(pipe.add(a3)); + assert(pipe.add(a3)); + + // check full + assert(!pipe.add(a3)); + + // read to empty + for (std::size_t count = 2; count < pipe.capacity(); ++count) { + assert(pipe.get(a1)); + assert(a1.type() == Alarm::Type(count % 3 + 1)); + } + for (std::size_t count = 0; count < 2; ++count) { + assert(pipe.get(a1)); + assert(a1.type() == a3.type()); + } + assert(pipe.is_empty()); + } + + std::cout << "Completed OK\n"; +} diff --git a/solutions/03_connecting_objects/src/Display.cpp b/solutions/03_connecting_objects/src/Display.cpp deleted file mode 100644 index 4eab42c..0000000 --- a/solutions/03_connecting_objects/src/Display.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// Display.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Event.h" -#include "Pipe.h" -#include - - -void connect(Display& disp, Pipe& pipe) -{ - disp.input = &pipe; -} - -void Display::execute() -{ - std::cout << "DISPLAY : ------------------------" << '\n'; - - if (input) { - if (auto event = input->pull()) { - std::cout << "Received event: " << event->as_string() << '\n'; - std::cout << '\n'; - } - } - else { - std::cerr << "DISPLAY : No input pipe connected" << '\n'; - } -} diff --git a/solutions/03_connecting_objects/src/Event.cpp b/solutions/03_connecting_objects/src/Event.cpp deleted file mode 100644 index 4d34a2e..0000000 --- a/solutions/03_connecting_objects/src/Event.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// Event.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Event.h" - -static char const* strings[]{ "unknown ", - "advisory ", - "caution ", - "warning " }; - -Event::Event(Alarm init) : event_type{ init } {} - -Alarm Event::type() const -{ - return event_type; -} - -char const* Event::as_string() const -{ - return strings[static_cast(event_type)]; -} diff --git a/solutions/03_connecting_objects/src/Event.h b/solutions/03_connecting_objects/src/Event.h deleted file mode 100644 index a79b8dd..0000000 --- a/solutions/03_connecting_objects/src/Event.h +++ /dev/null @@ -1,23 +0,0 @@ -// Event.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef EVENT_H -#define EVENT_H - -enum class Alarm { unknown, advisory, caution, warning }; - -class Event { -public: - Event() = default; - Event(Alarm init); - - Alarm type() const; - char const* as_string() const; - -private: - Alarm event_type{ Alarm::unknown }; -}; - -#endif diff --git a/solutions/03_connecting_objects/src/Generator.cpp b/solutions/03_connecting_objects/src/Generator.cpp deleted file mode 100644 index 8ddc516..0000000 --- a/solutions/03_connecting_objects/src/Generator.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Generator.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Generator.h" -#include "Event.h" -#include "Pipe.h" -#include -#include - - -void connect(Generator& gen, Pipe& pipe) -{ - gen.output = &pipe; -} - -namespace -{ - inline Alarm random_alarm() { return static_cast((rand() % 3) + 1); } -} // namespace - -void Generator::execute() -{ - std::cout << "GENERATOR: ------------------------" << '\n'; - - if (output) { - Event event{ random_alarm() }; - output->push(event); - std::cout << "Pushed event: " << event.as_string() << '\n'; - std::cout << '\n'; - } - else { - std::cerr << "GENERATOR : No output pipe connected" << '\n'; - } -} diff --git a/solutions/03_connecting_objects/src/Pipe.cpp b/solutions/03_connecting_objects/src/Pipe.cpp deleted file mode 100644 index 0a47902..0000000 --- a/solutions/03_connecting_objects/src/Pipe.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// Pipe.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Pipe.h" - -void Pipe::push(const Pipe::element_type& in_val) -{ - element = in_val; -} - -std::optional Pipe::pull() -{ - if (element.type() != Alarm::unknown) - return element; - else { - return std::nullopt; - } -} diff --git a/solutions/03_connecting_objects/src/Pipe.h b/solutions/03_connecting_objects/src/Pipe.h deleted file mode 100644 index f217fd8..0000000 --- a/solutions/03_connecting_objects/src/Pipe.h +++ /dev/null @@ -1,25 +0,0 @@ -// Pipe.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef PIPE_H -#define PIPE_H - -#include "Event.h" -#include - -class Pipe { -public: - using element_type = Event; - - Pipe() = default; - - void push(const element_type& in_val); - std::optional pull(); - -private: - element_type element{}; -}; - -#endif diff --git a/solutions/03_connecting_objects/src/main.cpp b/solutions/03_connecting_objects/src/main.cpp deleted file mode 100644 index 66a8d21..0000000 --- a/solutions/03_connecting_objects/src/main.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// main.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Generator.h" -#include "Pipe.h" - -int main() -{ - Pipe pipe{}; - Generator generator{ pipe }; - Display display{ pipe }; - - // Generator generator{}; - // Display display{}; - // connect(generator, pipe); - // connect(display, pipe); - - for (int i = 0; i < 10; ++i) { - generator.execute(); - display.execute(); - } -} diff --git a/solutions/04-algorithms/src/Alarm.cpp b/solutions/04-algorithms/src/Alarm.cpp new file mode 100644 index 0000000..71036be --- /dev/null +++ b/solutions/04-algorithms/src/Alarm.cpp @@ -0,0 +1,43 @@ +// Alarm.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include + +Alarm::Alarm(Type alarm_init) : value{ alarm_init } +{} + +const char* Alarm::to_string() const { + switch (value) { + case Type::advisory: + return "advisory"; + case Type::caution: + return "caution"; + case Type::warning: + return "warning"; + default: + return "invalid"; + } +} + +Alarm::Type Alarm::type() const { + return value; +} + +std::ostream& operator<<(std::ostream& os, Alarm const& alarm) { + os << alarm.to_string(); + return os; +} + +Alarm make_alarm(Alarm::Type type) +{ + return Alarm{ type }; +} + +void print_alarm(Alarm const& alarm) +{ + std::cout << static_cast(alarm.type()) << ':' + << alarm.to_string() + << '\n'; +} diff --git a/solutions/04-algorithms/src/Alarm.h b/solutions/04-algorithms/src/Alarm.h new file mode 100644 index 0000000..dac824c --- /dev/null +++ b/solutions/04-algorithms/src/Alarm.h @@ -0,0 +1,30 @@ +// Alarm.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_H +#define ALARM_H + +#include + +class Alarm { +public: + enum class Type { invalid, advisory, caution, warning }; + + Alarm() = default; + explicit Alarm(Type alarm_init); + + const char* to_string() const; + Type type() const; + +private: + Type value{ Type::invalid }; +}; + +std::ostream& operator<<(std::ostream& os, const Alarm& alarm); + +void print_alarm(Alarm const& alarm); +Alarm make_alarm(Alarm::Type type); + +#endif diff --git a/solutions/04-algorithms/src/Buffer.cpp b/solutions/04-algorithms/src/Buffer.cpp new file mode 100644 index 0000000..865366d --- /dev/null +++ b/solutions/04-algorithms/src/Buffer.cpp @@ -0,0 +1,39 @@ +// Buffer.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Buffer.h" + +bool Buffer::add(Alarm const& in) +{ + if (num_elems == sz) return false; + + *write_pos = in; + ++num_elems; + ++write_pos; + if (write_pos == std::end(elems)) write_pos = std::begin(elems); + + return true; +} + +bool Buffer::get(Alarm& out) +{ + if (num_elems == 0) return false; + + out = *read_pos; + --num_elems; + ++read_pos; + if (read_pos == std::end(elems)) read_pos = std::begin(elems); + + return true; +} + +bool Buffer::is_empty() const +{ + return (num_elems == 0); +} + +bool Buffer::is_full() const +{ + return (num_elems == sz); +} \ No newline at end of file diff --git a/solutions/04-algorithms/src/Buffer.h b/solutions/04-algorithms/src/Buffer.h new file mode 100644 index 0000000..073e6c3 --- /dev/null +++ b/solutions/04-algorithms/src/Buffer.h @@ -0,0 +1,33 @@ +// Buffer.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef BUFFER_H +#define BUFFER_H + +#include "Alarm.h" +#include +#include + +class Buffer { +public: + Buffer() = default; + + bool add(Alarm const& in); + bool get(Alarm& out); + + bool is_empty() const; + bool is_full() const; + +private: + static constexpr std::size_t sz{ 8 }; + using Container = std::array; + + Container elems {}; + Container::iterator write_pos{std::begin(elems)}; + Container::iterator read_pos{std::begin(elems)}; + size_t num_elems {}; +}; + +#endif diff --git a/solutions/04-algorithms/src/main.cpp b/solutions/04-algorithms/src/main.cpp new file mode 100644 index 0000000..67e2094 --- /dev/null +++ b/solutions/04-algorithms/src/main.cpp @@ -0,0 +1,63 @@ +// main.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include +#include +#include +#include +#include + +static constexpr unsigned alarm_count {12}; + +static std::array alarms { + Alarm{Alarm::Type::caution}, + Alarm{Alarm::Type::advisory}, + Alarm{Alarm::Type::warning}, // 1 + Alarm{Alarm::Type::caution}, + Alarm{Alarm::Type::caution}, + Alarm{Alarm::Type::caution}, + Alarm{Alarm::Type::advisory}, + Alarm{Alarm::Type::warning}, // 2 + Alarm{Alarm::Type::warning}, // 3 + Alarm{Alarm::Type::caution}, + Alarm{Alarm::Type::advisory}, + Alarm{Alarm::Type::warning}, // 4 +}; + +static constexpr unsigned warning_count {4}; + +int main() { + { + auto count = std::count_if( + std::begin(alarms), std::end(alarms), + [](auto alarm) { return alarm.type() == Alarm::Type::warning; } + ); + assert(count == warning_count); + } + + { + auto remove = std::remove_if( + std::begin(alarms), std::end(alarms), + [](auto alarm) { return alarm.type() == Alarm::Type::warning; } + ); + + // fill end of array with invalid objects + std::fill(remove, std::end(alarms), Alarm{}); + + auto count = std::count_if( + std::begin(alarms), std::end(alarms), + [](auto alarm) { return alarm.type() == Alarm::Type::warning; } + ); + assert(count == 0); + + // check we din't remove everything including caution + count = std::count_if( + std::begin(alarms), std::end(alarms), + [](auto alarm) { return alarm.type() != Alarm::Type::invalid; } + ); + assert(count == (std::size(alarms) - warning_count)); + } + std::cout << "Completed OK\n"; +} diff --git a/solutions/04_containers/src/Display.cpp b/solutions/04_containers/src/Display.cpp deleted file mode 100644 index b7b5c53..0000000 --- a/solutions/04_containers/src/Display.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Display.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Event.h" -#include "Pipe.h" -#include - - -void connect(Display& disp, Pipe& pipe) -{ - disp.input = &pipe; -} - -void Display::execute() -{ - std::cout << "DISPLAY : ------------------------" << '\n'; - - if (auto events = input->pull()) { - for (auto& event : *events) { - std::cout << event.as_string() << '\n'; - } - - std::cout << '\n'; - } -} diff --git a/solutions/04_containers/src/Event.cpp b/solutions/04_containers/src/Event.cpp deleted file mode 100644 index 50e1dd2..0000000 --- a/solutions/04_containers/src/Event.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// Event.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Event.h" - -#ifdef TRACE_ENABLED -#include -#define TRACE(msg) \ - std::cout << "Event: " << as_string() << " : " << msg << '\n' -#else -#define TRACE(msg) -#endif - -static const char* strings[]{ "unknown ", - "advisory ", - "caution ", - "warning " }; - -Event::Event() -{ - TRACE("Default ctor"); -} - -Event::Event(Alarm init) : event_type{ init } -{ - TRACE("Non-default ctor"); -} - -Event::~Event() -{ - TRACE("Dtor"); -} - -Event::Event(const Event& src) : Event{ src.event_type } -{ - TRACE("Copy ctor"); -} - -Event& Event::operator=(const Event& rhs) -{ - TRACE("Copy assignment"); - - event_type = rhs.event_type; - return *this; -} - -Alarm Event::type() const -{ - return event_type; -} - -const char* Event::as_string() const -{ - return strings[static_cast(event_type)]; -} diff --git a/solutions/04_containers/src/Event.h b/solutions/04_containers/src/Event.h deleted file mode 100644 index 40ccb39..0000000 --- a/solutions/04_containers/src/Event.h +++ /dev/null @@ -1,29 +0,0 @@ -// Event.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef EVENT_H -#define EVENT_H - -enum class Alarm { unknown, advisory, caution, warning }; - -class Event { -public: - Event(); - Event(Alarm init); - ~Event(); - - // Copy interface - // - Event(const Event& src); - Event& operator=(const Event& rhs); - - Alarm type() const; - char const* as_string() const; - -private: - Alarm event_type{ Alarm::unknown }; -}; - -#endif diff --git a/solutions/04_containers/src/Generator.cpp b/solutions/04_containers/src/Generator.cpp deleted file mode 100644 index 6e192b2..0000000 --- a/solutions/04_containers/src/Generator.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Generator.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Generator.h" -#include "Pipe.h" -#include -#include - - -void connect(Generator& gen, Pipe& pipe) -{ - gen.output = &pipe; -} - -namespace -{ - inline Alarm random_alarm() { return static_cast((rand() % 3) + 1); } -} // namespace - -void Generator::execute() -{ - std::cout << "GENERATOR: ------------------------" << '\n'; - - auto num_events = rand() % 9 + 1; - Pipe::element_type events{}; - - std::cout << "Generating " << num_events << " event" - << (num_events == 1 ? "" : "s") << '\n'; - - for (int i{ 0 }; i < num_events; ++i) { - events.emplace_back(random_alarm()); - } - - output->push(events); - - std::cout << '\n'; -} diff --git a/solutions/04_containers/src/Pipe.cpp b/solutions/04_containers/src/Pipe.cpp deleted file mode 100644 index 77aa098..0000000 --- a/solutions/04_containers/src/Pipe.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Pipe.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Pipe.h" - -void Pipe::push(const Pipe::element_type& in_val) -{ - element = in_val; -} - -std::optional Pipe::pull() -{ - if (element.empty()) return std::nullopt; - return element; -} diff --git a/solutions/04_containers/src/Pipe.h b/solutions/04_containers/src/Pipe.h deleted file mode 100644 index ff6c9c5..0000000 --- a/solutions/04_containers/src/Pipe.h +++ /dev/null @@ -1,24 +0,0 @@ -// Pipe.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef PIPE_H -#define PIPE_H - -#include -#include -#include "Event.h" - -class Pipe { -public: - using element_type = std::vector; - - void push(const element_type& in_val); - std::optional pull(); - -private: - element_type element{}; -}; - -#endif diff --git a/solutions/04_containers/src/main.cpp b/solutions/04_containers/src/main.cpp deleted file mode 100644 index 77c39c1..0000000 --- a/solutions/04_containers/src/main.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// main.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Generator.h" -#include "Pipe.h" - -int main() -{ - Generator generator{}; - Display display{}; - Pipe pipe{}; - - connect(generator, pipe); - connect(display, pipe); - - for (int i = 0; i < 10; ++i) { - generator.execute(); - display.execute(); - } -} diff --git a/solutions/05-connecting-objects/src/Alarm.cpp b/solutions/05-connecting-objects/src/Alarm.cpp new file mode 100644 index 0000000..71036be --- /dev/null +++ b/solutions/05-connecting-objects/src/Alarm.cpp @@ -0,0 +1,43 @@ +// Alarm.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include + +Alarm::Alarm(Type alarm_init) : value{ alarm_init } +{} + +const char* Alarm::to_string() const { + switch (value) { + case Type::advisory: + return "advisory"; + case Type::caution: + return "caution"; + case Type::warning: + return "warning"; + default: + return "invalid"; + } +} + +Alarm::Type Alarm::type() const { + return value; +} + +std::ostream& operator<<(std::ostream& os, Alarm const& alarm) { + os << alarm.to_string(); + return os; +} + +Alarm make_alarm(Alarm::Type type) +{ + return Alarm{ type }; +} + +void print_alarm(Alarm const& alarm) +{ + std::cout << static_cast(alarm.type()) << ':' + << alarm.to_string() + << '\n'; +} diff --git a/solutions/05-connecting-objects/src/Alarm.h b/solutions/05-connecting-objects/src/Alarm.h new file mode 100644 index 0000000..dac824c --- /dev/null +++ b/solutions/05-connecting-objects/src/Alarm.h @@ -0,0 +1,30 @@ +// Alarm.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_H +#define ALARM_H + +#include + +class Alarm { +public: + enum class Type { invalid, advisory, caution, warning }; + + Alarm() = default; + explicit Alarm(Type alarm_init); + + const char* to_string() const; + Type type() const; + +private: + Type value{ Type::invalid }; +}; + +std::ostream& operator<<(std::ostream& os, const Alarm& alarm); + +void print_alarm(Alarm const& alarm); +Alarm make_alarm(Alarm::Type type); + +#endif diff --git a/solutions/05-connecting-objects/src/AlarmFilter.cpp b/solutions/05-connecting-objects/src/AlarmFilter.cpp new file mode 100644 index 0000000..9eeb9bd --- /dev/null +++ b/solutions/05-connecting-objects/src/AlarmFilter.cpp @@ -0,0 +1,33 @@ +// AlarmFilter.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include +#include "AlarmFilter.h" +#include "Pipe.h" + +AlarmFilter::AlarmFilter(Alarm::Type remove_this) +: value{ remove_this } +{ } + +AlarmFilter::AlarmFilter(Alarm::Type remove_this, Pipe& in, Pipe& out) +: value{ remove_this }, input{ &in }, output{ &out } +{ } + +void AlarmFilter::execute() +{ + if (auto alarm = input->pull()) { + if (alarm->type() != this->value) { + output->push(alarm.value()); + } + else { + std::cout << "Filter: " << alarm->to_string() << " removed\n"; + } + } +} + +void connect(AlarmFilter& filter, Pipe& in, Pipe& out) +{ + filter.input = ∈ + filter.output = &out; +} diff --git a/solutions/05-connecting-objects/src/AlarmFilter.h b/solutions/05-connecting-objects/src/AlarmFilter.h new file mode 100644 index 0000000..12b2cc1 --- /dev/null +++ b/solutions/05-connecting-objects/src/AlarmFilter.h @@ -0,0 +1,28 @@ +// AlarmFilter.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_FILTER_H +#define ALARM_FILTER_H + +#include "Alarm.h" + +class Pipe; + +class AlarmFilter +{ +public: + explicit AlarmFilter(Alarm::Type remove_this); + explicit AlarmFilter(Alarm::Type remove_this, Pipe& in, Pipe& out); + void execute(); + +private: + Alarm::Type value; + + Pipe* input{}; + Pipe* output{}; + friend void connect(AlarmFilter& filter, Pipe& in, Pipe& out); +}; + +#endif diff --git a/solutions/05-connecting-objects/src/Buffer.cpp b/solutions/05-connecting-objects/src/Buffer.cpp new file mode 100644 index 0000000..865366d --- /dev/null +++ b/solutions/05-connecting-objects/src/Buffer.cpp @@ -0,0 +1,39 @@ +// Buffer.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Buffer.h" + +bool Buffer::add(Alarm const& in) +{ + if (num_elems == sz) return false; + + *write_pos = in; + ++num_elems; + ++write_pos; + if (write_pos == std::end(elems)) write_pos = std::begin(elems); + + return true; +} + +bool Buffer::get(Alarm& out) +{ + if (num_elems == 0) return false; + + out = *read_pos; + --num_elems; + ++read_pos; + if (read_pos == std::end(elems)) read_pos = std::begin(elems); + + return true; +} + +bool Buffer::is_empty() const +{ + return (num_elems == 0); +} + +bool Buffer::is_full() const +{ + return (num_elems == sz); +} \ No newline at end of file diff --git a/solutions/05-connecting-objects/src/Buffer.h b/solutions/05-connecting-objects/src/Buffer.h new file mode 100644 index 0000000..073e6c3 --- /dev/null +++ b/solutions/05-connecting-objects/src/Buffer.h @@ -0,0 +1,33 @@ +// Buffer.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef BUFFER_H +#define BUFFER_H + +#include "Alarm.h" +#include +#include + +class Buffer { +public: + Buffer() = default; + + bool add(Alarm const& in); + bool get(Alarm& out); + + bool is_empty() const; + bool is_full() const; + +private: + static constexpr std::size_t sz{ 8 }; + using Container = std::array; + + Container elems {}; + Container::iterator write_pos{std::begin(elems)}; + Container::iterator read_pos{std::begin(elems)}; + size_t num_elems {}; +}; + +#endif diff --git a/solutions/05-connecting-objects/src/Display.cpp b/solutions/05-connecting-objects/src/Display.cpp new file mode 100644 index 0000000..6d077b4 --- /dev/null +++ b/solutions/05-connecting-objects/src/Display.cpp @@ -0,0 +1,23 @@ +// Display.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Display.h" +#include "Pipe.h" +#include +#include + +Display::Display(Pipe& ip) : input{&ip} {} + +void Display::execute() { + assert(input); + + if (auto alarm = input->pull()) { + std::cout << "Display: " << *alarm << '\n'; + } + +} + +void connect(Display& display, Pipe& pipe) { + display.input = &pipe; +} diff --git a/solutions/04_containers/src/Display.h b/solutions/05-connecting-objects/src/Display.h similarity index 68% rename from solutions/04_containers/src/Display.h rename to solutions/05-connecting-objects/src/Display.h index 1f39242..b42675b 100644 --- a/solutions/04_containers/src/Display.h +++ b/solutions/05-connecting-objects/src/Display.h @@ -11,13 +11,12 @@ class Pipe; class Display { public: Display() = default; - Display(Pipe& ip) : input{ &ip } {} - + explicit Display(Pipe& ip); void execute(); private: - Pipe* input{}; - friend void connect(Display& disp, Pipe& pipe); + Pipe* input{}; + friend void connect(Display& display, Pipe& pipe); }; #endif diff --git a/solutions/05-connecting-objects/src/Generator.cpp b/solutions/05-connecting-objects/src/Generator.cpp new file mode 100644 index 0000000..36ca129 --- /dev/null +++ b/solutions/05-connecting-objects/src/Generator.cpp @@ -0,0 +1,30 @@ +// Generator.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Generator.h" +#include "Pipe.h" +#include +#include +#include + +namespace +{ + Alarm random_alarm() { + return make_alarm(Alarm::Type((rand()%3) + 1)); + } +} // namespace + +void Generator::execute() { + assert(output); + + auto alarm = random_alarm(); + std::cout << "Generate: " << alarm << '\n'; + output->push(alarm); +} + +Generator::Generator(Pipe& pipe) : output{&pipe} {} + +void connect(Generator& gen, Pipe& pipe) { + gen.output = &pipe; +} diff --git a/solutions/03_connecting_objects/src/Generator.h b/solutions/05-connecting-objects/src/Generator.h similarity index 82% rename from solutions/03_connecting_objects/src/Generator.h rename to solutions/05-connecting-objects/src/Generator.h index 65e91e3..be04f4b 100644 --- a/solutions/03_connecting_objects/src/Generator.h +++ b/solutions/05-connecting-objects/src/Generator.h @@ -11,12 +11,11 @@ class Pipe; class Generator { public: Generator() = default; - Generator(Pipe& ip) : output{ &ip } {} - + explicit Generator(Pipe& pipe); void execute(); private: - Pipe* output{}; + Pipe* output{}; friend void connect(Generator& gen, Pipe& pipe); }; diff --git a/solutions/05-connecting-objects/src/Pipe.cpp b/solutions/05-connecting-objects/src/Pipe.cpp new file mode 100644 index 0000000..7e6db46 --- /dev/null +++ b/solutions/05-connecting-objects/src/Pipe.cpp @@ -0,0 +1,24 @@ +// Pipe.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Pipe.h" + +bool Pipe::push(Alarm const& alarm) +{ + return buffer.add(alarm); +} + +std::optional Pipe::pull() +{ + Alarm alarm{}; + if (buffer.get(alarm)) { + return alarm; + } + return std::nullopt; +} + +bool Pipe::is_empty() const +{ + return buffer.is_empty(); +} diff --git a/solutions/05-connecting-objects/src/Pipe.h b/solutions/05-connecting-objects/src/Pipe.h new file mode 100644 index 0000000..3cb977c --- /dev/null +++ b/solutions/05-connecting-objects/src/Pipe.h @@ -0,0 +1,23 @@ +// Pipe.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef _PIPE_H +#define _PIPE_H + +#include +#include "Buffer.h" + +class Pipe +{ +public: + bool push(Alarm const& alarm); + std::optional pull(); + bool is_empty() const; + +private: + Buffer buffer{}; +}; + +#endif diff --git a/solutions/05-connecting-objects/src/main.cpp b/solutions/05-connecting-objects/src/main.cpp new file mode 100644 index 0000000..fbf0282 --- /dev/null +++ b/solutions/05-connecting-objects/src/main.cpp @@ -0,0 +1,47 @@ +// main.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Display.h" +#include "Generator.h" +#include "AlarmFilter.h" +#include "Pipe.h" +#include +#include + +int main(int argc, char** argv) { + int run_count = (argc > 1) ? std::stoi(argv[1]) : 5; + + { + Pipe pipe{}; + // Generator generator{}; + Generator generator{pipe}; + Display display{pipe}; + + // connect(generator, pipe); + // connect(display, pipe); + + for (int i{0}; i < run_count; ++i) { + generator.execute(); + display.execute(); + } + } + + std::cout << '\n'; + + { + Pipe pipe1{}; + Pipe pipe2{}; + Generator generator{pipe1}; + AlarmFilter filter{Alarm::Type::advisory, pipe1, pipe2}; + Display display{pipe2}; + + for (int i{0}; i < run_count; ++i) { + generator.execute(); + filter.execute(); + display.execute(); + } + } + + std::cout << "\nCompleted OK\n"; +} diff --git a/solutions/05-connecting-objects/tests/Alarm_tests.cpp b/solutions/05-connecting-objects/tests/Alarm_tests.cpp new file mode 100644 index 0000000..f01ef8f --- /dev/null +++ b/solutions/05-connecting-objects/tests/Alarm_tests.cpp @@ -0,0 +1,78 @@ +// Alarm_tests.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include "gtest/gtest.h" + +namespace { +class AlarmTest : public ::testing::Test { +protected: + AlarmTest() = default; + std::stringstream ss{}; +}; +} // namespace + +TEST_F(AlarmTest, type_invalid) { + Alarm a{}; + ASSERT_EQ(Alarm::Type::invalid, a.type()); +} + +TEST_F(AlarmTest, type_advisory) { + Alarm a{Alarm::Type::advisory}; + ASSERT_EQ(Alarm::Type::advisory, a.type()); +} + +TEST_F(AlarmTest, type_caution) { + Alarm a{Alarm::Type::caution}; + ASSERT_EQ(Alarm::Type::caution, a.type()); +} + +TEST_F(AlarmTest, type_warning) { + Alarm a{Alarm::Type::warning}; + ASSERT_EQ(Alarm::Type::warning, a.type()); +} + +TEST_F(AlarmTest, string_invalid) { + Alarm a{}; + ASSERT_EQ("invalid", a.to_string()); +} + +TEST_F(AlarmTest, string_advisory) { + Alarm a{Alarm::Type::advisory}; + ASSERT_EQ("advisory", a.to_string()); +} + +TEST_F(AlarmTest, string_caution) { + Alarm a{Alarm::Type::caution}; + ASSERT_EQ("caution", a.to_string()); +} + +TEST_F(AlarmTest, string_warning) { + Alarm a{Alarm::Type::warning}; + ASSERT_EQ("warning", a.to_string()); +} + +TEST_F(AlarmTest, ostream_invalid) { + Alarm a{}; + ss << a; + ASSERT_EQ("invalid", ss.str()); +} + +TEST_F(AlarmTest, ostream_advisory) { + Alarm a{Alarm::Type::advisory}; + ss << a; + ASSERT_EQ("advisory", ss.str()); +} + +TEST_F(AlarmTest, ostream_caution) { + Alarm a{Alarm::Type::caution}; + ss << a; + ASSERT_EQ("caution", ss.str()); +} + +TEST_F(AlarmTest, ostream_warning) { + Alarm a{Alarm::Type::warning}; + ss << a; + ASSERT_EQ("warning", ss.str()); +} diff --git a/solutions/05-connecting-objects/tests/CMakeLists.txt b/solutions/05-connecting-objects/tests/CMakeLists.txt new file mode 100644 index 0000000..5b2e90e --- /dev/null +++ b/solutions/05-connecting-objects/tests/CMakeLists.txt @@ -0,0 +1,56 @@ +find_package(GTest REQUIRED) +include(GoogleTest) + +set(units_under_test + Pipe + Alarm +) + +# set(UUT_SOURCES +# ${PROJECT_SOURCE_DIR}/src/Pipe.cpp +# ${PROJECT_SOURCE_DIR}/src/Alarm.cpp +# ) + +# add_executable(AlarmTest alarm_tests.cpp ${UUT_SOURCES}) +# target_include_directories(AlarmTest PRIVATE +# ${CMAKE_SOURCE_DIR}/src +# ) +# target_link_libraries(AlarmTest GTest::gtest GTest::gtest_main) +# gtest_discover_tests(AlarmTest) + +# add_executable(PipeTest pipe_tests.cpp ${UUT_SOURCES}) +# target_include_directories(PipeTest PRIVATE +# ${CMAKE_SOURCE_DIR}/src +# ) +# target_link_libraries(PipeTest GTest::gtest GTest::gtest_main) +# gtest_discover_tests(PipeTest) + +set(UUT_SOURCES) + +# Build list of source files required for unit testing +foreach(unit IN LISTS units_under_test) + set(SOURCES ${PROJECT_SOURCE_DIR}/src/${unit}.cpp) + if(EXISTS ${SOURCES}) + list(APPEND UUT_SOURCES ${PROJECT_SOURCE_DIR}/src/${unit}.cpp) + endif() +endforeach() + + +macro(add_test_targets test_case) + set(TEST_SOURCE ${PROJECT_SOURCE_DIR}/tests/${test_case}_tests.cpp) + if(EXISTS ${TEST_SOURCE}) + add_executable(${test_case}Test ${TEST_SOURCE} ${UUT_SOURCES}) + target_include_directories(${test_case}Test PRIVATE + ${CMAKE_SOURCE_DIR}/src + ) + target_link_libraries(${test_case}Test GTest::gtest GTest::gtest_main) + gtest_discover_tests(${test_case}Test) + endif() +endmacro() + + +# create test for each source file +foreach(unit IN LISTS units_under_test) + message(STATUS "Adding test: ${units}") + add_test_targets(${unit}) +endforeach() \ No newline at end of file diff --git a/solutions/05-connecting-objects/tests/Pipe_tests.cpp b/solutions/05-connecting-objects/tests/Pipe_tests.cpp new file mode 100644 index 0000000..94b5109 --- /dev/null +++ b/solutions/05-connecting-objects/tests/Pipe_tests.cpp @@ -0,0 +1,52 @@ +// Pipe_tests.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Pipe.h" +#include "gtest/gtest.h" + +namespace { +class PipeTest : public ::testing::Test { +protected: + PipeTest() = default; + Pipe pipe{}; +}; +} // namespace + +TEST_F(PipeTest, ctor) { + ASSERT_TRUE(pipe.is_empty()); +} + +TEST_F(PipeTest, pull_empty) { + auto rv = pipe.pull(); + ASSERT_EQ(std::nullopt, rv); +} + +TEST_F(PipeTest, push_not_empty) { + pipe.push(Alarm{}); + ASSERT_FALSE(pipe.is_empty()); +} + +TEST_F(PipeTest, push) { + pipe.push(Alarm{}); + auto rv = pipe.pull(); + ASSERT_NE(std::nullopt, rv); +} + +TEST_F(PipeTest, push_value) { + pipe.push(Alarm{}); + auto rv = pipe.pull(); + ASSERT_EQ(Alarm::Type::invalid, rv->type()); +} + +TEST_F(PipeTest, push_pull) { + pipe.push(Alarm{Alarm::Type::advisory}); + if (auto rv = pipe.pull()) { + ASSERT_EQ(Alarm::Type::advisory, rv->type()); + } else { + FAIL() << "missing object in pipe"; + } + if (auto rv = pipe.pull()) { + FAIL() << "unexpected object in pipe"; + } +} diff --git a/solutions/05_algorithms/src/Buffer.h b/solutions/05_algorithms/src/Buffer.h deleted file mode 100644 index 37e79dc..0000000 --- a/solutions/05_algorithms/src/Buffer.h +++ /dev/null @@ -1,82 +0,0 @@ -// Buffer.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef BUFFER_H -#define BUFFER_H - -#include -#include - -template -class Buffer { -public: - using value_type = T; - - bool add(const T& in); - bool add(T&& in); - std::optional get(); - bool is_empty() const; - size_t size() const; - -private: - using Container = std::array; - using Iterator = typename Container::iterator; - - Container buffer{}; - Iterator write{ std::begin(buffer) }; - Iterator read{ std::begin(buffer) }; - size_t num_items{ 0 }; -}; - -template -bool Buffer::add(const T& in) -{ - if (num_items == sz) return false; - - *write = in; - ++write; - ++num_items; - if (write == std::end(buffer)) write = std::begin(buffer); - return true; -} - -template -bool Buffer::add(T&& in) -{ - if (num_items == sz) return false; - - *write = std::move(in); - ++write; - ++num_items; - if (write == std::end(buffer)) write = std::begin(buffer); - return true; -} - -template -std::optional Buffer::get() -{ - if (num_items == 0) return std::nullopt; - - Iterator out = read; - ++read; - --num_items; - if (read == std::end(buffer)) read = std::begin(buffer); - - return std::move(*out); -} - -template -bool Buffer::is_empty() const -{ - return (num_items == 0); -} - -template -size_t Buffer::size() const -{ - return num_items; -} - -#endif diff --git a/solutions/05_algorithms/src/Display.cpp b/solutions/05_algorithms/src/Display.cpp deleted file mode 100644 index 78c1576..0000000 --- a/solutions/05_algorithms/src/Display.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// Display.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Event.h" -#include "Pipe.h" -#include - - -void connect(Display& disp, Pipe& pipe) -{ - disp.input = &pipe; -} - -void Display::execute() -{ - std::cout << "DISPLAY : ------------------------" << '\n'; - if (auto events = input->pull()) { - for (auto& event : *events) { - std::cout << event.as_string() << '\n'; - } - - std::cout << '\n'; - } -} diff --git a/solutions/05_algorithms/src/Event.cpp b/solutions/05_algorithms/src/Event.cpp deleted file mode 100644 index 50e1dd2..0000000 --- a/solutions/05_algorithms/src/Event.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// Event.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Event.h" - -#ifdef TRACE_ENABLED -#include -#define TRACE(msg) \ - std::cout << "Event: " << as_string() << " : " << msg << '\n' -#else -#define TRACE(msg) -#endif - -static const char* strings[]{ "unknown ", - "advisory ", - "caution ", - "warning " }; - -Event::Event() -{ - TRACE("Default ctor"); -} - -Event::Event(Alarm init) : event_type{ init } -{ - TRACE("Non-default ctor"); -} - -Event::~Event() -{ - TRACE("Dtor"); -} - -Event::Event(const Event& src) : Event{ src.event_type } -{ - TRACE("Copy ctor"); -} - -Event& Event::operator=(const Event& rhs) -{ - TRACE("Copy assignment"); - - event_type = rhs.event_type; - return *this; -} - -Alarm Event::type() const -{ - return event_type; -} - -const char* Event::as_string() const -{ - return strings[static_cast(event_type)]; -} diff --git a/solutions/05_algorithms/src/Event.h b/solutions/05_algorithms/src/Event.h deleted file mode 100644 index 40ccb39..0000000 --- a/solutions/05_algorithms/src/Event.h +++ /dev/null @@ -1,29 +0,0 @@ -// Event.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef EVENT_H -#define EVENT_H - -enum class Alarm { unknown, advisory, caution, warning }; - -class Event { -public: - Event(); - Event(Alarm init); - ~Event(); - - // Copy interface - // - Event(const Event& src); - Event& operator=(const Event& rhs); - - Alarm type() const; - char const* as_string() const; - -private: - Alarm event_type{ Alarm::unknown }; -}; - -#endif diff --git a/solutions/05_algorithms/src/Generator.cpp b/solutions/05_algorithms/src/Generator.cpp deleted file mode 100644 index 468602e..0000000 --- a/solutions/05_algorithms/src/Generator.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Generator.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Generator.h" -#include "Pipe.h" -#include -#include -#include - - -void connect(Generator& gen, Pipe& pipe) -{ - gen.output = &pipe; -} - -namespace -{ - inline Alarm random_alarm() { return static_cast((rand() % 3) + 1); } - inline Event random_event() {return Event {random_alarm()}; } -} // namespace - -void Generator::execute() -{ - std::cout << "GENERATOR: ------------------------" << '\n'; - - auto num_events = rand() % 9 + 1; - Pipe::element_type events{}; - - std::cout << "Generating " << num_events << " event" - << (num_events == 1 ? "" : "s") << '\n'; - - std::generate_n(std::back_inserter(events), num_events, random_event); - - output->push(events); - - std::cout << '\n'; -} diff --git a/solutions/05_algorithms/src/Pipe.cpp b/solutions/05_algorithms/src/Pipe.cpp deleted file mode 100644 index 77aa098..0000000 --- a/solutions/05_algorithms/src/Pipe.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Pipe.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Pipe.h" - -void Pipe::push(const Pipe::element_type& in_val) -{ - element = in_val; -} - -std::optional Pipe::pull() -{ - if (element.empty()) return std::nullopt; - return element; -} diff --git a/solutions/05_algorithms/src/Pipe.h b/solutions/05_algorithms/src/Pipe.h deleted file mode 100644 index ff6c9c5..0000000 --- a/solutions/05_algorithms/src/Pipe.h +++ /dev/null @@ -1,24 +0,0 @@ -// Pipe.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef PIPE_H -#define PIPE_H - -#include -#include -#include "Event.h" - -class Pipe { -public: - using element_type = std::vector; - - void push(const element_type& in_val); - std::optional pull(); - -private: - element_type element{}; -}; - -#endif diff --git a/solutions/05_algorithms/src/main.cpp b/solutions/05_algorithms/src/main.cpp deleted file mode 100644 index 77c39c1..0000000 --- a/solutions/05_algorithms/src/main.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// main.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Generator.h" -#include "Pipe.h" - -int main() -{ - Generator generator{}; - Display display{}; - Pipe pipe{}; - - connect(generator, pipe); - connect(display, pipe); - - for (int i = 0; i < 10; ++i) { - generator.execute(); - display.execute(); - } -} diff --git a/solutions/06-move-semantics/src/Alarm.cpp b/solutions/06-move-semantics/src/Alarm.cpp new file mode 100644 index 0000000..000b917 --- /dev/null +++ b/solutions/06-move-semantics/src/Alarm.cpp @@ -0,0 +1,46 @@ +// Alarm.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include +#include + + + +Alarm::Alarm(Type alarm_init) : value{alarm_init} +{} + +const char* Alarm::to_string() const { + switch (value) { + case Type::advisory: + return "advisory"; + case Type::caution: + return "caution"; + case Type::warning: + return "warning"; + default: + return "invalid"; + } +} + +Alarm::Type Alarm::type() const { + return value; +} + +std::ostream& operator<<(std::ostream& os, Alarm const& alarm) { + os << alarm.to_string(); + return os; +} + +Alarm make_alarm(Alarm::Type type) +{ + return Alarm{ type }; +} + +void print_alarm(Alarm const& alarm) +{ + std::cout << static_cast(alarm.type()) << ':' + << alarm.to_string() + << '\n'; +} diff --git a/solutions/06-move-semantics/src/Alarm.h b/solutions/06-move-semantics/src/Alarm.h new file mode 100644 index 0000000..6731b78 --- /dev/null +++ b/solutions/06-move-semantics/src/Alarm.h @@ -0,0 +1,37 @@ +// Alarm.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_H +#define ALARM_H + +#include + +class Alarm { +public: + enum class Type { invalid, advisory, caution, warning }; + + Alarm() = default; + explicit Alarm(Type alarm_init); + + // Implictly delete when move semantics are explicity defined + Alarm(Alarm const&) = delete; + Alarm& operator=(Alarm const&) = delete; + + Alarm(Alarm&& rhs) noexcept = default; + Alarm& operator=(Alarm&& rhs) noexcept = default; + + const char* to_string() const; + Type type() const; + +private: + Type value{ Type::invalid }; +}; + +std::ostream& operator<<(std::ostream& os, const Alarm& alarm); + +void print_alarm(Alarm const& alarm); +Alarm make_alarm(Alarm::Type type); + +#endif diff --git a/solutions/06-move-semantics/src/AlarmFilter.cpp b/solutions/06-move-semantics/src/AlarmFilter.cpp new file mode 100644 index 0000000..1c2676c --- /dev/null +++ b/solutions/06-move-semantics/src/AlarmFilter.cpp @@ -0,0 +1,33 @@ +// AlarmFilter.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include +#include "AlarmFilter.h" +#include "Pipe.h" + +AlarmFilter::AlarmFilter(Alarm::Type remove_this) +: value{ remove_this } +{ } + +AlarmFilter::AlarmFilter(Alarm::Type remove_this, Pipe& in, Pipe& out) +: value{ remove_this }, input{ &in }, output{ &out } +{ } + +void AlarmFilter::execute() +{ + if (std::optional alarm = input->pull()) { + if (alarm->type() != this->value) { + output->push(std::move(alarm.value())); + } + else { + std::cout << "Filter: " << alarm->to_string() << " removed\n"; + } + } +} + +void connect(AlarmFilter& filter, Pipe& in, Pipe& out) +{ + filter.input = ∈ + filter.output = &out; +} diff --git a/solutions/06-move-semantics/src/AlarmFilter.h b/solutions/06-move-semantics/src/AlarmFilter.h new file mode 100644 index 0000000..12b2cc1 --- /dev/null +++ b/solutions/06-move-semantics/src/AlarmFilter.h @@ -0,0 +1,28 @@ +// AlarmFilter.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_FILTER_H +#define ALARM_FILTER_H + +#include "Alarm.h" + +class Pipe; + +class AlarmFilter +{ +public: + explicit AlarmFilter(Alarm::Type remove_this); + explicit AlarmFilter(Alarm::Type remove_this, Pipe& in, Pipe& out); + void execute(); + +private: + Alarm::Type value; + + Pipe* input{}; + Pipe* output{}; + friend void connect(AlarmFilter& filter, Pipe& in, Pipe& out); +}; + +#endif diff --git a/solutions/06-move-semantics/src/Buffer.cpp b/solutions/06-move-semantics/src/Buffer.cpp new file mode 100644 index 0000000..53afa33 --- /dev/null +++ b/solutions/06-move-semantics/src/Buffer.cpp @@ -0,0 +1,39 @@ +// Buffer.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Buffer.h" + +bool Buffer::add(Alarm&& in) +{ + if (num_elems == sz) return false; + + *write_pos = std::move(in); + ++num_elems; + ++write_pos; + if (write_pos == std::end(elems)) write_pos = std::begin(elems); + + return true; +} + +bool Buffer::get(Alarm& out) +{ + if (num_elems == 0) return false; + + out = std::move(*read_pos); + --num_elems; + ++read_pos; + if (read_pos == std::end(elems)) read_pos = std::begin(elems); + + return true; +} + +bool Buffer::is_empty() const +{ + return (num_elems == 0); +} + +bool Buffer::is_full() const +{ + return (num_elems == sz); +} diff --git a/solutions/06-move-semantics/src/Buffer.h b/solutions/06-move-semantics/src/Buffer.h new file mode 100644 index 0000000..9bddbbf --- /dev/null +++ b/solutions/06-move-semantics/src/Buffer.h @@ -0,0 +1,33 @@ +// Buffer.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef BUFFER_H +#define BUFFER_H + +#include "Alarm.h" +#include +#include + +class Buffer { +public: + Buffer() = default; + + bool add(Alarm&& in); + bool get(Alarm& out); + + bool is_empty() const; + bool is_full() const; + +private: + static constexpr std::size_t sz{ 4 }; + using Container = std::array; + + Container elems {}; + Container::iterator write_pos{std::begin(elems)}; + Container::iterator read_pos{std::begin(elems)}; + size_t num_elems {}; +}; + +#endif diff --git a/solutions/06-move-semantics/src/Display.cpp b/solutions/06-move-semantics/src/Display.cpp new file mode 100644 index 0000000..6d077b4 --- /dev/null +++ b/solutions/06-move-semantics/src/Display.cpp @@ -0,0 +1,23 @@ +// Display.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Display.h" +#include "Pipe.h" +#include +#include + +Display::Display(Pipe& ip) : input{&ip} {} + +void Display::execute() { + assert(input); + + if (auto alarm = input->pull()) { + std::cout << "Display: " << *alarm << '\n'; + } + +} + +void connect(Display& display, Pipe& pipe) { + display.input = &pipe; +} diff --git a/solutions/03_connecting_objects/src/Display.h b/solutions/06-move-semantics/src/Display.h similarity index 64% rename from solutions/03_connecting_objects/src/Display.h rename to solutions/06-move-semantics/src/Display.h index 1f39242..eecd5fc 100644 --- a/solutions/03_connecting_objects/src/Display.h +++ b/solutions/06-move-semantics/src/Display.h @@ -8,16 +8,16 @@ class Pipe; -class Display { +class Display +{ public: Display() = default; - Display(Pipe& ip) : input{ &ip } {} - + explicit Display(Pipe& ip); void execute(); private: - Pipe* input{}; - friend void connect(Display& disp, Pipe& pipe); + Pipe* input{}; + friend void connect(Display& display, Pipe& pipe); }; #endif diff --git a/solutions/06-move-semantics/src/Generator.cpp b/solutions/06-move-semantics/src/Generator.cpp new file mode 100644 index 0000000..ea4fd20 --- /dev/null +++ b/solutions/06-move-semantics/src/Generator.cpp @@ -0,0 +1,30 @@ +// Generator.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Generator.h" +#include "Pipe.h" +#include +#include +#include + +namespace +{ + Alarm random_alarm() { + return make_alarm(Alarm::Type((rand()%3) + 1)); + } +} // namespace + +void Generator::execute() { + assert(output); + + auto alarm = random_alarm(); + std::cout << "Generate: " << alarm << '\n'; + output->push(std::move(alarm)); +} + +Generator::Generator(Pipe& pipe) : output{&pipe} {} + +void connect(Generator& gen, Pipe& pipe) { + gen.output = &pipe; +} diff --git a/solutions/05_algorithms/src/Generator.h b/solutions/06-move-semantics/src/Generator.h similarity index 73% rename from solutions/05_algorithms/src/Generator.h rename to solutions/06-move-semantics/src/Generator.h index 609a5f3..1ef610d 100644 --- a/solutions/05_algorithms/src/Generator.h +++ b/solutions/06-move-semantics/src/Generator.h @@ -8,12 +8,15 @@ class Pipe; -class Generator { +class Generator +{ public: + Generator() = default; + explicit Generator(Pipe& pipe); void execute(); private: - Pipe* output{}; + Pipe* output{}; friend void connect(Generator& gen, Pipe& pipe); }; diff --git a/solutions/06-move-semantics/src/Pipe.cpp b/solutions/06-move-semantics/src/Pipe.cpp new file mode 100644 index 0000000..e72f081 --- /dev/null +++ b/solutions/06-move-semantics/src/Pipe.cpp @@ -0,0 +1,24 @@ +// Pipe.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Pipe.h" + +bool Pipe::push(Alarm&& alarm) +{ + return buffer.add(std::move(alarm)); +} + +std::optional Pipe::pull() +{ + Alarm alarm{}; + if (buffer.get(alarm)) { + return alarm; + } + return std::nullopt; +} + +bool Pipe::is_empty() const +{ + return buffer.is_empty(); +} diff --git a/solutions/06-move-semantics/src/Pipe.h b/solutions/06-move-semantics/src/Pipe.h new file mode 100644 index 0000000..5178993 --- /dev/null +++ b/solutions/06-move-semantics/src/Pipe.h @@ -0,0 +1,23 @@ +// Pipe.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef _PIPE_H +#define _PIPE_H + +#include +#include "Buffer.h" + +class Pipe +{ +public: + bool push(Alarm&& alarm); + std::optional pull(); + bool is_empty() const; + +private: + Buffer buffer{}; +}; + +#endif diff --git a/solutions/06-move-semantics/src/main.cpp b/solutions/06-move-semantics/src/main.cpp new file mode 100644 index 0000000..9799f80 --- /dev/null +++ b/solutions/06-move-semantics/src/main.cpp @@ -0,0 +1,30 @@ +// main.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Pipe.h" +#include "Display.h" +#include "Generator.h" +#include "AlarmFilter.h" +#include +#include + +static constexpr int run_count {4}; + +int main() +{ + Pipe pipe1{}; + Pipe pipe2{}; + Generator generator{ pipe1 }; + AlarmFilter filter{ Alarm::Type::advisory, pipe1, pipe2 }; + Display display{ pipe2 }; + + for (int i{0}; i < run_count; ++i) { + generator.execute(); + filter.execute(); + display.execute(); + } + + std::cout << "\nCompleted OK\n"; +} + diff --git a/solutions/06_callable_objects/src/Buffer.h b/solutions/06_callable_objects/src/Buffer.h deleted file mode 100644 index 37e79dc..0000000 --- a/solutions/06_callable_objects/src/Buffer.h +++ /dev/null @@ -1,82 +0,0 @@ -// Buffer.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef BUFFER_H -#define BUFFER_H - -#include -#include - -template -class Buffer { -public: - using value_type = T; - - bool add(const T& in); - bool add(T&& in); - std::optional get(); - bool is_empty() const; - size_t size() const; - -private: - using Container = std::array; - using Iterator = typename Container::iterator; - - Container buffer{}; - Iterator write{ std::begin(buffer) }; - Iterator read{ std::begin(buffer) }; - size_t num_items{ 0 }; -}; - -template -bool Buffer::add(const T& in) -{ - if (num_items == sz) return false; - - *write = in; - ++write; - ++num_items; - if (write == std::end(buffer)) write = std::begin(buffer); - return true; -} - -template -bool Buffer::add(T&& in) -{ - if (num_items == sz) return false; - - *write = std::move(in); - ++write; - ++num_items; - if (write == std::end(buffer)) write = std::begin(buffer); - return true; -} - -template -std::optional Buffer::get() -{ - if (num_items == 0) return std::nullopt; - - Iterator out = read; - ++read; - --num_items; - if (read == std::end(buffer)) read = std::begin(buffer); - - return std::move(*out); -} - -template -bool Buffer::is_empty() const -{ - return (num_items == 0); -} - -template -size_t Buffer::size() const -{ - return num_items; -} - -#endif diff --git a/solutions/06_callable_objects/src/Display.cpp b/solutions/06_callable_objects/src/Display.cpp deleted file mode 100644 index 78c1576..0000000 --- a/solutions/06_callable_objects/src/Display.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// Display.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Event.h" -#include "Pipe.h" -#include - - -void connect(Display& disp, Pipe& pipe) -{ - disp.input = &pipe; -} - -void Display::execute() -{ - std::cout << "DISPLAY : ------------------------" << '\n'; - if (auto events = input->pull()) { - for (auto& event : *events) { - std::cout << event.as_string() << '\n'; - } - - std::cout << '\n'; - } -} diff --git a/solutions/06_callable_objects/src/Event.cpp b/solutions/06_callable_objects/src/Event.cpp deleted file mode 100644 index 50e1dd2..0000000 --- a/solutions/06_callable_objects/src/Event.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// Event.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Event.h" - -#ifdef TRACE_ENABLED -#include -#define TRACE(msg) \ - std::cout << "Event: " << as_string() << " : " << msg << '\n' -#else -#define TRACE(msg) -#endif - -static const char* strings[]{ "unknown ", - "advisory ", - "caution ", - "warning " }; - -Event::Event() -{ - TRACE("Default ctor"); -} - -Event::Event(Alarm init) : event_type{ init } -{ - TRACE("Non-default ctor"); -} - -Event::~Event() -{ - TRACE("Dtor"); -} - -Event::Event(const Event& src) : Event{ src.event_type } -{ - TRACE("Copy ctor"); -} - -Event& Event::operator=(const Event& rhs) -{ - TRACE("Copy assignment"); - - event_type = rhs.event_type; - return *this; -} - -Alarm Event::type() const -{ - return event_type; -} - -const char* Event::as_string() const -{ - return strings[static_cast(event_type)]; -} diff --git a/solutions/06_callable_objects/src/Event.h b/solutions/06_callable_objects/src/Event.h deleted file mode 100644 index 40ccb39..0000000 --- a/solutions/06_callable_objects/src/Event.h +++ /dev/null @@ -1,29 +0,0 @@ -// Event.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef EVENT_H -#define EVENT_H - -enum class Alarm { unknown, advisory, caution, warning }; - -class Event { -public: - Event(); - Event(Alarm init); - ~Event(); - - // Copy interface - // - Event(const Event& src); - Event& operator=(const Event& rhs); - - Alarm type() const; - char const* as_string() const; - -private: - Alarm event_type{ Alarm::unknown }; -}; - -#endif diff --git a/solutions/06_callable_objects/src/EventFilter.cpp b/solutions/06_callable_objects/src/EventFilter.cpp deleted file mode 100644 index a780f61..0000000 --- a/solutions/06_callable_objects/src/EventFilter.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// EventFilter.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "EventFilter.h" -#include "Pipe.h" -#include -#include - - -void connect(EventFilter& filter, Pipe& in, Pipe& out) -{ - filter.input = ∈ - filter.output = &out; -} - -void EventFilter::execute() -{ - std::cout << "FILTER : ------------------------" << '\n'; - if (auto events = input->pull()) { - auto initial_size = events->size(); - - auto it = remove_if( - std::begin(*events), end(*events), [this](const Event& event) { - return event.type() == filter_value; - }); - - events->erase(it, std::end(*events)); - - auto event_removed = initial_size - events->size(); - - std::cout << "Removed " << event_removed << " event"; - std::cout << (event_removed == 1 ? "" : "s") << '\n'; - - output->push(*events); - - std::cout << '\n'; - } -} diff --git a/solutions/06_callable_objects/src/EventFilter.h b/solutions/06_callable_objects/src/EventFilter.h deleted file mode 100644 index c148a65..0000000 --- a/solutions/06_callable_objects/src/EventFilter.h +++ /dev/null @@ -1,27 +0,0 @@ -// EventFilter.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef ID_FILTER -#define ID_FILTER - -#include "Event.h" - -class Pipe; - -class EventFilter { -public: - EventFilter(Alarm remove_this) : filter_value{ remove_this } {} - - void execute(); - -private: - Alarm filter_value{ Alarm::unknown }; - - Pipe* input{}; - Pipe* output{}; - friend void connect(EventFilter& filter, Pipe& in, Pipe& out); -}; - -#endif diff --git a/solutions/06_callable_objects/src/Generator.cpp b/solutions/06_callable_objects/src/Generator.cpp deleted file mode 100644 index 0cdb360..0000000 --- a/solutions/06_callable_objects/src/Generator.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Generator.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Generator.h" -#include "Pipe.h" -#include -#include -#include - - -void connect(Generator& gen, Pipe& pipe) -{ - gen.output = &pipe; -} - -namespace -{ - inline Alarm random_alarm() { return static_cast((rand() % 3) + 1); } - inline Event random_event() {return Event {random_alarm()}; } -} // namespace - -void Generator::execute() -{ - std::cout << "GENERATOR: ------------------------" << '\n'; - - auto num_events = rand() % 9 + 1; - Pipe::element_type events{}; - - std::cout << "Generating " << num_events << " event" - << (num_events == 1 ? "" : "s") << '\n'; - - std::generate_n(std::back_inserter(events), num_events, []() { - return Event{ random_alarm() }; - }); - - output->push(events); - - std::cout << '\n'; -} diff --git a/solutions/06_callable_objects/src/Pipe.cpp b/solutions/06_callable_objects/src/Pipe.cpp deleted file mode 100644 index 77aa098..0000000 --- a/solutions/06_callable_objects/src/Pipe.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Pipe.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Pipe.h" - -void Pipe::push(const Pipe::element_type& in_val) -{ - element = in_val; -} - -std::optional Pipe::pull() -{ - if (element.empty()) return std::nullopt; - return element; -} diff --git a/solutions/06_callable_objects/src/Pipe.h b/solutions/06_callable_objects/src/Pipe.h deleted file mode 100644 index ff6c9c5..0000000 --- a/solutions/06_callable_objects/src/Pipe.h +++ /dev/null @@ -1,24 +0,0 @@ -// Pipe.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef PIPE_H -#define PIPE_H - -#include -#include -#include "Event.h" - -class Pipe { -public: - using element_type = std::vector; - - void push(const element_type& in_val); - std::optional pull(); - -private: - element_type element{}; -}; - -#endif diff --git a/solutions/06_callable_objects/src/main.cpp b/solutions/06_callable_objects/src/main.cpp deleted file mode 100644 index 1ebd0ba..0000000 --- a/solutions/06_callable_objects/src/main.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// main.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Generator.h" -#include "EventFilter.h" -#include "Pipe.h" - -int main() -{ - Generator generator{}; - Display display{}; - EventFilter filter{ Alarm::advisory }; - - Pipe pipe1{}; - Pipe pipe2{}; - - connect(generator, pipe1); - connect(filter, pipe1, pipe2); - connect(display, pipe2); - - for (int i = 0; i < 10; ++i) { - generator.execute(); - filter.execute(); - display.execute(); - } -} diff --git a/solutions/07-smart-pointers/src/Alarm.cpp b/solutions/07-smart-pointers/src/Alarm.cpp new file mode 100644 index 0000000..e361ea1 --- /dev/null +++ b/solutions/07-smart-pointers/src/Alarm.cpp @@ -0,0 +1,60 @@ +// Alarm.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include +#include + + +Alarm::Alarm(Type alarm_init) : value{alarm_init} {} + +Alarm::Alarm(Alarm&& rhs) noexcept : Alarm{} { + swap(*this, rhs); +} + +Alarm& Alarm::operator=(Alarm&& rhs) noexcept { + if (this != &rhs) { + value = std::exchange(rhs.value, Type::invalid); + } + return *this; +} + +void swap(Alarm& lhs, Alarm& rhs) { + using std::swap; + swap(lhs.value, rhs.value); +} + +const char* Alarm::to_string() const { + switch (value) { + case Type::advisory: + return "advisory"; + case Type::caution: + return "caution"; + case Type::warning: + return "warning"; + default: + return "invalid"; + } +} + +Alarm::Type Alarm::type() const { + return value; +} + +std::ostream& operator<<(std::ostream& os, Alarm const& alarm) { + os << alarm.to_string(); + return os; +} + +Alarm make_alarm(Alarm::Type type) +{ + return Alarm{ type }; +} + +void print_alarm(Alarm const& alarm) +{ + std::cout << static_cast(alarm.type()) << ':' + << alarm.to_string() + << '\n'; +} diff --git a/solutions/07-smart-pointers/src/Alarm.h b/solutions/07-smart-pointers/src/Alarm.h new file mode 100644 index 0000000..aac144b --- /dev/null +++ b/solutions/07-smart-pointers/src/Alarm.h @@ -0,0 +1,34 @@ +// Alarm.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_H +#define ALARM_H + +#include + +class Alarm { +public: + enum class Type { invalid, advisory, caution, warning }; + + Alarm() = default; + explicit Alarm(Type alarm_init); + + Alarm(Alarm&& rhs) noexcept; + Alarm& operator=(Alarm&& rhs) noexcept; + friend void swap(Alarm& lhs, Alarm& rhs); + + const char* to_string() const; + Type type() const; + +private: + Type value{ Type::invalid }; +}; + +std::ostream& operator<<(std::ostream& os, const Alarm& alarm); + +void print_alarm(Alarm const& alarm); +Alarm make_alarm(Alarm::Type type); + +#endif diff --git a/solutions/07-smart-pointers/src/AlarmFilter.cpp b/solutions/07-smart-pointers/src/AlarmFilter.cpp new file mode 100644 index 0000000..708f880 --- /dev/null +++ b/solutions/07-smart-pointers/src/AlarmFilter.cpp @@ -0,0 +1,33 @@ +// AlarmFilter.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include +#include "AlarmFilter.h" +#include "Pipe.h" + +AlarmFilter::AlarmFilter(Alarm::Type remove_this) +: value{ remove_this } +{ } + +AlarmFilter::AlarmFilter(Alarm::Type remove_this, Pipe& in, Pipe& out) +: value{ remove_this }, input{ &in }, output{ &out } +{ } + +void AlarmFilter::execute() +{ + if (auto alarm = input->pull()) { + if (alarm->type() != this->value) { + output->push(std::move(alarm)); + } + else { + std::cout << "Filter: " << alarm->to_string() << " removed\n"; + } + } +} + +void connect(AlarmFilter& filter, Pipe& in, Pipe& out) +{ + filter.input = ∈ + filter.output = &out; +} diff --git a/solutions/07-smart-pointers/src/AlarmFilter.h b/solutions/07-smart-pointers/src/AlarmFilter.h new file mode 100644 index 0000000..12b2cc1 --- /dev/null +++ b/solutions/07-smart-pointers/src/AlarmFilter.h @@ -0,0 +1,28 @@ +// AlarmFilter.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_FILTER_H +#define ALARM_FILTER_H + +#include "Alarm.h" + +class Pipe; + +class AlarmFilter +{ +public: + explicit AlarmFilter(Alarm::Type remove_this); + explicit AlarmFilter(Alarm::Type remove_this, Pipe& in, Pipe& out); + void execute(); + +private: + Alarm::Type value; + + Pipe* input{}; + Pipe* output{}; + friend void connect(AlarmFilter& filter, Pipe& in, Pipe& out); +}; + +#endif diff --git a/solutions/07-smart-pointers/src/Buffer.cpp b/solutions/07-smart-pointers/src/Buffer.cpp new file mode 100644 index 0000000..49dc2b4 --- /dev/null +++ b/solutions/07-smart-pointers/src/Buffer.cpp @@ -0,0 +1,39 @@ +// Buffer.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Buffer.h" + +bool Buffer::add(std::unique_ptr in) +{ + if (num_elems == sz) return false; + + *write_pos = std::move(in); + ++num_elems; + ++write_pos; + if (write_pos == std::end(elems)) write_pos = std::begin(elems); + + return true; +} + +bool Buffer::get(std::unique_ptr& out) +{ + if (num_elems == 0) return false; + + out = std::move(*read_pos); + --num_elems; + ++read_pos; + if (read_pos == std::end(elems)) read_pos = std::begin(elems); + + return true; +} + +bool Buffer::is_empty() const +{ + return (num_elems == 0); +} + +bool Buffer::is_full() const +{ + return (num_elems == sz); +} diff --git a/solutions/07-smart-pointers/src/Buffer.h b/solutions/07-smart-pointers/src/Buffer.h new file mode 100644 index 0000000..911afd5 --- /dev/null +++ b/solutions/07-smart-pointers/src/Buffer.h @@ -0,0 +1,34 @@ +// Buffer.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef BUFFER_H +#define BUFFER_H + +#include "Alarm.h" +#include +#include +#include + +class Buffer { +public: + Buffer() = default; + + bool add(std::unique_ptr in); + bool get(std::unique_ptr& out); + + bool is_empty() const; + bool is_full() const; + +private: + static constexpr std::size_t sz{ 8 }; + using Container = std::array, sz>; + + Container elems {}; + Container::iterator write_pos{std::begin(elems)}; + Container::iterator read_pos{std::begin(elems)}; + size_t num_elems {}; +}; + +#endif diff --git a/solutions/07-smart-pointers/src/Display.cpp b/solutions/07-smart-pointers/src/Display.cpp new file mode 100644 index 0000000..6d077b4 --- /dev/null +++ b/solutions/07-smart-pointers/src/Display.cpp @@ -0,0 +1,23 @@ +// Display.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Display.h" +#include "Pipe.h" +#include +#include + +Display::Display(Pipe& ip) : input{&ip} {} + +void Display::execute() { + assert(input); + + if (auto alarm = input->pull()) { + std::cout << "Display: " << *alarm << '\n'; + } + +} + +void connect(Display& display, Pipe& pipe) { + display.input = &pipe; +} diff --git a/solutions/06_callable_objects/src/Display.h b/solutions/07-smart-pointers/src/Display.h similarity index 64% rename from solutions/06_callable_objects/src/Display.h rename to solutions/07-smart-pointers/src/Display.h index 1f39242..eecd5fc 100644 --- a/solutions/06_callable_objects/src/Display.h +++ b/solutions/07-smart-pointers/src/Display.h @@ -8,16 +8,16 @@ class Pipe; -class Display { +class Display +{ public: Display() = default; - Display(Pipe& ip) : input{ &ip } {} - + explicit Display(Pipe& ip); void execute(); private: - Pipe* input{}; - friend void connect(Display& disp, Pipe& pipe); + Pipe* input{}; + friend void connect(Display& display, Pipe& pipe); }; #endif diff --git a/solutions/07-smart-pointers/src/Generator.cpp b/solutions/07-smart-pointers/src/Generator.cpp new file mode 100644 index 0000000..d3008ed --- /dev/null +++ b/solutions/07-smart-pointers/src/Generator.cpp @@ -0,0 +1,30 @@ +// Generator.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Generator.h" +#include "Pipe.h" +#include +#include +#include + +namespace +{ + Alarm random_alarm() { + return make_alarm(Alarm::Type((rand()%3) + 1)); + } +} // namespace + +void Generator::execute() { + assert(output); + + auto alarm = std::make_unique(random_alarm()); + std::cout << "Generate: " << *alarm << '\n'; + output->push(std::move(alarm)); +} + +Generator::Generator(Pipe& pipe) : output{&pipe} {} + +void connect(Generator& gen, Pipe& pipe) { + gen.output = &pipe; +} diff --git a/solutions/06_callable_objects/src/Generator.h b/solutions/07-smart-pointers/src/Generator.h similarity index 73% rename from solutions/06_callable_objects/src/Generator.h rename to solutions/07-smart-pointers/src/Generator.h index 4f65d17..1ef610d 100644 --- a/solutions/06_callable_objects/src/Generator.h +++ b/solutions/07-smart-pointers/src/Generator.h @@ -8,14 +8,16 @@ class Pipe; -class Generator { +class Generator +{ public: + Generator() = default; + explicit Generator(Pipe& pipe); void execute(); private: - Pipe* output{}; + Pipe* output{}; friend void connect(Generator& gen, Pipe& pipe); }; #endif - diff --git a/solutions/07-smart-pointers/src/Pipe.cpp b/solutions/07-smart-pointers/src/Pipe.cpp new file mode 100644 index 0000000..de184aa --- /dev/null +++ b/solutions/07-smart-pointers/src/Pipe.cpp @@ -0,0 +1,24 @@ +// Pipe.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Pipe.h" + +bool Pipe::push(std::unique_ptr alarm) +{ + return buffer.add(std::move(alarm)); +} + +std::unique_ptr Pipe::pull() +{ + std::unique_ptr alarm{}; + if (buffer.get(alarm)) { + return alarm; + } + return nullptr; +} + +bool Pipe::is_empty() const +{ + return buffer.is_empty(); +} diff --git a/solutions/07-smart-pointers/src/Pipe.h b/solutions/07-smart-pointers/src/Pipe.h new file mode 100644 index 0000000..413b42e --- /dev/null +++ b/solutions/07-smart-pointers/src/Pipe.h @@ -0,0 +1,23 @@ +// Pipe.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef _PIPE_H +#define _PIPE_H + +#include +#include "Buffer.h" + +class Pipe +{ +public: + bool push(std::unique_ptr alarm); + std::unique_ptr pull(); + bool is_empty() const; + +private: + Buffer buffer{}; +}; + +#endif diff --git a/solutions/07-smart-pointers/src/main.cpp b/solutions/07-smart-pointers/src/main.cpp new file mode 100644 index 0000000..06c2d24 --- /dev/null +++ b/solutions/07-smart-pointers/src/main.cpp @@ -0,0 +1,29 @@ +// main.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Pipe.h" +#include "Display.h" +#include "Generator.h" +#include "AlarmFilter.h" +#include +#include + +static constexpr int run_count {4}; + +int main() +{ + Pipe pipe1{}; + Pipe pipe2{}; + Generator generator{ pipe1 }; + AlarmFilter filter{ Alarm::Type::advisory, pipe1, pipe2 }; + Display display{ pipe2 }; + + for (int i{0}; i < run_count; ++i) { + generator.execute(); + filter.execute(); + display.execute(); + } + + std::cout << "\nCompleted OK\n"; +} diff --git a/solutions/07_resource_management/src/Display.cpp b/solutions/07_resource_management/src/Display.cpp deleted file mode 100644 index cc382f0..0000000 --- a/solutions/07_resource_management/src/Display.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Display.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Event.h" -#include "Pipe.h" -#include - - -void connect(Display& disp, Pipe& pipe) -{ - disp.input = &pipe; -} - -void Display::execute() -{ - std::cout << "DISPLAY : ------------------------" << '\n'; - - if (auto events = input->pull()) { - for (auto& event : *events) { - std::cout << event.as_string() << " : " << event.what() << '\n'; - } - - std::cout << '\n'; - } -} diff --git a/solutions/07_resource_management/src/Display.h b/solutions/07_resource_management/src/Display.h deleted file mode 100644 index 1f39242..0000000 --- a/solutions/07_resource_management/src/Display.h +++ /dev/null @@ -1,23 +0,0 @@ -// Display.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef DISPLAY_H -#define DISPLAY_H - -class Pipe; - -class Display { -public: - Display() = default; - Display(Pipe& ip) : input{ &ip } {} - - void execute(); - -private: - Pipe* input{}; - friend void connect(Display& disp, Pipe& pipe); -}; - -#endif diff --git a/solutions/07_resource_management/src/Event.cpp b/solutions/07_resource_management/src/Event.cpp deleted file mode 100644 index 21f6f19..0000000 --- a/solutions/07_resource_management/src/Event.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Event.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Event.h" -#include -#include - -#ifdef TRACE_ENABLED -#include -#define TRACE(msg) \ - std::cout << "Event: " << as_string() << " : " << msg << '\n' -#else -#define TRACE(msg) -#endif - - -static char const* strings[]{ "unknown ", - "advisory ", - "caution ", - "warning " }; - -Event::Event() -{ - TRACE("Default ctor"); -} - -Event::Event(Alarm init) : event_type{ init } -{ - TRACE("Non-default ctor"); -} - -Event::Event(Alarm init, char const* str) : event_type{ init } -{ - TRACE("Non-default ctor with string"); - - if (str) { - description = new char[strlen(str) + 1]; - strcpy(description, str); - } -} - -Event::~Event() -{ - TRACE("Dtor"); - - delete[] description; -} - -Event::Event(const Event& src) : Event{ src.event_type, src.description } -{ - TRACE("Copy ctor"); -} - -Event& Event::operator=(const Event& rhs) -{ - TRACE("Copy assignment"); - Event temp{rhs}; - swap(*this, temp); - return *this; -} - -Alarm Event::type() const -{ - return event_type; -} - -char const* Event::as_string() const -{ - return strings[static_cast(event_type)]; -} - -char const* Event::what() const -{ - return (description ? description : ""); -} - -void swap(Event& lhs, Event& rhs) -{ - using std::swap; - swap(lhs.event_type, rhs.event_type); - swap(lhs.description, rhs.description); -} diff --git a/solutions/07_resource_management/src/Event.h b/solutions/07_resource_management/src/Event.h deleted file mode 100644 index d27e5e5..0000000 --- a/solutions/07_resource_management/src/Event.h +++ /dev/null @@ -1,33 +0,0 @@ -// Event.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef EVENT_H -#define EVENT_H - -enum class Alarm { unknown, advisory, caution, warning }; - -class Event { -public: - Event(); - Event(Alarm init); - Event(Alarm init, char const* str); - - // Copy and move policy - // - ~Event(); - Event(const Event& src); - Event& operator=(const Event& rhs); - friend void swap(Event& lhs, Event& rhs); - - Alarm type() const; - char const* as_string() const; - char const* what() const; - -private: - Alarm event_type{ Alarm::unknown }; - char* description{}; -}; - -#endif diff --git a/solutions/07_resource_management/src/EventFilter.cpp b/solutions/07_resource_management/src/EventFilter.cpp deleted file mode 100644 index a780f61..0000000 --- a/solutions/07_resource_management/src/EventFilter.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// EventFilter.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "EventFilter.h" -#include "Pipe.h" -#include -#include - - -void connect(EventFilter& filter, Pipe& in, Pipe& out) -{ - filter.input = ∈ - filter.output = &out; -} - -void EventFilter::execute() -{ - std::cout << "FILTER : ------------------------" << '\n'; - if (auto events = input->pull()) { - auto initial_size = events->size(); - - auto it = remove_if( - std::begin(*events), end(*events), [this](const Event& event) { - return event.type() == filter_value; - }); - - events->erase(it, std::end(*events)); - - auto event_removed = initial_size - events->size(); - - std::cout << "Removed " << event_removed << " event"; - std::cout << (event_removed == 1 ? "" : "s") << '\n'; - - output->push(*events); - - std::cout << '\n'; - } -} diff --git a/solutions/07_resource_management/src/EventFilter.h b/solutions/07_resource_management/src/EventFilter.h deleted file mode 100644 index c148a65..0000000 --- a/solutions/07_resource_management/src/EventFilter.h +++ /dev/null @@ -1,27 +0,0 @@ -// EventFilter.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef ID_FILTER -#define ID_FILTER - -#include "Event.h" - -class Pipe; - -class EventFilter { -public: - EventFilter(Alarm remove_this) : filter_value{ remove_this } {} - - void execute(); - -private: - Alarm filter_value{ Alarm::unknown }; - - Pipe* input{}; - Pipe* output{}; - friend void connect(EventFilter& filter, Pipe& in, Pipe& out); -}; - -#endif diff --git a/solutions/07_resource_management/src/Generator.cpp b/solutions/07_resource_management/src/Generator.cpp deleted file mode 100644 index b7b1248..0000000 --- a/solutions/07_resource_management/src/Generator.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// Generator.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Generator.h" -#include "Pipe.h" -#include -#include -#include -#include -#include - - -void connect(Generator& gen, Pipe& pipe) -{ - gen.output = &pipe; -} - -namespace -{ - inline Alarm random_alarm() { return static_cast((rand() % 3) + 1); } - inline Event random_event() {return Event {random_alarm()}; } - - char const* warning_text[]{ - "It's all gone wrong!", "Panic!", "Run away!", - "Danger, Will Robinson!", "Aaaaaaargh!", "Oh no!" - }; - - inline char const* random_text() { return warning_text[rand() % 6]; } - -} // namespace - -void Generator::execute() -{ - std::cout << "GENERATOR: ------------------------" << '\n'; - - auto num_events = rand() % 9 + 1; - Pipe::element_type events{}; - - std::cout << "Generating " << num_events << " event" - << (num_events == 1 ? "" : "s") << '\n'; - - std::generate_n(std::back_inserter(events), num_events, []() { - return Event{ random_alarm(), random_text() }; - }); - - output->push(events); - - std::cout << '\n'; -} diff --git a/solutions/07_resource_management/src/Generator.h b/solutions/07_resource_management/src/Generator.h deleted file mode 100644 index 4f65d17..0000000 --- a/solutions/07_resource_management/src/Generator.h +++ /dev/null @@ -1,21 +0,0 @@ -// Generator.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef GENERATOR_H -#define GENERATOR_H - -class Pipe; - -class Generator { -public: - void execute(); - -private: - Pipe* output{}; - friend void connect(Generator& gen, Pipe& pipe); -}; - -#endif - diff --git a/solutions/07_resource_management/src/Pipe.cpp b/solutions/07_resource_management/src/Pipe.cpp deleted file mode 100644 index 77aa098..0000000 --- a/solutions/07_resource_management/src/Pipe.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Pipe.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Pipe.h" - -void Pipe::push(const Pipe::element_type& in_val) -{ - element = in_val; -} - -std::optional Pipe::pull() -{ - if (element.empty()) return std::nullopt; - return element; -} diff --git a/solutions/07_resource_management/src/Pipe.h b/solutions/07_resource_management/src/Pipe.h deleted file mode 100644 index ff6c9c5..0000000 --- a/solutions/07_resource_management/src/Pipe.h +++ /dev/null @@ -1,24 +0,0 @@ -// Pipe.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef PIPE_H -#define PIPE_H - -#include -#include -#include "Event.h" - -class Pipe { -public: - using element_type = std::vector; - - void push(const element_type& in_val); - std::optional pull(); - -private: - element_type element{}; -}; - -#endif diff --git a/solutions/07_resource_management/src/main.cpp b/solutions/07_resource_management/src/main.cpp deleted file mode 100644 index 53ce585..0000000 --- a/solutions/07_resource_management/src/main.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// main.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Generator.h" -#include "Pipe.h" -#include "EventFilter.h" - -int main() -{ - Generator generator{}; - Display display{}; - EventFilter filter{ Alarm::advisory }; - - Pipe pipe1{}; - Pipe pipe2{}; - - connect(generator, pipe1); - connect(filter, pipe1, pipe2); - connect(display, pipe2); - - for (int i = 0; i < 10; ++i) { - generator.execute(); - filter.execute(); - display.execute(); - } -} diff --git a/solutions/08-templates/src/Alarm.cpp b/solutions/08-templates/src/Alarm.cpp new file mode 100644 index 0000000..e361ea1 --- /dev/null +++ b/solutions/08-templates/src/Alarm.cpp @@ -0,0 +1,60 @@ +// Alarm.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include +#include + + +Alarm::Alarm(Type alarm_init) : value{alarm_init} {} + +Alarm::Alarm(Alarm&& rhs) noexcept : Alarm{} { + swap(*this, rhs); +} + +Alarm& Alarm::operator=(Alarm&& rhs) noexcept { + if (this != &rhs) { + value = std::exchange(rhs.value, Type::invalid); + } + return *this; +} + +void swap(Alarm& lhs, Alarm& rhs) { + using std::swap; + swap(lhs.value, rhs.value); +} + +const char* Alarm::to_string() const { + switch (value) { + case Type::advisory: + return "advisory"; + case Type::caution: + return "caution"; + case Type::warning: + return "warning"; + default: + return "invalid"; + } +} + +Alarm::Type Alarm::type() const { + return value; +} + +std::ostream& operator<<(std::ostream& os, Alarm const& alarm) { + os << alarm.to_string(); + return os; +} + +Alarm make_alarm(Alarm::Type type) +{ + return Alarm{ type }; +} + +void print_alarm(Alarm const& alarm) +{ + std::cout << static_cast(alarm.type()) << ':' + << alarm.to_string() + << '\n'; +} diff --git a/solutions/08-templates/src/Alarm.h b/solutions/08-templates/src/Alarm.h new file mode 100644 index 0000000..30ed4e5 --- /dev/null +++ b/solutions/08-templates/src/Alarm.h @@ -0,0 +1,37 @@ +// Alarm.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_H +#define ALARM_H + +#include + +class Alarm { +public: + enum class Type { invalid, advisory, caution, warning }; + + Alarm() = default; + explicit Alarm(Type alarm_init); + + Alarm(Alarm const& rhs) = default; + Alarm& operator=(Alarm const& rhs) = default; + + Alarm(Alarm&& rhs) noexcept; + Alarm& operator=(Alarm&& rhs) noexcept; + friend void swap(Alarm& lhs, Alarm& rhs); + + const char* to_string() const; + Type type() const; + +private: + Type value{ Type::invalid }; +}; + +std::ostream& operator<<(std::ostream& os, const Alarm& alarm); + +void print_alarm(Alarm const& alarm); +Alarm make_alarm(Alarm::Type type); + +#endif diff --git a/solutions/08-templates/src/AlarmFilter.cpp b/solutions/08-templates/src/AlarmFilter.cpp new file mode 100644 index 0000000..303189b --- /dev/null +++ b/solutions/08-templates/src/AlarmFilter.cpp @@ -0,0 +1,33 @@ +// AlarmFilter.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include +#include "AlarmFilter.h" +#include "Pipe.h" + +AlarmFilter::AlarmFilter(Alarm::Type remove_this) +: value{ remove_this } +{ } + +AlarmFilter::AlarmFilter(Alarm::Type remove_this, Pipe& in, Pipe& out) +: value{ remove_this }, input{ &in }, output{ &out } +{ } + +void AlarmFilter::execute() +{ + if (auto alarm = input->pull()) { + if (alarm->type() != this->value) { + output->push(std::move(alarm)); + } + else { + std::cout << "Filter: " << alarm->to_string() << " removed\n"; + } + } +} + +void connect(AlarmFilter& filter, Pipe& in, Pipe& out) +{ + filter.input = ∈ + filter.output = &out; +} diff --git a/solutions/08-templates/src/AlarmFilter.h b/solutions/08-templates/src/AlarmFilter.h new file mode 100644 index 0000000..12b2cc1 --- /dev/null +++ b/solutions/08-templates/src/AlarmFilter.h @@ -0,0 +1,28 @@ +// AlarmFilter.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_FILTER_H +#define ALARM_FILTER_H + +#include "Alarm.h" + +class Pipe; + +class AlarmFilter +{ +public: + explicit AlarmFilter(Alarm::Type remove_this); + explicit AlarmFilter(Alarm::Type remove_this, Pipe& in, Pipe& out); + void execute(); + +private: + Alarm::Type value; + + Pipe* input{}; + Pipe* output{}; + friend void connect(AlarmFilter& filter, Pipe& in, Pipe& out); +}; + +#endif diff --git a/solutions/08-templates/src/Buffer.h b/solutions/08-templates/src/Buffer.h new file mode 100644 index 0000000..3c46be9 --- /dev/null +++ b/solutions/08-templates/src/Buffer.h @@ -0,0 +1,87 @@ +// Buffer.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef BUFFER_H +#define BUFFER_H + +#include +#include + +template +class Buffer { +public: + using value_type = T; + Buffer() = default; + + bool add(value_type const& in); + bool add(value_type&& in); + auto get() -> std::optional; + + bool is_empty() const; + bool is_full() const; + + constexpr auto capacity() const -> std::size_t { return sz; } + +private: + using Container = std::array; + + Container elems {}; + typename Container::iterator write_pos{std::begin(elems)}; + typename Container::iterator read_pos{std::begin(elems)}; + std::size_t num_elems {}; +}; + +template +bool Buffer::add(value_type const& in) +{ + if (num_elems == sz) return false; + + *write_pos = in; + ++num_elems; + ++write_pos; + if (write_pos == std::end(elems)) write_pos = std::begin(elems); + + return true; +} + +template +bool Buffer::add(value_type&& in) +{ + if (num_elems == sz) return false; + + *write_pos = std::move(in); + ++num_elems; + ++write_pos; + if (write_pos == std::end(elems)) write_pos = std::begin(elems); + + return true; +} + +template +auto Buffer::get() -> std::optional +{ + if (num_elems == 0) return std::nullopt; + + auto value = std::move(*read_pos); + --num_elems; + ++read_pos; + if (read_pos == std::end(elems)) read_pos = std::begin(elems); + + return value; +} + +template +bool Buffer::is_empty() const +{ + return (num_elems == 0); +} + +template +bool Buffer::is_full() const +{ + return (num_elems == sz); +} + +#endif diff --git a/solutions/08-templates/src/Display.cpp b/solutions/08-templates/src/Display.cpp new file mode 100644 index 0000000..8c06890 --- /dev/null +++ b/solutions/08-templates/src/Display.cpp @@ -0,0 +1,22 @@ +// Display.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Display.h" +#include "Pipe.h" +#include +#include + +Display::Display(Pipe& ip) : input{&ip} {} + +void Display::execute() { + assert(input); + + if (auto alarm = input->pull()) { + std::cout << "Display: " << *alarm << '\n'; + } +} + +void connect(Display& display, Pipe& pipe) { + display.input = &pipe; +} diff --git a/solutions/05_algorithms/src/Display.h b/solutions/08-templates/src/Display.h similarity index 64% rename from solutions/05_algorithms/src/Display.h rename to solutions/08-templates/src/Display.h index 1f39242..eecd5fc 100644 --- a/solutions/05_algorithms/src/Display.h +++ b/solutions/08-templates/src/Display.h @@ -8,16 +8,16 @@ class Pipe; -class Display { +class Display +{ public: Display() = default; - Display(Pipe& ip) : input{ &ip } {} - + explicit Display(Pipe& ip); void execute(); private: - Pipe* input{}; - friend void connect(Display& disp, Pipe& pipe); + Pipe* input{}; + friend void connect(Display& display, Pipe& pipe); }; #endif diff --git a/solutions/08-templates/src/Generator.cpp b/solutions/08-templates/src/Generator.cpp new file mode 100644 index 0000000..d3008ed --- /dev/null +++ b/solutions/08-templates/src/Generator.cpp @@ -0,0 +1,30 @@ +// Generator.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Generator.h" +#include "Pipe.h" +#include +#include +#include + +namespace +{ + Alarm random_alarm() { + return make_alarm(Alarm::Type((rand()%3) + 1)); + } +} // namespace + +void Generator::execute() { + assert(output); + + auto alarm = std::make_unique(random_alarm()); + std::cout << "Generate: " << *alarm << '\n'; + output->push(std::move(alarm)); +} + +Generator::Generator(Pipe& pipe) : output{&pipe} {} + +void connect(Generator& gen, Pipe& pipe) { + gen.output = &pipe; +} diff --git a/solutions/04_containers/src/Generator.h b/solutions/08-templates/src/Generator.h similarity index 73% rename from solutions/04_containers/src/Generator.h rename to solutions/08-templates/src/Generator.h index 609a5f3..1ef610d 100644 --- a/solutions/04_containers/src/Generator.h +++ b/solutions/08-templates/src/Generator.h @@ -8,12 +8,15 @@ class Pipe; -class Generator { +class Generator +{ public: + Generator() = default; + explicit Generator(Pipe& pipe); void execute(); private: - Pipe* output{}; + Pipe* output{}; friend void connect(Generator& gen, Pipe& pipe); }; diff --git a/solutions/08-templates/src/Pipe.cpp b/solutions/08-templates/src/Pipe.cpp new file mode 100644 index 0000000..6d29182 --- /dev/null +++ b/solutions/08-templates/src/Pipe.cpp @@ -0,0 +1,23 @@ +// Pipe.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Pipe.h" + +bool Pipe::push(value_type&& alarm) +{ + return buffer.add(std::move(alarm)); +} + +auto Pipe::pull() -> value_type +{ + if (auto alarm = buffer.get()) { + return std::move(alarm.value()); + } + return nullptr; +} + +bool Pipe::is_empty() const +{ + return buffer.is_empty(); +} diff --git a/solutions/08-templates/src/Pipe.h b/solutions/08-templates/src/Pipe.h new file mode 100644 index 0000000..2b353c2 --- /dev/null +++ b/solutions/08-templates/src/Pipe.h @@ -0,0 +1,28 @@ +// Pipe.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef _PIPE_H +#define _PIPE_H + +#include +#include +#include "Buffer.h" +#include "Alarm.h" + +class Pipe +{ +public: + using value_type = std::unique_ptr; + + bool push(value_type&& alarm); + value_type pull(); + bool is_empty() const; + +private: + using Container = Buffer; + Container buffer{}; +}; + +#endif diff --git a/solutions/08-templates/src/main.cpp b/solutions/08-templates/src/main.cpp new file mode 100644 index 0000000..06c2d24 --- /dev/null +++ b/solutions/08-templates/src/main.cpp @@ -0,0 +1,29 @@ +// main.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Pipe.h" +#include "Display.h" +#include "Generator.h" +#include "AlarmFilter.h" +#include +#include + +static constexpr int run_count {4}; + +int main() +{ + Pipe pipe1{}; + Pipe pipe2{}; + Generator generator{ pipe1 }; + AlarmFilter filter{ Alarm::Type::advisory, pipe1, pipe2 }; + Display display{ pipe2 }; + + for (int i{0}; i < run_count; ++i) { + generator.execute(); + filter.execute(); + display.execute(); + } + + std::cout << "\nCompleted OK\n"; +} diff --git a/solutions/08_move_semantics/src/Display.cpp b/solutions/08_move_semantics/src/Display.cpp deleted file mode 100644 index f446be8..0000000 --- a/solutions/08_move_semantics/src/Display.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Display.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Event.h" -#include "Pipe.h" -#include - - -void connect(Display& disp, Pipe& pipe) -{ - disp.input = &pipe; -} - -void Display::execute() -{ - std::cout << "DISPLAY : ------------------------" << '\n'; - - // Using the return value from pull to - // initialise events => copy elision; - // therefore no move required - // - auto events = input->pull(); - - for (auto& event : *events) { - std::cout << event.as_string() << " : " << event.what() << '\n'; - } - - std::cout << '\n'; -} diff --git a/solutions/08_move_semantics/src/Display.h b/solutions/08_move_semantics/src/Display.h deleted file mode 100644 index 1f39242..0000000 --- a/solutions/08_move_semantics/src/Display.h +++ /dev/null @@ -1,23 +0,0 @@ -// Display.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef DISPLAY_H -#define DISPLAY_H - -class Pipe; - -class Display { -public: - Display() = default; - Display(Pipe& ip) : input{ &ip } {} - - void execute(); - -private: - Pipe* input{}; - friend void connect(Display& disp, Pipe& pipe); -}; - -#endif diff --git a/solutions/08_move_semantics/src/Event.cpp b/solutions/08_move_semantics/src/Event.cpp deleted file mode 100644 index 8c737df..0000000 --- a/solutions/08_move_semantics/src/Event.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// Event.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Event.h" -#include -#include - -#ifdef TRACE_ENABLED -#include -#define TRACE(msg) \ - std::cout << "Event: " << as_string() << " : " << msg << '\n' -#else -#define TRACE(msg) -#endif - - -static char const* strings[]{ "unknown ", - "advisory ", - "caution ", - "warning " }; - -Event::Event() -{ - TRACE("Default ctor"); -} - -Event::Event(Alarm init) : event_type{ init } -{ - TRACE("Non-default ctor"); -} - -Event::Event(Alarm init, char const* str) : event_type{ init } -{ - TRACE("Non-default ctor with string"); - - if (str) { - description = new char[strlen(str) + 1]; - strcpy(description, str); - } -} - -Event::Event(Event&& src) noexcept : Event{} -{ - TRACE("Move ctor"); - - swap(*this, src); -} - -Event::~Event() -{ - TRACE("Dtor"); - - delete[] description; -} - -// Event::Event(const Event& src) : Event{ src.event_type, src.description } -// { -// TRACE("Copy ctor"); -// } - -Event& Event::operator=(Event && rhs) -{ - TRACE("Assignment"); - swap(*this, rhs); - return *this; -} - -Alarm Event::type() const -{ - return event_type; -} - -char const* Event::as_string() const -{ - return strings[static_cast(event_type)]; -} - -char const* Event::what() const -{ - return (description ? description : ""); -} - -void swap(Event& lhs, Event& rhs) -{ - using std::swap; - swap(lhs.event_type, rhs.event_type); - swap(lhs.description, rhs.description); -} diff --git a/solutions/08_move_semantics/src/Event.h b/solutions/08_move_semantics/src/Event.h deleted file mode 100644 index 2091956..0000000 --- a/solutions/08_move_semantics/src/Event.h +++ /dev/null @@ -1,35 +0,0 @@ -// Event.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef EVENT_H -#define EVENT_H - -enum class Alarm { unknown, advisory, caution, warning }; - -class Event { -public: - Event(); - Event(Alarm init); - Event(Alarm init, char const* str); - - // Copy and move policy - // - ~Event(); - Event(Event const& src) = delete; - Event(Event&&) noexcept; - Event& operator=(const Event& rhs) = delete; - Event& operator=(Event&& rhs); - friend void swap(Event& lhs, Event& rhs); - - Alarm type() const; - char const* as_string() const; - char const* what() const; - -private: - Alarm event_type{ Alarm::unknown }; - char* description{}; -}; - -#endif diff --git a/solutions/08_move_semantics/src/EventFilter.cpp b/solutions/08_move_semantics/src/EventFilter.cpp deleted file mode 100644 index 3157b95..0000000 --- a/solutions/08_move_semantics/src/EventFilter.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// EventFilter.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "EventFilter.h" -#include "Pipe.h" -#include -#include - - -void connect(EventFilter& filter, Pipe& in, Pipe& out) -{ - filter.input = ∈ - filter.output = &out; -} - -void EventFilter::execute() -{ - std::cout << "FILTER : ------------------------" << '\n'; - if (auto events = input->pull()) { - auto initial_size = events->size(); - - auto it = remove_if( - std::begin(*events), end(*events), [this](const Event& event) { - return event.type() == filter_value; - }); - - events->erase(it, std::end(*events)); - - auto event_removed = initial_size - events->size(); - - std::cout << "Removed " << event_removed << " event"; - std::cout << (event_removed == 1 ? "" : "s") << '\n'; - - output->push(std::move(*events)); - - std::cout << '\n'; - } -} diff --git a/solutions/08_move_semantics/src/EventFilter.h b/solutions/08_move_semantics/src/EventFilter.h deleted file mode 100644 index c148a65..0000000 --- a/solutions/08_move_semantics/src/EventFilter.h +++ /dev/null @@ -1,27 +0,0 @@ -// EventFilter.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef ID_FILTER -#define ID_FILTER - -#include "Event.h" - -class Pipe; - -class EventFilter { -public: - EventFilter(Alarm remove_this) : filter_value{ remove_this } {} - - void execute(); - -private: - Alarm filter_value{ Alarm::unknown }; - - Pipe* input{}; - Pipe* output{}; - friend void connect(EventFilter& filter, Pipe& in, Pipe& out); -}; - -#endif diff --git a/solutions/08_move_semantics/src/Generator.cpp b/solutions/08_move_semantics/src/Generator.cpp deleted file mode 100644 index 8d9cf0b..0000000 --- a/solutions/08_move_semantics/src/Generator.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// Generator.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Generator.h" -#include "Pipe.h" -#include -#include -#include -#include - - -void connect(Generator& gen, Pipe& pipe) -{ - gen.output = &pipe; -} - -namespace -{ - inline Alarm random_alarm() { return static_cast((rand() % 3) + 1); } - inline Event random_event() {return Event {random_alarm()}; } - - char const* warning_text[]{ - "It's all gone wrong!", "Panic!", "Run away!", - "Danger, Will Robinson!", "Aaaaaaargh!", "Oh no!" - }; - - inline char const* random_text() { return warning_text[rand() % 6]; } -} // namespace - -void Generator::execute() -{ - std::cout << "GENERATOR: ------------------------" << '\n'; - - auto num_events = rand() % 9 + 1; - Pipe::element_type events{}; - - // To avoid copying during insertion - // - events.reserve(static_cast(num_events)); - - std::cout << "Generating " << num_events << " event" - << (num_events == 1 ? "" : "s") << '\n'; - - std::generate_n(std::back_inserter(events), num_events, []() { - return Event{ random_alarm(), random_text() }; - }); - - // Move the Event_list into the pipe. - // events is now an x-value - // - output->push(std::move(events)); - - std::cout << '\n'; -} diff --git a/solutions/08_move_semantics/src/Generator.h b/solutions/08_move_semantics/src/Generator.h deleted file mode 100644 index 4f65d17..0000000 --- a/solutions/08_move_semantics/src/Generator.h +++ /dev/null @@ -1,21 +0,0 @@ -// Generator.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef GENERATOR_H -#define GENERATOR_H - -class Pipe; - -class Generator { -public: - void execute(); - -private: - Pipe* output{}; - friend void connect(Generator& gen, Pipe& pipe); -}; - -#endif - diff --git a/solutions/08_move_semantics/src/Pipe.cpp b/solutions/08_move_semantics/src/Pipe.cpp deleted file mode 100644 index 1583ae2..0000000 --- a/solutions/08_move_semantics/src/Pipe.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Pipe.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Pipe.h" -#include - - -// void Pipe::push(const Pipe::element_type& in_val) -// { -// element = in_val; -// } - -void Pipe::push(Pipe::element_type&& in_val) -{ - // in_val is an Lvalue expression - // here, so must be moved again - // - element = std::move(in_val); -} - -std::optional Pipe::pull() -{ - // element is an Lvalue (it - // will exist after pull ends) - // so we must turn it into an - // Xvalue so as to move from it - // - return std::move(element); -} diff --git a/solutions/08_move_semantics/src/Pipe.h b/solutions/08_move_semantics/src/Pipe.h deleted file mode 100644 index e8dce0d..0000000 --- a/solutions/08_move_semantics/src/Pipe.h +++ /dev/null @@ -1,25 +0,0 @@ -// Pipe.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef PIPE_H -#define PIPE_H - -#include -#include -#include "Event.h" - -class Pipe { -public: - using element_type = std::vector; - - // void push(const element_type& in_val); - void push(element_type&& in_val); - std::optional pull(); - -private: - element_type element{}; -}; - -#endif diff --git a/solutions/08_move_semantics/src/main.cpp b/solutions/08_move_semantics/src/main.cpp deleted file mode 100644 index 53ce585..0000000 --- a/solutions/08_move_semantics/src/main.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// main.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Generator.h" -#include "Pipe.h" -#include "EventFilter.h" - -int main() -{ - Generator generator{}; - Display display{}; - EventFilter filter{ Alarm::advisory }; - - Pipe pipe1{}; - Pipe pipe2{}; - - connect(generator, pipe1); - connect(filter, pipe1, pipe2); - connect(display, pipe2); - - for (int i = 0; i < 10; ++i) { - generator.execute(); - filter.execute(); - display.execute(); - } -} diff --git a/solutions/09-threading/src/Alarm.cpp b/solutions/09-threading/src/Alarm.cpp new file mode 100644 index 0000000..e361ea1 --- /dev/null +++ b/solutions/09-threading/src/Alarm.cpp @@ -0,0 +1,60 @@ +// Alarm.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include +#include + + +Alarm::Alarm(Type alarm_init) : value{alarm_init} {} + +Alarm::Alarm(Alarm&& rhs) noexcept : Alarm{} { + swap(*this, rhs); +} + +Alarm& Alarm::operator=(Alarm&& rhs) noexcept { + if (this != &rhs) { + value = std::exchange(rhs.value, Type::invalid); + } + return *this; +} + +void swap(Alarm& lhs, Alarm& rhs) { + using std::swap; + swap(lhs.value, rhs.value); +} + +const char* Alarm::to_string() const { + switch (value) { + case Type::advisory: + return "advisory"; + case Type::caution: + return "caution"; + case Type::warning: + return "warning"; + default: + return "invalid"; + } +} + +Alarm::Type Alarm::type() const { + return value; +} + +std::ostream& operator<<(std::ostream& os, Alarm const& alarm) { + os << alarm.to_string(); + return os; +} + +Alarm make_alarm(Alarm::Type type) +{ + return Alarm{ type }; +} + +void print_alarm(Alarm const& alarm) +{ + std::cout << static_cast(alarm.type()) << ':' + << alarm.to_string() + << '\n'; +} diff --git a/solutions/09-threading/src/Alarm.h b/solutions/09-threading/src/Alarm.h new file mode 100644 index 0000000..30ed4e5 --- /dev/null +++ b/solutions/09-threading/src/Alarm.h @@ -0,0 +1,37 @@ +// Alarm.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_H +#define ALARM_H + +#include + +class Alarm { +public: + enum class Type { invalid, advisory, caution, warning }; + + Alarm() = default; + explicit Alarm(Type alarm_init); + + Alarm(Alarm const& rhs) = default; + Alarm& operator=(Alarm const& rhs) = default; + + Alarm(Alarm&& rhs) noexcept; + Alarm& operator=(Alarm&& rhs) noexcept; + friend void swap(Alarm& lhs, Alarm& rhs); + + const char* to_string() const; + Type type() const; + +private: + Type value{ Type::invalid }; +}; + +std::ostream& operator<<(std::ostream& os, const Alarm& alarm); + +void print_alarm(Alarm const& alarm); +Alarm make_alarm(Alarm::Type type); + +#endif diff --git a/solutions/09-threading/src/AlarmFilter.cpp b/solutions/09-threading/src/AlarmFilter.cpp new file mode 100644 index 0000000..22a21d1 --- /dev/null +++ b/solutions/09-threading/src/AlarmFilter.cpp @@ -0,0 +1,39 @@ +// AlarmFilter.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include +#include "AlarmFilter.h" +#include "Pipe.h" + +AlarmFilter::AlarmFilter(Alarm::Type remove_this) +: value{ remove_this } +{ } + +AlarmFilter::AlarmFilter(Alarm::Type remove_this, Pipe& in, Pipe& out) +: value{ remove_this }, input{ &in }, output{ &out } +{ } + +bool AlarmFilter::execute() +{ + if (auto alarm = input->pull()) { + if (alarm->type() == Alarm::Type::invalid) { + // shutdown + output->push(std::move(alarm)); + return false; + } + if (alarm->type() != this->value) { + output->push(std::move(alarm)); + } + else { + std::cout << "Filter: " << alarm->to_string() << " removed\n"; + } + } + return true; +} + +void connect(AlarmFilter& filter, Pipe& in, Pipe& out) +{ + filter.input = ∈ + filter.output = &out; +} diff --git a/solutions/09-threading/src/AlarmFilter.h b/solutions/09-threading/src/AlarmFilter.h new file mode 100644 index 0000000..5814058 --- /dev/null +++ b/solutions/09-threading/src/AlarmFilter.h @@ -0,0 +1,28 @@ +// AlarmFilter.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_FILTER_H +#define ALARM_FILTER_H + +#include "Alarm.h" + +class Pipe; + +class AlarmFilter +{ +public: + explicit AlarmFilter(Alarm::Type remove_this); + explicit AlarmFilter(Alarm::Type remove_this, Pipe& in, Pipe& out); + bool execute(); + +private: + Alarm::Type value; + + Pipe* input{}; + Pipe* output{}; + friend void connect(AlarmFilter& filter, Pipe& in, Pipe& out); +}; + +#endif diff --git a/solutions/09-threading/src/Buffer.h b/solutions/09-threading/src/Buffer.h new file mode 100644 index 0000000..ee5e00f --- /dev/null +++ b/solutions/09-threading/src/Buffer.h @@ -0,0 +1,72 @@ +// Buffer.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef BUFFER_H +#define BUFFER_H + +#include +#include + +template +class Buffer { +public: + using value_type = T; + Buffer() = default; + + template + bool add(U&& in); + auto get() -> std::optional; + + bool is_empty() const; + bool is_full() const; + +private: + using Container = std::array; + + Container elems {}; + typename Container::iterator write_pos{std::begin(elems)}; + typename Container::iterator read_pos{std::begin(elems)}; + std::size_t num_elems {}; +}; + +template +template +bool Buffer::add(U&& in) { + if (num_elems == sz) return false; + + *write_pos = std::forward(in); + ++num_elems; + ++write_pos; + if (write_pos == std::end(elems)) write_pos = std::begin(elems); + + return true; +} + +template +auto Buffer::get() -> std::optional +{ + if (num_elems == 0) return std::nullopt; + + auto value = std::move(*read_pos); + --num_elems; + ++read_pos; + if (read_pos == std::end(elems)) read_pos = std::begin(elems); + + return value; +} + +template +bool Buffer::is_empty() const +{ + return (num_elems == 0); +} + +template +bool Buffer::is_full() const +{ + return (num_elems == sz); +} + +#endif diff --git a/solutions/09-threading/src/Display.cpp b/solutions/09-threading/src/Display.cpp new file mode 100644 index 0000000..4613606 --- /dev/null +++ b/solutions/09-threading/src/Display.cpp @@ -0,0 +1,26 @@ +// Display.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Display.h" +#include "Pipe.h" +#include +#include + +Display::Display(Pipe& ip) : input{&ip} {} + +bool Display::execute() { + assert(input); + + if (auto alarm = input->pull()) { + if (alarm->type() == Alarm::Type::invalid) { + return false; + } + std::cout << "Display: " << *alarm << '\n'; + } + return true; +} + +void connect(Display& display, Pipe& pipe) { + display.input = &pipe; +} diff --git a/solutions/09-threading/src/Display.h b/solutions/09-threading/src/Display.h new file mode 100644 index 0000000..b32b838 --- /dev/null +++ b/solutions/09-threading/src/Display.h @@ -0,0 +1,23 @@ +// Display.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef DISPLAY_H +#define DISPLAY_H + +class Pipe; + +class Display +{ +public: + Display() = default; + explicit Display(Pipe& ip); + bool execute(); + +private: + Pipe* input{}; + friend void connect(Display& display, Pipe& pipe); +}; + +#endif diff --git a/solutions/09-threading/src/Generator.cpp b/solutions/09-threading/src/Generator.cpp new file mode 100644 index 0000000..82aacd1 --- /dev/null +++ b/solutions/09-threading/src/Generator.cpp @@ -0,0 +1,31 @@ +// Generator.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Generator.h" +#include "Pipe.h" +#include +#include +#include + +namespace +{ + Alarm random_alarm() { + return make_alarm(Alarm::Type((rand()%3) + 1)); + } +} // namespace + +bool Generator::execute() { + assert(output); + + auto alarm = std::make_unique(random_alarm()); + std::cout << "Generate: " << *alarm << '\n'; + output->push(std::move(alarm)); + return true; +} + +Generator::Generator(Pipe& pipe) : output{&pipe} {} + +void connect(Generator& gen, Pipe& pipe) { + gen.output = &pipe; +} diff --git a/solutions/11_threading/src/Generator.h b/solutions/09-threading/src/Generator.h similarity index 73% rename from solutions/11_threading/src/Generator.h rename to solutions/09-threading/src/Generator.h index b2e296e..6541318 100644 --- a/solutions/11_threading/src/Generator.h +++ b/solutions/09-threading/src/Generator.h @@ -5,18 +5,19 @@ #pragma once #ifndef GENERATOR_H #define GENERATOR_H -#include "Filter.h" class Pipe; -class Generator : public Filter { +class Generator +{ public: + Generator() = default; + explicit Generator(Pipe& pipe); bool execute(); private: - Pipe* output{}; + Pipe* output{}; friend void connect(Generator& gen, Pipe& pipe); }; #endif - diff --git a/solutions/09-threading/src/Pipe.cpp b/solutions/09-threading/src/Pipe.cpp new file mode 100644 index 0000000..6d29182 --- /dev/null +++ b/solutions/09-threading/src/Pipe.cpp @@ -0,0 +1,23 @@ +// Pipe.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Pipe.h" + +bool Pipe::push(value_type&& alarm) +{ + return buffer.add(std::move(alarm)); +} + +auto Pipe::pull() -> value_type +{ + if (auto alarm = buffer.get()) { + return std::move(alarm.value()); + } + return nullptr; +} + +bool Pipe::is_empty() const +{ + return buffer.is_empty(); +} diff --git a/solutions/09-threading/src/Pipe.h b/solutions/09-threading/src/Pipe.h new file mode 100644 index 0000000..2b353c2 --- /dev/null +++ b/solutions/09-threading/src/Pipe.h @@ -0,0 +1,28 @@ +// Pipe.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef _PIPE_H +#define _PIPE_H + +#include +#include +#include "Buffer.h" +#include "Alarm.h" + +class Pipe +{ +public: + using value_type = std::unique_ptr; + + bool push(value_type&& alarm); + value_type pull(); + bool is_empty() const; + +private: + using Container = Buffer; + Container buffer{}; +}; + +#endif diff --git a/solutions/09-threading/src/main.cpp b/solutions/09-threading/src/main.cpp new file mode 100644 index 0000000..ff51b13 --- /dev/null +++ b/solutions/09-threading/src/main.cpp @@ -0,0 +1,49 @@ +// main.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Pipe.h" +#include "Display.h" +#include "Generator.h" +#include "AlarmFilter.h" +#include +#include +#include + +using namespace std::chrono_literals; + +static constexpr int run_count {6}; + +int main() +{ + Pipe pipe1{}; + Pipe pipe2{}; + Generator generator{ pipe1 }; + AlarmFilter filter{ Alarm::Type::advisory, pipe1, pipe2 }; + Display display{ pipe2 }; + + auto run_fixed = [&pipe1](Generator& filter) { + for (int i{}; i < run_count; ++i) { + filter.execute(); + std::this_thread::sleep_for(500ms); + } + pipe1.push(std::make_unique(Alarm::Type::invalid)); + }; + + std::thread gen_thread {run_fixed, std::ref(generator)}; + std::thread filter_thread{[](AlarmFilter& filter) { + while (filter.execute()) {} + }, std::ref(filter)}; + std::thread display_thread{[](Display& filter) { + while (filter.execute()) {} + }, std::ref(display)}; + + // Wait for the threads to + // finish + // + gen_thread.join(); + filter_thread.join(); + display_thread.join(); + + std::cout << "\nCompleted OK\n"; +} diff --git a/solutions/09_smart_pointers/src/Display.cpp b/solutions/09_smart_pointers/src/Display.cpp deleted file mode 100644 index 1729d4c..0000000 --- a/solutions/09_smart_pointers/src/Display.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Display.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Event.h" -#include "Pipe.h" -#include - -void connect(Display& disp, Pipe& pipe) -{ - disp.input = &pipe; -} - -void Display::execute() -{ - std::cout << "DISPLAY : ------------------------" << '\n'; - - auto opt = input->pull(); - if (opt) { - auto events = std::move(opt.value()); - for (auto& event : *events) { - std::cout << event.as_string() << " : " << event.what() << '\n'; - } - std::cout << '\n'; - } -} diff --git a/solutions/09_smart_pointers/src/Display.h b/solutions/09_smart_pointers/src/Display.h deleted file mode 100644 index 1f39242..0000000 --- a/solutions/09_smart_pointers/src/Display.h +++ /dev/null @@ -1,23 +0,0 @@ -// Display.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef DISPLAY_H -#define DISPLAY_H - -class Pipe; - -class Display { -public: - Display() = default; - Display(Pipe& ip) : input{ &ip } {} - - void execute(); - -private: - Pipe* input{}; - friend void connect(Display& disp, Pipe& pipe); -}; - -#endif diff --git a/solutions/09_smart_pointers/src/Event.cpp b/solutions/09_smart_pointers/src/Event.cpp deleted file mode 100644 index 8c737df..0000000 --- a/solutions/09_smart_pointers/src/Event.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// Event.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Event.h" -#include -#include - -#ifdef TRACE_ENABLED -#include -#define TRACE(msg) \ - std::cout << "Event: " << as_string() << " : " << msg << '\n' -#else -#define TRACE(msg) -#endif - - -static char const* strings[]{ "unknown ", - "advisory ", - "caution ", - "warning " }; - -Event::Event() -{ - TRACE("Default ctor"); -} - -Event::Event(Alarm init) : event_type{ init } -{ - TRACE("Non-default ctor"); -} - -Event::Event(Alarm init, char const* str) : event_type{ init } -{ - TRACE("Non-default ctor with string"); - - if (str) { - description = new char[strlen(str) + 1]; - strcpy(description, str); - } -} - -Event::Event(Event&& src) noexcept : Event{} -{ - TRACE("Move ctor"); - - swap(*this, src); -} - -Event::~Event() -{ - TRACE("Dtor"); - - delete[] description; -} - -// Event::Event(const Event& src) : Event{ src.event_type, src.description } -// { -// TRACE("Copy ctor"); -// } - -Event& Event::operator=(Event && rhs) -{ - TRACE("Assignment"); - swap(*this, rhs); - return *this; -} - -Alarm Event::type() const -{ - return event_type; -} - -char const* Event::as_string() const -{ - return strings[static_cast(event_type)]; -} - -char const* Event::what() const -{ - return (description ? description : ""); -} - -void swap(Event& lhs, Event& rhs) -{ - using std::swap; - swap(lhs.event_type, rhs.event_type); - swap(lhs.description, rhs.description); -} diff --git a/solutions/09_smart_pointers/src/Event.h b/solutions/09_smart_pointers/src/Event.h deleted file mode 100644 index 2091956..0000000 --- a/solutions/09_smart_pointers/src/Event.h +++ /dev/null @@ -1,35 +0,0 @@ -// Event.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef EVENT_H -#define EVENT_H - -enum class Alarm { unknown, advisory, caution, warning }; - -class Event { -public: - Event(); - Event(Alarm init); - Event(Alarm init, char const* str); - - // Copy and move policy - // - ~Event(); - Event(Event const& src) = delete; - Event(Event&&) noexcept; - Event& operator=(const Event& rhs) = delete; - Event& operator=(Event&& rhs); - friend void swap(Event& lhs, Event& rhs); - - Alarm type() const; - char const* as_string() const; - char const* what() const; - -private: - Alarm event_type{ Alarm::unknown }; - char* description{}; -}; - -#endif diff --git a/solutions/09_smart_pointers/src/EventFilter.cpp b/solutions/09_smart_pointers/src/EventFilter.cpp deleted file mode 100644 index c2054ed..0000000 --- a/solutions/09_smart_pointers/src/EventFilter.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// EventFilter.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "EventFilter.h" -#include "Pipe.h" -#include -#include - - -void connect(EventFilter& filter, Pipe& in, Pipe& out) -{ - filter.input = ∈ - filter.output = &out; -} - -void EventFilter::execute() -{ - auto opt = input->pull(); - if (opt) { - auto events = std::move(opt.value()); - - std::cout << "FILTER : ------------------------" << '\n'; - - auto initial_size = events->size(); - - auto it = remove_if( - std::begin(*events), end(*events), [this](const Event& event) { - return event.type() == filter_value; - }); - - events->erase(it, std::end(*events)); - - auto event_removed = initial_size - events->size(); - - std::cout << "Removed " << event_removed << " event"; - std::cout << (event_removed == 1 ? "" : "s") << '\n'; - - output->push(std::move(events)); - std::cout << '\n'; - } -} diff --git a/solutions/09_smart_pointers/src/EventFilter.h b/solutions/09_smart_pointers/src/EventFilter.h deleted file mode 100644 index c148a65..0000000 --- a/solutions/09_smart_pointers/src/EventFilter.h +++ /dev/null @@ -1,27 +0,0 @@ -// EventFilter.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef ID_FILTER -#define ID_FILTER - -#include "Event.h" - -class Pipe; - -class EventFilter { -public: - EventFilter(Alarm remove_this) : filter_value{ remove_this } {} - - void execute(); - -private: - Alarm filter_value{ Alarm::unknown }; - - Pipe* input{}; - Pipe* output{}; - friend void connect(EventFilter& filter, Pipe& in, Pipe& out); -}; - -#endif diff --git a/solutions/09_smart_pointers/src/Generator.cpp b/solutions/09_smart_pointers/src/Generator.cpp deleted file mode 100644 index 5260a76..0000000 --- a/solutions/09_smart_pointers/src/Generator.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// Generator.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Generator.h" -#include "Pipe.h" -#include -#include -#include -#include - -void connect(Generator& gen, Pipe& pipe) -{ - gen.output = &pipe; -} - -namespace -{ - inline Alarm random_alarm() { return static_cast((rand() % 3) + 1); } - inline Event random_event() {return Event {random_alarm()}; } - - char const* warning_text[]{ - "It's all gone wrong!", "Panic!", "Run away!", - "Danger, Will Robinson!", "Aaaaaaargh!", "Oh no!" - }; - - inline char const* random_text() { return warning_text[rand() % 6]; } -} // namespace - -void Generator::execute() -{ - std::cout << "GENERATOR: ------------------------" << '\n'; - - auto num_events = rand() % 9 + 1; - auto events = std::make_unique(); - - // To avoid copying during insertion - // - events->reserve(static_cast(num_events)); - - std::cout << "Generating " << num_events << " event" - << (num_events == 1 ? "" : "s") << '\n'; - - std::generate_n(std::back_inserter(*events), num_events, []() { - return Event{ random_alarm(), random_text() }; - }); - - // Move the Event_list into the pipe. - // events is now an x-value - // - output->push(std::move(events)); - - std::cout << '\n'; -} diff --git a/solutions/09_smart_pointers/src/Generator.h b/solutions/09_smart_pointers/src/Generator.h deleted file mode 100644 index 4f65d17..0000000 --- a/solutions/09_smart_pointers/src/Generator.h +++ /dev/null @@ -1,21 +0,0 @@ -// Generator.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef GENERATOR_H -#define GENERATOR_H - -class Pipe; - -class Generator { -public: - void execute(); - -private: - Pipe* output{}; - friend void connect(Generator& gen, Pipe& pipe); -}; - -#endif - diff --git a/solutions/09_smart_pointers/src/Pipe.cpp b/solutions/09_smart_pointers/src/Pipe.cpp deleted file mode 100644 index 80ccc93..0000000 --- a/solutions/09_smart_pointers/src/Pipe.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Pipe.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Pipe.h" -#include - -void Pipe::push(Pipe::element_type in_val) -{ - element = std::move(in_val); -} - -std::optional Pipe::pull() -{ - return std::move(element); -} diff --git a/solutions/09_smart_pointers/src/Pipe.h b/solutions/09_smart_pointers/src/Pipe.h deleted file mode 100644 index 7c42a35..0000000 --- a/solutions/09_smart_pointers/src/Pipe.h +++ /dev/null @@ -1,26 +0,0 @@ -// Pipe.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef PIPE_H -#define PIPE_H - -#include -#include -#include -#include "Event.h" - -class Pipe { -public: - using value_type = std::vector; - using element_type = std::unique_ptr; - - void push(element_type in_val); - std::optional pull(); - -private: - element_type element{}; -}; - -#endif diff --git a/solutions/09_smart_pointers/src/main.cpp b/solutions/09_smart_pointers/src/main.cpp deleted file mode 100644 index 53ce585..0000000 --- a/solutions/09_smart_pointers/src/main.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// main.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Generator.h" -#include "Pipe.h" -#include "EventFilter.h" - -int main() -{ - Generator generator{}; - Display display{}; - EventFilter filter{ Alarm::advisory }; - - Pipe pipe1{}; - Pipe pipe2{}; - - connect(generator, pipe1); - connect(filter, pipe1, pipe2); - connect(display, pipe2); - - for (int i = 0; i < 10; ++i) { - generator.execute(); - filter.execute(); - display.execute(); - } -} diff --git a/solutions/10-monitors/src/Alarm.cpp b/solutions/10-monitors/src/Alarm.cpp new file mode 100644 index 0000000..e361ea1 --- /dev/null +++ b/solutions/10-monitors/src/Alarm.cpp @@ -0,0 +1,60 @@ +// Alarm.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Alarm.h" +#include +#include + + +Alarm::Alarm(Type alarm_init) : value{alarm_init} {} + +Alarm::Alarm(Alarm&& rhs) noexcept : Alarm{} { + swap(*this, rhs); +} + +Alarm& Alarm::operator=(Alarm&& rhs) noexcept { + if (this != &rhs) { + value = std::exchange(rhs.value, Type::invalid); + } + return *this; +} + +void swap(Alarm& lhs, Alarm& rhs) { + using std::swap; + swap(lhs.value, rhs.value); +} + +const char* Alarm::to_string() const { + switch (value) { + case Type::advisory: + return "advisory"; + case Type::caution: + return "caution"; + case Type::warning: + return "warning"; + default: + return "invalid"; + } +} + +Alarm::Type Alarm::type() const { + return value; +} + +std::ostream& operator<<(std::ostream& os, Alarm const& alarm) { + os << alarm.to_string(); + return os; +} + +Alarm make_alarm(Alarm::Type type) +{ + return Alarm{ type }; +} + +void print_alarm(Alarm const& alarm) +{ + std::cout << static_cast(alarm.type()) << ':' + << alarm.to_string() + << '\n'; +} diff --git a/solutions/10-monitors/src/Alarm.h b/solutions/10-monitors/src/Alarm.h new file mode 100644 index 0000000..30ed4e5 --- /dev/null +++ b/solutions/10-monitors/src/Alarm.h @@ -0,0 +1,37 @@ +// Alarm.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_H +#define ALARM_H + +#include + +class Alarm { +public: + enum class Type { invalid, advisory, caution, warning }; + + Alarm() = default; + explicit Alarm(Type alarm_init); + + Alarm(Alarm const& rhs) = default; + Alarm& operator=(Alarm const& rhs) = default; + + Alarm(Alarm&& rhs) noexcept; + Alarm& operator=(Alarm&& rhs) noexcept; + friend void swap(Alarm& lhs, Alarm& rhs); + + const char* to_string() const; + Type type() const; + +private: + Type value{ Type::invalid }; +}; + +std::ostream& operator<<(std::ostream& os, const Alarm& alarm); + +void print_alarm(Alarm const& alarm); +Alarm make_alarm(Alarm::Type type); + +#endif diff --git a/solutions/10-monitors/src/AlarmFilter.cpp b/solutions/10-monitors/src/AlarmFilter.cpp new file mode 100644 index 0000000..3b801f8 --- /dev/null +++ b/solutions/10-monitors/src/AlarmFilter.cpp @@ -0,0 +1,39 @@ +// AlarmFilter.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include +#include "AlarmFilter.h" +#include "Pipe.h" + +AlarmFilter::AlarmFilter(Alarm::Type remove_this) +: value{ remove_this } +{ } + +AlarmFilter::AlarmFilter(Alarm::Type remove_this, Pipe& in, Pipe& out) +: value{ remove_this }, input{ &in }, output{ &out } +{ } + +bool AlarmFilter::execute() +{ + if (auto alarm = input->pull()) { + if (alarm->type() != this->value) { + output->push(std::move(alarm)); + } + else { + std::cout << "Filter: " << alarm->to_string() << " removed\n"; + } + return true; + } + else { + // shutdown + output->push(std::move(alarm)); + return false; + } +} + +void connect(AlarmFilter& filter, Pipe& in, Pipe& out) +{ + filter.input = ∈ + filter.output = &out; +} diff --git a/solutions/10-monitors/src/AlarmFilter.h b/solutions/10-monitors/src/AlarmFilter.h new file mode 100644 index 0000000..5814058 --- /dev/null +++ b/solutions/10-monitors/src/AlarmFilter.h @@ -0,0 +1,28 @@ +// AlarmFilter.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef ALARM_FILTER_H +#define ALARM_FILTER_H + +#include "Alarm.h" + +class Pipe; + +class AlarmFilter +{ +public: + explicit AlarmFilter(Alarm::Type remove_this); + explicit AlarmFilter(Alarm::Type remove_this, Pipe& in, Pipe& out); + bool execute(); + +private: + Alarm::Type value; + + Pipe* input{}; + Pipe* output{}; + friend void connect(AlarmFilter& filter, Pipe& in, Pipe& out); +}; + +#endif diff --git a/solutions/10-monitors/src/Buffer.h b/solutions/10-monitors/src/Buffer.h new file mode 100644 index 0000000..ee5e00f --- /dev/null +++ b/solutions/10-monitors/src/Buffer.h @@ -0,0 +1,72 @@ +// Buffer.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef BUFFER_H +#define BUFFER_H + +#include +#include + +template +class Buffer { +public: + using value_type = T; + Buffer() = default; + + template + bool add(U&& in); + auto get() -> std::optional; + + bool is_empty() const; + bool is_full() const; + +private: + using Container = std::array; + + Container elems {}; + typename Container::iterator write_pos{std::begin(elems)}; + typename Container::iterator read_pos{std::begin(elems)}; + std::size_t num_elems {}; +}; + +template +template +bool Buffer::add(U&& in) { + if (num_elems == sz) return false; + + *write_pos = std::forward(in); + ++num_elems; + ++write_pos; + if (write_pos == std::end(elems)) write_pos = std::begin(elems); + + return true; +} + +template +auto Buffer::get() -> std::optional +{ + if (num_elems == 0) return std::nullopt; + + auto value = std::move(*read_pos); + --num_elems; + ++read_pos; + if (read_pos == std::end(elems)) read_pos = std::begin(elems); + + return value; +} + +template +bool Buffer::is_empty() const +{ + return (num_elems == 0); +} + +template +bool Buffer::is_full() const +{ + return (num_elems == sz); +} + +#endif diff --git a/solutions/10-monitors/src/ConcurrentFifo.h b/solutions/10-monitors/src/ConcurrentFifo.h new file mode 100644 index 0000000..4b791a6 --- /dev/null +++ b/solutions/10-monitors/src/ConcurrentFifo.h @@ -0,0 +1,63 @@ +// Buffer.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef CONCURRENTFIFO_H +#define CONCURRENTFIFO_H + +#include "Buffer.h" + +template +class ConcurrentFifo : private Buffer { +public: + using value_type = T; + ConcurrentFifo() = default; + + template + void add(U&& in); + auto get() -> value_type; + bool is_empty() const; + +private: + mutable std::mutex mtx{}; + std::condition_variable has_data{}; + std::condition_variable has_space{}; +}; + +template +template +void ConcurrentFifo::add(U&& in) { + { + // std::unique_lock lock{ mtx }; // C++14 + std::unique_lock lock{mtx}; // C++17 + while (Buffer::is_full()) { + has_space.wait(lock); + } + Buffer::add(std::move(in)); + } + has_data.notify_one(); +} + +template +auto ConcurrentFifo::get() -> value_type +{ + std::optional alarm{}; + { + // std::unique_lock lock{ mtx }; // C++14 + std::unique_lock lock{mtx}; // C++17 + has_data.wait(lock, [this]{ return !Buffer::is_empty(); }); + alarm = std::move(Buffer::get()); + } + has_space.notify_one(); + return std::move(alarm.value()); +} + +template +bool ConcurrentFifo::is_empty() const +{ + return Buffer::is_empty(); +} + + +#endif diff --git a/solutions/10-monitors/src/Display.cpp b/solutions/10-monitors/src/Display.cpp new file mode 100644 index 0000000..7712149 --- /dev/null +++ b/solutions/10-monitors/src/Display.cpp @@ -0,0 +1,24 @@ +// Display.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Display.h" +#include "Pipe.h" +#include +#include + +Display::Display(Pipe& ip) : input{&ip} {} + +bool Display::execute() { + assert(input); + + if (auto alarm = input->pull()) { + std::cout << "Display: " << *alarm << '\n'; + return true; + } + return false; +} + +void connect(Display& display, Pipe& pipe) { + display.input = &pipe; +} diff --git a/solutions/10-monitors/src/Display.h b/solutions/10-monitors/src/Display.h new file mode 100644 index 0000000..b32b838 --- /dev/null +++ b/solutions/10-monitors/src/Display.h @@ -0,0 +1,23 @@ +// Display.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef DISPLAY_H +#define DISPLAY_H + +class Pipe; + +class Display +{ +public: + Display() = default; + explicit Display(Pipe& ip); + bool execute(); + +private: + Pipe* input{}; + friend void connect(Display& display, Pipe& pipe); +}; + +#endif diff --git a/solutions/10-monitors/src/Generator.cpp b/solutions/10-monitors/src/Generator.cpp new file mode 100644 index 0000000..82aacd1 --- /dev/null +++ b/solutions/10-monitors/src/Generator.cpp @@ -0,0 +1,31 @@ +// Generator.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Generator.h" +#include "Pipe.h" +#include +#include +#include + +namespace +{ + Alarm random_alarm() { + return make_alarm(Alarm::Type((rand()%3) + 1)); + } +} // namespace + +bool Generator::execute() { + assert(output); + + auto alarm = std::make_unique(random_alarm()); + std::cout << "Generate: " << *alarm << '\n'; + output->push(std::move(alarm)); + return true; +} + +Generator::Generator(Pipe& pipe) : output{&pipe} {} + +void connect(Generator& gen, Pipe& pipe) { + gen.output = &pipe; +} diff --git a/solutions/12_mutual_exclusion/src/Generator.h b/solutions/10-monitors/src/Generator.h similarity index 73% rename from solutions/12_mutual_exclusion/src/Generator.h rename to solutions/10-monitors/src/Generator.h index b2e296e..6541318 100644 --- a/solutions/12_mutual_exclusion/src/Generator.h +++ b/solutions/10-monitors/src/Generator.h @@ -5,18 +5,19 @@ #pragma once #ifndef GENERATOR_H #define GENERATOR_H -#include "Filter.h" class Pipe; -class Generator : public Filter { +class Generator +{ public: + Generator() = default; + explicit Generator(Pipe& pipe); bool execute(); private: - Pipe* output{}; + Pipe* output{}; friend void connect(Generator& gen, Pipe& pipe); }; #endif - diff --git a/solutions/10-monitors/src/Pipe.cpp b/solutions/10-monitors/src/Pipe.cpp new file mode 100644 index 0000000..e8ad58f --- /dev/null +++ b/solutions/10-monitors/src/Pipe.cpp @@ -0,0 +1,20 @@ +// Pipe.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Pipe.h" + +void Pipe::push(value_type&& alarm) +{ + buffer.add(std::move(alarm)); +} + +auto Pipe::pull() -> value_type +{ + return buffer.get(); +} + +bool Pipe::is_empty() const +{ + return buffer.is_empty(); +} diff --git a/solutions/10-monitors/src/Pipe.h b/solutions/10-monitors/src/Pipe.h new file mode 100644 index 0000000..ccd09c2 --- /dev/null +++ b/solutions/10-monitors/src/Pipe.h @@ -0,0 +1,30 @@ +// Pipe.h +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#pragma once +#ifndef _PIPE_H +#define _PIPE_H + +#include +#include +#include +#include +#include "ConcurrentFifo.h" +#include "Alarm.h" + +class Pipe +{ +public: + using value_type = std::unique_ptr; + + void push(value_type&& alarm); + auto pull() -> value_type; + bool is_empty() const; + +private: + using Container = ConcurrentFifo; + Container buffer{}; +}; + +#endif diff --git a/solutions/10-monitors/src/main.cpp b/solutions/10-monitors/src/main.cpp new file mode 100644 index 0000000..a1a51ae --- /dev/null +++ b/solutions/10-monitors/src/main.cpp @@ -0,0 +1,50 @@ +// main.cpp +// See project README.md for disclaimer and additional information. +// Feabhas Ltd + +#include "Pipe.h" +#include "Display.h" +#include "Generator.h" +#include "AlarmFilter.h" +#include +#include +#include + +using namespace std::chrono_literals; + +static constexpr int run_count {6}; + +int main() +{ + Pipe pipe1{}; + Pipe pipe2{}; + Generator generator{ pipe1 }; + AlarmFilter filter{ Alarm::Type::advisory, pipe1, pipe2 }; + Display display{ pipe2 }; + + auto run_fixed = [&pipe1](Generator& filter) { + for (int i{}; i < run_count; ++i) { + filter.execute(); + // std::this_thread::sleep_for(500ms); + } + pipe1.push(nullptr); + }; + + + std::thread gen_thread {run_fixed, std::ref(generator)}; + std::thread filter_thread{[](AlarmFilter& filter) { + while (filter.execute()) {} + }, std::ref(filter)}; + std::thread display_thread{[](Display& filter) { + while (filter.execute()) {} + }, std::ref(display)}; + + // Wait for the threads to + // finish + // + gen_thread.join(); + filter_thread.join(); + display_thread.join(); + + std::cout << "\nCompleted OK\n"; +} diff --git a/solutions/10_templates/src/Buffer.h b/solutions/10_templates/src/Buffer.h deleted file mode 100644 index 37e79dc..0000000 --- a/solutions/10_templates/src/Buffer.h +++ /dev/null @@ -1,82 +0,0 @@ -// Buffer.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef BUFFER_H -#define BUFFER_H - -#include -#include - -template -class Buffer { -public: - using value_type = T; - - bool add(const T& in); - bool add(T&& in); - std::optional get(); - bool is_empty() const; - size_t size() const; - -private: - using Container = std::array; - using Iterator = typename Container::iterator; - - Container buffer{}; - Iterator write{ std::begin(buffer) }; - Iterator read{ std::begin(buffer) }; - size_t num_items{ 0 }; -}; - -template -bool Buffer::add(const T& in) -{ - if (num_items == sz) return false; - - *write = in; - ++write; - ++num_items; - if (write == std::end(buffer)) write = std::begin(buffer); - return true; -} - -template -bool Buffer::add(T&& in) -{ - if (num_items == sz) return false; - - *write = std::move(in); - ++write; - ++num_items; - if (write == std::end(buffer)) write = std::begin(buffer); - return true; -} - -template -std::optional Buffer::get() -{ - if (num_items == 0) return std::nullopt; - - Iterator out = read; - ++read; - --num_items; - if (read == std::end(buffer)) read = std::begin(buffer); - - return std::move(*out); -} - -template -bool Buffer::is_empty() const -{ - return (num_items == 0); -} - -template -size_t Buffer::size() const -{ - return num_items; -} - -#endif diff --git a/solutions/10_templates/src/Display.cpp b/solutions/10_templates/src/Display.cpp deleted file mode 100644 index 1729d4c..0000000 --- a/solutions/10_templates/src/Display.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Display.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Event.h" -#include "Pipe.h" -#include - -void connect(Display& disp, Pipe& pipe) -{ - disp.input = &pipe; -} - -void Display::execute() -{ - std::cout << "DISPLAY : ------------------------" << '\n'; - - auto opt = input->pull(); - if (opt) { - auto events = std::move(opt.value()); - for (auto& event : *events) { - std::cout << event.as_string() << " : " << event.what() << '\n'; - } - std::cout << '\n'; - } -} diff --git a/solutions/10_templates/src/Display.h b/solutions/10_templates/src/Display.h deleted file mode 100644 index 1f39242..0000000 --- a/solutions/10_templates/src/Display.h +++ /dev/null @@ -1,23 +0,0 @@ -// Display.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef DISPLAY_H -#define DISPLAY_H - -class Pipe; - -class Display { -public: - Display() = default; - Display(Pipe& ip) : input{ &ip } {} - - void execute(); - -private: - Pipe* input{}; - friend void connect(Display& disp, Pipe& pipe); -}; - -#endif diff --git a/solutions/10_templates/src/Event.cpp b/solutions/10_templates/src/Event.cpp deleted file mode 100644 index 8c737df..0000000 --- a/solutions/10_templates/src/Event.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// Event.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Event.h" -#include -#include - -#ifdef TRACE_ENABLED -#include -#define TRACE(msg) \ - std::cout << "Event: " << as_string() << " : " << msg << '\n' -#else -#define TRACE(msg) -#endif - - -static char const* strings[]{ "unknown ", - "advisory ", - "caution ", - "warning " }; - -Event::Event() -{ - TRACE("Default ctor"); -} - -Event::Event(Alarm init) : event_type{ init } -{ - TRACE("Non-default ctor"); -} - -Event::Event(Alarm init, char const* str) : event_type{ init } -{ - TRACE("Non-default ctor with string"); - - if (str) { - description = new char[strlen(str) + 1]; - strcpy(description, str); - } -} - -Event::Event(Event&& src) noexcept : Event{} -{ - TRACE("Move ctor"); - - swap(*this, src); -} - -Event::~Event() -{ - TRACE("Dtor"); - - delete[] description; -} - -// Event::Event(const Event& src) : Event{ src.event_type, src.description } -// { -// TRACE("Copy ctor"); -// } - -Event& Event::operator=(Event && rhs) -{ - TRACE("Assignment"); - swap(*this, rhs); - return *this; -} - -Alarm Event::type() const -{ - return event_type; -} - -char const* Event::as_string() const -{ - return strings[static_cast(event_type)]; -} - -char const* Event::what() const -{ - return (description ? description : ""); -} - -void swap(Event& lhs, Event& rhs) -{ - using std::swap; - swap(lhs.event_type, rhs.event_type); - swap(lhs.description, rhs.description); -} diff --git a/solutions/10_templates/src/Event.h b/solutions/10_templates/src/Event.h deleted file mode 100644 index 2091956..0000000 --- a/solutions/10_templates/src/Event.h +++ /dev/null @@ -1,35 +0,0 @@ -// Event.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef EVENT_H -#define EVENT_H - -enum class Alarm { unknown, advisory, caution, warning }; - -class Event { -public: - Event(); - Event(Alarm init); - Event(Alarm init, char const* str); - - // Copy and move policy - // - ~Event(); - Event(Event const& src) = delete; - Event(Event&&) noexcept; - Event& operator=(const Event& rhs) = delete; - Event& operator=(Event&& rhs); - friend void swap(Event& lhs, Event& rhs); - - Alarm type() const; - char const* as_string() const; - char const* what() const; - -private: - Alarm event_type{ Alarm::unknown }; - char* description{}; -}; - -#endif diff --git a/solutions/10_templates/src/EventFilter.cpp b/solutions/10_templates/src/EventFilter.cpp deleted file mode 100644 index c2054ed..0000000 --- a/solutions/10_templates/src/EventFilter.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// EventFilter.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "EventFilter.h" -#include "Pipe.h" -#include -#include - - -void connect(EventFilter& filter, Pipe& in, Pipe& out) -{ - filter.input = ∈ - filter.output = &out; -} - -void EventFilter::execute() -{ - auto opt = input->pull(); - if (opt) { - auto events = std::move(opt.value()); - - std::cout << "FILTER : ------------------------" << '\n'; - - auto initial_size = events->size(); - - auto it = remove_if( - std::begin(*events), end(*events), [this](const Event& event) { - return event.type() == filter_value; - }); - - events->erase(it, std::end(*events)); - - auto event_removed = initial_size - events->size(); - - std::cout << "Removed " << event_removed << " event"; - std::cout << (event_removed == 1 ? "" : "s") << '\n'; - - output->push(std::move(events)); - std::cout << '\n'; - } -} diff --git a/solutions/10_templates/src/EventFilter.h b/solutions/10_templates/src/EventFilter.h deleted file mode 100644 index c148a65..0000000 --- a/solutions/10_templates/src/EventFilter.h +++ /dev/null @@ -1,27 +0,0 @@ -// EventFilter.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef ID_FILTER -#define ID_FILTER - -#include "Event.h" - -class Pipe; - -class EventFilter { -public: - EventFilter(Alarm remove_this) : filter_value{ remove_this } {} - - void execute(); - -private: - Alarm filter_value{ Alarm::unknown }; - - Pipe* input{}; - Pipe* output{}; - friend void connect(EventFilter& filter, Pipe& in, Pipe& out); -}; - -#endif diff --git a/solutions/10_templates/src/Generator.cpp b/solutions/10_templates/src/Generator.cpp deleted file mode 100644 index 5260a76..0000000 --- a/solutions/10_templates/src/Generator.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// Generator.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Generator.h" -#include "Pipe.h" -#include -#include -#include -#include - -void connect(Generator& gen, Pipe& pipe) -{ - gen.output = &pipe; -} - -namespace -{ - inline Alarm random_alarm() { return static_cast((rand() % 3) + 1); } - inline Event random_event() {return Event {random_alarm()}; } - - char const* warning_text[]{ - "It's all gone wrong!", "Panic!", "Run away!", - "Danger, Will Robinson!", "Aaaaaaargh!", "Oh no!" - }; - - inline char const* random_text() { return warning_text[rand() % 6]; } -} // namespace - -void Generator::execute() -{ - std::cout << "GENERATOR: ------------------------" << '\n'; - - auto num_events = rand() % 9 + 1; - auto events = std::make_unique(); - - // To avoid copying during insertion - // - events->reserve(static_cast(num_events)); - - std::cout << "Generating " << num_events << " event" - << (num_events == 1 ? "" : "s") << '\n'; - - std::generate_n(std::back_inserter(*events), num_events, []() { - return Event{ random_alarm(), random_text() }; - }); - - // Move the Event_list into the pipe. - // events is now an x-value - // - output->push(std::move(events)); - - std::cout << '\n'; -} diff --git a/solutions/10_templates/src/Generator.h b/solutions/10_templates/src/Generator.h deleted file mode 100644 index 4f65d17..0000000 --- a/solutions/10_templates/src/Generator.h +++ /dev/null @@ -1,21 +0,0 @@ -// Generator.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef GENERATOR_H -#define GENERATOR_H - -class Pipe; - -class Generator { -public: - void execute(); - -private: - Pipe* output{}; - friend void connect(Generator& gen, Pipe& pipe); -}; - -#endif - diff --git a/solutions/10_templates/src/Pipe.cpp b/solutions/10_templates/src/Pipe.cpp deleted file mode 100644 index c1dcee9..0000000 --- a/solutions/10_templates/src/Pipe.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Pipe.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Pipe.h" -#include - -void Pipe::push(Pipe::element_type in_val) -{ - elements.add(std::move(in_val)); -} - -std::optional Pipe::pull() -{ - if (auto events = elements.get()) { - return events; - } - else { - return std::nullopt; - } -} diff --git a/solutions/10_templates/src/Pipe.h b/solutions/10_templates/src/Pipe.h deleted file mode 100644 index 56d835a..0000000 --- a/solutions/10_templates/src/Pipe.h +++ /dev/null @@ -1,27 +0,0 @@ -// Pipe.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef PIPE_H -#define PIPE_H - -#include -#include -#include -#include "Event.h" -#include "Buffer.h" - -class Pipe { -public: - using value_type = std::vector; - using element_type = std::unique_ptr; - - void push(element_type in_val); - std::optional pull(); - -private: - Buffer elements{}; -}; - -#endif diff --git a/solutions/10_templates/src/main.cpp b/solutions/10_templates/src/main.cpp deleted file mode 100644 index 53ce585..0000000 --- a/solutions/10_templates/src/main.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// main.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Generator.h" -#include "Pipe.h" -#include "EventFilter.h" - -int main() -{ - Generator generator{}; - Display display{}; - EventFilter filter{ Alarm::advisory }; - - Pipe pipe1{}; - Pipe pipe2{}; - - connect(generator, pipe1); - connect(filter, pipe1, pipe2); - connect(display, pipe2); - - for (int i = 0; i < 10; ++i) { - generator.execute(); - filter.execute(); - display.execute(); - } -} diff --git a/solutions/11_threading/src/Buffer.h b/solutions/11_threading/src/Buffer.h deleted file mode 100644 index 37e79dc..0000000 --- a/solutions/11_threading/src/Buffer.h +++ /dev/null @@ -1,82 +0,0 @@ -// Buffer.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef BUFFER_H -#define BUFFER_H - -#include -#include - -template -class Buffer { -public: - using value_type = T; - - bool add(const T& in); - bool add(T&& in); - std::optional get(); - bool is_empty() const; - size_t size() const; - -private: - using Container = std::array; - using Iterator = typename Container::iterator; - - Container buffer{}; - Iterator write{ std::begin(buffer) }; - Iterator read{ std::begin(buffer) }; - size_t num_items{ 0 }; -}; - -template -bool Buffer::add(const T& in) -{ - if (num_items == sz) return false; - - *write = in; - ++write; - ++num_items; - if (write == std::end(buffer)) write = std::begin(buffer); - return true; -} - -template -bool Buffer::add(T&& in) -{ - if (num_items == sz) return false; - - *write = std::move(in); - ++write; - ++num_items; - if (write == std::end(buffer)) write = std::begin(buffer); - return true; -} - -template -std::optional Buffer::get() -{ - if (num_items == 0) return std::nullopt; - - Iterator out = read; - ++read; - --num_items; - if (read == std::end(buffer)) read = std::begin(buffer); - - return std::move(*out); -} - -template -bool Buffer::is_empty() const -{ - return (num_items == 0); -} - -template -size_t Buffer::size() const -{ - return num_items; -} - -#endif diff --git a/solutions/11_threading/src/Display.cpp b/solutions/11_threading/src/Display.cpp deleted file mode 100644 index e4bdc1e..0000000 --- a/solutions/11_threading/src/Display.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Display.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Event.h" -#include "Pipe.h" -#include - -void connect(Display& disp, Pipe& pipe) -{ - disp.input = &pipe; -} - -bool Display::execute() -{ - if (auto opt = input->pull()) { - auto events = std::move(opt.value()); - if (!events) { - return false; - } - std::cout << "DISPLAY : ------------------------" << '\n'; - - for (auto& event : *events) { - std::cout << event.as_string() << " : " << event.what() << '\n'; - } - std::cout << '\n'; - } - - return true; -} diff --git a/solutions/11_threading/src/Display.h b/solutions/11_threading/src/Display.h deleted file mode 100644 index d44a2b7..0000000 --- a/solutions/11_threading/src/Display.h +++ /dev/null @@ -1,24 +0,0 @@ -// Display.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef DISPLAY_H -#define DISPLAY_H -#include "Filter.h" - -class Pipe; - -class Display : public Filter { -public: - Display() = default; - Display(Pipe& ip) : input{ &ip } {} - - bool execute(); - -private: - Pipe* input{}; - friend void connect(Display& disp, Pipe& pipe); -}; - -#endif diff --git a/solutions/11_threading/src/Event.cpp b/solutions/11_threading/src/Event.cpp deleted file mode 100644 index 8c737df..0000000 --- a/solutions/11_threading/src/Event.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// Event.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Event.h" -#include -#include - -#ifdef TRACE_ENABLED -#include -#define TRACE(msg) \ - std::cout << "Event: " << as_string() << " : " << msg << '\n' -#else -#define TRACE(msg) -#endif - - -static char const* strings[]{ "unknown ", - "advisory ", - "caution ", - "warning " }; - -Event::Event() -{ - TRACE("Default ctor"); -} - -Event::Event(Alarm init) : event_type{ init } -{ - TRACE("Non-default ctor"); -} - -Event::Event(Alarm init, char const* str) : event_type{ init } -{ - TRACE("Non-default ctor with string"); - - if (str) { - description = new char[strlen(str) + 1]; - strcpy(description, str); - } -} - -Event::Event(Event&& src) noexcept : Event{} -{ - TRACE("Move ctor"); - - swap(*this, src); -} - -Event::~Event() -{ - TRACE("Dtor"); - - delete[] description; -} - -// Event::Event(const Event& src) : Event{ src.event_type, src.description } -// { -// TRACE("Copy ctor"); -// } - -Event& Event::operator=(Event && rhs) -{ - TRACE("Assignment"); - swap(*this, rhs); - return *this; -} - -Alarm Event::type() const -{ - return event_type; -} - -char const* Event::as_string() const -{ - return strings[static_cast(event_type)]; -} - -char const* Event::what() const -{ - return (description ? description : ""); -} - -void swap(Event& lhs, Event& rhs) -{ - using std::swap; - swap(lhs.event_type, rhs.event_type); - swap(lhs.description, rhs.description); -} diff --git a/solutions/11_threading/src/Event.h b/solutions/11_threading/src/Event.h deleted file mode 100644 index 2091956..0000000 --- a/solutions/11_threading/src/Event.h +++ /dev/null @@ -1,35 +0,0 @@ -// Event.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef EVENT_H -#define EVENT_H - -enum class Alarm { unknown, advisory, caution, warning }; - -class Event { -public: - Event(); - Event(Alarm init); - Event(Alarm init, char const* str); - - // Copy and move policy - // - ~Event(); - Event(Event const& src) = delete; - Event(Event&&) noexcept; - Event& operator=(const Event& rhs) = delete; - Event& operator=(Event&& rhs); - friend void swap(Event& lhs, Event& rhs); - - Alarm type() const; - char const* as_string() const; - char const* what() const; - -private: - Alarm event_type{ Alarm::unknown }; - char* description{}; -}; - -#endif diff --git a/solutions/11_threading/src/EventFilter.cpp b/solutions/11_threading/src/EventFilter.cpp deleted file mode 100644 index 622d3fd..0000000 --- a/solutions/11_threading/src/EventFilter.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// EventFilter.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "EventFilter.h" -#include "Pipe.h" -#include -#include - - -void connect(EventFilter& filter, Pipe& in, Pipe& out) -{ - filter.input = ∈ - filter.output = &out; -} - -bool EventFilter::execute() -{ - if (auto opt = input->pull()) { - auto events = std::move(opt.value()); - if (!events) { - // pass on closedown action - output->push(std::move(events)); - return false; - } - - std::cout << "FILTER : ------------------------" << '\n'; - - auto initial_size = events->size(); - - auto it = remove_if( - std::begin(*events), end(*events), [this](const Event& event) { - return event.type() == filter_value; - }); - - events->erase(it, std::end(*events)); - - auto event_removed = initial_size - events->size(); - - std::cout << "Removed " << event_removed << " event"; - std::cout << (event_removed == 1 ? "" : "s") << '\n'; - - output->push(std::move(events)); - - std::cout << '\n'; - } - - return true; -} diff --git a/solutions/11_threading/src/EventFilter.h b/solutions/11_threading/src/EventFilter.h deleted file mode 100644 index 3cd5135..0000000 --- a/solutions/11_threading/src/EventFilter.h +++ /dev/null @@ -1,27 +0,0 @@ -// EventFilter.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef ID_FILTER -#define ID_FILTER -#include "Filter.h" -#include "Event.h" - -class Pipe; - -class EventFilter : public Filter { -public: - EventFilter(Alarm remove_this) : filter_value{ remove_this } {} - - bool execute(); - -private: - Alarm filter_value{ Alarm::unknown }; - - Pipe* input{}; - Pipe* output{}; - friend void connect(EventFilter& filter, Pipe& in, Pipe& out); -}; - -#endif diff --git a/solutions/11_threading/src/Filter.h b/solutions/11_threading/src/Filter.h deleted file mode 100644 index 2e54e13..0000000 --- a/solutions/11_threading/src/Filter.h +++ /dev/null @@ -1,16 +0,0 @@ -// Filter.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef FILTER_H -#define FILTER_H - -class Filter { -public: - virtual bool execute() = 0; - - virtual ~Filter() = default; -}; - -#endif diff --git a/solutions/11_threading/src/Generator.cpp b/solutions/11_threading/src/Generator.cpp deleted file mode 100644 index 6f125c8..0000000 --- a/solutions/11_threading/src/Generator.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// Generator.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Generator.h" -#include "Pipe.h" -#include -#include -#include -#include - -void connect(Generator& gen, Pipe& pipe) -{ - gen.output = &pipe; -} - -namespace -{ - inline Alarm random_alarm() { return static_cast((rand() % 3) + 1); } - inline Event random_event() {return Event {random_alarm()}; } - - char const* warning_text[]{ - "It's all gone wrong!", "Panic!", "Run away!", - "Danger, Will Robinson!", "Aaaaaaargh!", "Oh no!" - }; - - inline char const* random_text() { return warning_text[rand() % 6]; } -} // namespace - -bool Generator::execute() -{ - std::cout << "GENERATOR: ------------------------" << '\n'; - - auto num_events = rand() % 9 + 1; - auto events = std::make_unique(); - - // To avoid copying during insertion - // - events->reserve(static_cast(num_events)); - - std::cout << "Generating " << num_events << " event" - << (num_events == 1 ? "" : "s") << '\n'; - - std::generate_n(std::back_inserter(*events), num_events, []() { - return Event{ random_alarm(), random_text() }; - }); - - // Move the Event_list into the pipe. - // events is now an x-value - // - output->push(std::move(events)); - - std::cout << '\n'; - - return false; -} diff --git a/solutions/11_threading/src/Pipe.cpp b/solutions/11_threading/src/Pipe.cpp deleted file mode 100644 index c1dcee9..0000000 --- a/solutions/11_threading/src/Pipe.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Pipe.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Pipe.h" -#include - -void Pipe::push(Pipe::element_type in_val) -{ - elements.add(std::move(in_val)); -} - -std::optional Pipe::pull() -{ - if (auto events = elements.get()) { - return events; - } - else { - return std::nullopt; - } -} diff --git a/solutions/11_threading/src/Pipe.h b/solutions/11_threading/src/Pipe.h deleted file mode 100644 index 56d835a..0000000 --- a/solutions/11_threading/src/Pipe.h +++ /dev/null @@ -1,27 +0,0 @@ -// Pipe.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef PIPE_H -#define PIPE_H - -#include -#include -#include -#include "Event.h" -#include "Buffer.h" - -class Pipe { -public: - using value_type = std::vector; - using element_type = std::unique_ptr; - - void push(element_type in_val); - std::optional pull(); - -private: - Buffer elements{}; -}; - -#endif diff --git a/solutions/11_threading/src/main.cpp b/solutions/11_threading/src/main.cpp deleted file mode 100644 index a98d6d2..0000000 --- a/solutions/11_threading/src/main.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// main.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Generator.h" -#include "EventFilter.h" -#include "Pipe.h" -#include "Filter.h" -#include -#include -#include - -using namespace std::chrono_literals; - -int main() -{ - Pipe pipe1{}; - Pipe pipe2{}; - - Generator generator{}; - Display display{}; - EventFilter filter{ Alarm::advisory }; - - connect(generator, pipe1); - connect(filter, pipe1, pipe2); - connect(display, pipe2); - - auto run_n_times = [](int num_times, Filter& filter) { - for (int i{ 0 }; i < num_times; ++i) { - filter.execute(); - std::this_thread::sleep_for(1000ms); - } - }; - - auto run_forever = [](Filter& filter) { - while (filter.execute()) { - std::this_thread::yield(); - } - }; - - std::thread gen_thread{ run_n_times, 5, std::ref(generator) }; - std::thread filter_thread{ run_forever, std::ref(filter) }; - std::thread display_thread{ run_forever, std::ref(display) }; - - // Wait for the generator to finish - // - gen_thread.join(); - - // close down the pipeline - pipe1.push(nullptr); - - filter_thread.join(); - display_thread.join(); -} diff --git a/solutions/12_mutual_exclusion/src/Buffer.h b/solutions/12_mutual_exclusion/src/Buffer.h deleted file mode 100644 index 3f548d5..0000000 --- a/solutions/12_mutual_exclusion/src/Buffer.h +++ /dev/null @@ -1,82 +0,0 @@ -// Buffer.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef BUFFER_H -#define BUFFER_H - -#include -#include - -template -class Buffer { -public: - using value_type = T; - - bool add(const T& in); - bool add(T&& in); - std::optional get(); - bool is_empty() const; - size_t size() const; - -private: - using Container = std::array; - using Iterator = typename Container::iterator; - - Container buffer{}; - Iterator write{ std::begin(buffer) }; - Iterator read{ std::begin(buffer) }; - size_t num_items{ 0 }; -}; - -template -bool Buffer::add(const T& in) -{ - if (num_items == sz) return false; - - *write = in; - ++write; - ++num_items; - if (write == std::end(buffer)) write = std::begin(buffer); - return true; -} - -template -bool Buffer::add(T&& in) -{ - if (num_items == sz) return false; - - *write = std::move(in); - ++write; - ++num_items; - if (write == std::end(buffer)) write = std::begin(buffer); - return true; -} - -template -std::optional Buffer::get() -{ - if (num_items == 0) return std::nullopt; - - auto out = std::move(*read); - ++read; - --num_items; - if (read == std::end(buffer)) read = std::begin(buffer); - - return out; -} - -template -bool Buffer::is_empty() const -{ - return (num_items == 0); -} - -template -size_t Buffer::size() const -{ - return num_items; -} - -#endif diff --git a/solutions/12_mutual_exclusion/src/Display.cpp b/solutions/12_mutual_exclusion/src/Display.cpp deleted file mode 100644 index e4bdc1e..0000000 --- a/solutions/12_mutual_exclusion/src/Display.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Display.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Event.h" -#include "Pipe.h" -#include - -void connect(Display& disp, Pipe& pipe) -{ - disp.input = &pipe; -} - -bool Display::execute() -{ - if (auto opt = input->pull()) { - auto events = std::move(opt.value()); - if (!events) { - return false; - } - std::cout << "DISPLAY : ------------------------" << '\n'; - - for (auto& event : *events) { - std::cout << event.as_string() << " : " << event.what() << '\n'; - } - std::cout << '\n'; - } - - return true; -} diff --git a/solutions/12_mutual_exclusion/src/Display.h b/solutions/12_mutual_exclusion/src/Display.h deleted file mode 100644 index d44a2b7..0000000 --- a/solutions/12_mutual_exclusion/src/Display.h +++ /dev/null @@ -1,24 +0,0 @@ -// Display.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef DISPLAY_H -#define DISPLAY_H -#include "Filter.h" - -class Pipe; - -class Display : public Filter { -public: - Display() = default; - Display(Pipe& ip) : input{ &ip } {} - - bool execute(); - -private: - Pipe* input{}; - friend void connect(Display& disp, Pipe& pipe); -}; - -#endif diff --git a/solutions/12_mutual_exclusion/src/Event.cpp b/solutions/12_mutual_exclusion/src/Event.cpp deleted file mode 100644 index 8c737df..0000000 --- a/solutions/12_mutual_exclusion/src/Event.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// Event.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Event.h" -#include -#include - -#ifdef TRACE_ENABLED -#include -#define TRACE(msg) \ - std::cout << "Event: " << as_string() << " : " << msg << '\n' -#else -#define TRACE(msg) -#endif - - -static char const* strings[]{ "unknown ", - "advisory ", - "caution ", - "warning " }; - -Event::Event() -{ - TRACE("Default ctor"); -} - -Event::Event(Alarm init) : event_type{ init } -{ - TRACE("Non-default ctor"); -} - -Event::Event(Alarm init, char const* str) : event_type{ init } -{ - TRACE("Non-default ctor with string"); - - if (str) { - description = new char[strlen(str) + 1]; - strcpy(description, str); - } -} - -Event::Event(Event&& src) noexcept : Event{} -{ - TRACE("Move ctor"); - - swap(*this, src); -} - -Event::~Event() -{ - TRACE("Dtor"); - - delete[] description; -} - -// Event::Event(const Event& src) : Event{ src.event_type, src.description } -// { -// TRACE("Copy ctor"); -// } - -Event& Event::operator=(Event && rhs) -{ - TRACE("Assignment"); - swap(*this, rhs); - return *this; -} - -Alarm Event::type() const -{ - return event_type; -} - -char const* Event::as_string() const -{ - return strings[static_cast(event_type)]; -} - -char const* Event::what() const -{ - return (description ? description : ""); -} - -void swap(Event& lhs, Event& rhs) -{ - using std::swap; - swap(lhs.event_type, rhs.event_type); - swap(lhs.description, rhs.description); -} diff --git a/solutions/12_mutual_exclusion/src/Event.h b/solutions/12_mutual_exclusion/src/Event.h deleted file mode 100644 index 2091956..0000000 --- a/solutions/12_mutual_exclusion/src/Event.h +++ /dev/null @@ -1,35 +0,0 @@ -// Event.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef EVENT_H -#define EVENT_H - -enum class Alarm { unknown, advisory, caution, warning }; - -class Event { -public: - Event(); - Event(Alarm init); - Event(Alarm init, char const* str); - - // Copy and move policy - // - ~Event(); - Event(Event const& src) = delete; - Event(Event&&) noexcept; - Event& operator=(const Event& rhs) = delete; - Event& operator=(Event&& rhs); - friend void swap(Event& lhs, Event& rhs); - - Alarm type() const; - char const* as_string() const; - char const* what() const; - -private: - Alarm event_type{ Alarm::unknown }; - char* description{}; -}; - -#endif diff --git a/solutions/12_mutual_exclusion/src/EventFilter.cpp b/solutions/12_mutual_exclusion/src/EventFilter.cpp deleted file mode 100644 index 622d3fd..0000000 --- a/solutions/12_mutual_exclusion/src/EventFilter.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// EventFilter.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "EventFilter.h" -#include "Pipe.h" -#include -#include - - -void connect(EventFilter& filter, Pipe& in, Pipe& out) -{ - filter.input = ∈ - filter.output = &out; -} - -bool EventFilter::execute() -{ - if (auto opt = input->pull()) { - auto events = std::move(opt.value()); - if (!events) { - // pass on closedown action - output->push(std::move(events)); - return false; - } - - std::cout << "FILTER : ------------------------" << '\n'; - - auto initial_size = events->size(); - - auto it = remove_if( - std::begin(*events), end(*events), [this](const Event& event) { - return event.type() == filter_value; - }); - - events->erase(it, std::end(*events)); - - auto event_removed = initial_size - events->size(); - - std::cout << "Removed " << event_removed << " event"; - std::cout << (event_removed == 1 ? "" : "s") << '\n'; - - output->push(std::move(events)); - - std::cout << '\n'; - } - - return true; -} diff --git a/solutions/12_mutual_exclusion/src/EventFilter.h b/solutions/12_mutual_exclusion/src/EventFilter.h deleted file mode 100644 index 3cd5135..0000000 --- a/solutions/12_mutual_exclusion/src/EventFilter.h +++ /dev/null @@ -1,27 +0,0 @@ -// EventFilter.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef ID_FILTER -#define ID_FILTER -#include "Filter.h" -#include "Event.h" - -class Pipe; - -class EventFilter : public Filter { -public: - EventFilter(Alarm remove_this) : filter_value{ remove_this } {} - - bool execute(); - -private: - Alarm filter_value{ Alarm::unknown }; - - Pipe* input{}; - Pipe* output{}; - friend void connect(EventFilter& filter, Pipe& in, Pipe& out); -}; - -#endif diff --git a/solutions/12_mutual_exclusion/src/Filter.h b/solutions/12_mutual_exclusion/src/Filter.h deleted file mode 100644 index 2e54e13..0000000 --- a/solutions/12_mutual_exclusion/src/Filter.h +++ /dev/null @@ -1,16 +0,0 @@ -// Filter.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef FILTER_H -#define FILTER_H - -class Filter { -public: - virtual bool execute() = 0; - - virtual ~Filter() = default; -}; - -#endif diff --git a/solutions/12_mutual_exclusion/src/Generator.cpp b/solutions/12_mutual_exclusion/src/Generator.cpp deleted file mode 100644 index 6f125c8..0000000 --- a/solutions/12_mutual_exclusion/src/Generator.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// Generator.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Generator.h" -#include "Pipe.h" -#include -#include -#include -#include - -void connect(Generator& gen, Pipe& pipe) -{ - gen.output = &pipe; -} - -namespace -{ - inline Alarm random_alarm() { return static_cast((rand() % 3) + 1); } - inline Event random_event() {return Event {random_alarm()}; } - - char const* warning_text[]{ - "It's all gone wrong!", "Panic!", "Run away!", - "Danger, Will Robinson!", "Aaaaaaargh!", "Oh no!" - }; - - inline char const* random_text() { return warning_text[rand() % 6]; } -} // namespace - -bool Generator::execute() -{ - std::cout << "GENERATOR: ------------------------" << '\n'; - - auto num_events = rand() % 9 + 1; - auto events = std::make_unique(); - - // To avoid copying during insertion - // - events->reserve(static_cast(num_events)); - - std::cout << "Generating " << num_events << " event" - << (num_events == 1 ? "" : "s") << '\n'; - - std::generate_n(std::back_inserter(*events), num_events, []() { - return Event{ random_alarm(), random_text() }; - }); - - // Move the Event_list into the pipe. - // events is now an x-value - // - output->push(std::move(events)); - - std::cout << '\n'; - - return false; -} diff --git a/solutions/12_mutual_exclusion/src/Pipe.cpp b/solutions/12_mutual_exclusion/src/Pipe.cpp deleted file mode 100644 index f38ce77..0000000 --- a/solutions/12_mutual_exclusion/src/Pipe.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Pipe.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Pipe.h" -#include - -void Pipe::push(Pipe::element_type in_val) -{ - { - std::unique_lock lock{ mtx }; - while (elements.size() == capacity) { - has_space.wait(lock); - } - elements.add(std::move(in_val)); - } - has_data.notify_all(); -} - -std::optional Pipe::pull() -{ - std::optional opt; - { - std::unique_lock lock{ mtx }; - while ((opt = elements.get()) == std::nullopt) { - has_data.wait(lock); - } - } - has_space.notify_all(); - return std::move(opt.value()); -} diff --git a/solutions/12_mutual_exclusion/src/Pipe.h b/solutions/12_mutual_exclusion/src/Pipe.h deleted file mode 100644 index 4a86dba..0000000 --- a/solutions/12_mutual_exclusion/src/Pipe.h +++ /dev/null @@ -1,33 +0,0 @@ -// Pipe.h -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#pragma once -#ifndef PIPE_H -#define PIPE_H - -#include -#include -#include -#include -#include -#include "Event.h" -#include "Buffer.h" - -class Pipe { -public: - using value_type = std::vector; - using element_type = std::unique_ptr; - - void push(element_type in_val); - std::optional pull(); - -private: - static constexpr int capacity {8}; - Buffer elements{}; - mutable std::mutex mtx{}; - std::condition_variable has_data{}; - std::condition_variable has_space{}; -}; - -#endif diff --git a/solutions/12_mutual_exclusion/src/main.cpp b/solutions/12_mutual_exclusion/src/main.cpp deleted file mode 100644 index 1c23ada..0000000 --- a/solutions/12_mutual_exclusion/src/main.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// main.cpp -// See project README.md for disclaimer and additional information. -// Feabhas Ltd - -#include "Display.h" -#include "Generator.h" -#include "EventFilter.h" -#include "Pipe.h" -#include "Filter.h" -#include -#include -#include - -using namespace std::chrono_literals; - -int main() -{ - Pipe pipe1{}; - Pipe pipe2{}; - - Generator generator{}; - Display display{}; - EventFilter filter{ Alarm::advisory }; - - connect(generator, pipe1); - connect(filter, pipe1, pipe2); - connect(display, pipe2); - - auto run_n_times = [](int num_times, Filter& filter) { - for (int i{ 0 }; i < num_times; ++i) { - filter.execute(); - // std::this_thread::sleep_for(1000ms); - } - }; - - auto run_forever = [](Filter& filter) { - while (filter.execute()) { - std::this_thread::yield(); - } - }; - - std::thread gen_thread{ run_n_times, 5, std::ref(generator) }; - std::thread filter_thread{ run_forever, std::ref(filter) }; - std::thread display_thread{ run_forever, std::ref(display) }; - - // Wait for the generator to finish - // - gen_thread.join(); - - // close down the pipeline - pipe1.push(nullptr); - - filter_thread.join(); - display_thread.join(); -}