├── .gitignore ├── examples ├── Makefile ├── rvalue.cpp ├── filter.cpp └── reverse.cpp ├── Makefile ├── LICENSE ├── tests.cpp ├── README.md └── iterator_tpl.h /.gitignore: -------------------------------------------------------------------------------- 1 | tests 2 | *.o 3 | *.exe 4 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: rvalue filter reverse 3 | 4 | rvalue: 5 | g++ -g -Wall -pedantic -std=c++11 rvalue.cpp -o rvalue 6 | ./rvalue 7 | 8 | filter: 9 | g++ -g -Wall -pedantic -std=c++11 filter.cpp -o filter 10 | ./filter 11 | 12 | reverse: 13 | g++ -g -Wall -pedantic -std=c++98 reverse.cpp -o reverse 14 | ./reverse 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: 3 | g++ -g -Wall -pedantic -std=c++11 tests.cpp -o tests.exe 4 | ./tests.exe 5 | 6 | example1: filter 7 | filter: 8 | g++ -g -Wall -pedantic -std=c++11 examples/filter.cpp -o filter.exe 9 | ./filter.exe 10 | 11 | example2: reverse 12 | reverse: 13 | g++ -g -Wall -pedantic -std=c++11 examples/reverse.cpp -o reverse.exe 14 | ./reverse.exe 15 | 16 | example3: rvalue 17 | rvalue: 18 | g++ -g -Wall -pedantic -std=c++11 examples/rvalue.cpp -o rvalue.exe 19 | ./rvalue.exe 20 | 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Vinícius Garcia (vingarcia00@gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/rvalue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../iterator_tpl.h" 5 | 6 | struct Point { 7 | int x; 8 | int y; 9 | Point() {} 10 | Point(int x, int y) : x(x), y(y) {} 11 | Point operator+(Point other) const { 12 | other.x += x; 13 | other.y += y; 14 | return other; 15 | } 16 | }; 17 | 18 | struct Shape { 19 | std::vector vec; 20 | }; 21 | 22 | struct Piece { 23 | Shape& shape; 24 | Point offset; 25 | Piece(Shape& shape, int x, int y) : shape(shape), offset(x,y) {} 26 | 27 | struct it_state { 28 | int pos; 29 | inline void next(const Piece* ref) { ++pos; } 30 | inline void begin(const Piece* ref) { pos = 0; } 31 | inline void end(const Piece* ref) { pos = ref->shape.vec.size(); } 32 | inline Point get(Piece* ref) { return ref->offset + ref->shape.vec[pos]; } 33 | inline bool equals(const it_state& s) const { return pos == s.pos; } 34 | }; 35 | SETUP_ITERATORS(Piece, Point, it_state); 36 | }; 37 | 38 | int main() { 39 | Shape shape; 40 | shape.vec.emplace_back(1,2); 41 | shape.vec.emplace_back(2,3); 42 | shape.vec.emplace_back(3,4); 43 | 44 | Piece piece(shape, 1, 1); 45 | 46 | for (Point p : piece) { 47 | std::cout << p.x << " " << p.y << std::endl; 48 | // Output: 49 | // 2 3 50 | // 3 4 51 | // 4 5 52 | } 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /examples/filter.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "../iterator_tpl.h" 6 | 7 | struct Point { 8 | int x; 9 | int y; 10 | Point(int x, int y) : x(x), y(y) {} 11 | }; 12 | 13 | struct Shape { 14 | std::vector vec; 15 | 16 | static bool some_filter (const Point& p) { 17 | return p.x > p.y; 18 | } 19 | 20 | struct it_state { 21 | int pos; 22 | int end_pos; 23 | 24 | // Find next valid item: 25 | inline void next(const Shape* ref) { 26 | ++pos; 27 | while (some_filter(ref->vec[pos]) && pos < end_pos) ++pos; 28 | } 29 | 30 | // Prepare the iterator: 31 | inline void begin(const Shape* ref) { 32 | pos = -1; 33 | end_pos = ref->vec.size(); 34 | // Find first valid item: 35 | next(ref); 36 | } 37 | 38 | inline void end(const Shape* ref) { pos = ref->vec.size(); } 39 | inline Point& get(Shape* ref) { return ref->vec[pos]; } 40 | inline bool equals(const it_state& s) const { return pos == s.pos; } 41 | 42 | // Optional for const_iterator to work: 43 | inline const Point& get(const Shape* ref) { return ref->vec[pos]; } 44 | }; 45 | SETUP_ITERATORS(Shape, Point&, it_state); 46 | }; 47 | 48 | int main() { 49 | Shape shape; 50 | shape.vec.emplace_back(1,2); 51 | shape.vec.emplace_back(2,3); 52 | shape.vec.emplace_back(3,4); 53 | shape.vec.emplace_back(2,1); 54 | shape.vec.emplace_back(3,2); 55 | shape.vec.emplace_back(4,3); 56 | 57 | for (Point p : shape) { 58 | std::cout << p.x << " " << p.y << std::endl; 59 | // Output: 60 | // 1 2 61 | // 2 3 62 | // 3 4 63 | } 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /examples/reverse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../iterator_tpl.h" 4 | 5 | struct myClass { 6 | std::vector vec; 7 | 8 | // Add some sane typedefs for STL compliance: 9 | STL_TYPEDEFS(float); 10 | 11 | struct it_state { 12 | int pos; 13 | inline void begin(const myClass* ref) { pos = 0; } 14 | inline void next(const myClass* ref) { ++pos; } 15 | inline void end(const myClass* ref) { pos = ref->vec.size(); } 16 | inline float& get(myClass* ref) { return ref->vec[pos]; } 17 | inline bool equals(const it_state& s) const { return pos == s.pos; } 18 | 19 | // Optional to allow operator--() and reverse iterators: 20 | inline void prev(const myClass* ref) { --pos; } 21 | // Optional to allow `const_iterator`: 22 | inline const float& get(const myClass* ref) const { return ref->vec[pos]; } 23 | }; 24 | // Declare typedef ... iterator;, begin() and end() functions: 25 | SETUP_ITERATORS(myClass, float&, it_state); 26 | // Declare typedef ... reverse_iterator;, rbegin() and rend() functions: 27 | SETUP_REVERSE_ITERATORS(myClass, float&, it_state); 28 | }; 29 | 30 | int main() { 31 | myClass c1; 32 | c1.vec.push_back(1.0); 33 | c1.vec.push_back(2.0); 34 | c1.vec.push_back(3.0); 35 | 36 | std::cout << std::endl; 37 | std::cout << "mutable iterator:" << std::endl; 38 | for (myClass::iterator it = c1.begin(); it != c1.end(); ++it) { 39 | float& val = *it; 40 | std::cout << val << " "; // val1 val2 val3 41 | } 42 | std::cout << std::endl; 43 | 44 | std::cout << std::endl; 45 | std::cout << "const iterator:" << std::endl; 46 | const myClass& c2 = c1; 47 | for (myClass::const_iterator it = c2.begin(); it != c2.end(); ++it) { 48 | const float& val = *it; 49 | std::cout << val << " "; // val1 val2 val3 50 | } 51 | std::cout << std::endl; 52 | 53 | std::cout << std::endl; 54 | std::cout << "reverse iterator:" << std::endl; 55 | for (myClass::reverse_iterator it = c1.rbegin(); it != c1.rend(); ++it) { 56 | std::cout << *it << " "; // val3 val2 val1 57 | } 58 | std::cout << std::endl; 59 | 60 | std::cout << std::endl; 61 | std::cout << "reverse const iterator:" << std::endl; 62 | for (myClass::const_reverse_iterator it = c2.rbegin(); it != c2.rend(); ++it) { 63 | std::cout << *it << " "; // val3 val2 val1 64 | } 65 | std::cout << std::endl; 66 | std::cout << std::endl; 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "iterator_tpl.h" 4 | 5 | #define ASSERT(COND) if ((COND) == 0) {\ 6 | std::cout << std::string("Assertion error for cond: " #COND)\ 7 | << std::endl;\ 8 | throw "failed";\ 9 | } 10 | 11 | struct myClass { 12 | std::vector vec; 13 | 14 | struct it_state { 15 | int pos; 16 | inline void next(const myClass* ref) { ++pos; } 17 | inline void prev(const myClass* ref) { --pos; } 18 | inline void begin(const myClass* ref) { pos = 0; } 19 | inline void end(const myClass* ref) { pos = ref->vec.size(); } 20 | inline float& get(myClass* ref) { return ref->vec[pos]; } 21 | inline const float& get(const myClass* ref) const { return ref->vec[pos]; } 22 | inline bool equals(const it_state& s) const { return pos == s.pos; } 23 | }; 24 | SETUP_ITERATORS(myClass, float&, it_state); 25 | SETUP_REVERSE_ITERATORS(myClass, float&, it_state); 26 | }; 27 | 28 | // This class's iterator will return only rvalues, i.e. 29 | // `float` instead of `float&` 30 | struct myClass_rvalue { 31 | std::vector vec; 32 | 33 | struct it_state { 34 | int pos; 35 | inline void next(const myClass_rvalue* ref) { ++pos; } 36 | inline void prev(const myClass_rvalue* ref) { --pos; } 37 | inline void begin(const myClass_rvalue* ref) { pos = 0; } 38 | inline void end(const myClass_rvalue* ref) { pos = ref->vec.size(); } 39 | inline float get(myClass_rvalue* ref) { return ref->vec[pos] - 1; } 40 | inline const float get(const myClass_rvalue* ref) { return ref->vec[pos] - 1; } 41 | inline bool equals(const it_state& s) const { return pos == s.pos; } 42 | }; 43 | SETUP_ITERATORS(myClass_rvalue, float, it_state); 44 | SETUP_REVERSE_ITERATORS(myClass_rvalue, float, it_state); 45 | }; 46 | 47 | int main() { 48 | myClass c1; 49 | c1.vec.push_back(1.0); 50 | c1.vec.push_back(2.0); 51 | c1.vec.push_back(3.0); 52 | 53 | std::cout << std::endl; 54 | std::cout << "mutable iterator:" << std::endl; 55 | for (float& val : c1) { 56 | std::cout << val << " "; // val1 val2 val3 57 | } 58 | std::cout << std::endl; 59 | 60 | std::cout << std::endl; 61 | std::cout << "const iterator:" << std::endl; 62 | const myClass& c2 = c1; 63 | for (const float& val : c2) { 64 | std::cout << val << " "; // val1 val2 val3 65 | } 66 | std::cout << std::endl; 67 | 68 | std::cout << std::endl; 69 | std::cout << "reversed iterator:" << std::endl; 70 | for (auto it = c1.rbegin(); it != c1.rend(); ++it) { 71 | std::cout << *it << " "; // val3 val2 val1 72 | } 73 | std::cout << std::endl; 74 | 75 | std::cout << std::endl; 76 | std::cout << "reversed const iterator:" << std::endl; 77 | for (auto it = c2.rbegin(); it != c2.rend(); ++it) { 78 | std::cout << *it << " "; // val3 val2 val1 79 | } 80 | std::cout << std::endl; 81 | 82 | myClass_rvalue c1_rvalue; 83 | c1_rvalue.vec.push_back(1.0); 84 | c1_rvalue.vec.push_back(2.0); 85 | c1_rvalue.vec.push_back(3.0); 86 | const myClass_rvalue& c2_rvalue = c1_rvalue; 87 | 88 | std::cout << std::endl; 89 | std::cout << "rvalue mutable iterator:" << std::endl; 90 | for (auto it = c1_rvalue.begin(); it != c1_rvalue.end(); ++it) { 91 | float val = *it; 92 | std::cout << val << " "; // val3 val2 val1 93 | } 94 | std::cout << std::endl; 95 | 96 | std::cout << std::endl; 97 | std::cout << "rvalue const iterator:" << std::endl; 98 | for (auto it = c2_rvalue.begin(); it != c2_rvalue.end(); ++it) { 99 | float val = *it; 100 | std::cout << val << " "; // val3 val2 val1 101 | } 102 | std::cout << std::endl; 103 | 104 | std::cout << std::endl; 105 | std::cout << "rvalue reversed mutable iterator:" << std::endl; 106 | for (auto it = c1_rvalue.rbegin(); it != c1_rvalue.rend(); ++it) { 107 | float val = *it; 108 | std::cout << val << " "; // val3 val2 val1 109 | } 110 | std::cout << std::endl; 111 | 112 | std::cout << std::endl; 113 | std::cout << "rvalue reversed const iterator:" << std::endl; 114 | for (auto it = c2_rvalue.rbegin(); it != c2_rvalue.rend(); ++it) { 115 | float val = *it; 116 | std::cout << val << " "; // val3 val2 val1 117 | } 118 | std::cout << std::endl; 119 | std::cout << std::endl; 120 | 121 | // Testing copy-constructor and copy-assignment between 122 | // const_iterators and iterators: 123 | myClass::const_iterator it1 = c1.end(); 124 | ASSERT(it1 == c2.end()); 125 | myClass::const_iterator it2; 126 | it1 = c1.begin(); 127 | ASSERT(it1 != c2.end()); 128 | it2 = c1.begin(); 129 | ASSERT(it2 == c2.begin()); 130 | 131 | // Testing comparisons between const and normal iterators: 132 | ASSERT(it2 == c2.begin()); 133 | ASSERT((it2 != c2.begin()) == 0); 134 | ASSERT(c2.begin() == it2); 135 | ASSERT((c2.begin() != it2) == 0); 136 | 137 | // Testing operators++ pre and post-fixed: 138 | ASSERT(*c1.begin() == 1); 139 | ASSERT(*(++c1.begin()) == 2); 140 | ASSERT(*(c1.begin()++) == 1); 141 | 142 | // Testing operators++ pre and post-fixed for const classes: 143 | ASSERT(*c2.begin() == 1); 144 | ASSERT(*(++c2.begin()) == 2); 145 | ASSERT(*(c2.begin()++) == 1); 146 | 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple Iterator Template 2 | 3 | Provides a header-only C++ iterator template that is easy to adapt for any custom container. 4 | 5 | ## Change Log: 6 | 7 | Recently PR #14 was merged, and it adds a backward-incompatible change: 8 | 9 | - Now instead of defining the function `cmp` for the iterators the template 10 | expects a function `equals` that semantically means `!cmp()` 11 | 12 | The reason for that is because it was argued that the behavior where cmp would 13 | return true when the iterators were different was not obvious and was prone to 14 | causing implementation errors. 15 | 16 | This backward-incompatible change should be a one-off since there aren't all that 17 | many things to change in this template, but I thought this was important enough for that, 18 | I am hoping this won't cause much trouble for the people already using the library. 19 | 20 | ## Features: 21 | 22 | - Single header. 23 | - STL Compliant. 24 | - No efficiency loss, it is as efficient as it could possibly be. 25 | - Really easy to understand. 26 | - Concise: on simple cases it takes only 10 lines to adapt a container, 27 | and on more complex cases it takes only a few extra lines. 28 | - Implements Forward Iterator, Input Iterator, Output Iterator and Bidirectional Iterator. 29 | - Compatible with all C++ standards (see `example/reverse.cpp`). 30 | 31 | It not only provides a forward `iterator` to your class but also a `const_iterator` 32 | reusing the same definitions except for the `get()` function, for whom a const 33 | version must be provided (still included in the 9 lines). 34 | 35 | It also includes an optional `reversed_iterator` and `const_reversed_iterator`, to add them you need to add a function `prev()` described below and a single macro that accepts the same arguments used for the normal iterators. 36 | 37 | ## Usage: 38 | 39 | ```C++ 40 | #include 41 | #include 42 | 43 | #include "iterator_tpl.h" 44 | 45 | struct myClass { 46 | std::vector vec; 47 | 48 | struct it_state { 49 | int pos; 50 | inline void next(const myClass* ref) { ++pos; } 51 | inline void begin(const myClass* ref) { pos = 0; } 52 | inline void end(const myClass* ref) { pos = ref->vec.size(); } 53 | inline float& get(myClass* ref) { return ref->vec[pos]; } 54 | inline const float& get(const myClass* ref) { return ref->vec[pos]; } 55 | inline bool equals(const it_state& s) const { return pos == s.pos; } 56 | }; 57 | SETUP_ITERATORS(myClass, float&, it_state); 58 | }; 59 | ``` 60 | 61 | Then it is easy to use the container as a normal iterator, e.g.: 62 | 63 | ```C++ 64 | int main() { 65 | myClass a1; 66 | a1.vec.push_back(1.0); 67 | a1.vec.push_back(2.0); 68 | a1.vec.push_back(3.0); 69 | 70 | std::cout << "mutable iterator:" << std::endl; 71 | for (float& val : a1) { 72 | std::cout << val << " "; // 1 2 3 73 | } 74 | std::cout << std::endl; 75 | 76 | std::cout << "const iterator:" << std::endl; 77 | const myClass& a2 = a1; 78 | for (const float& val : a2) { 79 | std::cout << val << " "; // 1 2 3 80 | } 81 | std::cout << std::endl; 82 | 83 | return 0; 84 | } 85 | ``` 86 | 87 | ## Add reverse iterators: 88 | 89 | To add reverse iterators only two things are required: 90 | 91 | 1. Add a void `prev(const myClass* ref) { --pos; }` function to `state_it`. 92 | 2. Add the macro `SETUP_REVERSE_ITERATORS` with the same 3 arguments as `SETUP_ITERATORS`. 93 | 94 | ```C++ 95 | struct myClass { 96 | std::vector vec; 97 | 98 | struct it_state { 99 | int pos; 100 | inline void next(const myClass* ref) { ++pos; } 101 | inline void prev(const myClass* ref) { --pos; } // <-- Add `prev()` 102 | inline void begin(const myClass* ref) { pos = 0; } 103 | inline void end(const myClass* ref) { pos = ref->vec.size(); } 104 | inline float& get(myClass* ref) { return ref->vec[pos]; } 105 | inline const float& get(const myClass* ref) { return ref->vec[pos]; } 106 | inline bool equals(const it_state& s) const { return pos == s.pos; } 107 | }; 108 | SETUP_ITERATORS(myClass, float&, it_state); 109 | SETUP_REVERSE_ITERATORS(myClass, float&, it_state); // <-- Add REVERSE_ITERATORS macro 110 | }; 111 | ``` 112 | 113 | Then it is possible to use `rbegin()` and `rend()` normally: 114 | 115 | ```C++ 116 | int main() { 117 | myClass a1; 118 | const myClass& a2 = a1; 119 | 120 | a1.vec.push_back(1.0); 121 | a1.vec.push_back(2.0); 122 | a1.vec.push_back(3.0); 123 | 124 | std::cout << "mutable reverse iterator:" << std::endl; 125 | for (auto it = a1.rbegin(); it != a1.rend(); ++it) { 126 | float& val = *it; 127 | std::cout << val << " "; // 3 2 1 128 | } 129 | std::cout << std::endl; 130 | 131 | std::cout << "const reverse iterator:" << std::endl; 132 | for (auto it = a2.rbegin(); it != a2.rend(); ++it) { 133 | const float& val = *it; 134 | std::cout << val << " "; // 3 2 1 135 | } 136 | std::cout << std::endl; 137 | 138 | return 0; 139 | } 140 | ``` 141 | 142 | ## Returning RValues 143 | 144 | Returning by reference is nice, it allows you to change the internal values of the iterator 145 | and prevents unnecessary copies. However, sometimes it is not possible. 146 | 147 | For these cases the library allows you to specify the template with a type `float` instead 148 | of `float&`, e.g.: 149 | 150 | ```C++ 151 | SETUP_ITERATORS(myClass, float, it_state); 152 | SETUP_REVERSE_ITERATORS(myClass, float, it_state); 153 | ``` 154 | 155 | This allows for the get() functions to return `float` when returning `float&` 156 | would not be possible, e.g.: 157 | 158 | ```C++ 159 | struct it_state { 160 | int pos; 161 | inline void next(const myClass* ref) { ++pos; } 162 | inline void prev(const myClass* ref) { --pos; } 163 | inline void begin(const myClass* ref) { pos = 0; } 164 | inline void end(const myClass* ref) { pos = ref->vec.size(); } 165 | inline float get(myClass* ref) { return 1 + ref->vec[pos]; } 166 | inline const float get(const myClass* ref) { return 1 + ref->vec[pos]; } 167 | inline bool equals(const it_state& s) const { return pos == s.pos; } 168 | }; 169 | ``` 170 | 171 | ## STL Typedefs 172 | 173 | To offer full compliance with STL iterators there is an easy way to add some sane defaults for the required typedefs to your class, the macro `STL_TYPEDEFS`: 174 | 175 | ```C++ 176 | struct myClass { 177 | std::vector vec; 178 | 179 | STL_TYPEDEFS(float); // (Optional) 180 | struct it_state { 181 | int pos; 182 | inline void next(const myClass* ref) { ++pos; } 183 | inline void prev(const myClass* ref) { --pos; } // (Optional) 184 | inline void begin(const myClass* ref) { pos = 0; } 185 | inline void end(const myClass* ref) { pos = ref->vec.size(); } 186 | inline float& get(myClass* ref) { return ref->vec[pos]; } 187 | inline const float& get(const myClass* ref) { return ref->vec[pos]; } 188 | inline bool equals(const it_state& s) const { return pos == s.pos; } 189 | }; 190 | SETUP_ITERATORS(myClass, float&, it_state); 191 | SETUP_REVERSE_ITERATORS(myClass, float&, it_state); // (Optional) 192 | }; 193 | ``` 194 | 195 | This adds the following typedefs to your class (you might just write them by hand if you prefer): 196 | 197 | ```C++ 198 | typedef std::ptrdiff_t difference_type; 199 | typedef size_t size_type; 200 | typedef T value_type; 201 | typedef T* pointer; 202 | typedef const T* const_pointer; 203 | typedef T& reference; 204 | typedef const T& const_reference; 205 | ``` 206 | 207 | ## I don't like macros, can I skip them? 208 | 209 | Yes, actually even without the macros the template library is still quite concise in comparison to writing everything manually: 210 | 211 | ```C++ 212 | struct myClass { 213 | std::vector vec; 214 | 215 | typedef std::ptrdiff_t difference_type; 216 | typedef size_t size_type; 217 | typedef float value_type; 218 | typedef float* pointer; 219 | typedef const float* const_pointer; 220 | typedef float& reference; 221 | typedef const float& const_reference; 222 | 223 | struct it_state { 224 | int pos; 225 | inline void next(const myClass* ref) { ++pos; } 226 | inline void prev(const myClass* ref) { --pos; } 227 | inline void begin(const myClass* ref) { pos = 0; } 228 | inline void end(const myClass* ref) { pos = ref->vec.size(); } 229 | inline float& get(myClass* ref) { return ref->vec[pos]; } 230 | inline const float& get(const myClass* ref) { return ref->vec[pos]; } 231 | inline bool equals(const it_state& s) const { return pos == s.pos; } 232 | }; 233 | 234 | // Mutable Iterator: 235 | typedef iterator_tpl::iterator iterator; 236 | iterator begin() { return iterator::begin(this); } 237 | iterator end() { return iterator::end(this); } 238 | 239 | // Const Iterator: 240 | typedef iterator_tpl::const_iterator const_iterator; 241 | const_iterator begin() const { return const_iterator::begin(this); } 242 | const_iterator end() const { return const_iterator::end(this); } 243 | 244 | // Reverse `it_state`: 245 | struct reverse_it_state : public it_state { 246 | inline void next(const myClass* ref) { it_state::prev(ref); } 247 | inline void prev(const myClass* ref) { it_state::next(ref); } 248 | inline void begin(const myClass* ref) { it_state::end(ref); it_state::prev(ref);} 249 | inline void end(const myClass* ref) { it_state::begin(ref); it_state::prev(ref);} 250 | }; 251 | 252 | // Mutable Reverse Iterator: 253 | typedef iterator_tpl::iterator reverse_iterator; 254 | reverse_iterator rbegin() { return reverse_iterator::begin(this); } 255 | reverse_iterator rend() { return reverse_iterator::end(this); } 256 | 257 | // Const Reverse Iterator: 258 | typedef iterator_tpl::const_iterator const_reverse_iterator; 259 | const_reverse_iterator rbegin() const { 260 | return const_reverse_iterator::begin(this); 261 | } 262 | const_reverse_iterator rend() const { 263 | return const_reverse_iterator::end(this); 264 | } 265 | }; 266 | ``` 267 | 268 | You can then run the `iterators`, `const_iterators`, and `reversed_iterators` as before: 269 | 270 | ```C++ 271 | int main() { 272 | myClass a1; 273 | const myClass& a2 = a1; 274 | 275 | a1.vec.push_back(1.0); 276 | a1.vec.push_back(2.0); 277 | a1.vec.push_back(3.0); 278 | 279 | std::cout << "mutable iterator:" << std::endl; 280 | for (float& val : a1) { 281 | std::cout << val << " "; // 1 2 3 282 | } 283 | std::cout << std::endl; 284 | 285 | std::cout << "const iterator:" << std::endl; 286 | for (const float& val : a2) { 287 | std::cout << val << " "; // 1 2 3 288 | } 289 | std::cout << std::endl; 290 | 291 | std::cout << "mutable reverse iterator:" << std::endl; 292 | for (auto it = a1.rbegin(); it != a1.rend(); ++it) { 293 | float& val = *it; 294 | std::cout << val << " "; // 3 2 1 295 | } 296 | std::cout << std::endl; 297 | 298 | std::cout << "const reverse iterator:" << std::endl; 299 | for (auto it = a2.rbegin(); it != a2.rend(); ++it) { 300 | const float& val = *it; 301 | std::cout << val << " "; // 3 2 1 302 | } 303 | std::cout << std::endl; 304 | 305 | return 0; 306 | } 307 | ``` 308 | 309 | ## Macro Colisions: 310 | 311 | For having a way to avoid macro colisions a new version of the macros was 312 | created, so for every macro you see on the examples you can also use the 313 | fullnamed version below if macro colisions is a concern: 314 | 315 | - `VGSI_SETUP_ITERATORS(C, T, S)` 316 | - `VGSI_SETUP_MUTABLE_ITERATOR(C, T, S)` 317 | - `VGSI_SETUP_CONST_ITERATOR(C, T, S)` 318 | - `VGSI_SETUP_REVERSE_ITERATORS(C, T, S)` 319 | - `VGSI_SETUP_MUTABLE_RITERATOR(C, T, S)` 320 | - `VGSI_SETUP_CONST_RITERATOR(C, T, S)` 321 | - `VGSI_STL_TYPEDEFS(T)` 322 | -------------------------------------------------------------------------------- /iterator_tpl.h: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2017 Vinícius Garcia (vingarcia00@gmail.com) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | #ifndef _iterator_tpl_h_ 24 | #define _iterator_tpl_h_ 25 | 26 | namespace iterator_tpl { 27 | 28 | // Use this define to declare both: 29 | // - `iterator` 30 | // - `const_iterator`: 31 | // As members of your class 32 | #define VGSI_SETUP_ITERATORS(C, T, S) \ 33 | VGSI_SETUP_MUTABLE_ITERATOR(C, T, S) \ 34 | VGSI_SETUP_CONST_ITERATOR(C, T, S) 35 | 36 | // Use this define to declare only `iterator` 37 | #define VGSI_SETUP_MUTABLE_ITERATOR(C, T, S) \ 38 | typedef iterator_tpl::iterator iterator; \ 39 | iterator begin() { return iterator::begin(this); } \ 40 | iterator end() { return iterator::end(this); } 41 | 42 | // Use this define to declare only `const_iterator` 43 | #define VGSI_SETUP_CONST_ITERATOR(C, T, S) \ 44 | typedef iterator_tpl::const_iterator const_iterator; \ 45 | const_iterator begin() const { return const_iterator::begin(this); } \ 46 | const_iterator end() const { return const_iterator::end(this); } \ 47 | const_iterator cbegin() const { return const_iterator::begin(this); } \ 48 | const_iterator cend() const { return const_iterator::end(this); } 49 | 50 | // S should be the state struct used to forward iteration: 51 | #define VGSI_SETUP_REVERSE_ITERATORS(C, T, S) \ 52 | struct S##_reversed : public S { \ 53 | inline void next (const C* ref) { S::prev(ref); } \ 54 | inline void prev (const C* ref) { S::next(ref); } \ 55 | inline void begin(const C* ref) { S::end(ref); S::prev(ref);} \ 56 | inline void end (const C* ref) { S::begin(ref); S::prev(ref);} \ 57 | }; \ 58 | VGSI_SETUP_MUTABLE_RITERATOR(C, T, S) \ 59 | VGSI_SETUP_CONST_RITERATOR(C, T, S) 60 | 61 | #define VGSI_SETUP_MUTABLE_RITERATOR(C, T, S) \ 62 | typedef iterator_tpl::iterator reverse_iterator; \ 63 | reverse_iterator rbegin() { return reverse_iterator::begin(this); } \ 64 | reverse_iterator rend() { return reverse_iterator::end(this); } \ 65 | 66 | #define VGSI_SETUP_CONST_RITERATOR(C, T, S) \ 67 | typedef iterator_tpl::const_iterator const_reverse_iterator; \ 68 | const_reverse_iterator rbegin() const { \ 69 | return const_reverse_iterator::begin(this); \ 70 | } \ 71 | const_reverse_iterator rend() const { \ 72 | return const_reverse_iterator::end(this); \ 73 | } \ 74 | const_reverse_iterator crbegin() const { \ 75 | return const_reverse_iterator::begin(this); \ 76 | } \ 77 | const_reverse_iterator crend() const { \ 78 | return const_reverse_iterator::end(this); \ 79 | } 80 | 81 | #define VGSI_STL_TYPEDEFS(T) \ 82 | typedef std::ptrdiff_t difference_type; \ 83 | typedef size_t size_type; \ 84 | typedef T value_type; \ 85 | typedef T* pointer; \ 86 | typedef const T* const_pointer; \ 87 | typedef T& reference; \ 88 | typedef const T& const_reference 89 | 90 | // Unsafe, and slighly cleaner, version of the macros above: 91 | // (Note: its unsafe only in the sense of macro collisions) 92 | #ifndef SETUP_ITERATORS 93 | #define SETUP_ITERATORS(C, T, S) VGSI_SETUP_ITERATORS(C, T, S) 94 | #endif 95 | 96 | #ifndef SETUP_MUTABLE_ITERATOR 97 | #define SETUP_MUTABLE_ITERATOR(C, T, S) VGSI_SETUP_MUTABLE_ITERATOR(C, T, S) 98 | #endif 99 | 100 | #ifndef SETUP_CONST_ITERATOR 101 | #define SETUP_CONST_ITERATOR(C, T, S) VGSI_SETUP_CONST_ITERATOR(C, T, S) 102 | #endif 103 | 104 | #ifndef SETUP_REVERSE_ITERATORS 105 | #define SETUP_REVERSE_ITERATORS(C, T, S) VGSI_SETUP_REVERSE_ITERATORS(C, T, S) 106 | #endif 107 | 108 | #ifndef SETUP_MUTABLE_RITERATOR 109 | #define SETUP_MUTABLE_RITERATOR(C, T, S) VGSI_SETUP_MUTABLE_RITERATOR(C, T, S) 110 | #endif 111 | 112 | #ifndef SETUP_CONST_RITERATOR 113 | #define SETUP_CONST_RITERATOR(C, T, S) VGSI_SETUP_CONST_RITERATOR(C, T, S) 114 | #endif 115 | 116 | #ifndef STL_TYPEDEFS 117 | #define STL_TYPEDEFS(T) VGSI_STL_TYPEDEFS(T) 118 | #endif 119 | 120 | // Forward declaration of const_iterator: 121 | template 122 | struct const_iterator; 123 | 124 | /* * * * * MUTABLE ITERATOR TEMPLATE: * * * * */ 125 | 126 | // C - The container type 127 | // T - The content type 128 | // S - The state keeping structure 129 | template 130 | // The non-specialized version is used for T=rvalue: 131 | struct iterator { 132 | // Keeps a reference to the container: 133 | C* ref; 134 | 135 | // User defined struct to describe the iterator state: 136 | // This struct should provide the functions listed below, 137 | // however, note that some of them are optional 138 | S state; 139 | 140 | // Set iterator to next() state: 141 | void next() { state.next(ref); } 142 | // Initialize iterator to first state: 143 | void begin() { state.begin(ref); } 144 | // Initialize iterator to end state: 145 | void end() { state.end(ref); } 146 | // Returns current `value` 147 | T get() { return state.get(ref); } 148 | // Return true if `state != s`: 149 | bool equals(const S& s) const { return state.equals(s); } 150 | 151 | // Optional function for reverse iteration: 152 | void prev() { state.prev(ref); } 153 | 154 | public: 155 | static iterator begin(C* ref) { 156 | iterator it(ref); 157 | it.begin(); 158 | return it; 159 | } 160 | static iterator end(C* ref) { 161 | iterator it(ref); 162 | it.end(); 163 | return it; 164 | } 165 | 166 | protected: 167 | iterator(C* ref) : ref(ref) {} 168 | 169 | public: 170 | // Note: Instances build with this constructor should 171 | // be used only after copy-assigning from other iterator! 172 | iterator() {} 173 | 174 | public: 175 | T operator*() { return get(); } 176 | iterator& operator++() { next(); return *this; } 177 | iterator operator++(int) { iterator temp(*this); next(); return temp; } 178 | iterator& operator--() { prev(); return *this; } 179 | iterator operator--(int) { iterator temp(*this); prev(); return temp; } 180 | bool operator!=(const iterator& other) const { 181 | return ref != other.ref || !equals(other.state); 182 | } 183 | bool operator==(const iterator& other) const { 184 | return !operator!=(other); 185 | } 186 | 187 | friend struct iterator_tpl::const_iterator; 188 | 189 | // Comparisons between const and normal iterators: 190 | bool operator!=(const const_iterator& other) const { 191 | return ref != other.ref || !equals(other.state); 192 | } 193 | bool operator==(const const_iterator& other) const { 194 | return !operator!=(other); 195 | } 196 | }; 197 | 198 | template 199 | // This specialization is used for iterators to reference types: 200 | struct iterator { 201 | // Keeps a reference to the container: 202 | C* ref; 203 | 204 | // User defined struct to describe the iterator state: 205 | // This struct should provide the functions listed below, 206 | // however, note that some of them are optional 207 | S state; 208 | 209 | // Set iterator to next() state: 210 | void next() { state.next(ref); } 211 | // Initialize iterator to first state: 212 | void begin() { state.begin(ref); } 213 | // Initialize iterator to end state: 214 | void end() { state.end(ref); } 215 | // Returns current `value` 216 | T& get() { return state.get(ref); } 217 | // Return true if `state != s`: 218 | bool equals(const S& s) const { return state.equals(s); } 219 | 220 | // Optional function for reverse iteration: 221 | void prev() { state.prev(ref); } 222 | 223 | public: 224 | static iterator begin(C* ref) { 225 | iterator it(ref); 226 | it.begin(); 227 | return it; 228 | } 229 | static iterator end(C* ref) { 230 | iterator it(ref); 231 | it.end(); 232 | return it; 233 | } 234 | 235 | protected: 236 | iterator(C* ref) : ref(ref) {} 237 | 238 | public: 239 | // Note: Instances build with this constructor should 240 | // be used only after copy-assigning from other iterator! 241 | iterator() {} 242 | 243 | public: 244 | T& operator*() { return get(); } 245 | T* operator->() { return &get(); } 246 | iterator& operator++() { next(); return *this; } 247 | iterator operator++(int) { iterator temp(*this); next(); return temp; } 248 | iterator& operator--() { prev(); return *this; } 249 | iterator operator--(int) { iterator temp(*this); prev(); return temp; } 250 | bool operator!=(const iterator& other) const { 251 | return ref != other.ref || !equals(other.state); 252 | } 253 | bool operator==(const iterator& other) const { 254 | return !operator!=(other); 255 | } 256 | 257 | friend struct iterator_tpl::const_iterator; 258 | 259 | // Comparisons between const and normal iterators: 260 | bool operator!=(const const_iterator& other) const { 261 | return ref != other.ref || !equals(other.state); 262 | } 263 | bool operator==(const const_iterator& other) const { 264 | return !operator!=(other); 265 | } 266 | }; 267 | 268 | /* * * * * CONST ITERATOR TEMPLATE: * * * * */ 269 | 270 | // C - The container type 271 | // T - The content type 272 | // S - The state keeping structure 273 | template 274 | // The non-specialized version is used for T=rvalue: 275 | struct const_iterator { 276 | // Keeps a reference to the container: 277 | const C* ref; 278 | 279 | // User defined struct to describe the iterator state: 280 | // This struct should provide the functions listed below, 281 | // however, note that some of them are optional 282 | S state; 283 | 284 | // Set iterator to next() state: 285 | void next() { state.next(ref); } 286 | // Initialize iterator to first state: 287 | void begin() { state.begin(ref); } 288 | // Initialize iterator to end state: 289 | void end() { state.end(ref); } 290 | // Returns current `value` 291 | const T get() { return state.get(ref); } 292 | // Return true if `state != s`: 293 | bool equals(const S& s) const { return state.equals(s); } 294 | 295 | // Optional function for reverse iteration: 296 | void prev() { state.prev(ref); } 297 | 298 | public: 299 | static const_iterator begin(const C* ref) { 300 | const_iterator it(ref); 301 | it.begin(); 302 | return it; 303 | } 304 | static const_iterator end(const C* ref) { 305 | const_iterator it(ref); 306 | it.end(); 307 | return it; 308 | } 309 | 310 | protected: 311 | const_iterator(const C* ref) : ref(ref) {} 312 | 313 | public: 314 | // Note: Instances build with this constructor should 315 | // be used only after copy-assigning from other iterator! 316 | const_iterator() {} 317 | 318 | // To make possible copy-construct non-const iterators: 319 | const_iterator(const iterator& other) : ref(other.ref) { 320 | state = other.state; 321 | } 322 | 323 | public: 324 | const T operator*() { return get(); } 325 | const_iterator& operator++() { next(); return *this; } 326 | const_iterator operator++(int) { const_iterator temp(*this); next(); return temp; } 327 | const_iterator& operator--() { prev(); return *this; } 328 | const_iterator operator--(int) { const_iterator temp(*this); prev(); return temp; } 329 | bool operator!=(const const_iterator& other) const { 330 | return ref != other.ref || !equals(other.state); 331 | } 332 | bool operator==(const const_iterator& other) const { 333 | return !operator!=(other); 334 | } 335 | const_iterator& operator=(const iterator& other) { 336 | ref = other.ref; 337 | state = other.state; 338 | return *this; 339 | } 340 | 341 | friend struct iterator_tpl::iterator; 342 | 343 | // Comparisons between const and normal iterators: 344 | bool operator!=(const iterator& other) const { 345 | return ref != other.ref || !equals(other.state); 346 | } 347 | bool operator==(const iterator& other) const { 348 | return !operator!=(other); 349 | } 350 | }; 351 | 352 | // This specialization is used for iterators to reference types: 353 | template 354 | struct const_iterator { 355 | // Keeps a reference to the container: 356 | const C* ref; 357 | 358 | // User defined struct to describe the iterator state: 359 | // This struct should provide the functions listed below, 360 | // however, note that some of them are optional 361 | S state; 362 | 363 | // Set iterator to next() state: 364 | void next() { state.next(ref); } 365 | // Initialize iterator to first state: 366 | void begin() { state.begin(ref); } 367 | // Initialize iterator to end state: 368 | void end() { state.end(ref); } 369 | // Returns current `value` 370 | const T& get() { return state.get(ref); } 371 | // Return true if `state != s`: 372 | bool equals(const S& s) const { return state.equals(s); } 373 | 374 | // Optional function for reverse iteration: 375 | void prev() { state.prev(ref); } 376 | 377 | public: 378 | static const_iterator begin(const C* ref) { 379 | const_iterator it(ref); 380 | it.begin(); 381 | return it; 382 | } 383 | static const_iterator end(const C* ref) { 384 | const_iterator it(ref); 385 | it.end(); 386 | return it; 387 | } 388 | 389 | protected: 390 | const_iterator(const C* ref) : ref(ref) {} 391 | 392 | public: 393 | // Note: Instances build with this constructor should 394 | // be used only after copy-assigning from other iterator! 395 | const_iterator() {} 396 | 397 | // To make possible copy-construct non-const iterators: 398 | const_iterator(const iterator& other) : ref(other.ref) { 399 | state = other.state; 400 | } 401 | 402 | public: 403 | const T& operator*() { return get(); } 404 | const T* operator->() { return &get(); } 405 | const_iterator& operator++() { next(); return *this; } 406 | const_iterator operator++(int) { const_iterator temp(*this); next(); return temp; } 407 | const_iterator& operator--() { prev(); return *this; } 408 | const_iterator operator--(int) { const_iterator temp(*this); prev(); return temp; } 409 | bool operator!=(const const_iterator& other) const { 410 | return ref != other.ref || !equals(other.state); 411 | } 412 | bool operator==(const const_iterator& other) const { 413 | return !operator!=(other); 414 | } 415 | const_iterator& operator=(const iterator& other) { 416 | ref = other.ref; 417 | state = other.state; 418 | return *this; 419 | } 420 | 421 | friend struct iterator_tpl::iterator; 422 | 423 | // Comparisons between const and normal iterators: 424 | bool operator!=(const iterator& other) const { 425 | return ref != other.ref || !equals(other.state); 426 | } 427 | bool operator==(const iterator& other) const { 428 | return !operator!=(other); 429 | } 430 | }; 431 | 432 | } // namespace iterator_tpl 433 | 434 | #endif 435 | --------------------------------------------------------------------------------