diff options
-rw-r--r-- | src/core/Managed.hpp | 193 | ||||
-rw-r--r-- | test/core/ManagedTest.cpp | 49 |
2 files changed, 242 insertions, 0 deletions
diff --git a/src/core/Managed.hpp b/src/core/Managed.hpp index 3e7bbdd..3386ff8 100644 --- a/src/core/Managed.hpp +++ b/src/core/Managed.hpp @@ -24,6 +24,7 @@ #include <type_traits> #include <unordered_map> #include <unordered_set> +#include <vector> namespace ousia { @@ -735,6 +736,198 @@ public: */ Managed *getOwner() const { return owner; } }; + +/** + * Template class which can be used to collect "Owned" refrences to a certain + * type of managed object. This class should be used in favour of other + * collections of handles, it takes care of acquiring an owned handle from the + * 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 container of Owned<T> + */ +template <class T, class Collection> +class ManagedCollection { +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; + +private: + Handle<Managed> owner; + collection_type c; + +protected: + /** + * Function which can be overridden by child classes to execute special code + * whenever a new element is added to the collection. + */ + virtual void addManaged(Handle<T> h) {} + + /** + * Function which can be overriden by child classes to execute special code + * whenever an element is removed from the collection. + */ + virtual void deleteManaged(Handle<T> h) {} + +public: + /** + * Default constructor. + * + * @param owner is the managed object which owns the collection and all + * handles to other managed objects stored within. + */ + ManagedCollection(Handle<Managed> owner) : owner(owner){}; + + /** + * 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> + ManagedCollection(Handle<Managed> owner, InputIterator first, + InputIterator last) + : owner(owner) + { + insert(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> + ManagedCollection(Handle<Managed> owner, const InputCollection &in) + : owner(owner) + { + for (const auto &e : in) { + push_back(e); + } + } + + /** + * Virtual destructor. + */ + virtual ~ManagedCollection(){}; + + /* State functions */ + size_type size() const noexcept { return c.size(); } + bool empty() const noexcept { return c.empty(); } + + /* Front and back */ + reference front() { return c.front(); } + const_reference front() const { return c.front(); } + reference back() { return c.back(); } + const_reference back() const { return c.back(); } + + /* Iterators */ + iterator begin() { return c.begin(); } + iterator end() { return c.end(); } + + iterator rbegin() { return c.rbegin(); } + iterator rend() { return c.rend(); } + + const_iterator begin() const { return c.cbegin(); } + const_iterator end() const { return c.cend(); } + + const_iterator cbegin() const { return c.cbegin(); } + const_iterator cend() const { return c.cend(); } + + const_iterator rbegin() const { return c.crbegin(); } + const_iterator rend() const { return c.crend(); } + + const_iterator crbegin() const { return c.crbegin(); } + const_iterator crend() const { return c.crend(); } + + /* Insert and delete operations */ + + iterator insert(const_iterator position, Handle<T> h) + { + Rooted<T> rooted{h}; + addManaged(rooted); + return c.insert(position, owner->acquire(h)); + } + + template <class InputIterator> + iterator insert(const_iterator position, InputIterator first, + InputIterator last) + { + for (InputIterator it = first; it != last; it++) { + position = insert(position, *it); + position++; + } + } + + iterator erase(iterator position) + { + deleteManaged(*position); + return c.erase(position); + } + + iterator erase(iterator first, iterator last) + { + for (const_iterator it = first; it != last; it++) { + deleteManaged(*it); + } + return c.erase(first, last); + } + + iterator find(const Handle<T> h) { + for (iterator it = begin(); it != end(); it++) { + if (*it == h) { + return it; + } + } + return end(); + } + + const_iterator find(const Handle<T> h) const { + for (const_iterator it = cbegin(); it != cend(); it++) { + if (*it == h) { + return it; + } + } + return cend(); + } + + void push_back(Handle<T> h) + { + Rooted<T> rooted{h}; + addManaged(rooted); + c.push_back(owner->acquire(rooted)); + } + + void pop_back() + { + if (!empty()) { + deleteElement(c.back()); + } + c.pop_back(); + } +}; + +/** + * Special type of ManagedCollection based on a STL vector. + */ +template<class T> +class ManagedVector : public ManagedCollection<T, std::vector<Owned<T>>> { +public: + using ManagedCollection<T, std::vector<Owned<T>>>::ManagedCollection; +}; + } #endif /* _OUSIA_MANAGED_HPP_ */ diff --git a/test/core/ManagedTest.cpp b/test/core/ManagedTest.cpp index 3085a74..1aada5a 100644 --- a/test/core/ManagedTest.cpp +++ b/test/core/ManagedTest.cpp @@ -542,5 +542,54 @@ TEST(Manager, hiddenRootedGraph) } } +TEST(ManagedVector, managedVector) +{ + // 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::vector<TestManaged*> elems; + for (int i = 0; i < nElem; i++) { + elems.push_back(new TestManaged{mgr, a[i]}); + } + + for (bool v : a) { + ASSERT_TRUE(v); + } + + ManagedVector<TestManaged> v(root, elems); + + // Remove the last element from the list. It should be garbage collected. + v.pop_back(); + ASSERT_FALSE(a[nElem - 1]); + + // Insert a new element into the list. + v.push_back(new TestManaged{mgr, a[nElem - 1]}); + ASSERT_TRUE(a[nElem - 1]); + + // Erase element 10 + { + auto it = v.find(elems[10]); + ASSERT_TRUE(it != v.end()); + v.erase(it); + ASSERT_FALSE(a[10]); + } + + // Erase element 3 - 5 + v.erase(v.find(elems[3]), v.find(elems[5])); + ASSERT_FALSE(a[3] || a[4]); + ASSERT_TRUE(a[5]); + } + + for (bool v : a) { + ASSERT_FALSE(v); + } +} + } |