guesscontainer.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. ///////////////////////////////////////////////////////////////////////////////////////
  2. /// \file guesscontainer.h
  3. /// \brief Container class for the main LPJ-GUESS classes which contain sub-objects
  4. ///
  5. /// \author Joe Siltberg
  6. /// $Date$
  7. ///
  8. ///////////////////////////////////////////////////////////////////////////////////////
  9. #ifndef LPJ_GUESS_GUESS_CONTAINER_H
  10. #define LPJ_GUESS_GUESS_CONTAINER_H
  11. #include <vector>
  12. /// Container class for the main LPJ-GUESS classes which contain sub-objects
  13. /** This is supposed to be the base class for classes like Gridcell, Stand
  14. * and Vegetation.
  15. *
  16. * It's meant to replace the ListArray class and its variants, although
  17. * it will be introduced gradually.
  18. *
  19. * The main reasons for replacing ListArray are:
  20. *
  21. * - Polymorphic behaviour, in other words we want the container to be able
  22. * to contain objects of different sub-classes. ListArray instantiates its
  23. * objects itself, which means all objects are of the same type.
  24. * With GuessContainer the objects are instantiated outside and added to
  25. * the container.
  26. *
  27. * - Support for nested/simultaneous iteration. In ListArray the container
  28. * owns the one and only iterator, which means you can't have two
  29. * iterations happening over the same container at the same time.
  30. * With GuessContainer, iteration works like for the standard STL containers.
  31. *
  32. * The main reasons for having a container class in the first case instead of
  33. * using for instance std::vector are:
  34. *
  35. * - The STL container classes aren't meant to be inherited from
  36. *
  37. * - GuessContainer takes ownership of the objects. When an object is removed
  38. * from the container it is also deallocated, and when the container itself
  39. * is destroyed all objects are deallocated.
  40. *
  41. * - The pointers are more or less hidden. The iterators and operator[]
  42. * returns references to objects instead of pointers. (We're trying to avoid
  43. * pointers in most of the LPJ-GUESS code)
  44. *
  45. * This class is implemented as a thin layer around std::vector, much of the
  46. * interface is the same.
  47. */
  48. template<typename T>
  49. class GuessContainer {
  50. public:
  51. GuessContainer() : next_unique_id(0) {
  52. }
  53. /// Destructor, deallocates all objects
  54. virtual ~GuessContainer() {
  55. clear();
  56. }
  57. /// Returns object at position i
  58. T& operator[](unsigned int i) {
  59. return *objects[i];
  60. }
  61. /// Returns number of objects in the container
  62. size_t size() const {
  63. return objects.size();
  64. }
  65. /// Adds an object to the end of the container
  66. void push_back(T* object) {
  67. objects.push_back(object);
  68. }
  69. /// Removes and deallocates all objects
  70. void clear() {
  71. for (size_t i = 0; i < objects.size(); ++i) {
  72. delete objects[i];
  73. }
  74. objects.clear();
  75. }
  76. // Iteration
  77. /// Works like std::vector::iterator
  78. class iterator {
  79. public:
  80. friend class GuessContainer<T>;
  81. bool operator==(const iterator& other) const {
  82. return itr == other.itr;
  83. }
  84. bool operator!=(const iterator& other) const {
  85. return itr != other.itr;
  86. }
  87. /// prefix ++
  88. iterator& operator++() {
  89. ++itr;
  90. return *this;
  91. }
  92. /// postfix ++
  93. iterator operator++(int) {
  94. iterator copy(*this);
  95. ++itr;
  96. return copy;
  97. }
  98. T& operator*() const {
  99. return **itr;
  100. }
  101. private:
  102. typedef typename std::vector<T*>::iterator internal_iterator;
  103. iterator(const internal_iterator& start) : itr(start) {}
  104. internal_iterator itr;
  105. };
  106. /// Returns an interator pointing to the first object
  107. iterator begin() {
  108. return iterator(objects.begin());
  109. }
  110. /// Returns an interator pointing past the end
  111. /** Just like STL containers, end() refers to a theoretical
  112. * position past the end. It does not point to an object
  113. * and must not be dereferenced, but should be used to detect
  114. * when the whole range has been passed.
  115. */
  116. iterator end() {
  117. return iterator(objects.end());
  118. }
  119. /// Removes and deletes an object
  120. /** Works like std::vector::erase - returns an iterator
  121. * pointing to the object following the erased object.
  122. * Iterators pointing after the object being erased may be
  123. * invalidated. See documentation for std::vector::erase for
  124. * details.
  125. */
  126. iterator erase(iterator itr) {
  127. delete *(itr.itr);
  128. return iterator(objects.erase(itr.itr));
  129. }
  130. protected:
  131. /// Returns a new unique id number
  132. /** Some sub-classes may wish to assign unique id numbers to their objects,
  133. * so this functionality is provided here as a convenience.
  134. */
  135. unsigned int get_next_id() {
  136. return next_unique_id++;
  137. }
  138. private:
  139. /// Everything is implemented with std::vector
  140. std::vector<T*> objects;
  141. /// The next id number to return, \see get_next_id()
  142. unsigned int next_unique_id;
  143. };
  144. #endif // LPJ_GUESS_GUESS_CONTAINER_H