1 /**
2  ** Objiter.h - Game objects iterator.
3  **
4  ** Written: 7/29/2000 - JSF
5  **/
6 
7 /*
8 Copyright (C) 2000  Jeffrey S. Freedman
9 
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23 */
24 
25 #ifndef INCL_OBJITER
26 #define INCL_OBJITER    1
27 
28 #include "objlist.h"
29 
30 class   Map_chunk;
31 class   Game_object;
32 
33 /*
34  *  Want to make all object iterators modification-safe.  For now, just
35  *  trying to detect modification during iteration.
36  */
37 template<class T>
38 class T_Safe_object_iterator {
39 	T_Object_list<T> &list;
40 public:
T_Safe_object_iterator(T_Object_list<T> & l)41 	T_Safe_object_iterator(T_Object_list<T> &l) : list(l) {
42 		list.add_iterator();
43 	}
~T_Safe_object_iterator()44 	~T_Safe_object_iterator() {
45 		list.remove_iterator();
46 	}
47 };
48 
49 /*
50  *  Iterate through list of objects.
51  */
52 template<class T>
53 class T_Object_iterator : public T_Safe_object_iterator<T> {
54 protected:
55 	T *first;
56 	T *stop;
57 	T *cur;      // Next to return.
58 public:
reset()59 	void reset() {
60 		cur = first;
61 		stop = nullptr;
62 	}
T_Object_iterator(T_Object_list<T> & objects)63 	T_Object_iterator(T_Object_list<T> &objects)
64 		: T_Safe_object_iterator<T>(objects), first(objects.get_first()) {
65 		reset();
66 	}
get_next()67 	T *get_next() {
68 		if (cur == stop)
69 			return nullptr;
70 		T *ret = cur;
71 		cur = cur->next.get();
72 		stop = first;
73 		return ret;
74 	}
75 };
76 
77 using Object_iterator = T_Object_iterator<Game_object>;
78 
79 /*
80  *  Iterate through a chunk's nonflat objects.
81  */
82 template<class T, class L>
83 class T_Nonflat_object_iterator : public T_Object_iterator<T> {
84 	T *nonflats;
85 public:
reset()86 	void reset() {
87 		this->cur = nonflats;
88 		this->stop = nullptr;
89 	}
T_Nonflat_object_iterator(L chunk)90 	T_Nonflat_object_iterator(L chunk)
91 		: T_Object_iterator<T>(chunk->get_objects()), nonflats(chunk->get_first_nonflat()) {
92 		reset();
93 	}
94 };
95 
96 using Nonflat_object_iterator = T_Nonflat_object_iterator<Game_object, Map_chunk *>;
97 
98 /*
99  *  Iterate through a chunk's flat objects.
100  */
101 template<class T, class L>
102 class T_Flat_object_iterator : public T_Safe_object_iterator<T> {
103 	T *first;
104 	T *stop;
105 	T *cur;      // Next to return.
106 	T *stop_at;
107 public:
reset()108 	void reset() {
109 		cur = first;
110 		stop = nullptr;
111 	}
T_Flat_object_iterator(L chunk)112 	T_Flat_object_iterator(L chunk)
113 		: T_Safe_object_iterator<T>(chunk->get_objects()) {
114 		first = chunk->get_objects().get_first() == chunk->get_first_nonflat() ? nullptr :
115 		        chunk->get_objects().get_first();
116 		stop_at = chunk->get_first_nonflat() ? chunk->get_first_nonflat()
117 		          : chunk->get_objects().get_first();
118 		reset();
119 	}
get_next()120 	T *get_next() {
121 		if (cur == stop)
122 			return nullptr;
123 		T *ret = cur;
124 		cur = cur->get_next();
125 		stop = stop_at;
126 		return ret;
127 	}
128 };
129 
130 using Flat_object_iterator = T_Flat_object_iterator<Game_object, Map_chunk *>;
131 
132 /*
133  *  Iterate backwards through list of objects.
134  */
135 template<class T, class L>
136 class T_Object_iterator_backwards : public T_Safe_object_iterator<T> {
137 	T *first;
138 	T *stop;
139 	T *cur;      // Return prev. to this.
140 public:
reset()141 	void reset() {
142 		cur = first;
143 		stop = nullptr;
144 	}
T_Object_iterator_backwards(L chunk)145 	T_Object_iterator_backwards(L chunk)
146 		: T_Safe_object_iterator<T>(chunk->get_objects()),
147 		  first(chunk->get_objects().get_first()) {
148 		reset();
149 	}
T_Object_iterator_backwards(T_Object_list<T> & objects)150 	T_Object_iterator_backwards(T_Object_list<T> &objects)
151 		: T_Safe_object_iterator<T>(objects),
152 		  first(objects.get_first()) {
153 		reset();
154 	}
get_next()155 	T *get_next() {
156 		if (cur == stop)
157 			return nullptr;
158 		cur = cur->prev;
159 		stop = first;
160 		return cur;
161 	}
162 };
163 
164 using Object_iterator_backwards = T_Object_iterator_backwards<Game_object, Map_chunk *>;
165 
166 /*
167  *  Iterate through a list of objects (recursively).
168  */
169 template<class D> class D_Recursive_object_iterator {
170 	// Child we're going through, or nullptr.
171 	D_Recursive_object_iterator<D> *child;
172 	D elems;            // Goes through our elements.
173 public:
D_Recursive_object_iterator(Object_list & objs)174 	D_Recursive_object_iterator(Object_list &objs)
175 		: child(nullptr), elems(objs)
176 	{  }
177 	// Start at given object.
178 	D_Recursive_object_iterator(Game_object *start);
179 	Game_object *get_next();    // Get next, going into containers.
180 };
181 
182 /*
183  *  Iterate forwards/backwards through a list of objects (recursively).
184  */
185 using Recursive_object_iterator_backwards = D_Recursive_object_iterator<Object_iterator_backwards>;
186 using Recursive_object_iterator = D_Recursive_object_iterator<Object_iterator>;
187 
188 #endif
189