View difference between Paste ID: rJv7PVxm and ky4itKsj
SHOW: | | - or go back to the newest paste.
1
#ifndef COMMON_CONTAINERS_GRID_H
2
#define COMMON_CONTAINERS_GRID_H
3
4
#include "Common/Basics.h"
5
6
#include <utility> //For std::move()
7
#include <stdexcept> //For std::out_of_range exception.
8
9
class cPoint;
10
class cRect;
11
12
namespace Common {
13
14-
template<class Type> class GridIterator;
14+
template<typename Type, typename ContainerType> class GridIterator;
15
16
/*
17
    A resizable 2D array container, that resizes without harming the relative location of the elements held
18
    by the container, and supports negative indices, like a 2D Cartesian grid.
19
*/
20
template<typename Type>
21
class Grid
22
{
23
public:
24-
    typedef GridIterator<Type> iterator;
24+
    typedef GridIterator<Type, Grid> iterator;
25
    typedef GridIterator<const Type, const Grid<Type> > const_iterator;
26
    
27-
    Grid() : memory(nullptr), boundsOffset(0)
27+
28
    enum CopyMode {MoveConstructor, CopyConstructor};
29
    
30
public:
31
    Grid() : memory(nullptr)
32
    {   }
33
    
34
    //Construct and call Resize().
35
    Grid(const cRect &newBounds, const Type &value = Type()) : memory(nullptr)
36
    {
37
        this->Resize(newBounds, value);
38
    }
39
    
40
    ~Grid()
41
    {
42
        //Clear the grid, calling the destructors on any constructed elements.
43
        this->Clear();
44
        
45
        //Deallocate any reserved memory.
46
        this->deallocate(this->memory);
47
    }
48
    
49
    //Copy constructor.
50
    Grid(const Grid &other) : memory(nullptr)
51
    {
52
        //Note: Both Reserve() and copyElements() can throw exceptions. If they succeed properly, they will save the new state
53
        //to member-variables - but no member-variables should be manually altered within this function before their call.
54
        
55
        //Reserve enough memory.
56
        this->Reserve(other.capacity);
57
        
58
        //Copy-construct the elements.
59
        this->copyElements(other.memory, other.capacity, this->memory, this->capacity, other.bounds, CopyMode::CopyConstructor);
60
        
61
        //Save the new bounds (once we are sure copyElements() didn't throw).
62
        this->bounds = other.bounds;
63
    }
64
    
65
    //Move constructor.
66
    Grid(Grid &&other) : memory(nullptr)
67
    {
68
        this->operator=(std::forward<Grid>(other));
69
    }
70
    
71
    //Assignment operator
72
    Grid &operator=(const Grid &other)
73
    {
74
        Grid<Type> temp(other);
75
        this->Swap(temp);
76
        return *this;
77
    }
78
    
79
    //Move-assignment.
80
    Grid &operator=(Grid &&other)
81
    {
82
        this->Swap(other);
83-
        this->ensureCapacity(newBounds, true);
83+
84-
        this->constructAdditions(this->bounds, newBounds, value);
84+
85
    
86
    //Swaps the contents of this grid with 'other'.
87-
        this->boundsOffset = this->capacity.Index(this->bounds.position);
87+
    void Swap(Grid &other) throw()
88
    {
89
        //Swap pointers.
90
        std::swap(this->memory, other.memory);
91
        
92
        //Swap bounds and capacity.
93
        std::swap(this->bounds, other.bounds);
94
        std::swap(this->capacity, other.capacity);
95
    }
96
    
97
    //================================================================
98
    
99
    //Erases the grid, resetting the bounds to (0,0,0,0).
100
    //Does not free the reserved capacity. Call Conserve() afterward to do that.
101
    void Clear()
102-
        this->ensureCapacity(newCapacity, false);
102+
103
        this->Resize(cRect(0,0,0,0));
104
    }
105
    
106
    //Resets the grid to (0,0,0,0) and releases the reserved memory as well.
107
    //This is the same as calling Clear() followed by Conserve().
108
    void Reset()
109
    {
110
        this->Clear();
111
        this->Conserve();
112
    }
113
    
114
    //================================================================
115
    
116
    //Returns true if the width *or* the height (or both) of the grid is 0, *even* if its position is *not* at (0,0).
117
    bool IsEmpty() const
118
    {
119
        return this->bounds.IsEmpty();
120-
    void Expand(int amount)
120+
121
    
122-
        this->Expand(amount, amount, amount, amount);
122+
123
    bool IsNull() const
124
    {
125-
    void Expand(int horizontal, int vertical)
125+
126
    }
127-
        this->Expand(horizontal, horizontal, vertical, vertical);
127+
128
    //================================================================
129
    
130-
    void Expand(int left, int right, int top, int bottom)
130+
131
    //If Grid doesn't have enough capacity, it'll reallocate storage and move the elements to new memory addresses.
132
    //Throws std::bad_alloc if the allocation failed, and rethrows any exceptions thrown by element constructors or destructors.
133
    void Resize(const cRect &newBounds, const Type &value = Type())
134
    {
135-
        this->Resize(newBounds);
135+
        try
136
        {
137
            //[CAN THROW - Make sure no member variables are changed before these function calls]
138
            cRect newCapacity = this->ensureCapacity(newBounds, true);
139-
    void Shrink(int amount)
139+
140
            //[CAN THROW - Make sure no member variables are changed before these function calls]
141-
        this->Shrink(amount, amount, amount, amount);
141+
            this->constructAdditions(this->bounds, newBounds, value);
142
            
143
            //Record the new capacity, after we are sure no exceptions were thrown and everything succeeded.
144-
    void Shrink(int horizontal, int vertical)
144+
            this->capacity = newCapacity;
145
        }
146-
        this->Shrink(horizontal, horizontal, vertical, vertical);
146+
        catch(std::exception &exception)
147
        {
148
            Log::Message(MSG_SOURCE("Common", Log::Severity::Error)) << "std::exception caught, when resizing to:\n"
149-
    void Shrink(int left, int right, int top, int bottom)
149+
                                                                    << "newBounds = " << Log_HighlightValue(newBounds.ToString()) << "\n"
150
                                                                    << "exception.what() = " << Log_HighlightBad(exception.what()) << Log::FlushStream;
151
            throw;
152
        }
153
        catch(...)
154-
        this->Resize(newBounds);
154+
155
            Log::Message(MSG_SOURCE("Common", Log::Severity::Error)) << "Unknown exception caught, when resizing to:\n"
156
                                       << "newBounds = " << Log_HighlightValue(newBounds.ToString()) << Log::FlushStream;
157
            throw;
158
        }
159
160
        this->bounds = newBounds;
161
    }
162
163
    const cRect &GetBounds() const
164
    {
165
        return this->bounds;
166
    }
167
    
168
    //================================================================
169
    
170
    //Reserves 'newCapacity' amount of memory, without actually resizing the grid. This will reallocate the memory and move the elements to new addresses.
171
    //Reserve() will not allow the grid to shrink smaller than the capacity currently is reserved to.
172
    //Throws std::bad_alloc if the allocation failed, and rethrows any exceptions thrown by element constructors.
173
    void Reserve(const cRect &newCapacity)
174
    {
175
        //[CAN THROW - Make sure no member variables are changed before this function call]
176
        this->capacity = this->ensureCapacity(newCapacity, false);
177
    }
178
    
179
    //Releases all capacity that is no longer needed. This will reallocate the memory and move the elements to new addresses.
180
    void Conserve()
181
    {
182
        //[CAN THROW - Make sure no member variables are changed before this function call]
183
        this->reallocateMemory(this->bounds);
184
    }
185
    
186
    //Returns the amount of memory held in reserve for future resizing.
187
    const cRect &GetCapacity() const
188
    {
189
        return this->capacity;
190
    }
191
    
192
    //================================================================
193
    
194
    //Resizes the grid. Negative values shrink the grid.
195
    void Expand(int amount, const Type &value = Type())
196
    {
197
        this->Expand(amount, amount, amount, amount, value);
198
    }
199
    
200
    void Expand(int horizontal, int vertical, const Type &value = Type())
201
    {
202
        this->Expand(horizontal, horizontal, vertical, vertical, value);
203
    }
204
    
205
    void Expand(int left, int right, int top, int bottom, const Type &value = Type())
206
    {
207
        cRect newBounds = this->bounds;
208
        newBounds.Pad(left, right, top, bottom);
209
        
210
        this->Resize(newBounds, value);
211
    }
212-
        size_t constructed = 0, destructed = 0, preserved = 0, ignored = 0;
212+
213
    //Resizes the grid. Negative values enlarge the grid.
214-
        for(cPoint point : totalArea)
214+
    void Shrink(int amount, const Type &value = Type())
215
    {
216
        this->Shrink(amount, amount, amount, amount, value);
217
    }
218-
                //Do nothing - this area is already constructed.
218+
219-
                preserved++;
219+
    void Shrink(int horizontal, int vertical, const Type &value = Type())
220
    {
221-
            else if(newBounds.Contains(point))
221+
        this->Shrink(horizontal, horizontal, vertical, vertical, value);
222
    }
223-
                //Needs to be constructed.
223+
224-
                this->construct((*this)[point], value);
224+
    void Shrink(int left, int right, int top, int bottom, const Type &value = Type())
225
    {
226-
                constructed++;
226+
227
        newBounds.Pad(-left, -right, -top, -bottom);
228-
            else if(oldBounds.Contains(point))
228+
229
        this->Resize(newBounds, value);
230
    }
231
    
232
    //================================================================
233-
                destructed++;
233+
234
    //Throws std::out_of_range if out of range.
235
    Type &At(const cPoint &pos)
236
    {
237-
                //Do nothing - this area is already destructed.
237+
238
        {
239-
                ignored++;
239+
240
                                + "\t'pos' = " + pos.ToString()
241
                                + "\n\t'bounds' = " + this->bounds.ToString();
242
            
243
            throw std::out_of_range(message);
244
        }
245
        
246
        return (*this)[pos];
247
    }
248
249
    //Doesn't check for range.
250
    Type &operator[](const cPoint &pos)
251
    {
252
        //Convert the point to a index into the memory.
253
        size_t index = this->capacity.Index(pos);
254
        
255
        return this->memory[index];
256
    }
257
258
    //Doesn't check for range. Index-based lookup for iteration (from index '0' to "this->bounds: (width * height)").
259
    Type &AtIndex(unsigned index)
260
    {
261
        cPoint pos = this->bounds.FromIndex(index);
262
        int newIndex = this->capacity.Index(std::move(pos));
263
        
264
        return this->memory[newIndex];
265
    }
266-
    //Ensures *at least* enough room for 'bounds'.
266+
267
    //Const version, for const_iterator.
268-
    void ensureCapacity(const cRect &bounds, bool addExtra)
268+
    const Type &AtIndex(unsigned index) const
269
    {
270
        cPoint pos = this->bounds.FromIndex(index);
271
        int newIndex = this->capacity.Index(std::move(pos));
272
        
273
        return this->memory[newIndex];
274
    }
275
    
276
    //================================================================
277
    
278
    iterator begin()
279
    { return iterator(*this, 0); }
280
    iterator end()
281
    { return iterator(*this, this->bounds.Area()); }
282
    
283
    const_iterator begin() const
284
    { return const_iterator(*this, 0); }
285
    const_iterator end() const
286
    { return const_iterator(*this, this->bounds.Area()); }
287
    
288
    //================================================================
289
    
290
private:
291
    //Constructs all the new elements between oldBounds and newBounds setting them to 'value'.
292
    //If 'newBounds' is smaller than 'oldBounds', deconstructs the old elements.
293
    void constructAdditions(const cRect &oldBounds, const cRect &newBounds, const Type &value = Type())
294
    {
295
        //The largest extent of both rects.
296
        cRect totalArea = cRect::Encompassing(oldBounds, newBounds);
297
        //The overlapping portion of both rects (if any).
298
        cRect reducedArea = cRect::Intersection(oldBounds, newBounds);
299
        
300
        //-------------------------------------------
301
        
302
        //If a constructor throws an exception, we want to know which element it was,
303
        //so we keep track of what the last point was before the exception was thrown.
304
        cPoint lastPoint;
305
        
306
        try
307
        {
308
            for(cPoint point : newBounds)
309
            {
310
                if(reducedArea.Contains(point))
311
                {
312
                    //Do nothing - this area is already constructed.
313
                }
314
                else
315
                {
316
                    lastPoint = point;
317-
           this->memory = this->allocate(newCapacity);
317+
                    
318
                    //Needs to be constructed.
319
                    this->construct((*this)[point], value);
320
                }
321
            }
322
        }
323
        catch(...)
324
        {
325
            //Since we caught an exception, destruct every element we had previously constructed.
326
            for(cPoint point : newBounds)
327
            {
328
                if(reducedArea.Contains(point))
329-
            Type *newMemory = this->allocate(newCapacity);
329+
                {
330
                    //Do nothing - this area is already constructed.
331
                }
332
                else if(point == lastPoint)
333
                {
334
                    //Stop here - we didn't construct anything beyond this element.
335
                    break;
336-
            this->moveElements(oldMemory, oldCapacity, newMemory, newCapacity, this->bounds);
336+
                }
337
                else
338
                {
339
                    //Destruct the element we previously constructed.
340-
            oldMemory = nullptr;
340+
                    this->destruct((*this)[point]);
341
                }
342-
            //And store the new pointer.
342+
343-
            this->memory = newMemory;
343+
344
            throw;
345
        }
346
        
347
        //-------------------------------------------
348
        
349
        //Destruct any elements that we no longer want (if we're resizing smaller than our previous size).
350-
    //Called by 'reallocateMemory' only.
350+
        for(cPoint point : oldBounds)
351-
    void moveElements(Type *oldMemory, const cRect &oldCapacity, Type *newMemory,
351+
352-
                      const cRect &newCapacity, const cRect &bounds)
352+
353
            {
354
                //Do nothing - we're preserving these elements.
355
            }
356
            else
357
            {
358
                //Needs to be destructed.
359
                this->destruct((*this)[point]);
360
            }
361
        }
362
    }
363
    
364
    //================================================================
365
    
366
    //Construct a single element.
367-
        //The length of each 'row' of the grid's capacity in memory.
367+
368-
        size_t oldStride = oldCapacity.size.width;
368+
369-
        size_t newStride = newCapacity.size.width;
369+
370
    } 
371
    
372
    //Constructs an element with move semantics.
373
    void moveConstruct(Type &element, Type &&value)
374
    {
375-
        //The number of rows and columns of actual elements we need to move.
375+
376-
        size_t rows = bounds.size.height;
376+
377-
        size_t columns = bounds.size.width;
377+
378
    //Destruct a single element.
379-
        for(size_t row = 0; row < rows; row++)
379+
380
    {
381-
            for(size_t column = 0; column < columns; column++)
381+
382
    }
383-
                size_t oldIndex = (row * oldStride) + column;
383+
384
    //Destructs multiple elements in a block of memory.
385
    void destructBounds(Type *memory, const cRect &capacity, const cRect &bounds)
386-
                size_t newIndex = (row * newStride) + column;
386+
387
        //The initial offset of the actual bounds from the memory capacity.
388
        size_t offset = capacity.Index(bounds.position);
389-
                //Construct the new location, and move the element.
389+
390-
                this->moveConstruct(newMemory[newIndex], std::move(oldMemory[oldIndex]));
390+
        //Destruct all the old elements.
391
        for(cPoint pos : bounds.size)
392-
                //Destruct old location.
392+
393-
                this->destruct(oldMemory[oldIndex]);
393+
            //Convert to position in the bound's area (from {0,0} to {width, height})
394
            //to the actual location in the memory capacity.
395
            size_t index = (pos.y * capacity.size.width) + pos.x;
396
            index += offset;
397
            
398
            //Destruct the element we constructed in the previous for() loops.
399
            this->destruct(memory[index]);
400
        }
401
    }
