1 // Copyright 2016-2017 the nyan authors, LGPLv3+. See copying.md for legal info.
2 #pragma once
3 
4 
5 #include <iterator>
6 
7 #include "value.h"
8 
9 
10 namespace nyan {
11 
12 
13 /**
14  * Base class for container iterators.
15  * Inherited from and implemented for each nyan container
16  * in order to support iteration.
17  *
18  * The child class adds stuff so it can iterate over whatever the
19  * target container needs for iteration state storage.
20  *
21  * The begin() and end() functions of the container class
22  * instanciate this by wrapping it in the ContainerIterator below.
23  */
24 template<typename elem_type>
25 class ContainerIterBase : public std::iterator<std::forward_iterator_tag,
26                                                elem_type> {
27 public:
28 	using this_type = ContainerIterBase<elem_type>;
29 
30 	ContainerIterBase() = default;
31 	virtual ~ContainerIterBase() = default;
32 
33 	/**
34 	 * Advance the iterator to the next element.
35 	 */
36 	virtual this_type &operator ++() = 0;
37 
38 	/**
39 	 * Get the element the iterator is currently pointing to.
40 	 */
41 	virtual elem_type &operator *() const = 0;
42 
43 	/**
44 	 * Compare if both iterators are pointing
45 	 * to the same container position.
46 	 */
47 	bool operator ==(const ContainerIterBase &other) const {
48 		return (typeid(*this) == typeid(other)) and this->equals(other);
49 	}
50 
51 protected:
52 	/**
53 	 * Actually perform the comparison if both iterators
54 	 * point to the same element.
55 	 */
56 	virtual bool equals(const ContainerIterBase &other) const = 0;
57 };
58 
59 
60 /**
61  * Nyan container iterator wrapper class.
62  * Wraps the ContainerIterBase so we can have virtual calls.
63  *
64  * Just relays the calls to the wrapped actual container.
65  */
66 template<typename T>
67 class ContainerIterator : public std::iterator<std::forward_iterator_tag, T> {
68 public:
69 	using elem_type = T;
70 	using real_iterator = ContainerIterBase<elem_type>;
71 
72 
73 	ContainerIterator() = default;
ContainerIterator(std::unique_ptr<ContainerIterBase<elem_type>> && real)74 	ContainerIterator(std::unique_ptr<ContainerIterBase<elem_type>> &&real) noexcept
75 		:
76 		iter{std::move(real)} {}
77 
ContainerIterator(const ContainerIterator & other)78 	ContainerIterator(const ContainerIterator &other)
79 		:
80 		iter{std::make_unique(other)} {}
81 
ContainerIterator(ContainerIterator && other)82 	ContainerIterator(ContainerIterator &&other) noexcept
83 		:
84 		iter{std::move(other.iter)} {}
85 
86 	ContainerIterator &operator =(const ContainerIterator &other) {
87 		this->iter = std::make_unique(other);
88 	}
89 
90 	ContainerIterator &operator =(ContainerIterator &&other) noexcept {
91 		this->iter = std::move(other);
92 	}
93 
94 	virtual ~ContainerIterator() = default;
95 
96 	/**
97 	 * Advance the inner iterator to the next element.
98 	 */
99 	ContainerIterator &operator ++() {
100 		++(*this->iter);
101 		return *this;
102 	}
103 
104 	/**
105 	 * Get the element the inner iterator points to.
106 	 */
107 	elem_type &operator *() const {
108 		return *(*this->iter);
109 	}
110 
111 	/**
112 	 * Check if this iterator points to the same container element
113 	 * as the other iterator.
114 	 */
115 	bool operator ==(const ContainerIterator& other) const {
116 		return (this->iter == other.iter) or (*this->iter == *other.iter);
117 	}
118 
119 	/**
120 	 * Check if the iterator does not point to the same container element
121 	 * as the other iterator.
122 	 */
123 	bool operator !=(const ContainerIterator& other) const {
124 		return not (*this == other);
125 	}
126 
127 protected:
128 	/**
129 	 * The real iterator.
130 	 * Just wrapped here to enable virtual function calls.
131 	 */
132 	std::unique_ptr<ContainerIterBase<elem_type>> iter;
133 };
134 
135 
136 /**
137  * Implementation for wrapping standard STL container forward iterators.
138  */
139 template <typename iter_type, typename elem_type>
140 class DefaultIterator : public ContainerIterBase<elem_type> {
141 public:
142 	using this_type = DefaultIterator<iter_type, elem_type>;
143 	using base_type = ContainerIterBase<elem_type>;
144 
DefaultIterator(iter_type && iter)145 	explicit DefaultIterator(iter_type &&iter)
146 		:
147 		iterator{std::move(iter)} {}
148 
149 	/**
150 	 * Advance the iterator to the next element in the set.
151 	 */
152 	base_type &operator ++() override {
153 		++this->iterator;
154 		return *this;
155 	}
156 
157 	/**
158 	 * Return the iterator value.
159 	 */
160 	elem_type &operator *() const override {
161 		return *this->iterator;
162 	}
163 
164 protected:
165 	/**
166 	 * Compare two iterators for pointing at the same element.
167 	 */
equals(const base_type & other)168 	bool equals(const base_type &other) const override {
169 		auto other_me = dynamic_cast<const this_type &>(other);
170 		return (this->iterator == other_me.iterator);
171 	}
172 
173 	/**
174 	 * The wrapped std::iterator.
175 	 */
176 	iter_type iterator;
177 };
178 
179 
180 /**
181  * Value that can store other Values.
182  * Provides iterators and add/remove methods.
183  */
184 class Container : public Value {
185 public:
186 	using iterator = ContainerIterator<Value>;
187 	using const_iterator = ContainerIterator<const Value>;
188 
189 	using holder_iterator = ContainerIterator<ValueHolder>;
190 	using holder_const_iterator = ContainerIterator<const ValueHolder>;
191 
192 	Container() = default;
193 	virtual ~Container() = default;
194 
195 	/**
196 	 * Return the number of elements in this container.
197 	 */
198 	virtual size_t size() const = 0;
199 
200 	/**
201 	 * Add the given value to this container.
202 	 * @returns if the value was added successfully,
203 	 * false if it was already in there.
204 	 */
205 	virtual bool add(const ValueHolder &value) = 0;
206 
207 	/**
208 	 * Test if this value is in the container.
209 	 */
210 	virtual bool contains(const ValueHolder &value) const = 0;
211 
212 	/**
213 	 * Remove the given value from the container if it is in there.
214 	 * @returns if if was removed successfully.
215 	 */
216 	virtual bool remove(const ValueHolder &value) = 0;
217 
218 	/**
219 	 * Get an iterator to the first element in that container.
220 	 */
221 	virtual iterator begin() = 0;
222 
223 	/**
224 	 * Get an iterator to the slot beyond the last element in the container.
225 	 */
226 	virtual iterator end() = 0;
227 
228 	/**
229 	 * Get a constant iterator to the first element in that container.
230 	 */
231 	virtual const_iterator begin() const = 0;
232 
233 	/**
234 	 * Get a constant iterator to the slot beyond the last element in the
235 	 * container.
236 	 */
237 	virtual const_iterator end() const = 0;
238 
239 	/**
240 	 * Guarantee a const_iterator beginning.
241 	 */
cbegin()242 	const_iterator cbegin() const { return this->begin(); };
243 
244 	/**
245 	 * Guarantee a const_iterator end.
246 	 */
cend()247 	const_iterator cend() const { return this->end(); };
248 
249 	/**
250 	 * Get an iterator to the first value holder in that container.
251 	 */
252 	virtual holder_iterator values_begin() = 0;
253 
254 	/**
255 	 * Get an iterator to the slot beyond the last value holder
256 	 * in the container.
257 	 */
258 	virtual holder_iterator values_end() = 0;
259 
260 	/**
261 	 * Get a constant iterator to the first value holder in the container.
262 	 */
263 	virtual holder_const_iterator values_begin() const = 0;
264 
265 	/**
266 	 * Get a constant iterator to the slot beyond the last value holder
267 	 * in the container.
268 	 */
269 	virtual holder_const_iterator values_end() const = 0;
270 
271 	/**
272 	 * Guarantee a const_iterator to the value iterator beginning.
273 	 */
values_cbegin()274 	holder_const_iterator values_cbegin() const { return this->values_begin(); };
275 
276 	/**
277 	 * Guarantee a const_iterator to the value iterator end.
278 	 */
values_cend()279 	holder_const_iterator values_cend() const { return this->values_end(); };
280 };
281 
282 } // namespace nyan
283