smallmatrix_type.hpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #ifndef SMALLMATRIX_TYPE_HPP
00013 #define SMALLMATRIX_TYPE_HPP
00014 
00015 #include "alloc_func.hpp"
00016 #include "mem_func.hpp"
00017 
00039 template <typename T>
00040 class SmallMatrix {
00041 protected:
00042   T *data;
00043   uint width;
00044   uint height;
00045   uint capacity;
00046 
00047 public:
00048 
00049   SmallMatrix() : data(NULL), width(0), height(0), capacity(0) {}
00050 
00055   SmallMatrix(const SmallMatrix &other) : data(NULL), width(0), height(0), capacity(0)
00056   {
00057     this->Assign(other);
00058   }
00059 
00060   ~SmallMatrix()
00061   {
00062     free(this->data);
00063   }
00064 
00069   SmallMatrix &operator=(const SmallMatrix &other)
00070   {
00071     this->Assign(other);
00072     return *this;
00073   }
00074 
00078   inline void Assign(const SmallMatrix &other)
00079   {
00080     if (&other == this) return;
00081 
00082     this->height = other.Height();
00083     this->width = other.Width();
00084     uint num_items = this->width * this->height;
00085     if (num_items > this->capacity) {
00086       this->capacity = num_items;
00087       free(this->data);
00088       this->data = MallocT<T>(num_items);
00089       MemCpyT(this->data, other[0], num_items);
00090     } else if (num_items > 0) {
00091       MemCpyT(this->data, other[0], num_items);
00092     }
00093   }
00094 
00098   inline void Clear()
00099   {
00100     /* In fact we just reset the width avoiding the need to
00101      * probably reallocate the same amount of memory the matrix was
00102      * previously using. */
00103     this->width = 0;
00104   }
00105 
00109   inline void Reset()
00110   {
00111     this->height = 0;
00112     this->width = 0;
00113     this->capacity = 0;
00114     free(this->data);
00115     this->data = NULL;
00116   }
00117 
00121   inline void Compact()
00122   {
00123     uint capacity = this->height * this->width;
00124     if (capacity >= this->capacity) return;
00125     this->capacity = capacity;
00126     this->data = ReallocT(this->data, this->capacity);
00127   }
00128 
00133   void EraseColumn(uint x)
00134   {
00135     if (x < --this->width) {
00136       MemCpyT<T>(this->data + x * this->height,
00137           this->data + this->width * this->height,
00138           this->height);
00139     }
00140   }
00141 
00147   void EraseColumnPreservingOrder(uint x, uint count = 1)
00148   {
00149     if (count == 0) return;
00150     assert(x < this->width);
00151     assert(x + count <= this->width);
00152     this->width -= count;
00153     uint to_move = (this->width - x) * this->height;
00154     if (to_move > 0) {
00155       MemMoveT(this->data + x * this->height,
00156           this->data + (x + count) * this->height, to_move);
00157     }
00158   }
00159 
00164   void EraseRow(uint y)
00165   {
00166     if (y < this->height - 1) {
00167       for (uint x = 0; x < this->width; ++x) {
00168         this->data[x * this->height + y] =
00169             this->data[(x + 1) * this->height - 1];
00170       }
00171     }
00172     this->Resize(this->width, this->height - 1);
00173   }
00174 
00180   void EraseRowPreservingOrder(uint y, uint count = 1)
00181   {
00182     if (this->height > count + y) {
00183       for (uint x = 0; x < this->width; ++x) {
00184         MemMoveT(this->data + x * this->height + y,
00185             this->data + x * this->height + y + count,
00186             this->height - count - y);
00187       }
00188     }
00189     this->Resize(this->width, this->height - count);
00190   }
00191 
00196   inline void AppendRow(uint to_add = 1)
00197   {
00198     this->Resize(this->width, to_add + this->height);
00199   }
00200 
00205   inline void AppendColumn(uint to_add = 1)
00206   {
00207     this->Resize(to_add + this->width, this->height);
00208   }
00209 
00216   inline void Resize(uint new_width, uint new_height)
00217   {
00218     uint new_capacity = new_width * new_height;
00219     T *new_data = NULL;
00220     void (*copy)(T *dest, const T *src, size_t count) = NULL;
00221     if (new_capacity > this->capacity) {
00222       /* If the data doesn't fit into current capacity, resize and copy ... */
00223       new_data = MallocT<T>(new_capacity);
00224       copy = &MemCpyT<T>;
00225     } else {
00226       /* ... otherwise just move the columns around, if necessary. */
00227       new_data = this->data;
00228       copy = &MemMoveT<T>;
00229     }
00230     if (this->height != new_height || new_data != this->data) {
00231       if (this->height > 0) {
00232         if (new_height > this->height) {
00233           /* If matrix is growing, copy from the back to avoid
00234            * overwriting uncopied data. */
00235           for (uint x = this->width; x > 0; --x) {
00236             if (x * new_height > new_capacity) continue;
00237             (*copy)(new_data + (x - 1) * new_height,
00238                 this->data + (x - 1) * this->height,
00239                 min(this->height, new_height));
00240           }
00241         } else {
00242           /* If matrix is shrinking copy from the front. */
00243           for (uint x = 0; x < this->width; ++x) {
00244             if ((x + 1) * new_height > new_capacity) break;
00245             (*copy)(new_data + x * new_height,
00246                 this->data + x * this->height,
00247                 min(this->height, new_height));
00248           }
00249         }
00250       }
00251       this->height = new_height;
00252       if (new_data != this->data) {
00253         free(this->data);
00254         this->data = new_data;
00255         this->capacity = new_capacity;
00256       }
00257     }
00258     this->width = new_width;
00259   }
00260 
00261   inline uint Height() const
00262   {
00263     return this->height;
00264   }
00265 
00266   inline uint Width() const
00267   {
00268     return this->width;
00269   }
00270 
00278   inline const T &Get(uint x, uint y) const
00279   {
00280     assert(x < this->width && y < this->height);
00281     return this->data[x * this->height + y];
00282   }
00283 
00291   inline T &Get(uint x, uint y)
00292   {
00293     assert(x < this->width && y < this->height);
00294     return this->data[x * this->height + y];
00295   }
00296 
00303   inline const T *operator[](uint x) const
00304   {
00305     assert(x < this->width);
00306     return this->data + x * this->height;
00307   }
00308 
00315   inline T *operator[](uint x)
00316   {
00317     assert(x < this->width);
00318     return this->data + x * this->height;
00319   }
00320 };
00321 
00322 #endif /* SMALLMATRIX_TYPE_HPP */