diff options
| author | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2014-11-16 01:41:54 +0100 | 
|---|---|---|
| committer | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2014-11-16 01:41:54 +0100 | 
| commit | adf0b5eaef95484a8d3b8ad1e6e6765018658bdc (patch) | |
| tree | d39d900c02ca57387b70f7b9bf26b622ec936574 | |
| parent | 2910a2e310b04dfa1983cc9b9af7dc1f5d045c99 (diff) | |
added ManagedContainer and ManagedVector templates which allow automatic acquiring of a Managed objects stored within that container owned by another Managed object
| -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); +	} +} +  }  | 
