diff options
author | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2014-12-15 18:45:01 +0100 |
---|---|---|
committer | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2014-12-15 18:45:01 +0100 |
commit | 84cbdcaba520f89eb3ddbdaf1fe2ab3db412501a (patch) | |
tree | ca3df3c791834e65479c6b9a8720f8e55150a396 /src/core/managed/ManagedContainer.hpp | |
parent | c5d18a42da8e9ed19c9520308fef087f4fb76323 (diff) |
Improved ManagedContainer classes
Diffstat (limited to 'src/core/managed/ManagedContainer.hpp')
-rw-r--r-- | src/core/managed/ManagedContainer.hpp | 520 |
1 files changed, 352 insertions, 168 deletions
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; }; } |