From 4f433e9e491a64b468dbf3c1caf22bdd170453fd Mon Sep 17 00:00:00 2001 From: Nicolas Pope <nwpope@utu.fi> Date: Sun, 7 Jun 2020 21:16:00 +0300 Subject: [PATCH] Add reference returns --- .../structures/include/ftl/data/new_frame.hpp | 60 ++++++-- components/structures/test/frame_unit.cpp | 130 ++++++++++++++---- 2 files changed, 153 insertions(+), 37 deletions(-) diff --git a/components/structures/include/ftl/data/new_frame.hpp b/components/structures/include/ftl/data/new_frame.hpp index caec76a6d..68960b975 100644 --- a/components/structures/include/ftl/data/new_frame.hpp +++ b/components/structures/include/ftl/data/new_frame.hpp @@ -31,11 +31,16 @@ class Frame { return changed_.find(c) != changed_.end(); } + inline const std::unordered_set<ftl::codecs::Channel> &changed() const { return changed_; } + template <typename T> bool isType(ftl::codecs::Channel c); template <typename T> - const T *get(ftl::codecs::Channel c) const; + const T &get(ftl::codecs::Channel c) const; + + template <typename T> + const T *getPtr(ftl::codecs::Channel c) const; template <typename T> T *getMutable(ftl::codecs::Channel c); @@ -49,10 +54,13 @@ class Frame { } template <typename T> - void create(ftl::codecs::Channel c, const T &value); + T &create(ftl::codecs::Channel c, const T &value); template <typename T> - void create(ftl::codecs::Channel c); + T &create(ftl::codecs::Channel c); + + template <typename T, typename ...ARGS> + T &emplace(ftl::codecs::Channel, ARGS...); template <typename T> void push(ftl::codecs::Channel c, const T &v); @@ -69,9 +77,22 @@ class Frame { any_triggers_.push_back(cb); } + void merge(Frame &); + + void swap(Frame &); + + void swapChannel(ftl::codecs::Channel, Frame &); + + inline void reset() { changed_.clear(); } + + void clear(); + /** Send changes back through origin stream. */ bool flush(); + inline auto begin() const { return data_.begin(); } + inline auto end() const { return data_.end(); } + // onBeginFlush // onEndFlush // onError @@ -98,25 +119,46 @@ bool ftl::data::Frame::isType(ftl::codecs::Channel c) { } template <typename T> -const T *ftl::data::Frame::get(ftl::codecs::Channel c) const { +const T *ftl::data::Frame::getPtr(ftl::codecs::Channel c) const { auto i = data_.find(c); if (i != data_.end()) { return std::any_cast<T>(&i->second); } else if (parent_) { - return parent_->get<T>(c); + return parent_->getPtr<T>(c); } else return nullptr; } template <typename T> -void ftl::data::Frame::create(ftl::codecs::Channel c, const T &value) { - data_[c] = value; +const T &ftl::data::Frame::get(ftl::codecs::Channel c) const { + auto i = data_.find(c); + if (i != data_.end()) { + auto *p = std::any_cast<T>(&i->second); + if (!p) throw FTL_Error("'get' wrong type for channel (" << static_cast<unsigned int>(c) << ")"); + return *p; + } else if (parent_) { + return parent_->get<T>(c); + } else throw FTL_Error("'get' on missing channel (" << static_cast<unsigned int>(c) << ")"); +} + +template <typename T> +T &ftl::data::Frame::create(ftl::codecs::Channel c, const T &value) { touch(c); + auto &d = data_[c]; + d = value; + return *std::any_cast<T>(&d); } template <typename T> -void ftl::data::Frame::create(ftl::codecs::Channel c) { - if (!isType<T>(c)) data_[c] = T{}; +T &ftl::data::Frame::create(ftl::codecs::Channel c) { + touch(c); + if (!isType<T>(c)) return data_[c].emplace<T>(); + else return *std::any_cast<T>(&data_[c]); +} + +template <typename T, typename ...ARGS> +T &ftl::data::Frame::emplace(ftl::codecs::Channel c, ARGS... args) { touch(c); + return data_[c].emplace<T>(std::forward<ARGS...>(args...)); } template <typename T> diff --git a/components/structures/test/frame_unit.cpp b/components/structures/test/frame_unit.cpp index a866b8e44..af9c9387d 100644 --- a/components/structures/test/frame_unit.cpp +++ b/components/structures/test/frame_unit.cpp @@ -11,18 +11,16 @@ TEST_CASE("ftl::data::Frame create get", "[Frame]") { Frame f; f.create<int>(Channel::Pose, 55); - auto x = f.get<int>(Channel::Pose); - REQUIRE( x ); - REQUIRE( *x == 55 ); + const auto &x = f.get<int>(Channel::Pose); + REQUIRE( x == 55 ); } SECTION("write and read floats") { Frame f; f.create<float>(Channel::Pose, 44.0f); - auto x = f.get<float>(Channel::Pose); - REQUIRE( x ); - REQUIRE( *x == 44.0f ); + const auto &x = f.get<float>(Channel::Pose); + REQUIRE( x == 44.0f ); } SECTION("write and read structures") { @@ -33,10 +31,9 @@ TEST_CASE("ftl::data::Frame create get", "[Frame]") { Frame f; f.create<Test>(Channel::Pose, {}); - auto x = f.get<Test>(Channel::Pose); - REQUIRE( x ); - REQUIRE( x->a == 44 ); - REQUIRE( x->b == 33.0f ); + const auto &x = f.get<Test>(Channel::Pose); + REQUIRE( x.a == 44 ); + REQUIRE( x.b == 33.0f ); } SECTION("write and read fail") { @@ -47,8 +44,15 @@ TEST_CASE("ftl::data::Frame create get", "[Frame]") { Frame f; f.create<Test>(Channel::Pose, {}); - auto x = f.get<int>(Channel::Pose); - REQUIRE( !x ); + bool err = false; + + try { + int x = f.get<int>(Channel::Pose); + REQUIRE(x); + } catch (...) { + err = true; + } + REQUIRE(err); } } @@ -104,28 +108,24 @@ TEST_CASE("ftl::data::Frame create", "[Frame]") { Frame f; f.create<int>(Channel::Pose, 55); - auto x = f.get<int>(Channel::Pose); - REQUIRE( x ); - REQUIRE( *x == 55 ); + const auto &x = f.get<int>(Channel::Pose); + REQUIRE( x == 55 ); f.create<int>(Channel::Pose); - auto y = f.get<int>(Channel::Pose); - REQUIRE( y ); - REQUIRE( *y == 55 ); - - REQUIRE( x == y ); + const auto &y = f.get<int>(Channel::Pose); + REQUIRE( y == 55 ); } SECTION("change of type") { Frame f; f.create<int>(Channel::Pose, 55); - auto x = f.get<int>(Channel::Pose); + auto x = f.getPtr<int>(Channel::Pose); REQUIRE( x ); REQUIRE( *x == 55 ); f.create<float>(Channel::Pose); - auto y = f.get<float>(Channel::Pose); + auto y = f.getPtr<float>(Channel::Pose); REQUIRE( y ); REQUIRE( *y == 0.0f ); } @@ -138,11 +138,11 @@ TEST_CASE("ftl::data::Frame use of parent", "[Frame]") { p.create<int>(Channel::Pose, 55); - auto x = f.get<int>(Channel::Pose); + auto x = f.getPtr<int>(Channel::Pose); REQUIRE( x ); REQUIRE( *x == 55 ); - auto y = p.get<int>(Channel::Pose); + auto y = p.getPtr<int>(Channel::Pose); REQUIRE( x == y ); } @@ -169,11 +169,11 @@ TEST_CASE("ftl::data::Frame use of parent", "[Frame]") { REQUIRE( f.changed(Channel::Pose) ); REQUIRE( !p.changed(Channel::Pose) ); - auto x = f.get<int>(Channel::Pose); + auto x = f.getPtr<int>(Channel::Pose); REQUIRE( x ); REQUIRE( *x == 66 ); - auto y = p.get<int>(Channel::Pose); + auto y = p.getPtr<int>(Channel::Pose); REQUIRE( y ); REQUIRE( *y == 55 ); } @@ -221,12 +221,12 @@ TEST_CASE("ftl::data::Frame flush", "[Frame]") { p.flush(); f.set<int>(Channel::Pose, 66); - auto x = p.get<int>(Channel::Pose); + auto x = p.getPtr<int>(Channel::Pose); REQUIRE( x ); REQUIRE( *x == 55 ); f.flush(); - x = p.get<int>(Channel::Pose); + x = p.getPtr<int>(Channel::Pose); REQUIRE( x ); REQUIRE( *x == 66 ); } @@ -241,3 +241,77 @@ TEST_CASE("ftl::data::Frame flush", "[Frame]") { REQUIRE( !f.changed(Channel::Pose) ); } } + +// ==== Complex type overload test ============================================= + +struct TestA { + int a=55; +}; + +struct TestB { + int b=99; +}; + +struct TestC { + TestA a; + TestB b; +}; + +template <> +TestA &ftl::data::Frame::create<TestA>(ftl::codecs::Channel c) { + return create<TestC>(c).a; +} + +template <> +TestA &ftl::data::Frame::create<TestA>(ftl::codecs::Channel c, const TestA &a) { + TestC cc; + cc.a = a; + return create<TestC>(c, cc).a; +} + +template <> +TestB &ftl::data::Frame::create<TestB>(ftl::codecs::Channel c, const TestB &b) { + TestC cc; + cc.b = b; + return create<TestC>(c, cc).b; +} + +template <> +const TestA *ftl::data::Frame::getPtr<TestA>(ftl::codecs::Channel c) const { + auto *ptr = getPtr<TestC>(c); + return (ptr) ? &ptr->a : nullptr; +} + +template <> +const TestB *ftl::data::Frame::getPtr<TestB>(ftl::codecs::Channel c) const { + auto *ptr = getPtr<TestC>(c); + return (ptr) ? &ptr->b : nullptr; +} + +TEST_CASE("ftl::data::Frame Complex Overload", "[Frame]") { + SECTION("Create and get first type with default") { + Frame f; + f.create<TestA>(Channel::Pose); + + auto *x = f.getPtr<TestA>(Channel::Pose); + REQUIRE( x ); + REQUIRE( x->a == 55 ); + + auto *y = f.getPtr<TestB>(Channel::Pose); + REQUIRE( y ); + REQUIRE( y->b == 99 ); + } + + SECTION("Create and get first type with value") { + Frame f; + f.create<TestA>(Channel::Pose, {77}); + + auto *x = f.getPtr<TestA>(Channel::Pose); + REQUIRE( x ); + REQUIRE( x->a == 77 ); + + auto *y = f.getPtr<TestB>(Channel::Pose); + REQUIRE( y ); + REQUIRE( y->b == 99 ); + } +} -- GitLab