changeset 251:0b7566e27eaa

TreeNode: * use std::unique_ptr as children to avoid useless copy/move constructor calls of the element type. * add over 1000 lines of unit test. * TreeNode is now considered ready to use.
author David Demelier <markand@malikania.fr>
date Thu, 02 Oct 2014 11:17:08 +0200
parents b686a09fb9c6
children 19bfc11f77c2
files C++/Tests/TreeNode/CMakeLists.txt C++/Tests/TreeNode/main.cpp C++/TreeNode.h CMakeLists.txt
diffstat 4 files changed, 1350 insertions(+), 198 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Tests/TreeNode/CMakeLists.txt	Thu Oct 02 11:17:08 2014 +0200
@@ -0,0 +1,25 @@
+#
+# CMakeLists.txt -- tests for TreeNode
+#
+# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+set(
+	SOURCES
+	${code_SOURCE_DIR}/C++/TreeNode.h
+	main.cpp
+)
+
+define_test(treenode "${SOURCES}")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Tests/TreeNode/main.cpp	Thu Oct 02 11:17:08 2014 +0200
@@ -0,0 +1,1241 @@
+/*
+ * main.cpp -- main test file for TreeNode
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <TreeNode.h>
+
+class Object final : public TreeNode<Object> {
+private:
+	std::string	m_name;
+
+public:
+	Object(std::string name)
+		: TreeNode()
+	{
+		m_name = std::move(name);
+	}
+
+	const std::string &name() const
+	{
+		return m_name;
+	}
+};
+
+/*
+ * Random trees are created and then we test each node with the following preferred order:
+ *
+ * ASSERT_(TRUE|FALSE) isRoot()
+ * ASSERT_(TRUE|FALSE) isLeaf()
+ * ASSERT_EQ countChildren()
+ * ASSERT_EQ() name()
+ * ASSERT_TRUE & addresses
+ */
+
+/* --------------------------------------------------------
+ * Basic construction and insertion
+ * -------------------------------------------------------- */
+
+/*
+ * @root
+ */
+TEST(Basic, construct)
+{
+	Object object("root");
+
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_TRUE(object.isLeaf());
+	ASSERT_EQ(0, object.countChildren());
+	ASSERT_EQ("root", object.name());
+}
+
+/*
+ * @root -> append move -> @root
+ *                         |
+ *                         @a
+ */
+TEST(Insertion, simpleAppendMove)
+{
+	Object object("root");
+	Object a("a");
+
+	object.append(std::move(a));
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(1, object.countChildren());
+	ASSERT_EQ("root", object.name());
+
+	// test moved a
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ("a", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test original a
+	ASSERT_TRUE(a.isRoot());
+	ASSERT_TRUE(a.isLeaf());
+	ASSERT_EQ(0, a.countChildren());
+}
+
+/*
+ * @root -> append copy -> @root
+ *                         |
+ *                         @a
+ */
+TEST(Insertion, simpleAppendCopy)
+{
+	Object object("root");
+	Object copy("b");
+
+	object.append(copy);
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(1, object.countChildren());
+	ASSERT_EQ("root", object.name());
+
+	// test copied b
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ("b", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test original b
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_TRUE(copy.isLeaf());
+	ASSERT_EQ(0, copy.countChildren());
+	ASSERT_EQ("b", copy.name());
+}
+
+/*
+ * @root -> append move -> @root
+ *                        / \
+ *                      1@   @2
+ */
+TEST(Insertion, doubleAppendMove)
+{
+	Object object("root");
+	Object o1("1");
+	Object o2("2");
+
+	object.append(std::move(o1));
+	object.append(std::move(o2));
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(2, object.countChildren());
+	ASSERT_EQ("root", object.name());
+
+	// test moved 1
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ(0, object[0].countChildren());
+	ASSERT_EQ("1", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test moved 2
+	ASSERT_FALSE(object[1].isRoot());
+	ASSERT_TRUE(object[1].isLeaf());
+	ASSERT_EQ("2", object[1].name());
+	ASSERT_EQ(0, object[1].countChildren());
+	ASSERT_TRUE(&object == &object[1].parent());
+
+	// test original 1
+	ASSERT_TRUE(o1.isRoot());
+	ASSERT_TRUE(o1.isLeaf());
+	ASSERT_EQ(0, o1.countChildren());
+
+	// test original 2
+	ASSERT_TRUE(o2.isRoot());
+	ASSERT_TRUE(o2.isLeaf());
+	ASSERT_EQ(0, o2.countChildren());
+}
+
+/*
+ * @root -> append copy -> @root
+ *                        / \
+ *                      1@   @2
+ */
+TEST(Insertion, doubleAppendCopy)
+{
+	Object object("root");
+	Object o1("1");
+	Object o2("2");
+
+	object.append(o1);
+	object.append(o2);
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(2, object.countChildren());
+	ASSERT_EQ("root", object.name());
+
+	// test copied 1
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ(0, object[0].countChildren());
+	ASSERT_EQ("1", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test copied 2
+	ASSERT_FALSE(object[1].isRoot());
+	ASSERT_TRUE(object[1].isLeaf());
+	ASSERT_EQ(0, object[1].countChildren());
+	ASSERT_EQ("2", object[1].name());
+	ASSERT_TRUE(&object == &object[1].parent());
+
+	// test original 1
+	ASSERT_TRUE(o1.isRoot());
+	ASSERT_TRUE(o1.isLeaf());
+	ASSERT_EQ(0, o1.countChildren());
+	ASSERT_EQ("1", o1.name());
+
+	// test original 2
+	ASSERT_TRUE(o2.isRoot());
+	ASSERT_TRUE(o2.isLeaf());
+	ASSERT_EQ(0, o2.countChildren());
+	ASSERT_EQ("2", o2.name());
+}
+
+/*
+ * @root -> push move -> @root
+ *                       |
+ *                       @a
+ */
+TEST(Insertion, simplePushMove)
+{
+	Object object("root");
+	Object a("a");
+
+	object.push(std::move(a));
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(1, object.countChildren());
+	ASSERT_EQ("a", object[0].name());
+
+	// test moved a
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ(0, object[0].countChildren());
+	ASSERT_EQ("a", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test original a
+	ASSERT_TRUE(a.isRoot());
+	ASSERT_TRUE(a.isLeaf());
+	ASSERT_EQ(0, a.countChildren());
+}
+
+/*
+ * @root -> push copy -> @root
+ *                       |
+ *                       @a
+ */
+TEST(Insertion, simplePushCopy)
+{
+	Object object("root");
+	Object copy("a");
+
+	object.push(copy);
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(1, object.countChildren());
+	ASSERT_EQ("a", object[0].name());
+
+	// test copied a
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ(0, object[0].countChildren());
+	ASSERT_EQ("a", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test original b
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_TRUE(copy.isLeaf());
+	ASSERT_EQ(0, copy.countChildren());
+	ASSERT_EQ("a", copy.name());
+}
+
+/*
+ * @root -> push move -> @root
+ *                      / \
+ *                    2@   @1
+ */
+TEST(Insertion, doublePushMove)
+{
+	Object object("root");
+	Object o1("1");
+	Object o2("2");
+
+	object.push(std::move(o1));
+	object.push(std::move(o2));
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(2, object.countChildren());
+	ASSERT_EQ("root", object.name());
+
+	// test moved 2
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ(0, object[0].countChildren());
+	ASSERT_EQ("2", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test moved 1
+	ASSERT_FALSE(object[1].isRoot());
+	ASSERT_TRUE(object[1].isLeaf());
+	ASSERT_EQ("1", object[1].name());
+	ASSERT_EQ(0, object[1].countChildren());
+	ASSERT_TRUE(&object == &object[1].parent());
+
+	// test original 1
+	ASSERT_TRUE(o1.isRoot());
+	ASSERT_TRUE(o1.isLeaf());
+	ASSERT_EQ(0, o1.countChildren());
+
+	// test original 2
+	ASSERT_TRUE(o2.isRoot());
+	ASSERT_TRUE(o2.isLeaf());
+	ASSERT_EQ(0, o2.countChildren());
+}
+
+/*
+ * @root -> push copy -> @root
+ *                      / \
+ *                    2@   @1
+ */
+TEST(Insertion, doublePushCopy)
+{
+	Object object("root");
+	Object o1("1");
+	Object o2("2");
+
+	object.push(o1);
+	object.push(o2);
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(2, object.countChildren());
+	ASSERT_EQ("root", object.name());
+
+	// test copied 2
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_TRUE(object[0].isLeaf());
+	ASSERT_EQ(0, object[0].countChildren());
+	ASSERT_EQ("2", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test copied 1
+	ASSERT_FALSE(object[1].isRoot());
+	ASSERT_TRUE(object[1].isLeaf());
+	ASSERT_EQ(0, object[1].countChildren());
+	ASSERT_EQ("1", object[1].name());
+	ASSERT_TRUE(&object == &object[1].parent());
+
+	// test original 1
+	ASSERT_TRUE(o1.isRoot());
+	ASSERT_TRUE(o1.isLeaf());
+	ASSERT_EQ(0, o1.countChildren());
+	ASSERT_EQ("1", o1.name());
+
+	// test original 2
+	ASSERT_TRUE(o2.isRoot());
+	ASSERT_TRUE(o2.isLeaf());
+	ASSERT_EQ(0, o2.countChildren());
+	ASSERT_EQ("2", o2.name());
+}
+
+/* --------------------------------------------------------
+ * Sub insertion
+ * -------------------------------------------------------- */
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b
+ *        / \   / \
+ *      c@  d@ @e  @f
+ */
+TEST(SubInsert, append)
+{
+	Object object("root");
+
+	object.append(Object("a"));
+	object.append(Object("b"));
+
+	object[0].append(Object("c"));
+	object[0].append(Object("d"));
+	object[1].append(Object("e"));
+	object[1].append(Object("f"));
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(2, object.countChildren());
+	ASSERT_EQ("root", object.name());
+
+	// test a
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_FALSE(object[0].isLeaf());
+	ASSERT_EQ(2, object[0].countChildren());
+	ASSERT_EQ("a", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test b
+	ASSERT_FALSE(object[1].isRoot());
+	ASSERT_FALSE(object[1].isLeaf());
+	ASSERT_EQ(2, object[1].countChildren());
+	ASSERT_EQ("b", object[1].name());
+	ASSERT_TRUE(&object == &object[1].parent());
+
+	// test c
+	ASSERT_FALSE(object[0][0].isRoot());
+	ASSERT_TRUE(object[0][0].isLeaf());
+	ASSERT_EQ(0, object[0][0].countChildren());
+	ASSERT_EQ("c", object[0][0].name());
+	ASSERT_TRUE(&object[0] == &object[0][0].parent());
+
+	// test d
+	ASSERT_FALSE(object[0][1].isRoot());
+	ASSERT_TRUE(object[0][1].isLeaf());
+	ASSERT_EQ(0, object[0][1].countChildren());
+	ASSERT_EQ("d", object[0][1].name());
+	ASSERT_TRUE(&object[0] == &object[0][1].parent());
+
+	// test e
+	ASSERT_FALSE(object[1][0].isRoot());
+	ASSERT_TRUE(object[1][0].isLeaf());
+	ASSERT_EQ(0, object[1][0].countChildren());
+	ASSERT_EQ("e", object[1][0].name());
+	ASSERT_TRUE(&object[1] == &object[1][0].parent());
+
+	// test f
+	ASSERT_FALSE(object[1][1].isRoot());
+	ASSERT_TRUE(object[1][1].isLeaf());
+	ASSERT_EQ(0, object[1][1].countChildren());
+	ASSERT_EQ("f", object[1][1].name());
+	ASSERT_TRUE(&object[1] == &object[1][1].parent());
+}
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        b@     @a
+ *        / \   / \
+ *      d@  c@ @f  @e
+ */
+TEST(SubInsert, push)
+{
+	Object object("root");
+
+	object.push(Object("a"));
+	object.push(Object("b"));
+
+	object[0].push(Object("c"));
+	object[0].push(Object("d"));
+	object[1].push(Object("e"));
+	object[1].push(Object("f"));
+
+	// test root
+	ASSERT_TRUE(object.isRoot());
+	ASSERT_FALSE(object.isLeaf());
+	ASSERT_EQ(2, object.countChildren());
+	ASSERT_EQ("root", object.name());
+
+	// test b
+	ASSERT_FALSE(object[0].isRoot());
+	ASSERT_FALSE(object[0].isLeaf());
+	ASSERT_EQ(2, object[0].countChildren());
+	ASSERT_EQ("b", object[0].name());
+	ASSERT_TRUE(&object == &object[0].parent());
+
+	// test a
+	ASSERT_FALSE(object[1].isRoot());
+	ASSERT_FALSE(object[1].isLeaf());
+	ASSERT_EQ(2, object[1].countChildren());
+	ASSERT_EQ("a", object[1].name());
+	ASSERT_TRUE(&object == &object[1].parent());
+
+	// test d
+	ASSERT_FALSE(object[0][0].isRoot());
+	ASSERT_TRUE(object[0][0].isLeaf());
+	ASSERT_EQ(0, object[0][0].countChildren());
+	ASSERT_EQ("d", object[0][0].name());
+	ASSERT_TRUE(&object[0] == &object[0][0].parent());
+
+	// test c
+	ASSERT_FALSE(object[0][1].isRoot());
+	ASSERT_TRUE(object[0][1].isLeaf());
+	ASSERT_EQ(0, object[0][1].countChildren());
+	ASSERT_EQ("c", object[0][1].name());
+	ASSERT_TRUE(&object[0] == &object[0][1].parent());
+
+	// test f
+	ASSERT_FALSE(object[1][0].isRoot());
+	ASSERT_TRUE(object[1][0].isLeaf());
+	ASSERT_EQ(0, object[1][0].countChildren());
+	ASSERT_EQ("f", object[1][0].name());
+	ASSERT_TRUE(&object[1] == &object[1][0].parent());
+
+	// test e
+	ASSERT_FALSE(object[1][1].isRoot());
+	ASSERT_TRUE(object[1][1].isLeaf());
+	ASSERT_EQ(0, object[1][1].countChildren());
+	ASSERT_EQ("e", object[1][1].name());
+	ASSERT_TRUE(&object[1] == &object[1][1].parent());
+}
+
+/* --------------------------------------------------------
+ * Move constructor
+ * -------------------------------------------------------- */
+
+TEST(MoveConstructor, simple)
+{
+	Object root("root");
+	Object moved(std::move(root));
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_TRUE(root.isLeaf());
+	ASSERT_EQ(0, root.countChildren());
+
+	// test moved
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_TRUE(moved.isLeaf());
+	ASSERT_EQ(0, moved.countChildren());
+	ASSERT_EQ("root", moved.name());
+}
+
+/*
+ *            @root -> copy
+ *           / \
+ *          /   \
+ *        a@     @b 
+ */
+TEST(MoveConstructor, oneLevel)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	Object moved(std::move(root));
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_EQ(2, moved.countChildren());
+	ASSERT_EQ("a", moved[0].name());
+	ASSERT_EQ("b", moved[1].name());
+	ASSERT_EQ("root", moved[0].parent().name());
+	ASSERT_EQ("root", moved[1].parent().name());
+	ASSERT_TRUE(&moved == &moved[0].parent());
+	ASSERT_TRUE(&moved == &moved[1].parent());
+}
+
+/*
+ *            @root -> copy
+ *           / \
+ *          /   \
+ *        a@     @b 
+ *        / \   / \
+ *      c@  d@ @e  @f
+ *
+ */
+TEST(MoveConstructor, twoLevels)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	root[0].append(Object("c"));
+	root[0].append(Object("d"));
+	root[1].append(Object("e"));
+	root[1].append(Object("f"));
+
+	Object moved(std::move(root));
+
+	// test root
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_EQ(2, moved.countChildren());
+
+	// test a, b
+	ASSERT_EQ("a", moved[0].name());
+	ASSERT_EQ("b", moved[1].name());
+	ASSERT_EQ(2, moved[0].countChildren());
+	ASSERT_EQ(2, moved[1].countChildren());
+	ASSERT_EQ("root", moved[0].parent().name());
+	ASSERT_EQ("root", moved[1].parent().name());
+	ASSERT_TRUE(&moved == &moved[0].parent());
+	ASSERT_TRUE(&moved == &moved[1].parent());
+
+	// test c, d
+	ASSERT_EQ("c", moved[0][0].name());
+	ASSERT_EQ("d", moved[0][1].name());
+	ASSERT_EQ("a", moved[0][0].parent().name());
+	ASSERT_EQ("a", moved[0][1].parent().name());
+	ASSERT_TRUE(&moved[0] == &moved[0][0].parent());
+	ASSERT_TRUE(&moved[0] == &moved[0][1].parent());
+	ASSERT_TRUE(moved[0][0].isLeaf());
+	ASSERT_TRUE(moved[0][1].isLeaf());
+	ASSERT_FALSE(moved[0][0].isRoot());
+	ASSERT_FALSE(moved[0][1].isRoot());
+
+	// test e, f
+	ASSERT_EQ("e", moved[1][0].name());
+	ASSERT_EQ("f", moved[1][1].name());
+	ASSERT_EQ("b", moved[1][0].parent().name());
+	ASSERT_EQ("b", moved[1][1].parent().name());
+	ASSERT_TRUE(&moved[1] == &moved[1][0].parent());
+	ASSERT_TRUE(&moved[1] == &moved[1][1].parent());
+	ASSERT_TRUE(moved[1][0].isLeaf());
+	ASSERT_TRUE(moved[1][1].isLeaf());
+	ASSERT_FALSE(moved[1][0].isRoot());
+	ASSERT_FALSE(moved[1][1].isRoot());
+}
+
+/* --------------------------------------------------------
+ * Copy constructor
+ * -------------------------------------------------------- */
+
+TEST(CopyConstructor, simple)
+{
+	Object root("root");
+	Object moved(root);
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_TRUE(root.isLeaf());
+	ASSERT_EQ(0, root.countChildren());
+	ASSERT_EQ("root", root.name());
+
+	// test copy
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_TRUE(moved.isLeaf());
+	ASSERT_EQ(0, moved.countChildren());
+	ASSERT_EQ("root", moved.name());
+}
+
+/*
+ *            @root -> copy
+ *           / \
+ *          /   \
+ *        a@     @b 
+ */
+TEST(CopyConstructor, oneLevel)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	Object copy(root);
+
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_FALSE(copy.isLeaf());
+	ASSERT_EQ("root", root.name());
+	ASSERT_EQ("root", copy.name());
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_EQ("b", root[1].name());
+	ASSERT_EQ("a", copy[0].name());
+	ASSERT_EQ("b", copy[1].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+	ASSERT_TRUE(&root == &root[1].parent());
+	ASSERT_TRUE(&copy == &copy[0].parent());
+	ASSERT_TRUE(&copy == &copy[1].parent());
+}
+
+/*
+ *            @root -> copy
+ *           / \
+ *          /   \
+ *        a@     @b 
+ *        / \   / \
+ *      c@  d@ @e  @f
+ *
+ */
+TEST(CopyConstructor, twoLevels)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	root[0].append(Object("c"));
+	root[0].append(Object("d"));
+	root[1].append(Object("e"));
+	root[1].append(Object("f"));
+
+	Object copy(root);
+
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_FALSE(copy.isLeaf());
+	ASSERT_EQ("root", root.name());
+	ASSERT_EQ("root", copy.name());
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_EQ("a", copy[0].name());
+	ASSERT_EQ("c", root[0][0].name());
+	ASSERT_EQ("c", copy[0][0].name());
+	ASSERT_EQ("d", root[0][1].name());
+	ASSERT_EQ("d", copy[0][1].name());
+	ASSERT_EQ("b", root[1].name());
+	ASSERT_EQ("b", copy[1].name());
+	ASSERT_EQ("e", root[1][0].name());
+	ASSERT_EQ("e", copy[1][0].name());
+	ASSERT_EQ("f", root[1][1].name());
+	ASSERT_EQ("f", copy[1][1].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+	ASSERT_TRUE(&root == &root[1].parent());
+	ASSERT_TRUE(&copy == &copy[0].parent());
+	ASSERT_TRUE(&copy == &copy[1].parent());
+	ASSERT_TRUE(&root[0] == &root[0][0].parent());
+	ASSERT_TRUE(&root[0] == &root[0][1].parent());
+	ASSERT_TRUE(&copy[0] == &copy[0][0].parent());
+	ASSERT_TRUE(&copy[0] == &copy[0][1].parent());
+	ASSERT_TRUE(&root[1] == &root[1][0].parent());
+	ASSERT_TRUE(&root[1] == &root[1][1].parent());
+	ASSERT_TRUE(&copy[1] == &copy[1][0].parent());
+	ASSERT_TRUE(&copy[1] == &copy[1][1].parent());
+}
+
+/* --------------------------------------------------------
+ * Move extraction
+ * -------------------------------------------------------- */
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b -> move -> @b
+ */
+TEST(MoveExtraction, simple)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	Object moved(std::move(root[1]));
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_EQ(2, root.countChildren());
+	ASSERT_EQ("root", root.name());
+
+	// test a
+	ASSERT_TRUE(root[0].isLeaf());
+	ASSERT_FALSE(root[0].isRoot());
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_EQ(0, root[0].countChildren());
+	ASSERT_TRUE(&root == &root[0].parent());
+
+	// test b
+	ASSERT_TRUE(root[1].isLeaf());
+	ASSERT_FALSE(root[1].isRoot());
+	ASSERT_EQ(0, root[1].countChildren());
+	ASSERT_TRUE(&root == &root[1].parent());
+
+	// test moved b
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_TRUE(moved.isLeaf());
+	ASSERT_EQ(0, moved.countChildren());
+	ASSERT_EQ("b", moved.name());
+}
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b -> move
+ *        / \   / \
+ *      c@  d@ @e  @f
+ *                  \
+ *                   @g
+ */
+TEST(MoveExtraction, bigger)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	root[0].append(Object("c"));
+	root[0].append(Object("d"));
+	root[1].append(Object("e"));
+	root[1].append(Object("f"));
+	root[1][1].append(Object("g"));
+
+	Object moved(std::move(root[1]));
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_EQ(2, root.countChildren());
+	ASSERT_EQ("root", root.name());
+
+	// test a
+	ASSERT_FALSE(root[0].isRoot());
+	ASSERT_FALSE(root[0].isLeaf());
+	ASSERT_EQ(2, root[0].countChildren());
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+
+	// test c
+	ASSERT_FALSE(root[0][0].isRoot());
+	ASSERT_TRUE(root[0][0].isLeaf());
+	ASSERT_EQ(0, root[0][0].countChildren());
+	ASSERT_EQ("c", root[0][0].name());
+	ASSERT_TRUE(&root[0] == &root[0][0].parent());
+
+	// test d
+	ASSERT_FALSE(root[0][1].isRoot());
+	ASSERT_TRUE(root[0][1].isLeaf());
+	ASSERT_EQ(0, root[0][1].countChildren());
+	ASSERT_EQ("d", root[0][1].name());
+	ASSERT_TRUE(&root[0] == &root[0][1].parent());
+
+	// test b
+	ASSERT_FALSE(root[1].isRoot());
+	ASSERT_TRUE(root[1].isLeaf());
+	ASSERT_EQ(0, root[1].countChildren());
+	ASSERT_TRUE(&root == &root[1].parent());
+
+	// test moved b
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_FALSE(moved.isLeaf());
+	ASSERT_EQ(2, moved.countChildren());
+	ASSERT_EQ("b", moved.name());
+
+	// test moved b-e
+	ASSERT_FALSE(moved[0].isRoot());
+	ASSERT_TRUE(moved[0].isLeaf());
+	ASSERT_EQ(0, moved[0].countChildren());
+	ASSERT_EQ("e", moved[0].name());
+	ASSERT_TRUE(&moved == &moved[0].parent());
+
+	// test moved b-f
+	ASSERT_FALSE(moved[1].isRoot());
+	ASSERT_FALSE(moved[1].isLeaf());
+	ASSERT_EQ(1, moved[1].countChildren());
+	ASSERT_EQ("f", moved[1].name());
+	ASSERT_TRUE(&moved == &moved[1].parent());
+
+	// test moved b-g
+	ASSERT_FALSE(moved[1][0].isRoot());
+	ASSERT_TRUE(moved[1][0].isLeaf());
+	ASSERT_EQ(0, moved[1][0].countChildren());
+	ASSERT_EQ("g", moved[1][0].name());
+	ASSERT_TRUE(&moved[1] == &moved[1][0].parent());
+}
+
+/* --------------------------------------------------------
+ * Copy extraction
+ * -------------------------------------------------------- */
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b -> copy -> @b
+ */
+TEST(CopyExtraction, simple)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	Object copy(root[1]);
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_EQ(2, root.countChildren());
+	ASSERT_EQ("root", root.name());
+
+	// test a
+	ASSERT_TRUE(root[0].isLeaf());
+	ASSERT_FALSE(root[0].isRoot());
+	ASSERT_EQ(0, root[0].countChildren());
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+
+	// test b
+	ASSERT_TRUE(root[1].isLeaf());
+	ASSERT_FALSE(root[1].isRoot());
+	ASSERT_EQ(0, root[1].countChildren());
+	ASSERT_EQ("b", root[1].name());
+	ASSERT_TRUE(&root == &root[1].parent());
+
+	// test copied b
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_TRUE(copy.isLeaf());
+	ASSERT_EQ(0, copy.countChildren());
+	ASSERT_EQ("b", copy.name());
+}
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b -> copy
+ *        / \   / \
+ *      c@  d@ @e  @f
+ *                  \
+ *                   @g
+ */
+TEST(CopyExtraction, bigger)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	root[0].append(Object("c"));
+	root[0].append(Object("d"));
+	root[1].append(Object("e"));
+	root[1].append(Object("f"));
+	root[1][1].append(Object("g"));
+
+	Object copy(root[1]);
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_EQ(2, root.countChildren());
+	ASSERT_EQ("root", root.name());
+
+	// test a
+	ASSERT_FALSE(root[0].isRoot());
+	ASSERT_FALSE(root[0].isLeaf());
+	ASSERT_EQ(2, root[0].countChildren());
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+
+	// test c
+	ASSERT_FALSE(root[0][0].isRoot());
+	ASSERT_TRUE(root[0][0].isLeaf());
+	ASSERT_EQ(0, root[0][0].countChildren());
+	ASSERT_EQ("c", root[0][0].name());
+	ASSERT_TRUE(&root[0] == &root[0][0].parent());
+
+	// test d
+	ASSERT_FALSE(root[0][1].isRoot());
+	ASSERT_TRUE(root[0][1].isLeaf());
+	ASSERT_EQ(0, root[0][1].countChildren());
+	ASSERT_EQ("d", root[0][1].name());
+	ASSERT_TRUE(&root[0] == &root[0][1].parent());
+
+	// test b
+	ASSERT_FALSE(root[1].isRoot());
+	ASSERT_FALSE(root[1].isLeaf());
+	ASSERT_EQ(2, root[1].countChildren());
+	ASSERT_TRUE(&root == &root[1].parent());
+
+	// test e
+	ASSERT_FALSE(root[1][0].isRoot());
+	ASSERT_TRUE(root[1][0].isLeaf());
+	ASSERT_EQ(0, root[1][0].countChildren());
+	ASSERT_EQ("e", root[1][0].name());
+	ASSERT_TRUE(&root[1] == &root[1][0].parent());
+
+	// test f
+	ASSERT_FALSE(root[1][1].isRoot());
+	ASSERT_FALSE(root[1][1].isLeaf());
+	ASSERT_EQ(1, root[1][1].countChildren());
+	ASSERT_EQ("f", root[1][1].name());
+	ASSERT_TRUE(&root[1] == &root[1][1].parent());
+
+	// test g
+	ASSERT_FALSE(root[1][1][0].isRoot());
+	ASSERT_TRUE(root[1][1][0].isLeaf());
+	ASSERT_EQ(0, root[1][1][0].countChildren());
+	ASSERT_EQ("g", root[1][1][0].name());
+	ASSERT_TRUE(&root[1][1] == &root[1][1][0].parent());
+
+	// test copied b
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_FALSE(copy.isLeaf());
+	ASSERT_EQ(2, copy.countChildren());
+	ASSERT_EQ("b", copy.name());
+
+	// test copied b-e
+	ASSERT_FALSE(copy[0].isRoot());
+	ASSERT_TRUE(copy[0].isLeaf());
+	ASSERT_EQ(0, copy[0].countChildren());
+	ASSERT_EQ("e", copy[0].name());
+	ASSERT_TRUE(&copy == &copy[0].parent());
+
+	// test copied b-f
+	ASSERT_FALSE(copy[1].isRoot());
+	ASSERT_FALSE(copy[1].isLeaf());
+	ASSERT_EQ(1, copy[1].countChildren());
+	ASSERT_EQ("f", copy[1].name());
+	ASSERT_TRUE(&copy == &copy[1].parent());
+
+	// test copied b-g
+	ASSERT_FALSE(copy[1][0].isRoot());
+	ASSERT_TRUE(copy[1][0].isLeaf());
+	ASSERT_EQ(0, copy[1][0].countChildren());
+	ASSERT_EQ("g", copy[1][0].name());
+	ASSERT_TRUE(&copy[1] == &copy[1][0].parent());
+}
+
+/* --------------------------------------------------------
+ * Move assignment
+ * -------------------------------------------------------- */
+
+/*
+ * @root -> @moved
+ */
+TEST(MoveAssignment, simple)
+{
+	Object root("root");
+	Object moved("dummy");
+
+	moved = std::move(root);
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_TRUE(root.isLeaf());
+	ASSERT_EQ(0, root.countChildren());
+	
+	// test moved
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_TRUE(moved.isLeaf());
+	ASSERT_EQ(0, moved.countChildren());
+	ASSERT_EQ("root", moved.name());
+}
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b <- move <- @x
+ *        / \   / \           / \
+ *      c@  d@ @e  @f       y@   @z
+ *                  \
+ *                   @g
+ */
+TEST(MoveAssignment, bigger)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	root[0].append(Object("c"));
+	root[0].append(Object("d"));
+	root[1].append(Object("e"));
+	root[1].append(Object("f"));
+	root[1][1].append(Object("g"));
+
+	Object moved("x");
+
+	moved.append(Object("y"));
+	moved.append(Object("z"));
+
+	root[1] = std::move(moved);
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_EQ(2, root.countChildren());
+	ASSERT_EQ("root", root.name());
+
+	// test a
+	ASSERT_FALSE(root[0].isRoot());
+	ASSERT_FALSE(root[0].isLeaf());
+	ASSERT_EQ(2, root[0].countChildren());
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+
+	// test c
+	ASSERT_FALSE(root[0][0].isRoot());
+	ASSERT_TRUE(root[0][0].isLeaf());
+	ASSERT_EQ(0, root[0][0].countChildren());
+	ASSERT_EQ("c", root[0][0].name());
+	ASSERT_TRUE(&root[0] == &root[0][0].parent());
+
+	// test copied x to b
+	ASSERT_FALSE(root[1].isRoot());
+	ASSERT_FALSE(root[1].isLeaf());
+	ASSERT_EQ(2, root[1].countChildren());
+	ASSERT_EQ("x", root[1].name());
+	ASSERT_TRUE(&root == &root[1].parent());
+
+	// test y
+	ASSERT_FALSE(root[1][0].isRoot());
+	ASSERT_TRUE(root[1][0].isLeaf());
+	ASSERT_EQ(0, root[1][0].countChildren());
+	ASSERT_EQ("y", root[1][0].name());
+	ASSERT_TRUE(&root[1] == &root[1][0].parent());
+
+	// test z
+	ASSERT_FALSE(root[1][1].isRoot());
+	ASSERT_TRUE(root[1][1].isLeaf());
+	ASSERT_EQ(0, root[1][1].countChildren());
+	ASSERT_EQ("z", root[1][1].name());
+	ASSERT_TRUE(&root[1] == &root[1][1].parent());
+
+	// test moved
+	ASSERT_TRUE(moved.isRoot());
+	ASSERT_TRUE(moved.isLeaf());
+	ASSERT_EQ(0, moved.countChildren());
+}
+
+/* --------------------------------------------------------
+ * Copy assignment
+ * -------------------------------------------------------- */
+
+/*
+ * @root -> @copy
+ */
+TEST(CopyAssignment, simple)
+{
+	Object root("root");
+	Object copy("copy");
+
+	copy = root;
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_TRUE(root.isLeaf());
+	ASSERT_EQ(0, root.countChildren());
+	ASSERT_EQ("root", root.name());
+	
+	// test copied
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_TRUE(copy.isLeaf());
+	ASSERT_EQ(0, copy.countChildren());
+	ASSERT_EQ("root", copy.name());
+}
+
+/*
+ *            @root
+ *           / \
+ *          /   \
+ *        a@     @b <- copy <- @x
+ *        / \   / \           / \
+ *      c@  d@ @e  @f       y@   @z
+ *                  \
+ *                   @g
+ */
+TEST(CopyAssignment, bigger)
+{
+	Object root("root");
+
+	root.append(Object("a"));
+	root.append(Object("b"));
+
+	root[0].append(Object("c"));
+	root[0].append(Object("d"));
+	root[1].append(Object("e"));
+	root[1].append(Object("f"));
+	root[1][1].append(Object("g"));
+
+	Object copy("x");
+
+	copy.append(Object("y"));
+	copy.append(Object("z"));
+
+	root[1] = copy;
+
+	// test root
+	ASSERT_TRUE(root.isRoot());
+	ASSERT_FALSE(root.isLeaf());
+	ASSERT_EQ(2, root.countChildren());
+	ASSERT_EQ("root", root.name());
+
+	// test a
+	ASSERT_FALSE(root[0].isRoot());
+	ASSERT_FALSE(root[0].isLeaf());
+	ASSERT_EQ(2, root[0].countChildren());
+	ASSERT_EQ("a", root[0].name());
+	ASSERT_TRUE(&root == &root[0].parent());
+
+	// test c
+	ASSERT_FALSE(root[0][0].isRoot());
+	ASSERT_TRUE(root[0][0].isLeaf());
+	ASSERT_EQ(0, root[0][0].countChildren());
+	ASSERT_EQ("c", root[0][0].name());
+	ASSERT_TRUE(&root[0] == &root[0][0].parent());
+
+	// test copied x to b
+	ASSERT_FALSE(root[1].isRoot());
+	ASSERT_FALSE(root[1].isLeaf());
+	ASSERT_EQ(2, root[1].countChildren());
+	ASSERT_EQ("x", root[1].name());
+	ASSERT_TRUE(&root == &root[1].parent());
+
+	// test y
+	ASSERT_FALSE(root[1][0].isRoot());
+	ASSERT_TRUE(root[1][0].isLeaf());
+	ASSERT_EQ(0, root[1][0].countChildren());
+	ASSERT_EQ("y", root[1][0].name());
+	ASSERT_TRUE(&root[1] == &root[1][0].parent());
+
+	// test z
+	ASSERT_FALSE(root[1][1].isRoot());
+	ASSERT_TRUE(root[1][1].isLeaf());
+	ASSERT_EQ(0, root[1][1].countChildren());
+	ASSERT_EQ("z", root[1][1].name());
+	ASSERT_TRUE(&root[1] == &root[1][1].parent());
+
+	// test original x
+	ASSERT_TRUE(copy.isRoot());
+	ASSERT_FALSE(copy.isLeaf());
+	ASSERT_EQ(2, copy.countChildren());
+	ASSERT_EQ("x", copy.name());
+
+	// test original y
+	ASSERT_FALSE(copy[0].isRoot());
+	ASSERT_TRUE(copy[0].isLeaf());
+	ASSERT_EQ(0, copy[0].countChildren());
+	ASSERT_EQ("y", copy[0].name());
+	ASSERT_TRUE(&copy == &copy[0].parent());
+
+	// test original z
+	ASSERT_FALSE(copy[1].isRoot());
+	ASSERT_TRUE(copy[1].isLeaf());
+	ASSERT_EQ(0, copy[1].countChildren());
+	ASSERT_EQ("z", copy[1].name());
+	ASSERT_TRUE(&copy == &copy[1].parent());
+}
+
+int main(int argc, char **argv)
+{
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
\ No newline at end of file
--- a/C++/TreeNode.h	Wed Oct 01 14:39:24 2014 +0200
+++ b/C++/TreeNode.h	Thu Oct 02 11:17:08 2014 +0200
@@ -24,112 +24,11 @@
  * @brief N-ary tree without pointers
  */
 
-#include <algorithm>
+#include <deque>
+#include <memory>
 #include <stdexcept>
-#include <type_traits>
-#include <vector>
-
-namespace
-{
-
-/**
- * @class ContainerTraits
- * @brief Check capabilities
- *
- * This class checks for several functions in the container to disable or enable functions
- * depending on the container.
- *
- * Provides the following static members:
- *
- *	pushCopy	- Set to true if we can push to the beginning by lvalue
- *	pushMove	- Set to true if we can push to the beginning by rvalue
- *	appendCopy	- Set to true if we can append to the end by lvalue
- *	appendMove	- Set to true if we can append to the end by rvalue
- *	at		- Set to true if container has at (also require typedef size_type)
- *	constAt		- Set to true if container has const at (also require typedef size_type)
- */
-template <typename Container, typename Type>
-class ContainerTraits
-{
-private:
-	typedef char Yes[2];
-	typedef char No[1];
-
-	template <typename U, void (U::*)(const Type &)>
-	struct InsertCopy;
-
-	template <typename U, void (U::*)(Type &&)>
-	struct InsertMove;
-
-	template <typename U, const Type &(U::*)(typename U::size_type) const>
-	struct ConstAt;
-
-	template <typename U, Type &(U::*)(typename U::size_type)>
-	struct At;
-
-	/*
-	 * Container::push_front(const T &)
-	 */
-
-	template <typename U>
-	static Yes &testPushCopy(InsertCopy<U, &U::push_front> *);
-	template <typename U>
-	static No &testPushCopy(...);
 
-	/*
-	 * Container::push_front(T &&)
-	 */
-
-	template <typename U>
-	static Yes &testPushMove(InsertMove<U, &U::push_front> *);
-	template <typename U>
-	static No &testPushMove(...);
-
-	/*
-	 * Container::push_back(const T &)
-	 */
-
-	template <typename U>
-	static Yes &testAppendCopy(InsertCopy<U, &U::push_back> *);
-	template <typename U>
-	static No &testAppendCopy(...);
-
-	/*
-	 * Container::push_back(T &&)
-	 */
-
-	template <typename U>
-	static Yes &testAppendMove(InsertMove<U, &U::push_back> *);
-	template <typename U>
-	static No &testAppendMove(...);
-
-
-	/*
-	 * Container::at(size_type)
-	 */
-
-	template <typename U>
-	static Yes &testConstAt(ConstAt<U, &U::at> *);
-	template <typename U>
-	static No &testConstAt(...);
-
-	/*
-	 * Container::at(size_type)
-	 */
-
-	template <typename U>
-	static Yes &testAt(At<U, &U::at> *);
-	template <typename U>
-	static No &testAt(...);
-
-public:
-	static const bool pushCopy = sizeof (testPushCopy<Container>(nullptr)) == sizeof (Yes);
-	static const bool pushMove = sizeof (testPushMove<Container>(nullptr)) == sizeof (Yes);
-	static const bool appendCopy = sizeof (testAppendCopy<Container>(nullptr)) == sizeof( Yes);
-	static const bool appendMove = sizeof (testAppendMove<Container>(nullptr)) == sizeof (Yes);
-	static const bool constAt = sizeof (testConstAt<Container>(nullptr)) == sizeof (Yes);
-	static const bool at = sizeof (testAt<Container>(nullptr)) == sizeof (Yes);
-};
+namespace {
 
 /**
  * @class TypeTraits
@@ -154,15 +53,15 @@
 		static_assert(sizeof (char) != sizeof (long), "buy a new compiler");
 
 		template <typename Value>
-		static auto check(Value *u) -> decltype(*u == *u, char(0));
+		static constexpr auto check(Value *u) -> decltype(*u == *u, char(0));
 
-		static long check(...);
+		static constexpr long check(...);
 
-		static const bool value = sizeof (check((U*)0)) == sizeof (char);
+		static constexpr const bool value = sizeof (check((U *)0)) == sizeof (char);
 	};
 
 public:
-	static const bool equalityComparable = HasEqualsTo<T>::value;
+	static constexpr const bool equalityComparable = HasEqualsTo<T>::value;
 };
 
 } // !namespace
@@ -171,79 +70,36 @@
  * @class TreeNode
  * @brief Safe C++11 N-ary tree
  *
- * This class template can be used to implement N-ary trees without any pointers. It uses
- * move semantics and copy constructs to avoid usage of pointers.
- *
- * The container must have at least the following types:
- *	size_type			- Typedef for indexation
- *
- * And the following functions:
- *	T &at(size_type)		- Indexation at specified index
- *	const T &at(size_type) const	- Indexation at specified index (const version)
- *
- * The typename T must be at least one of the following requirement:
- *	CopyConstructible
- *	MoveConstructible
- *	Comparable with operator==
-
+ * This class use a std::deque as the container, it allocate object on the heap to avoid useless
+ * copy and move when adding new elements.
  */
-template <typename T, typename Container = std::vector<T>>
-class TNewTreeNode
-{
-	static_assert(ContainerTraits<Container, T>::at, "container must have at(size_type)");
-	static_assert(ContainerTraits<Container, T>::constAt, "container must have at(size_type) const");
-
+template <typename T>
+class TreeNode {
 private:
-	TNewTreeNode	*m_parent;
-	Container	 m_children;
+	using Container	= std::deque<std::unique_ptr<T>>;
 
-public:
-	/*
-	 * This is used by move constructors and assignment. It removes the
-	 * reference to the object in the old tree.
-	 */
-	inline void updateOther(TNewTreeNode &&other)
-	{
-		if (other.m_parent) {
-			Container &children = other.m_parent->m_children;
-
-			children.erase(std::find_if(children.begin(), children.end(), [&] (TNewTreeNode &i) {
-				return &other == &i;
-			}));
-		}
-
-		other.m_parent = nullptr;
-	}
-
-	/*
-	 * When reallocation of m_children occurs, we need to update the relations.
-	 */
-	inline void refreshChildren()
-	{
-		for (T &child : m_children)
-			child.m_parent = this;
-	}
+	TreeNode	*m_parent { nullptr };
+	Container	 m_children;
 
 public:
 	/**
 	 * Default constructor.
 	 */
-	TNewTreeNode()
-		: m_parent(nullptr)
-	{
-	}
+	TreeNode() = default;
 
 	/**
 	 * Copy constructor.
 	 *
 	 * @param other the other node
 	 */
-	TNewTreeNode(const TNewTreeNode &other)
+	TreeNode(const TreeNode &other)
 	{
 		m_parent = nullptr;
-		m_children = other.m_children;
 
-		refreshChildren();
+		for (const auto &c : other.m_children) {
+			m_children.push_back(std::make_unique<T>(*c));
+			m_children.back()->m_parent = this;
+		}
 	}
 
 	/**
@@ -251,13 +107,16 @@
 	 *
 	 * @param other the other node
 	 */
-	TNewTreeNode(TNewTreeNode &&other)
+	TreeNode(TreeNode &&other)
 	{
 		m_parent = nullptr;
 		m_children = std::move(other.m_children);
 
-		updateOther(std::move(other));
-		refreshChildren();
+		// Update children to update to *this
+		for (auto &c : m_children)
+			c->m_parent = this;
+
+		other.m_children.clear();
 	}
 
 	/**
@@ -265,13 +124,14 @@
 	 *
 	 * @param other the other node
 	 */
-	TNewTreeNode &operator=(const TNewTreeNode &other)
+	TreeNode &operator=(const TreeNode &other)
 	{
-		m_children = other.m_children;
+		m_children.clear();
 
-		refreshChildren();
-
-		return *this;
+		for (const auto &c : other.m_children) {
+			m_children.push_back(std::make_unique<T>(*c));
+			m_children.back()->m_parent = this;
+		}
 	}
 
 	/**
@@ -279,14 +139,15 @@
 	 *
 	 * @param other the other node
 	 */
-	TNewTreeNode &operator=(TNewTreeNode &&other)
+	TreeNode &operator=(TreeNode &&other)
 	{
 		m_children = std::move(other.m_children);
 
-		updateOther(std::move(other));
-		refreshChildren();
+		// Update children to update to *this
+		for (auto &c : m_children)
+			c->m_parent = this;
 
-		return *this;
+		other.m_children.clear();
 	}
 
 	/**
@@ -294,11 +155,10 @@
 	 *
 	 * @param child the children
 	 */
-	template <typename Value>
-	void push(const Value &child, typename std::enable_if<ContainerTraits<Container, Value>::pushCopy>::type * = 0)
+	void push(const T &child)
 	{
-		m_children.push_front(child);
-		refreshChildren();
+		m_children.push_front(std::make_unique<T>(child));
+		m_children.front()->m_parent = this;
 	}
 
 	/**
@@ -306,11 +166,22 @@
 	 *
 	 * @param child the children
 	 */
-	template <typename Value>
-	void push(Value &&child, typename std::enable_if<std::is_rvalue_reference<Value&&>::value && ContainerTraits<Container, Value>::pushMove>::type * = 0)
+	void push(T &&child)
 	{
-		m_children.push_front(std::move(child));
-		refreshChildren();
+		m_children.push_front(std::make_unique<T>(std::move(child)));
+		m_children.front()->m_parent = this;
+	}
+
+	/**
+	 * Construct an element at the beginning in place.
+	 *
+	 * @param args the arguments
+	 */
+	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;
 	}
 
 	/**
@@ -318,11 +189,10 @@
 	 *
 	 * @param child the children
 	 */
-	template <typename Value>
-	void append(const Value &child, typename std::enable_if<ContainerTraits<Container, Value>::appendCopy>::type * = 0)
+	void append(const T &child)
 	{
-		m_children.push_back(child);
-		refreshChildren();
+		m_children.push_back(std::make_unique<T>(child));
+		m_children.back()->m_parent = this;
 	}
 
 	/**
@@ -330,11 +200,22 @@
 	 *
 	 * @param child the children
 	 */
-	template <typename Value>
-	void append(Value &&child, typename std::enable_if<std::is_rvalue_reference<Value &&>::value && ContainerTraits<Container, Value>::appendMove>::type * = 0)
+	void append(T &&child)
 	{
-		m_children.push_back(std::move(child));
-		refreshChildren();
+		m_children.push_back(std::make_unique<T>(std::move(child)));
+		m_children.back()->m_parent = this;
+	}
+
+	/**
+	 * Construct an element at the end in place.
+	 *
+	 * @param args the arguments
+	 */
+	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;
 	}
 
 	/**
@@ -396,13 +277,13 @@
 	}
 
 	/**
-	 * Find a children in this. The type must have operator==.
+	 * Find a child in this. The type must have operator==.
 	 *
 	 * @param child the child
 	 * @return the index or -1 if not found
 	 */
 	template <typename Value>
-	int indexOf(const Value &child, typename std::enable_if<TypeTraits<Value>::equalityComparable>::type * = 0) const
+	int indexOf(const Value &child, typename std::enable_if<TypeTraits<Value>::equalityComparable>::type * = nullptr) const
 	{
 		for (int i = 0; i < (int)m_children.size(); ++i)
 			if (m_children[i] == child)
@@ -412,7 +293,7 @@
 	}
 
 	/**
-	 * Access a children.
+	 * Access a child.
 	 *
 	 * @param index the index
 	 * @return the reference to the children node
@@ -420,11 +301,11 @@
 	 */
 	T &operator[](int index)
 	{
-		return static_cast<T &>(m_children.at(index));
+		return static_cast<T &>(*m_children.at(index));
 	}
 
 	/**
-	 * Access a children.
+	 * Access a child.
 	 *
 	 * @param index the index
 	 * @return the reference to the children node
@@ -432,7 +313,7 @@
 	 */
 	const T &operator[](int index) const
 	{
-		return static_cast<const T &>(m_children.at(index));
+		return static_cast<const T &>(*m_children.at(index));
 	}
 };
 
--- a/CMakeLists.txt	Wed Oct 01 14:39:24 2014 +0200
+++ b/CMakeLists.txt	Thu Oct 02 11:17:08 2014 +0200
@@ -56,6 +56,7 @@
 option(WITH_PACK "Enable pack functions" On)
 option(WITH_PARSER "Enable parser tests" On)
 option(WITH_SOCKET "Enable sockets tests" On)
+option(WITH_TREENODE "Enable treenode tests" On)
 option(WITH_UTF8 "Enable Utf8 functions tests" On)
 option(WITH_XMLPARSER "Enable XML tests" On)
 
@@ -95,6 +96,10 @@
 	add_subdirectory(C++/Tests/Parser)
 endif ()
 
+if (WITH_TREENODE)
+	add_subdirectory(C++/Tests/TreeNode)
+endif ()
+
 if (WITH_XDG AND UNIX)
 	add_subdirectory(C++/Tests/Xdg)
 endif ()