diff --git a/src/util/double_buffer.hpp b/src/util/double_buffer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..34dceb7f834768dd4fe768fee03f2ca83f24a7aa --- /dev/null +++ b/src/util/double_buffer.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include <array> +#include <atomic> + +#include <util/debug.hpp> + +namespace nest { +namespace mc { +namespace util { + +template <typename T> +class double_buffer { +private: + std::atomic<int> index_; + std::array<T, 2> buffers_; + + int other_index() { + return index_ ? 0 : 1; + } + +public: + using value_type = T; + + double_buffer() : + index_(0) + {} + + double_buffer(double_buffer&&) = delete; + double_buffer(const double_buffer&) = delete; + double_buffer& operator=(const double_buffer&) = delete; + double_buffer& operator=(double_buffer&&) = delete; + + void exchange() { + index_ ^= 1; + } + + value_type& get() { + return buffers_[index_]; + } + + const value_type& get() const { + return buffers_[index_]; + } + + value_type& other() { + return buffers_[other_index()]; + } + + const value_type& other() const { + return buffers_[other_index()]; + } +}; + +} // namespace util +} // namespace mc +} // namespace nest diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index a3a2d55333f6316b133bff3982ec58e1b03d525d..81976dd21ece69e5a7a520cf941c1fb1fe28022a 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -11,6 +11,7 @@ set(HEADERS set(TEST_SOURCES # unit tests test_algorithms.cpp + test_double_buffer.cpp test_cell.cpp test_compartments.cpp test_event_queue.cpp diff --git a/tests/unit/test_double_buffer.cpp b/tests/unit/test_double_buffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1689cc2faac17331694c78830c22cd1ea57777fe --- /dev/null +++ b/tests/unit/test_double_buffer.cpp @@ -0,0 +1,58 @@ +#include "gtest.h" + +#include <util/double_buffer.hpp> + +// not much to test here: just test that values passed into the constructor +// are correctly stored in members +TEST(double_buffer, exchange_and_get) +{ + using namespace nest::mc::util; + + double_buffer<int> buf; + + buf.get() = 2134; + buf.exchange(); + buf.get() = 8990; + buf.exchange(); + + EXPECT_EQ(buf.get(), 2134); + EXPECT_EQ(buf.other(), 8990); + buf.exchange(); + EXPECT_EQ(buf.get(), 8990); + EXPECT_EQ(buf.other(), 2134); + buf.exchange(); + EXPECT_EQ(buf.get(), 2134); + EXPECT_EQ(buf.other(), 8990); +} + +TEST(double_buffer, assign_get_other) +{ + using namespace nest::mc::util; + + double_buffer<std::string> buf; + + buf.get() = "1"; + buf.other() = "2"; + + EXPECT_EQ(buf.get(), "1"); + EXPECT_EQ(buf.other(), "2"); +} + +TEST(double_buffer, non_pod) +{ + using namespace nest::mc::util; + + double_buffer<std::string> buf; + + buf.get() = "1"; + buf.other() = "2"; + + EXPECT_EQ(buf.get(), "1"); + EXPECT_EQ(buf.other(), "2"); + buf.exchange(); + EXPECT_EQ(buf.get(), "2"); + EXPECT_EQ(buf.other(), "1"); + buf.exchange(); + EXPECT_EQ(buf.get(), "1"); + EXPECT_EQ(buf.other(), "2"); +}