402-
    unsigned int boundsOffset; //The offset of 'bounds' within 'capacity'. Only used for AtIndex, for faster iteration.
402+
403
    //================================================================
404-
    cRect bounds; //Current grid boundries.
404+
405-
    cRect capacity; //Currently allocated memory capacity, garunteed to be at least 'bounds' and maybe larger.
405+
    //Ensures *at least* enough room for 'bounds'. Returns the resulting capacity.
406
    //If 'addExtra' is true, includes even more capacity for future growth.
407
    cRect ensureCapacity(const cRect &bounds, bool addExtra)
408
    {
409
        //Check whether we have enough capacity to resize.
410
        if(!this->capacity.Contains(bounds))
411
        {
412-
//A random-access iterator for iterating over each element of a Common::Grid.
412+
413-
template <typename Type>
413+
414
            if(addExtra)
415
            {
416
                //If we're bothering to grow in size, we might as well reserve a little extra for future growth.
417-
    GridIterator(Common::Grid<Type> &grid, unsigned index) : grid(grid), index(index)
417+
418
                int quarterHeight = (bounds.size.height / 4) + 1;
419
                
420
                desiredCapacity.Pad(quarterWidth, quarterWidth, quarterHeight, quarterHeight);
421
            }
422
            
423
            //Allocate and move the elements.
424
            //[CAN THROW - Make sure no member variables are changed before this function call]
425
            this->reallocateMemory(desiredCapacity);
426
            
427
            //Return the new capacity.
428
            return desiredCapacity;
429
        }
430
        
431
        //Return the current capacity.
432
        return this->capacity;
433
    }    
