# smallstack_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 SMALLSTACK_TYPE_HPP
    00013 #define SMALLSTACK_TYPE_HPP
    00014
    00015 #include "smallvec_type.hpp"
    00016 #include "../thread/thread.h"
    00017
    00023 template<typename Titem, typename Tindex, Tindex Tgrowth_step, Tindex Tmax_size>
    00024 class SimplePool {
    00025 public:
    00026   inline SimplePool() : first_unused(0), first_free(0), mutex(ThreadMutex::New()) {}
    00027   inline ~SimplePool() { delete this->mutex; }
    00028
    00034   inline ThreadMutex *GetMutex() { return this->mutex; }
    00035
    00040   inline Titem &Get(Tindex index) { return this->data[index]; }
    00041
    00046   inline Tindex Create()
    00047   {
    00048     Tindex index = this->FindFirstFree();
    00049     if (index < Tmax_size) {
    00050       this->data[index].valid = true;
    00051       this->first_free = index + 1;
    00052       this->first_unused = max(this->first_unused, this->first_free);
    00053     }
    00054     return index;
    00055   }
    00056
    00061   inline void Destroy(Tindex index)
    00062   {
    00063     this->data[index].valid = false;
    00064     this->first_free = min(this->first_free, index);
    00065   }
    00066
    00067 private:
    00068
    00069   inline Tindex FindFirstFree()
    00070   {
    00071     Tindex index = this->first_free;
    00072     for (; index < this->first_unused; index++) {
    00073       if (!this->data[index].valid) return index;
    00074     }
    00075
    00076     if (index >= this->data.Length() && index < Tmax_size) {
    00077       this->data.Resize(index + 1);
    00078     }
    00079     return index;
    00080   }
    00081
    00082   struct SimplePoolPoolItem : public Titem {
    00083     bool valid;
    00084   };
    00085
    00086   Tindex first_unused;
    00087   Tindex first_free;
    00088
    00089   ThreadMutex *mutex;
    00090   SmallVector<SimplePoolPoolItem, Tgrowth_step> data;
    00091 };
    00092
    00097 template <typename Titem, typename Tindex>
    00098 struct SmallStackItem {
    00099   Tindex next;
    00100   Titem value;
    00101
    00107   inline SmallStackItem(const Titem &value, Tindex next) :
    00108     next(next), value(value) {}
    00109 };
    00110
    00137 template <typename Titem, typename Tindex, Titem Tinvalid, Tindex Tgrowth_step, Tindex Tmax_size>
    00138 class SmallStack : public SmallStackItem<Titem, Tindex> {
    00139 public:
    00140
    00141   typedef SmallStackItem<Titem, Tindex> Item;
    00142
    00146   struct PooledSmallStack : public Item {
    00147     Tindex branch_count;
    00148   };
    00149
    00150   typedef SimplePool<PooledSmallStack, Tindex, Tgrowth_step, Tmax_size> SmallStackPool;
    00151
    00156   inline SmallStack(const Titem &value = Tinvalid) : Item(value, Tmax_size) {}
    00157
    00161   inline ~SmallStack()
    00162   {
    00163     /* Pop() locks the mutex and after each pop the pool is consistent.*/
    00164     while (this->next != Tmax_size) this->Pop();
    00165   }
    00166
    00171   inline SmallStack(const SmallStack &other) : Item(other) { this->Branch(); }
    00172
    00178   inline SmallStack &operator=(const SmallStack &other)
    00179   {
    00180     if (this == &other) return *this;
    00181     while (this->next != Tmax_size) this->Pop();
    00182     this->next = other.next;
    00183     this->value = other.value;
    00184     /* Deleting and branching are independent operations, so it's fine to
    00185      * acquire separate locks for them. */
    00186     this->Branch();
    00187     return *this;
    00188   }
    00189
    00195   inline void Push(const Titem &item)
    00196   {
    00197     if (this->value != Tinvalid) {
    00198       ThreadMutexLocker lock(_pool.GetMutex());
    00199       Tindex new_item = _pool.Create();
    00200       if (new_item != Tmax_size) {
    00201         PooledSmallStack &pushed = _pool.Get(new_item);
    00202         pushed.value = this->value;
    00203         pushed.next = this->next;
    00204         pushed.branch_count = 0;
    00205         this->next = new_item;
    00206       }
    00207     }
    00208     this->value = item;
    00209   }
    00210
    00215   inline Titem Pop()
    00216   {
    00217     Titem ret = this->value;
    00218     if (this->next == Tmax_size) {
    00219       this->value = Tinvalid;
    00220     } else {
    00221       ThreadMutexLocker lock(_pool.GetMutex());
    00222       PooledSmallStack &popped = _pool.Get(this->next);
    00223       this->value = popped.value;
    00224       if (popped.branch_count == 0) {
    00225         _pool.Destroy(this->next);
    00226       } else {
    00227         --popped.branch_count;
    00228         /* We can't use Branch() here as we already have the mutex.*/
    00229         if (popped.next != Tmax_size) {
    00230           ++(_pool.Get(popped.next).branch_count);
    00231         }
    00232       }
    00233       /* Accessing popped here is no problem as the pool will only set
    00234        * the validity flag, not actually delete the item, on Destroy().
    00235        * It's impossible for another thread to acquire the same item in
    00236        * the mean time because of the mutex. */
    00237       this->next = popped.next;
    00238     }
    00239     return ret;
    00240   }
    00241
    00246   inline bool IsEmpty() const
    00247   {
    00248     return this->value == Tinvalid && this->next == Tmax_size;
    00249   }
    00250
    00256   inline bool Contains(const Titem &item) const
    00257   {
    00258     if (item == Tinvalid || item == this->value) return true;
    00259     if (this->next != Tmax_size) {
    00260       ThreadMutexLocker lock(_pool.GetMutex());
    00261       const SmallStack *in_list = this;
    00262       do {
    00263         in_list = static_cast<const SmallStack *>(
    00264             static_cast<const Item *>(&_pool.Get(in_list->next)));
    00265         if (in_list->value == item) return true;
    00266       } while (in_list->next != Tmax_size);
    00267     }
    00268     return false;
    00269   }
    00270
    00271 protected:
    00272   static SmallStackPool _pool;
    00273
    00277   inline void Branch()
    00278   {
    00279     if (this->next != Tmax_size) {
    00280       ThreadMutexLocker lock(_pool.GetMutex());
    00281       ++(_pool.Get(this->next).branch_count);
    00282     }
    00283   }
    00284 };
    00285
    00286 #endif