Mercurial > code
changeset 256:0080762c8983
TreeNode: support inheritance through proxies
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 02 Oct 2014 20:40:56 +0200 |
parents | 8196fdb0fc48 |
children | 60f71f245c5b |
files | C++/Tests/TreeNode/main.cpp C++/TreeNode.h extern/gtest/CMakeLists.txt |
diffstat | 3 files changed, 170 insertions(+), 31 deletions(-) [+] |
line wrap: on
line diff
--- a/C++/Tests/TreeNode/main.cpp Thu Oct 02 17:14:51 2014 +0200 +++ b/C++/Tests/TreeNode/main.cpp Thu Oct 02 20:40:56 2014 +0200 @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <chrono> +#include <iostream> #include <string> #include <gtest/gtest.h> @@ -1349,9 +1351,98 @@ ASSERT_EQ(-1, root.indexOfSame(same)); } +TEST(Misc, inplaceFront) +{ + Object root("root"); + + root.pushNew("a"); + root.pushNew("b"); + + ASSERT_TRUE(root.isRoot()); + ASSERT_FALSE(root.isLeaf()); + ASSERT_EQ(2, root.countChildren()); + ASSERT_EQ("b", root[0].name()); + ASSERT_EQ("a", root[1].name()); +} + +TEST(Misc, inplaceBack) +{ + Object root("root"); + + root.appendNew("a"); + root.appendNew("b"); + + ASSERT_TRUE(root.isRoot()); + ASSERT_FALSE(root.isLeaf()); + ASSERT_EQ(2, root.countChildren()); + ASSERT_EQ("a", root[0].name()); + ASSERT_EQ("b", root[1].name()); +} + +/* -------------------------------------------------------- + * Test inheritance + * -------------------------------------------------------- */ + +class Animal : public TreeNode<Animal> { +public: + virtual ~Animal() = default; + virtual std::string noise() const + { + return "standard"; + } +}; + +class Cat final : public Animal { +public: + std::string noise() const override + { + return "miaou"; + } +}; + +class Dog final : public Animal { +public: + std::string noise() const override + { + return "waouf"; + } +}; + +TEST(Inheritance, basic) +{ + Animal root; + + root.append(Animal()); + root.append(Cat()); + root.append(Dog()); + + ASSERT_EQ("standard", root[0].noise()); + ASSERT_EQ("miaou", root[1].noise()); + ASSERT_EQ("waouf", root[2].noise()); +} + +TEST(Inheritance, copy) +{ + Animal root; + + root.append(Animal()); + root.append(Cat()); + root.append(Dog()); + + ASSERT_EQ("standard", root[0].noise()); + ASSERT_EQ("miaou", root[1].noise()); + ASSERT_EQ("waouf", root[2].noise()); + + Animal copy(root); + + ASSERT_EQ("standard", copy[0].noise()); + ASSERT_EQ("miaou", copy[1].noise()); + ASSERT_EQ("waouf", copy[2].noise()); +} + int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +}
--- a/C++/TreeNode.h Thu Oct 02 17:14:51 2014 +0200 +++ b/C++/TreeNode.h Thu Oct 02 20:40:56 2014 +0200 @@ -28,6 +28,7 @@ #include <deque> #include <memory> #include <stdexcept> +#include <type_traits> namespace { @@ -77,7 +78,37 @@ template <typename T> class TreeNode { private: - using Container = std::deque<std::unique_ptr<T>>; + struct Object { + std::unique_ptr<T> value; + + virtual std::unique_ptr<Object> clone() const = 0; + }; + + template <typename U> + struct Proxy final : public Object { + inline Proxy(U &&u) + { + this->value = std::make_unique<U>(std::move(u)); + } + + inline Proxy(const U &u) + { + this->value = std::make_unique<U>(u); + } + + template <typename... Args> + inline Proxy(Args&&... args) + { + this->value = std::make_unique<U>(std::forward<Args>(args)...); + } + + std::unique_ptr<Object> clone() const override + { + return std::make_unique<Proxy<U>>(static_cast<const U &>(*this->value)); + } + }; + + using Container = std::deque<std::unique_ptr<Object>>; TreeNode *m_parent { nullptr }; Container m_children; @@ -89,6 +120,11 @@ TreeNode() = default; /** + * Default destructor. + */ + virtual ~TreeNode() = default; + + /** * Copy constructor. * * @param other the other node @@ -97,8 +133,8 @@ : m_parent(nullptr) { for (const auto &c : other.m_children) { - m_children.push_back(std::make_unique<T>(*c)); - m_children.back()->m_parent = this; + m_children.push_back(c->clone()); + m_children.back()->value->m_parent = this; } } @@ -113,7 +149,7 @@ { // Update children to update to *this for (auto &c : m_children) - c->m_parent = this; + c->value->m_parent = this; other.m_children.clear(); } @@ -128,8 +164,8 @@ m_children.clear(); for (const auto &c : other.m_children) { - m_children.push_back(std::make_unique<T>(*c)); - m_children.back()->m_parent = this; + m_children.push_back(c->clone()); + m_children.back()->value->m_parent = this; } return *this; @@ -146,7 +182,7 @@ // Update children to update to *this for (auto &c : m_children) - c->m_parent = this; + c->value->m_parent = this; other.m_children.clear(); @@ -158,10 +194,11 @@ * * @param child the children */ - void push(const T &child) + template <typename Value> + inline void push(const Value &child) { - m_children.push_front(std::make_unique<T>(child)); - m_children.front()->m_parent = this; + m_children.push_front(std::make_unique<Proxy<Value>>(child)); + m_children.front()->value->m_parent = this; } /** @@ -169,10 +206,13 @@ * * @param child the children */ - void push(T &&child) + template <typename Value> + inline void push(Value &&child, typename std::enable_if<std::is_rvalue_reference<Value &&>::value>::type * = nullptr) { - m_children.push_front(std::make_unique<T>(std::move(child))); - m_children.front()->m_parent = this; + using Type = typename std::decay<Value>::type; + + m_children.push_front(std::make_unique<Proxy<Type>>(std::move(child))); + m_children.front()->value->m_parent = this; } /** @@ -183,8 +223,8 @@ template <typename... Args> void pushNew(Args&&... args) { - m_children.emplace_front(std::make_unique<T>(std::forward<Args>(args)...)); - m_children.front()->m_parent = this; + m_children.emplace_front(std::make_unique<Proxy<T>>(std::forward<Args>(args)...)); + m_children.front()->value->m_parent = this; } /** @@ -192,10 +232,11 @@ * * @param child the children */ - void append(const T &child) + template <typename Value> + inline void append(const Value &child) { - m_children.push_back(std::make_unique<T>(child)); - m_children.back()->m_parent = this; + m_children.push_back(std::make_unique<Proxy<Value>>(child)); + m_children.back()->value->m_parent = this; } /** @@ -203,10 +244,13 @@ * * @param child the children */ - void append(T &&child) + template <typename Value> + inline void append(Value &&child, typename std::enable_if<std::is_rvalue_reference<Value &&>::value>::type * = nullptr) { - m_children.push_back(std::make_unique<T>(std::move(child))); - m_children.back()->m_parent = this; + using Type = typename std::decay<Value>::type; + + m_children.push_back(std::make_unique<Proxy<Type>>(std::move(child))); + m_children.back()->value->m_parent = this; } /** @@ -217,8 +261,8 @@ template <typename... Args> void appendNew(Args&&... args) { - m_children.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)); - m_children.back()->m_parent = this; + m_children.emplace_back(std::make_unique<Proxy<T>>(std::forward<Args>(args)...)); + m_children.back()->value->m_parent = this; } /** @@ -303,7 +347,7 @@ void remove(T &value) { m_children.erase(std::remove_if(m_children.begin(), m_children.end(), [&] (auto &p) { - return p.get() == &value; + return p->value.get() == &value; }), m_children.end()); } @@ -317,7 +361,7 @@ void removeSame(const Value &value, typename std::enable_if<TypeTraits<Value>::equalityComparable>::type * = nullptr) { m_children.erase(std::remove_if(m_children.begin(), m_children.end(), [&] (auto &p) { - return *p == value; + return *p->value == value; }), m_children.end()); } @@ -339,7 +383,7 @@ int indexOf(const T &child) const { for (unsigned i = 0; i < m_children.size(); ++i) - if (m_children[i].get() == &child) + if (m_children[i]->value.get() == &child) return i; return -1; @@ -356,7 +400,7 @@ int indexOfSame(const Value &value, typename std::enable_if<TypeTraits<Value>::equalityComparable>::type * = nullptr) { for (unsigned i = 0; i < m_children.size(); ++i) - if (*m_children[i] == value) + if (*m_children[i]->value == value) return i; return -1; @@ -371,7 +415,7 @@ */ T &operator[](int index) { - return static_cast<T &>(*m_children.at(index)); + return static_cast<T &>(*m_children.at(index)->value); } /** @@ -383,8 +427,8 @@ */ const T &operator[](int index) const { - return static_cast<const T &>(*m_children.at(index)); + return static_cast<const T &>(*m_children.at(index)->value); } }; -#endif // !_TREE_NODE_H_ \ No newline at end of file +#endif // !_TREE_NODE_H_