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