diff --git a/arbor/include/arbor/event_generator.hpp b/arbor/include/arbor/event_generator.hpp index ecd0e476a9dff5bb6367b3b25f1bd5aca59af301..8d12a21817ad54e2579dfea9625d052a3cbea77d 100644 --- a/arbor/include/arbor/event_generator.hpp +++ b/arbor/include/arbor/event_generator.hpp @@ -4,6 +4,7 @@ #include <cstdint> #include <memory> #include <random> +#include <type_traits> #include <arbor/assert.hpp> #include <arbor/common_types.hpp> @@ -61,18 +62,15 @@ using event_seq = std::pair<const spike_event*, const spike_event*>; struct empty_generator { void reset() {} event_seq events(time_type, time_type) { - return {&no_event, &no_event}; + return {nullptr, nullptr}; } - -private: - static spike_event no_event; }; class event_generator { public: event_generator(): event_generator(empty_generator()) {} - template <typename Impl> + template <typename Impl, std::enable_if_t<!std::is_same<std::decay_t<Impl>, event_generator>::value, int> = 0> event_generator(Impl&& impl): impl_(new wrap<Impl>(std::forward<Impl>(impl))) {} @@ -128,6 +126,7 @@ private: }; }; +// Convenience routines for making schedule_generator: // Generate events with a fixed target and weight according to // a provided time schedule. @@ -161,7 +160,7 @@ private: schedule sched_; }; -// Convenience routines for making schedule_generator: +// Generate events at integer multiples of dt that lie between tstart and tstop. inline event_generator regular_generator( cell_member_type target, diff --git a/test/unit/test_event_generators.cpp b/test/unit/test_event_generators.cpp index d79eb42388ae65424fa431e6984e3cd7f786d075..032abda3d88aa9b0795447b1e8e770b74ae9a733 100644 --- a/test/unit/test_event_generators.cpp +++ b/test/unit/test_event_generators.cpp @@ -1,5 +1,7 @@ #include "../gtest.h" +#include <utility> + #include <arbor/event_generator.hpp> #include <arbor/spike_event.hpp> @@ -15,8 +17,40 @@ namespace{ } } +TEST(event_generators, assign_and_copy) { + event_generator gen = regular_generator({1, 2}, 5., 0.5, 0.75); + spike_event expected{{1, 2}, 0.75, 5.}; + + auto first = [](const event_seq& seq) { + if (seq.first==seq.second) throw std::runtime_error("no events"); + return *seq.first; + }; + + ASSERT_EQ(expected, first(gen.events(0., 1.))); + gen.reset(); + + event_generator g1(gen); + EXPECT_EQ(expected, first(g1.events(0., 1.))); + + event_generator g2; + g2 = gen; + EXPECT_EQ(expected, first(g2.events(0., 1.))); + + const auto& const_gen = gen; + + event_generator g3(const_gen); + EXPECT_EQ(expected, first(g3.events(0., 1.))); + + event_generator g4; + g4 = gen; + EXPECT_EQ(expected, first(g4.events(0., 1.))); + + event_generator g5(std::move(gen)); + EXPECT_EQ(expected, first(g5.events(0., 1.))); +} + TEST(event_generators, regular) { - // make a regular generator that generates its first event at t=2ms and subsequent + // Make a regular generator that generates its first event at t=2ms and subsequent // events regularly spaced 0.5 ms apart. time_type t0 = 2.0; time_type dt = 0.5; @@ -25,7 +59,7 @@ TEST(event_generators, regular) { event_generator gen = regular_generator(target, weight, t0, dt); - // helper for building a set of + // Helper for building a set of expected events. auto expected = [&] (std::vector<time_type> times) { pse_vector events; for (auto t: times) {