123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- ///////////////////////////////////////////////////////////////////////////////////////
- /// \file guesscontainer.h
- /// \brief Container class for the main LPJ-GUESS classes which contain sub-objects
- ///
- /// \author Joe Siltberg
- /// $Date$
- ///
- ///////////////////////////////////////////////////////////////////////////////////////
- #ifndef LPJ_GUESS_GUESS_CONTAINER_H
- #define LPJ_GUESS_GUESS_CONTAINER_H
- #include <vector>
- /// Container class for the main LPJ-GUESS classes which contain sub-objects
- /** This is supposed to be the base class for classes like Gridcell, Stand
- * and Vegetation.
- *
- * It's meant to replace the ListArray class and its variants, although
- * it will be introduced gradually.
- *
- * The main reasons for replacing ListArray are:
- *
- * - Polymorphic behaviour, in other words we want the container to be able
- * to contain objects of different sub-classes. ListArray instantiates its
- * objects itself, which means all objects are of the same type.
- * With GuessContainer the objects are instantiated outside and added to
- * the container.
- *
- * - Support for nested/simultaneous iteration. In ListArray the container
- * owns the one and only iterator, which means you can't have two
- * iterations happening over the same container at the same time.
- * With GuessContainer, iteration works like for the standard STL containers.
- *
- * The main reasons for having a container class in the first case instead of
- * using for instance std::vector are:
- *
- * - The STL container classes aren't meant to be inherited from
- *
- * - GuessContainer takes ownership of the objects. When an object is removed
- * from the container it is also deallocated, and when the container itself
- * is destroyed all objects are deallocated.
- *
- * - The pointers are more or less hidden. The iterators and operator[]
- * returns references to objects instead of pointers. (We're trying to avoid
- * pointers in most of the LPJ-GUESS code)
- *
- * This class is implemented as a thin layer around std::vector, much of the
- * interface is the same.
- */
- template<typename T>
- class GuessContainer {
- public:
- GuessContainer() : next_unique_id(0) {
- }
- /// Destructor, deallocates all objects
- virtual ~GuessContainer() {
- clear();
- }
- /// Returns object at position i
- T& operator[](unsigned int i) {
- return *objects[i];
- }
- /// Returns number of objects in the container
- size_t size() const {
- return objects.size();
- }
- /// Adds an object to the end of the container
- void push_back(T* object) {
- objects.push_back(object);
- }
- /// Removes and deallocates all objects
- void clear() {
- for (size_t i = 0; i < objects.size(); ++i) {
- delete objects[i];
- }
-
- objects.clear();
- }
- // Iteration
- /// Works like std::vector::iterator
- class iterator {
- public:
- friend class GuessContainer<T>;
- bool operator==(const iterator& other) const {
- return itr == other.itr;
- }
- bool operator!=(const iterator& other) const {
- return itr != other.itr;
- }
- /// prefix ++
- iterator& operator++() {
- ++itr;
- return *this;
- }
- /// postfix ++
- iterator operator++(int) {
- iterator copy(*this);
- ++itr;
- return copy;
- }
- T& operator*() const {
- return **itr;
- }
-
- private:
- typedef typename std::vector<T*>::iterator internal_iterator;
- iterator(const internal_iterator& start) : itr(start) {}
- internal_iterator itr;
- };
- /// Returns an interator pointing to the first object
- iterator begin() {
- return iterator(objects.begin());
- }
- /// Returns an interator pointing past the end
- /** Just like STL containers, end() refers to a theoretical
- * position past the end. It does not point to an object
- * and must not be dereferenced, but should be used to detect
- * when the whole range has been passed.
- */
- iterator end() {
- return iterator(objects.end());
- }
- /// Removes and deletes an object
- /** Works like std::vector::erase - returns an iterator
- * pointing to the object following the erased object.
- * Iterators pointing after the object being erased may be
- * invalidated. See documentation for std::vector::erase for
- * details.
- */
- iterator erase(iterator itr) {
- delete *(itr.itr);
- return iterator(objects.erase(itr.itr));
- }
- protected:
-
- /// Returns a new unique id number
- /** Some sub-classes may wish to assign unique id numbers to their objects,
- * so this functionality is provided here as a convenience.
- */
- unsigned int get_next_id() {
- return next_unique_id++;
- }
- private:
- /// Everything is implemented with std::vector
- std::vector<T*> objects;
- /// The next id number to return, \see get_next_id()
- unsigned int next_unique_id;
- };
- #endif // LPJ_GUESS_GUESS_CONTAINER_H
|