# smallmatrix_type.hpp

Go to the documentation of this file.

    00001 /* $Id: smallmatrix_type.hpp 25256 2013-05-19 14:06:26Z rubidium $ */
    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 */