Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

2D resizable negative-positions Grid container

By: JaminGrey on Nov 7th, 2012  |  syntax: C++  |  size: 24.75 KB  |  views: 34  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
This paste has a previous version, view the difference. Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  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<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, Grid> iterator;
  25.     typedef GridIterator<const Type, const Grid<Type> > const_iterator;
  26.    
  27. private:
  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.         return *this;
  84.     }
  85.    
  86.     //Swaps the contents of this grid with 'other'.
  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.     {
  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.     }
  121.    
  122.     //True if the grid is 0 by 0 *and* its position is at (0,0).
  123.     bool IsNull() const
  124.     {
  125.         return this->bounds.IsNull();
  126.     }
  127.    
  128.     //================================================================
  129.    
  130.     //Resizes the grid to 'newBounds', constructing the new elements with 'value' (or the default constructor if 'value' is not set).
  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.         try
  136.         {
  137.             //[CAN THROW - Make sure no member variables are changed before these function calls]
  138.             cRect newCapacity = this->ensureCapacity(newBounds, true);
  139.            
  140.             //[CAN THROW - Make sure no member variables are changed before these function calls]
  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.             this->capacity = newCapacity;
  145.         }
  146.         catch(std::exception &exception)
  147.         {
  148.             Log::Message(MSG_SOURCE("Common", Log::Severity::Error)) << "std::exception caught, when resizing to:\n"
  149.                                                                     << "newBounds = " << Log_HighlightValue(newBounds.ToString()) << "\n"
  150.                                                                     << "exception.what() = " << Log_HighlightBad(exception.what()) << Log::FlushStream;
  151.             throw;
  152.         }
  153.         catch(...)
  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.    
  213.     //Resizes the grid. Negative values enlarge the grid.
  214.     void Shrink(int amount, const Type &value = Type())
  215.     {
  216.         this->Shrink(amount, amount, amount, amount, value);
  217.     }
  218.    
  219.     void Shrink(int horizontal, int vertical, const Type &value = Type())
  220.     {
  221.         this->Shrink(horizontal, horizontal, vertical, vertical, value);
  222.     }
  223.    
  224.     void Shrink(int left, int right, int top, int bottom, const Type &value = Type())
  225.     {
  226.         cRect newBounds = this->bounds;
  227.         newBounds.Pad(-left, -right, -top, -bottom);
  228.        
  229.         this->Resize(newBounds, value);
  230.     }
  231.    
  232.     //================================================================
  233.    
  234.     //Throws std::out_of_range if out of range.
  235.     Type &At(const cPoint &pos)
  236.     {
  237.         if(!this->bounds.Contains(pos))
  238.         {
  239.             std::string message = std::string("Grid::At() - 'pos' is not within range.\n")
  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.    
  267.     //Const version, for const_iterator.
  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.                    
  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.                 {
  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.                 }
  337.                 else
  338.                 {
  339.                     //Destruct the element we previously constructed.
  340.                     this->destruct((*this)[point]);
  341.                 }
  342.             }
  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.         for(cPoint point : oldBounds)
  351.         {
  352.             if(reducedArea.Contains(point))
  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.     void construct(Type &element, const Type &value = Type())
  368.     {
  369.         new (&element) Type(value); //Call constructor.
  370.     }
  371.    
  372.     //Constructs an element with move semantics.
  373.     void moveConstruct(Type &element, Type &&value)
  374.     {
  375.         new (&element) Type(value); //Call move constructor.
  376.     }
  377.  
  378.     //Destruct a single element.
  379.     void destruct(Type &element)
  380.     {
  381.         element.~Type(); //Call destructor.
  382.     }
  383.    
  384.     //Destructs multiple elements in a block of memory.
  385.     void destructBounds(Type *memory, const cRect &capacity, const cRect &bounds)
  386.     {
  387.         //The initial offset of the actual bounds from the memory capacity.
  388.         size_t offset = capacity.Index(bounds.position);
  389.        
  390.         //Destruct all the old elements.
  391.         for(cPoint pos : bounds.size)
  392.         {
  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.    
  403.     //================================================================
  404.    
  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.             cRect desiredCapacity = bounds;
  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.                 int quarterWidth = (bounds.size.width / 4) + 1;
  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.         ::operator delete(data);
  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.     void reallocateMemory(const cRect &newCapacity)
  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.         }
  466.         else if(newCapacity.IsEmpty())
  467.         {
  468.             //Destruct all the old elements.
  469.             this->destructBounds(this->memory, this->capacity, this->bounds);
  470.            
  471.             //Free all the memory.
  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.             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.             //[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.             this->memory = newMemory.release();
  496.         }
  497.        
  498.         //Record the new capacity.
  499.         this->capacity = newCapacity;
  500.     }
  501.    
  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.         //Assert that neither block of memory's size is empty (they have to have a positive non-zero width and height).
  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