434
    
435
    //================================================================
436
    
437
    //This allocates enough memory for 'capacity', without constructing any elements.
438
    Type *allocate(const cRect &capacity)
439
    {
440
        //Allocate the new memory.
441
        size_t numElements = capacity.size.Area();
442
        size_t numBytes = (sizeof(Type) * numElements);
443
        void *data = ::operator new(numBytes);
444
        
445
        return static_cast<Type*>(data);
446
    }
447
    
448
    //This deallocates 'memory', without calling any destructors.
449
    void deallocate(Type *data)
450
    {
451-
    GridIterator &operator++()
451+
452
    }
453
    
454
    //================================================================
455
    
456
    //Reallocates the memory and migrates the elements over using moveElements().
457
    //Throws std::bad_alloc if the allocation failed, and throws any exceptions thrown by element constructors.
458-
    GridIterator operator++(int)
458+
459
    {
460
        if(!this->memory)
461
        {
462
            //If we don't have any memory, just allocate some and don't worry about moving any elements.
463
            //[CAN THROW - Make sure no member variables are changed before this function call]
464
            this->memory = this->allocate(newCapacity);
465-
    GridIterator &operator--()
465+
466
        else if(newCapacity.IsEmpty())
467
        {
468
            //Destruct all the old elements.
469
            this->destructBounds(this->memory, this->capacity, this->bounds);
470
            
471-
    GridIterator operator--(int)
471+
472
            this->deallocate(this->memory);
473
            this->memory = nullptr;
474
        }
475
        else
476
        {
477
            //Allocate the new memory.
478
            //Note: I put the allocated memory into a unique_ptr here, incase moveElements() throws.
479
            //This way, the new memory is properly released.
480
            //[CAN THROW - Make sure no member variables are changed before this function call]
481-
    GridIterator operator+(int n)
481+
            std::unique_ptr<Type, use_operator_delete> newMemory(this->allocate(newCapacity));
482
483
            //A few extra variables for readability.
484
            Type *oldMemory = this->memory;
485
            const cRect &oldCapacity = this->capacity;
486
            
487
            //Move the elements.
488-
    GridIterator &operator+=(int n)
488+
            //[CAN THROW - Make sure no member variables are changed before this function call]
489
            this->copyElements(oldMemory, oldCapacity, newMemory.get(), newCapacity, this->bounds, CopyMode::MoveConstructor);
490
491
            //Delete the old memory.
492
            this->deallocate(oldMemory);
493
            
494
            //And store the new pointer. Have the unique_ptr release ownership of the memory as well.
495-
    GridIterator operator-(int n)
495+
            this->memory = newMemory.release();
496
        }
497
        
498
        //Record the new capacity.
499
        this->capacity = newCapacity;
500
    }
501
    
502-
    GridIterator &operator-=(int n)
502+
    //Called by 'reallocateMemory' and the copy-constructor.
503
    void copyElements(Type *oldMemory, const cRect &oldCapacity, Type *newMemory,
504
                      const cRect &newCapacity, const cRect &bounds, CopyMode copyMode = CopyMode::CopyConstructor)
505
    {
506
        //Insanity preservation.
507
        //Assert that our elements are actually within the capacity of both the new and old blocks of memory.
508
        BOOST_ASSERT(oldCapacity.Contains(bounds));
509
        BOOST_ASSERT(newCapacity.Contains(bounds));
510
        
511-
    Common::Grid<Type> &grid;
511+
512
        BOOST_ASSERT(!oldCapacity.IsEmpty());
513
        BOOST_ASSERT(!newCapacity.IsEmpty());
514
        
515
        //Assert that neither pointer to the allocated memory is empty.
516
        BOOST_ASSERT(oldMemory != nullptr);
517
        BOOST_ASSERT(newMemory != nullptr);
518
        
519
        //=================================================================
520
        
521
        //The initial offset of the actual bounds from the memory capacity.
522
        size_t oldOffset = oldCapacity.Index(bounds.position);
523
        size_t newOffset = newCapacity.Index(bounds.position);
524
        
525
        //Incase a constructor throws an exception, keep track of the last position we successfully constructed.
526
        cPoint lastPos;
527
        
528
        try
529
        {
530
            //Move-construct all the new elements.
531
            for(cPoint pos : bounds.size)
532
            {
533
                lastPos = pos;
534
                
535
                //Convert to position in the bound's area (from {0,0} to {width, height})
536
                //to the actual location in the memory capacity.
537
                size_t oldIndex = (pos.y * oldCapacity.size.width) + pos.x;
538
                oldIndex += oldOffset;
539
                
540
                size_t newIndex = (pos.y * newCapacity.size.width) + pos.x;
541
                newIndex += newOffset;
542
                
543
                //Construct the new location.
544
                if(copyMode == CopyMode::MoveConstructor)
545
                {
546
                    //Move-constructor.
547
                    this->moveConstruct(newMemory[newIndex], std::move(oldMemory[oldIndex]));
548
                }
549
                else
550
                {
551
                    //Copy-constructor.
552
                    this->construct(newMemory[newIndex], oldMemory[oldIndex]);
553
                }
554
            }
555
        }
556
        catch(...)
557
        {
558
            //Since we just caught an exception thrown from one of the element move-constructors,
559
            //destruct all the new elements we just constructed, up until the failed constructor.
560
            for(cPoint pos : bounds.size)
561
            {
562
                if(pos == lastPos)
563
                    break;
564
                
565
                //Convert to position in the bound's area (from {0,0} to {width, height})
566
                //to the actual location in the memory capacity.
567
                size_t newIndex = (pos.y * newCapacity.size.width) + pos.x;
568
                newIndex += newOffset;
569
                
570
                //Destruct the element we constructed in the previous for() loops.
571
                this->destruct(newMemory[newIndex]);
572
            }
573
            
574
            throw;
575
        }
576
        
577
        //Destruct all the old elements, unless we are copying and not moving.
578
        if(copyMode == CopyMode::MoveConstructor)
579
        {
580
            this->destructBounds(oldMemory, oldCapacity, bounds);
581
        }
582
    }
583
584
    //================================================================
585
    
586
private:
587
    Type *memory;
588
    
589
    cRect bounds; //Current grid boundaries.
590
    cRect capacity; //Currently allocated memory capacity, guaranteed to be at least 'bounds' and maybe larger.
591
};
592
593
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
594
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX//
595
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
596
597
/*
598
    A random-access iterator for iterating over each element of a Common::Grid.
599
600
    I'm doing a trick here, by taking the type of the container as a second template parameter.
601
    This allows me to do this:
602
        typedef GridIterator<const Type, const Grid<Type> > const_iterator;
603
    
604
    ...instead of having to create two seperate iterator classes (one for regular iterator and one for const).
605
*/
606
template <typename Type, typename ContainerType = typename Common::Grid<Type> >
607
class GridIterator
608
{
609
public: 
610
    GridIterator(ContainerType &grid, unsigned index) : grid(grid), index(index)
611
    {
612
        this->maxIndex = this->grid.GetBounds().Area();
613
    }
614
    
615
    //================================================================
616
    
617
    //De-reference.
618
    Type &operator*()
619
    {
620
        return this->grid.AtIndex(this->index);
621
    }
622
    Type &operator->()
623
    {
624
        return (operator*());
625
    }
626
    
627
    //================================================================
628
    
629
    //Comparison.
630
    bool operator==(const GridIterator &other) const
631
    {
632
        return (&this->grid == &other.grid) && (this->index == other.index);
633
    }
634
    
635
    bool operator!=(const GridIterator &other) const
636
    {
637
        return !operator==(other);
638
    }
639
    
640
    //================================================================
641
    
642
    //Increment/decrement.
643
    GridIterator &operator++() 
644
    {
645
        this->index++;
646
        Limit(this->index, this->maxIndex);
647
        return *this;
648
    }
649
    
650
    GridIterator operator++(int) 
651
    {
652
        GridIterator temp(*this);
653
        ++(*this);
654
        return temp;
655
    }
656
    
657
    GridIterator &operator--() 
658
    {
659
        this->index--;
660
        return *this;
661
    }
662
    
663
    GridIterator operator--(int) 
664
    {
665
        GridIterator temp(*this);
666
        --(*this);
667
        return temp;
668
    }
669
    
670
    //================================================================
671
672
    //Random access.
673
    GridIterator operator+(int n) const
674
    {
675
        GridIterator temp(*this);
676
        temp.index += n;
677
        return temp;
678
    }
679
    
680
    GridIterator &operator+=(int n) 
681
    {
682
        this->index += n;
683
        Limit(this->index, this->maxIndex);
684
        return *this;
685
    }
686
    
687
    GridIterator operator-(int n) const
688
    {
689
        GridIterator temp(*this);
690
        temp.index -= n;
691
        return temp;
692
    }
693
    
694
    GridIterator &operator-=(int n) 
695
    {
696
        this->index -= n;
697
        return *this;
698
    }
699
    
700
    //================================================================
701
    
702
private:
703
    ContainerType &grid;
704
705
    unsigned index; //The current index.
706
    unsigned maxIndex; //The maximum value (and the result returned by 'std::end()'.
707
};
708
709
//================================================================
710
711
} //End of namespace.
712
713
#endif // COMMON_CONTAINERS_GRID_H