diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/core/Node.hpp | 2 | ||||
-rw-r--r-- | src/core/managed/Managed.hpp | 2 | ||||
-rw-r--r-- | src/core/managed/ManagedContainer.cpp | 24 | ||||
-rw-r--r-- | src/core/managed/ManagedContainer.hpp | 520 | ||||
-rw-r--r-- | src/core/managed/Manager.cpp | 62 | ||||
-rw-r--r-- | src/core/managed/Manager.hpp | 25 | ||||
-rw-r--r-- | test/core/managed/ManagedContainerTest.cpp | 197 | ||||
-rw-r--r-- | test/core/managed/ManagedTest.cpp | 28 | ||||
-rw-r--r-- | test/core/managed/ManagerTest.cpp | 41 |
10 files changed, 618 insertions, 284 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 841d828..7f9e860 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,7 +113,6 @@ ADD_LIBRARY(ousia_core # src/core/common/VariantReader src/core/managed/Managed src/core/managed/Manager - src/core/managed/ManagedContainer # src/core/model/Domain # src/core/model/Typesystem # src/core/parser/Parser diff --git a/src/core/Node.hpp b/src/core/Node.hpp index e0d14a8..b7d050d 100644 --- a/src/core/Node.hpp +++ b/src/core/Node.hpp @@ -30,8 +30,6 @@ namespace ousia { -// TODO: Let Manager handle associated data - /* Forward declarations */ class Node; class Event; diff --git a/src/core/managed/Managed.hpp b/src/core/managed/Managed.hpp index eec2fc5..8b0bb17 100644 --- a/src/core/managed/Managed.hpp +++ b/src/core/managed/Managed.hpp @@ -64,7 +64,7 @@ public: /** * Virtual destuctor which may be overwritten by child classes. */ - virtual ~Managed(){ mgr.unmanage(this); }; + virtual ~Managed(){}; /** * Returns a reference ot the manager instance which owns this managed diff --git a/src/core/managed/ManagedContainer.cpp b/src/core/managed/ManagedContainer.cpp deleted file mode 100644 index e7f30fa..0000000 --- a/src/core/managed/ManagedContainer.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - Ousía - Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "ManagedContainer.hpp" - -namespace ousia { - -} - diff --git a/src/core/managed/ManagedContainer.hpp b/src/core/managed/ManagedContainer.hpp index 7b18bcd..1454608 100644 --- a/src/core/managed/ManagedContainer.hpp +++ b/src/core/managed/ManagedContainer.hpp @@ -16,6 +16,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/** + * @file ManagedContainer.hpp + * + * Container classes for conviniently storing managed instances. + * + * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) + */ + #ifndef _OUSIA_MANAGED_CONTAINER_H_ #define _OUSIA_MANAGED_CONTAINER_H_ @@ -31,48 +39,140 @@ namespace ousia { /** + * Default accessor class for accessing the managed element within a list value + * type. + * + * @tparam ValueType is the list value type that should be accessed. + */ +template <class ValueType> +struct ListAccessor { + Managed *getManaged(const ValueType &val) const { return val.get(); } +}; + +/** + * Default accessor class for accessing the managed element within a map value + * type. + * + * @tparam ValueType is the map value type that should be accessed. + */ +template <class ValueType> +struct MapAccessor { + Managed *getManaged(const ValueType &val) const { return val.second.get(); } +}; + +/** + * Default implementation of a Listener class. With empty functions. + */ +template <class ValueType> +struct DefaultListener { + void addElement(const ValueType &val, Managed *owner) {} + void deleteElement(const ValueType &val, Managed *owner) {} +}; + +/** * Template class which can be used to collect refrences to a certain type of * managed objects. Do not use this class directly, use ManagedMap or * ManagedVector instead. This class only provides functionality which is common * to list and map containers (iterators and state). * - * @param T is the type of the Managed object that should be managed. - * @param Collection should be a STL container of Owned<T> + * @tparam T is the type of the Managed object that should be managed. + * @tparam Collection is the underlying STL collection and should contain + * pointers of type T as value. + * @tparam Accessor is a type that allows to resolve the STL value type to the + * actual, underlying pointer to T -- this is important to generically support + * maps, where the value type is a pair of key type and the actual value. + * @tparam Listener is an optional type that allows to execute arbitrary code + * whenever data is read or written to the collection. */ -template <class T, class Collection> -class ManagedContainer : Managed { +template <class T, class Collection, class Accessor, class Listener> +class ManagedContainer { public: - using collection_type = Collection; - using value_type = typename collection_type::value_type; - using reference = typename collection_type::reference; - using const_reference = typename collection_type::const_reference; - using iterator = typename collection_type::iterator; - using const_iterator = typename collection_type::const_iterator; - using size_type = typename collection_type::size_type; + using own_type = ManagedContainer<T, Collection, Accessor, Listener>; + using value_type = typename Collection::value_type; + using reference = typename Collection::reference; + using const_reference = typename Collection::const_reference; + using iterator = typename Collection::iterator; + using const_iterator = typename Collection::const_iterator; + using size_type = typename Collection::size_type; -protected: +private: /** * Handle containing a reference to the owner of the collection. */ - Handle<Managed> owner; + Managed *owner; /** - * Underlying STL collection. + * Accessor used to access the managed instance inside a "reference type". + */ + Accessor accessor; + + /** + * Listener which is notified whenever an element is added to or removed + * from the list. + */ + Listener listener; + + /** + * Calls the "addElement" function of each element and thus initializes + * the references from the owner to the elements. + */ + void initialize() + { + for (const auto &elem : *this) { + addElement(elem); + } + } + + /** + * Calls the "deleteElement" function of each element and thus finalizes + * the references from the owner to the elements. */ - collection_type c; + void finalize() + { + if (owner) { + for (const auto &elem : *this) { + deleteElement(elem); + } + } + } protected: /** - * Function which can be overridden by child classes to execute special code - * whenever a new element is added to the collection. + * Underlying STL collection. + */ + Collection c; + + /** + * Function to be called whenever an element is added to the collection. + * This function makes sure that the association from the owner to the added + * element is established. + * + * @param managed is the managed instance that is being added to the + * container. + * @param elem is a reference to the actual element that is being added to + * the underlying container. */ - virtual void addElement(value_type h) {} + void addElement(const value_type &elem) + { + getManager().addRef(accessor.getManaged(elem), owner); + listener.addElement(elem, owner); + } /** - * Function which can be overriden by child classes to execute special code - * whenever an element is removed from the collection. + * Function to be called whenever an element is removed from the collection. + * This function makes sure that the association from the owner to the added + * element is removed. + * + * @param managed is the managed instance that is being deleted from the + * container. + * @param elem is a reference to the actual element that is being removed + * from the underlying container. */ - virtual void deleteElement(value_type h) {} + void deleteElement(const value_type &elem) + { + getManager().deleteRef(accessor.getManaged(elem), owner); + listener.deleteElement(elem, owner); + } public: /** @@ -81,15 +181,162 @@ public: * @param owner is the managed object which owns the collection and all * handles to other managed objects stored within. */ - ManagedContainer(Handle<Managed> owner) : Managed(owner->getManager), owner(owner){}; + ManagedContainer(Handle<Managed> owner) : owner(owner.get()){}; + + /** + * Copy constructor. Creates a copy of the given container with the same + * owner as the given container. + * + * @param other is the other coontainer that should be copied. + */ + ManagedContainer(const own_type &other) : owner(other.owner), c(other.c) + { + initialize(); + } + + /** + * Copy constructor. Creates a copy of the given container with another + * owner. + * + * @param other is the other container that should be copied. + */ + ManagedContainer(Handle<Managed> owner, const own_type &other) + : owner(owner.get()), c(other.c) + { + initialize(); + } + + /** + * Copy constructor. Creates a copy of the given container and takes over + * ownership. + */ + ManagedContainer(Handle<Managed> owner, const Collection &collection) + : owner(owner), c(collection) + { + initialize(); + } + + /** + * Move constructor. Moves the other instance to this instance. + * + * @param other is the other container that should be moved. + */ + ManagedContainer(own_type &&other) + : owner(other.owner), c(std::move(other.c)) + { + other.owner = nullptr; + } + + /** + * Copy constructor. Creates a copy of the given container with another + * owner. + * + * @param other is the other container that should be moved. + */ + ManagedContainer(Handle<Managed> owner, own_type &&other) + : owner(owner.get()), c(std::move(other.c)) + { + other.finalize(); + other.owner = nullptr; + initialize(); + } + + /** + * Copy constructor. Initialize with an iterator from another collection. + * + * @param owner is the managed object which owns the collection and all + * handles to other managed objects stored within. + * @param first is an iterator pointing at the first element to be copied + * from some other collection. + * @param last is an iterator pointing at the last element to be copied + * from some other collection. + */ + template <class InputIterator> + ManagedContainer(Handle<Managed> owner, InputIterator first, + InputIterator last) + : owner(owner.get()) + { + auto it = end(); + for (auto it2 = first; it2 != last; it2++) { + it = insert(it, *it2); + it++; + } + } + + /** + * Destructor of the ManagedContainer class. Calls the "deleteElement" + * function for each element in the container. + */ + ~ManagedContainer() { finalize(); }; + + /** + * Copy assignment operator. + * + * @param other is the collection instance that should be copied. + * @return this instance. + */ + own_type &operator=(const own_type &other) + { + finalize(); + owner = other.owner; + c = other.c; + initialize(); + return *this; + } + + /** + * Move assignment operator. + * + * @param other is the collection instance that should be moved; + * @return this instance. + */ + own_type &operator=(own_type &&other) + { + finalize(); + owner = other.owner; + c = std::move(other.c); + other.owner = nullptr; + return *this; + } + + /** + * Equality operator. + */ + bool operator==(const own_type &other) { + return (owner == other.owner) && (c == other.c); + } + + /** + * Inequality operator. + */ + bool operator!=(const own_type &other) { + return (owner != other.owner) || (c != other.c); + } /** - * Destructor of the ManagedContainer class. + * Returns the owner of the ManagedContainer instance. */ - virtual ~ManagedContainer() {}; + Managed *getOwner() { return owner; } + + /** + * Returns the manager instance associated with the owner. + */ + Manager &getManager() { return owner->getManager(); } /* State functions */ + + /** + * Returns the size of the container. + * + * @return the number of elements in the container. + */ size_type size() const noexcept { return c.size(); } + + /** + * Returns whether the container is empty. + * + * @return true if the container is empty, false otherwise. + */ bool empty() const noexcept { return c.empty(); } /* Iterators */ @@ -111,7 +358,9 @@ public: const_iterator crbegin() const { return c.crbegin(); } const_iterator crend() const { return c.crend(); } - /* Clear function */ + /** + * Removes all elements from the container. + */ void clear() noexcept { for (const_iterator it = cbegin(); it != cend(); it++) { @@ -119,6 +368,41 @@ public: } c.clear(); } + + /** + * Generic insert operation. + */ + iterator insert(const_iterator position, value_type val) + { + addElement(val); + return c.insert(position, val); + } + + /** + * Erases the element at the given position. + * + * @param position is the position at which the element should be removed. + * @return an iterator to the element after the deleted element. + */ + iterator erase(iterator position) + { + deleteElement(*position); + return c.erase(position); + } + + /** + * Erases a range of elements from the collection. + * + * @param position is the position at which the element should be removed. + * @return an iterator to the element after the deleted element. + */ + iterator erase(iterator first, iterator last) + { + for (const_iterator it = first; it != last; it++) { + this->deleteElement(*it); + } + return c.erase(first, last); + } }; /** @@ -128,16 +412,15 @@ public: * owner of this collection whenever a new element is added. * * @param T is the type of the Managed object that should be managed. - * @param Collection should be a STL list container of Owned<T> + * @param Collection should be a STL list container of T* */ -template <class T, class Collection> -class ManagedGenericList : public ManagedContainer<T, Collection> { +template <class T, class Collection, class Accessor, class Listener> +class ManagedGenericList + : public ManagedContainer<T, Collection, Accessor, Listener> { private: - using Base = ManagedContainer<T, Collection>; + using Base = ManagedContainer<T, Collection, Accessor, Listener>; public: - using Base::ManagedContainer; - using collection_type = typename Base::collection_type; using value_type = typename Base::value_type; using reference = typename Base::reference; using const_reference = typename Base::const_reference; @@ -145,40 +428,8 @@ public: using const_iterator = typename Base::const_iterator; using size_type = typename Base::size_type; - /** - * Initialize with an iterator from another collection. - * - * @param owner is the managed object which owns the collection and all - * handles to other managed objects stored within. - * @param first is an iterator pointing at the first element to be copied - * from some other collection. - * @param last is an iterator pointing at the last element to be copied - * from some other collection. - */ - template <class InputIterator> - ManagedGenericList(Handle<Managed> owner, InputIterator first, - InputIterator last) - : ManagedContainer<T, Collection>(owner) - { - insert(Base::c.begin(), first, last); - } - - /** - * Initialize with another collection. - * - * @param owner is the managed object which owns the collection and all - * handles to other managed objects stored within. - * @param in is a reference at some other collection with content that - * should be copied. - */ - template <class InputCollection> - ManagedGenericList(Handle<Managed> owner, const InputCollection &in) - : ManagedContainer<T, Collection>(owner) - { - for (const auto &e : in) { - push_back(e); - } - } + using Base::ManagedContainer; + using Base::insert; /* Front and back */ reference front() { return Base::c.front(); } @@ -188,13 +439,6 @@ public: /* Insert and delete operations */ - iterator insert(const_iterator position, Handle<T> h) - { - value_type v = Base::owner->acquire(h); - addElement(v); - return Base::c.insert(position, v); - } - template <class InputIterator> iterator insert(const_iterator position, InputIterator first, InputIterator last) @@ -212,20 +456,20 @@ public: return pos; } - iterator find(const Handle<T> h) + iterator find(const value_type &val) { for (iterator it = Base::begin(); it != Base::end(); it++) { - if (*it == h) { + if (*it == val) { return it; } } return Base::end(); } - const_iterator find(const Handle<T> h) const + const_iterator find(const value_type &val) const { for (const_iterator it = Base::cbegin(); it != Base::cend(); it++) { - if (*it == h) { + if (*it == val) { return it; } } @@ -234,9 +478,8 @@ public: void push_back(Handle<T> h) { - value_type v = Base::owner->acquire(h); - this->addElement(v); - Base::c.push_back(v); + this->addElement(h.get()); + Base::c.push_back(h.get()); } void pop_back() @@ -246,33 +489,18 @@ public: } Base::c.pop_back(); } - - iterator erase(iterator position) - { - this->deleteElement(*position); - return Base::c.erase(position); - } - - iterator erase(iterator first, iterator last) - { - for (const_iterator it = first; it != last; it++) { - this->deleteElement(*it); - } - return Base::c.erase(first, last); - } }; /** * Special type of ManagedContainer based on an STL map. */ -template <class K, class T, class Collection> -class ManagedGenericMap : public ManagedContainer<T, Collection> { +template <class K, class T, class Collection, class Accessor, class Listener> +class ManagedGenericMap + : public ManagedContainer<T, Collection, Accessor, Listener> { private: - using Base = ManagedContainer<T, Collection>; + using Base = ManagedContainer<T, Collection, Accessor, Listener>; public: - using Base::ManagedContainer; - using collection_type = typename Base::collection_type; using value_type = typename Base::value_type; using key_type = typename Collection::key_type; using reference = typename Base::reference; @@ -281,76 +509,30 @@ public: using const_iterator = typename Base::const_iterator; using size_type = typename Base::size_type; -private: - value_type acquirePair(std::pair<K, Handle<T>> val) - { - return value_type{val.first, Base::owner->acquire(val.second)}; - } - -public: - /** - * Initialize with an iterator from another collection. - * - * @param owner is the managed object which owns the collection and all - * handles to other managed objects stored within. - * @param first is an iterator pointing at the first element to be copied - * from some other collection. - * @param last is an iterator pointing at the last element to be copied - * from some other collection. - */ - template <class InputIterator> - ManagedGenericMap(Handle<Managed> owner, InputIterator first, - InputIterator last) - : ManagedContainer<T, Collection>(owner) - { - insert(first, last); - } - - /** - * Initialize with another collection. - * - * @param owner is the managed object which owns the collection and all - * handles to other managed objects stored within. - * @param in is a reference at some other collection with content that - * should be copied. - */ - template <class InputCollection> - ManagedGenericMap(Handle<Managed> owner, const InputCollection &in) - : ManagedContainer<T, Collection>(owner) - { - for (const auto &e : in) { - insert(*in); - } - } + using Base::ManagedContainer; + using Base::erase; + using Base::insert; - std::pair<iterator, bool> insert(std::pair<K, Handle<T>> val) + std::pair<iterator, bool> insert(value_type val) { - value_type v = acquirePair(val); - this->addElement(v); - return Base::c.insert(v); + this->addElement(val); + return Base::c.insert(val); } - iterator insert(const_iterator position, std::pair<K, Handle<T>> val) + iterator insert(const_iterator position, value_type val) { - value_type v = acquirePair(val); - this->addElement(v); - return Base::c.insert(position, v); + this->addElement(val); + return Base::c.insert(position, val); } template <class InputIterator> void insert(InputIterator first, InputIterator last) { for (auto it = first; it != last; it++) { - insert(acquirePair); + insert(*it); } } - iterator erase(const_iterator position) - { - this->deleteElement(*position); - return Base::c.erase(position); - } - size_t erase(const key_type &k) { iterator pos = find(k); @@ -361,14 +543,6 @@ public: return 0; } - iterator erase(const_iterator first, const_iterator last) - { - for (const_iterator it = first; it != last; it++) { - this->deleteElement(*it); - } - return Base::c.erase(first, last); - } - iterator find(const key_type &k) { return Base::c.find(k); } const_iterator find(const key_type &k) const { return Base::c.find(k); } }; @@ -376,19 +550,29 @@ public: /** * Special type of ManagedGenericList based on an STL vector. */ -template <class T> -class ManagedVector : public ManagedGenericList<T, std::vector<Owned<T>>> { +template <class T, class Listener = DefaultListener<Handle<T>>> +class ManagedVector + : public ManagedGenericList<T, std::vector<Handle<T>>, + ListAccessor<Handle<T>>, Listener> { public: - using ManagedGenericList<T, std::vector<Owned<T>>>::ManagedGenericList; + using Base = ManagedGenericList<T, std::vector<Handle<T>>, + ListAccessor<Handle<T>>, Listener>; + using Base::ManagedGenericList; }; /** * Special type of ManagedGenericMap based on an STL map. */ -template <class K, class T> -class ManagedMap : public ManagedGenericMap<K, T, std::map<K, Owned<T>>> { +template <class K, class T, + class Listener = DefaultListener<std::pair<K, Handle<T>>>> +class ManagedMap + : public ManagedGenericMap<K, T, std::map<K, Handle<T>>, + MapAccessor<std::pair<K, Handle<T>>>, Listener> { public: - using ManagedGenericMap<K, T, std::map<K, Owned<T>>>::ManagedGenericMap; + using Base = + ManagedGenericMap<K, T, std::map<K, Handle<T>>, + MapAccessor<std::pair<K, Handle<T>>>, Listener>; + using Base::ManagedGenericMap; }; } diff --git a/src/core/managed/Manager.cpp b/src/core/managed/Manager.cpp index 411c675..b81d89f 100644 --- a/src/core/managed/Manager.cpp +++ b/src/core/managed/Manager.cpp @@ -174,11 +174,6 @@ void Manager::addRef(Managed *tar, Managed *src) void Manager::deleteRef(Managed *tar, Managed *src, bool all) { - // Make sure the source and target manager are the same - if (src) { - assert(&tar->getManager() == &src->getManager()); - } - // Fetch the Managed descriptors for the two objects ObjectDescriptor *dTar = getDescriptor(tar); ObjectDescriptor *dSrc = getDescriptor(src); @@ -419,62 +414,5 @@ bool Manager::deleteData(Managed *ref, const std::string &key) return false; } -/* Class Manager: Tagged Memory */ - -void Manager::tagMemoryRegion(void *tag, void *pStart, void *pEnd) -{ - // Convert start and end to integers - uintptr_t s1 = reinterpret_cast<uintptr_t>(pStart); - uintptr_t e1 = reinterpret_cast<uintptr_t>(pEnd); - -#ifndef NDEBUG - // Make sure the same memory region is not tagged multiple times - const auto itStart = tags.lower_bound(s1); - const auto itEnd = tags.upper_bound(e1); - for (auto it = itStart; it != itEnd; it++) { - uintptr_t s2 = it->first; - uintptr_t e2 = it->second.first; - assert(!((s2 >= s1 && s2 < e1) || (e2 >= s1 && e2 < e1))); - } -#endif - - // Insert the new region - tags.emplace(s1, std::make_pair(e1, tag)); -} - -void Manager::untagMemoryRegion(void *pStart, void *pEnd) -{ - // Convert start and end to integers - uintptr_t s1 = reinterpret_cast<uintptr_t>(pStart); - uintptr_t e1 = reinterpret_cast<uintptr_t>(pEnd); - - auto itStart = tags.lower_bound(s1); - auto itEnd = tags.upper_bound(e1); - for (auto it = itStart; it != itEnd;) { - // Copy the data of the element - uintptr_t s2 = it->first; - uintptr_t e2 = it->second.first; - void* tag = it->second.second; - - // Remove the element from the map as we need to modify it - it = tags.erase(it); - if (s1 <= s2 && e1 >= e2) { - // Remove completely covered elements - continue; - } - if (s1 > s2) { - // Insert s1-s2 section - it = tags.emplace(s2, std::make_pair(s1, tag)).first; - } - if (e1 < e2) { - // Insert e1-e2 section - it = tags.emplace(e1, std::make_pair(e2, tag)).first; - } - - // Go to the next element - it++; - } -} - } diff --git a/src/core/managed/Manager.hpp b/src/core/managed/Manager.hpp index 5b08cf4..ae0d130 100644 --- a/src/core/managed/Manager.hpp +++ b/src/core/managed/Manager.hpp @@ -299,31 +299,6 @@ public: * @return true if data for this key was deleted, false otherwise. */ bool deleteData(Managed *ref, const std::string &key); - - /** - * Stores a tag for the given memory region. May not overlap with another - * memory region. - * - * @param tag is user defined data that should be stored. - * @param pStart marks the beginning of the memory region (inclusive), - * @param pEnd is the end of the memory region (not inclusive). - */ - void tagMemoryRegion(void *tag, void *pStart, void *pEnd); - - /** - * Removes the tag from the given memory region. May be a part of a - * previously tagged region. - */ - void untagMemoryRegion(void *pStart, void *pEnd); - - /** - * Returns the tag for the given pointer or nullptr if no tag is set. - * - * @param p is the pointer for which the tag should be queried. - * @return the associated tag or nullptr if p points at a memory region for - * which no tag is set. - */ - void* memoryRegionTag(void *p); }; } diff --git a/test/core/managed/ManagedContainerTest.cpp b/test/core/managed/ManagedContainerTest.cpp index db72295..a2f7aa6 100644 --- a/test/core/managed/ManagedContainerTest.cpp +++ b/test/core/managed/ManagedContainerTest.cpp @@ -47,7 +47,7 @@ TEST(ManagedVector, managedVector) ASSERT_TRUE(v); } - ManagedVector<TestManaged> v(root, elems); + ManagedVector<TestManaged> v(root, elems.begin(), elems.end()); // Remove the last element from the list. It should be garbage collected. v.pop_back(); @@ -69,6 +69,200 @@ TEST(ManagedVector, managedVector) v.erase(v.find(elems[3]), v.find(elems[5])); ASSERT_FALSE(a[3] || a[4]); ASSERT_TRUE(a[5]); + + { + // Copy the managed vector to another managed vector + ManagedVector<TestManaged> v2(v); + v2.push_back(new TestManaged{mgr, a[3]}); + ASSERT_TRUE(a[3]); + } + ASSERT_FALSE(a[3]); + ASSERT_TRUE(a[5]); + } + + for (bool v : a) { + ASSERT_FALSE(v); + } +} + + +TEST(ManagedVector, moveAssignment) +{ + constexpr int nElem = 16; + std::array<bool, nElem> a; + + Manager mgr(1); + { + Rooted<Managed> root{new Managed{mgr}}; + ManagedVector<TestManaged> v1(root); + { + ManagedVector<TestManaged> v2(root); + + for (int i = 0; i < nElem; i++) { + v2.push_back(new TestManaged{mgr, a[i]}); + } + for (bool v : a) { + ASSERT_TRUE(v); + } + + v1 = std::move(v2); + ASSERT_EQ(nullptr, v2.getOwner()); + } + for (bool v : a) { + ASSERT_TRUE(v); + } + } + + for (bool v : a) { + ASSERT_FALSE(v); + } +} + +TEST(ManagedVector, copyAssignment) +{ + constexpr int nElem = 16; + std::array<bool, nElem> a; + + Manager mgr(1); + { + Rooted<Managed> root{new Managed{mgr}}; + ManagedVector<TestManaged> v1(root); + { + ManagedVector<TestManaged> v2(root); + + for (int i = 0; i < nElem; i++) { + v2.push_back(new TestManaged{mgr, a[i]}); + } + for (bool v : a) { + ASSERT_TRUE(v); + } + + v1 = v2; + ASSERT_TRUE(v1 == v2); + } + for (bool v : a) { + ASSERT_TRUE(v); + } + } + + for (bool v : a) { + ASSERT_FALSE(v); + } +} + +TEST(ManagedVector, copyWithNewOwner) +{ + constexpr int nElem = 16; + std::array<bool, nElem> a; + + Manager mgr(1); + { + Rooted<Managed> root{new Managed{mgr}}; + ManagedVector<TestManaged> v1(root); + { + Rooted<Managed> root2{new Managed{mgr}}; + ManagedVector<TestManaged> v2(root2); + + for (int i = 0; i < nElem; i++) { + v2.push_back(new TestManaged{mgr, a[i]}); + } + for (bool v : a) { + ASSERT_TRUE(v); + } + + ManagedVector<TestManaged> v3{root, v2}; + v1 = std::move(v3); + ASSERT_EQ(nullptr, v3.getOwner()); + ASSERT_TRUE(v1 != v2); + } + for (bool v : a) { + ASSERT_TRUE(v); + } + } + + for (bool v : a) { + ASSERT_FALSE(v); + } +} + +TEST(ManagedVector, moveWithNewOwner) +{ + constexpr int nElem = 16; + std::array<bool, nElem> a; + + Manager mgr(1); + { + Rooted<Managed> root{new Managed{mgr}}; + ManagedVector<TestManaged> v1(root); + { + Rooted<Managed> root2{new Managed{mgr}}; + ManagedVector<TestManaged> v2(root2); + + for (int i = 0; i < nElem; i++) { + v2.push_back(new TestManaged{mgr, a[i]}); + } + for (bool v : a) { + ASSERT_TRUE(v); + } + + ManagedVector<TestManaged> v3{root, std::move(v2)}; + v1 = std::move(v3); + ASSERT_EQ(nullptr, v2.getOwner()); + ASSERT_EQ(nullptr, v3.getOwner()); + } + for (bool v : a) { + ASSERT_TRUE(v); + } + } + + for (bool v : a) { + ASSERT_FALSE(v); + } +} + +TEST(ManagedMap, managedMap) +{ + // TODO: This test is highly incomplete + + constexpr int nElem = 16; + std::array<bool, nElem> a; + + Manager mgr(1); + { + Rooted<Managed> root{new Managed{mgr}}; + + std::map<int, TestManaged*> elems; + for (int i = 0; i < nElem; i++) { + elems.insert(std::make_pair(i, new TestManaged{mgr, a[i]})); + } + + for (bool v : a) { + ASSERT_TRUE(v); + } + + ManagedMap<int, TestManaged> m(root, elems.begin(), elems.end()); + + // Remove the entry with the number 4 + m.erase(m.find(10)); + ASSERT_FALSE(a[10]); + + // Insert a new element + m.insert(std::make_pair(nElem + 1, new TestManaged{mgr, a[10]})); + ASSERT_TRUE(a[10]); + + // Erase element 3 - 5 + m.erase(m.find(3), m.find(5)); + ASSERT_FALSE(a[3] || a[4]); + ASSERT_TRUE(a[5]); + + { + // Copy the managed map to another managed map vector + ManagedMap<int, TestManaged> m2(m); + m2.insert(std::make_pair(3, new TestManaged{mgr, a[3]})); + ASSERT_TRUE(a[3]); + } + ASSERT_FALSE(a[3]); + ASSERT_TRUE(a[5]); } for (bool v : a) { @@ -76,5 +270,6 @@ TEST(ManagedVector, managedVector) } } + } diff --git a/test/core/managed/ManagedTest.cpp b/test/core/managed/ManagedTest.cpp index e8a24f2..707aeb9 100644 --- a/test/core/managed/ManagedTest.cpp +++ b/test/core/managed/ManagedTest.cpp @@ -16,7 +16,35 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <gtest/gtest.h> + +#include <core/managed/Managed.hpp> + +#include "TestManaged.hpp" + namespace ousia { +TEST(Managed, data) +{ + Manager mgr{1}; + + Rooted<Managed> n{new Managed{mgr}}; + + Managed *m1 = new Managed{mgr}; + n->storeData("info", m1); + ASSERT_TRUE(n->hasDataKey("info")); + ASSERT_FALSE(n->hasDataKey("test")); + + Managed *m2 = new Managed{mgr}; + n->storeData("test", m2); + ASSERT_TRUE(n->hasDataKey("info")); + ASSERT_TRUE(n->hasDataKey("test")); + + ASSERT_TRUE(n->deleteData("info")); + ASSERT_FALSE(n->deleteData("info")); + ASSERT_FALSE(n->hasDataKey("info")); + ASSERT_TRUE(n->hasDataKey("test")); +} + } diff --git a/test/core/managed/ManagerTest.cpp b/test/core/managed/ManagerTest.cpp index da42f0a..f597af7 100644 --- a/test/core/managed/ManagerTest.cpp +++ b/test/core/managed/ManagerTest.cpp @@ -548,5 +548,46 @@ TEST(Manager, hiddenRootedGraph) ASSERT_FALSE(v); } } + +TEST(Manager, storeData) +{ + Manager mgr(1); + + std::array<bool, 5> a; + + { + Rooted<TestManaged> n{new TestManaged{mgr, a[0]}}; + + mgr.storeData(n.get(), "key1", new TestManaged{mgr, a[1]}); + + Managed *m2 = new TestManaged{mgr, a[2]}; + mgr.storeData(n.get(), "key2", m2); + + ASSERT_TRUE(a[0] && a[1] && a[2]); + + ASSERT_TRUE(mgr.deleteData(n.get(), "key1")); + ASSERT_FALSE(a[1]); + ASSERT_FALSE(mgr.deleteData(n.get(), "key1")); + + mgr.storeData(n.get(), "key1", new TestManaged{mgr, a[3]}); + ASSERT_TRUE(a[3]); + + Managed *m = new TestManaged{mgr, a[4]}; + mgr.storeData(n.get(), "key1", m); + ASSERT_FALSE(a[3]); + ASSERT_TRUE(a[4]); + + ASSERT_EQ(m, mgr.readData(n.get(), "key1")); + ASSERT_EQ(m2, mgr.readData(n.get(), "key2")); + + auto map = mgr.readData(n.get()); + ASSERT_EQ(2U, map.size()); + ASSERT_TRUE(map.find("key1") != map.end()); + ASSERT_TRUE(map.find("key2") != map.end()); + } + + ASSERT_FALSE(a[0] || a[1] || a[2] || a[3] || a[4]); +} + } |