blob.hpp

Go to the documentation of this file.
00001 /* $Id: blob.hpp 19134 2010-02-14 18:33:57Z frosch $ */
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 BLOB_HPP
00013 #define BLOB_HPP
00014 
00015 #include "../core/alloc_func.hpp"
00016 #include "../core/mem_func.hpp"
00017 #include <new>
00018 
00048 class CBlobBaseSimple {
00049 public:
00050   typedef ::ptrdiff_t bsize_t;
00051   typedef ::byte      bitem_t;
00052 
00053 protected:
00055   struct CHdr {
00056     bsize_t    m_size;      
00057     bsize_t    m_max_size;  
00058   };
00059 
00061   union {
00062     bitem_t    *m_pData;    
00063     CHdr       *m_pHdr_1;   
00064   } ptr_u;
00065 
00066 private:
00072   static CHdr hdrEmpty[];
00073 
00074 public:
00075   static const bsize_t Ttail_reserve = 4; 
00076 
00078   FORCEINLINE CBlobBaseSimple() { InitEmpty(); }
00080   FORCEINLINE CBlobBaseSimple(const bitem_t *p, bsize_t num_bytes)
00081   {
00082     InitEmpty();
00083     AppendRaw(p, num_bytes);
00084   }
00085 
00087   FORCEINLINE CBlobBaseSimple(const CBlobBaseSimple& src)
00088   {
00089     InitEmpty();
00090     AppendRaw(src);
00091   }
00092 
00094   FORCEINLINE CBlobBaseSimple(CHdr * const & pHdr_1)
00095   {
00096     assert(pHdr_1 != NULL);
00097     ptr_u.m_pHdr_1 = pHdr_1;
00098     *const_cast<CHdr**>(&pHdr_1) = NULL;
00099   }
00100 
00102   FORCEINLINE ~CBlobBaseSimple()
00103   {
00104     Free();
00105   }
00106 
00107 protected:
00110   FORCEINLINE void InitEmpty()
00111   {
00112     ptr_u.m_pHdr_1 = const_cast<CHdr *>(&CBlobBaseSimple::hdrEmpty[1]);
00113   }
00114 
00116   FORCEINLINE void Init(CHdr *hdr)
00117   {
00118     ptr_u.m_pHdr_1 = &hdr[1];
00119   }
00120 
00122   FORCEINLINE CHdr& Hdr()
00123   {
00124     return *(ptr_u.m_pHdr_1 - 1);
00125   }
00126 
00128   FORCEINLINE const CHdr& Hdr() const
00129   {
00130     return *(ptr_u.m_pHdr_1 - 1);
00131   }
00132 
00134   FORCEINLINE bsize_t& RawSizeRef()
00135   {
00136     return Hdr().m_size;
00137   };
00138 
00139 public:
00141   FORCEINLINE bool IsEmpty() const
00142   {
00143     return RawSize() == 0;
00144   }
00145 
00147   FORCEINLINE bsize_t RawSize() const
00148   {
00149     return Hdr().m_size;
00150   };
00151 
00153   FORCEINLINE bsize_t MaxRawSize() const
00154   {
00155     return Hdr().m_max_size;
00156   };
00157 
00159   FORCEINLINE bitem_t *RawData()
00160   {
00161     return ptr_u.m_pData;
00162   }
00163 
00165   FORCEINLINE const bitem_t *RawData() const
00166   {
00167     return ptr_u.m_pData;
00168   }
00169 
00171   //FORCEINLINE bsize_t Crc32() const
00172   //{
00173   //  return CCrc32::Calc(RawData(), RawSize());
00174   //}
00175 
00177   FORCEINLINE void Clear()
00178   {
00179     RawSizeRef() = 0;
00180   }
00181 
00183   FORCEINLINE void Free()
00184   {
00185     if (MaxRawSize() > 0) {
00186       RawFree(&Hdr());
00187       InitEmpty();
00188     }
00189   }
00190 
00192   FORCEINLINE void CopyFrom(const CBlobBaseSimple& src)
00193   {
00194     Clear();
00195     AppendRaw(src);
00196   }
00197 
00199   FORCEINLINE void MoveFrom(CBlobBaseSimple& src)
00200   {
00201     Free();
00202     ptr_u.m_pData = src.ptr_u.m_pData;
00203     src.InitEmpty();
00204   }
00205 
00207   FORCEINLINE void Swap(CBlobBaseSimple& src)
00208   {
00209     bitem_t *tmp = ptr_u.m_pData; ptr_u.m_pData = src.ptr_u.m_pData;
00210     src.ptr_u.m_pData = tmp;
00211   }
00212 
00214   FORCEINLINE void AppendRaw(const void *p, bsize_t num_bytes)
00215   {
00216     assert(p != NULL);
00217     if (num_bytes > 0) {
00218       memcpy(GrowRawSize(num_bytes), p, num_bytes);
00219     } else {
00220       assert(num_bytes >= 0);
00221     }
00222   }
00223 
00225   FORCEINLINE void AppendRaw(const CBlobBaseSimple& src)
00226   {
00227     if (!src.IsEmpty())
00228       memcpy(GrowRawSize(src.RawSize()), src.RawData(), src.RawSize());
00229   }
00230 
00233   FORCEINLINE bitem_t *MakeRawFreeSpace(bsize_t num_bytes)
00234   {
00235     assert(num_bytes >= 0);
00236     bsize_t new_size = RawSize() + num_bytes;
00237     if (new_size > MaxRawSize()) SmartAlloc(new_size);
00238     return ptr_u.m_pData + RawSize();
00239   }
00240 
00243   FORCEINLINE bitem_t *GrowRawSize(bsize_t num_bytes)
00244   {
00245     bitem_t *pNewData = MakeRawFreeSpace(num_bytes);
00246     RawSizeRef() += num_bytes;
00247     return pNewData;
00248   }
00249 
00251   FORCEINLINE void ReduceRawSize(bsize_t num_bytes)
00252   {
00253     if (MaxRawSize() > 0 && num_bytes > 0) {
00254       assert(num_bytes <= RawSize());
00255       if (num_bytes < RawSize()) {
00256         RawSizeRef() -= num_bytes;
00257       } else {
00258         RawSizeRef() = 0;
00259       }
00260     }
00261   }
00262 
00264   void SmartAlloc(bsize_t new_size)
00265   {
00266     bsize_t old_max_size = MaxRawSize();
00267     if (old_max_size >= new_size) return;
00268     /* calculate minimum block size we need to allocate */
00269     bsize_t min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve;
00270     /* ask allocation policy for some reasonable block size */
00271     bsize_t alloc_size = AllocPolicy(min_alloc_size);
00272     /* allocate new block */
00273     CHdr *pNewHdr = RawAlloc(alloc_size);
00274     /* setup header */
00275     pNewHdr->m_size = RawSize();
00276     pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve);
00277     /* copy existing data */
00278     if (RawSize() > 0)
00279       memcpy(pNewHdr + 1, ptr_u.m_pData, pNewHdr->m_size);
00280     /* replace our block with new one */
00281     CHdr *pOldHdr = &Hdr();
00282     Init(pNewHdr);
00283     if (old_max_size > 0)
00284       RawFree(pOldHdr);
00285   }
00286 
00288   FORCEINLINE static bsize_t AllocPolicy(bsize_t min_alloc)
00289   {
00290     if (min_alloc < (1 << 9)) {
00291       if (min_alloc < (1 << 5)) return (1 << 5);
00292       return (min_alloc < (1 << 7)) ? (1 << 7) : (1 << 9);
00293     }
00294     if (min_alloc < (1 << 15)) {
00295       if (min_alloc < (1 << 11)) return (1 << 11);
00296       return (min_alloc < (1 << 13)) ? (1 << 13) : (1 << 15);
00297     }
00298     if (min_alloc < (1 << 20)) {
00299       if (min_alloc < (1 << 17)) return (1 << 17);
00300       return (min_alloc < (1 << 19)) ? (1 << 19) : (1 << 20);
00301     }
00302     min_alloc = (min_alloc | ((1 << 20) - 1)) + 1;
00303     return min_alloc;
00304   }
00305 
00307   static FORCEINLINE CHdr *RawAlloc(bsize_t num_bytes)
00308   {
00309     return (CHdr*)MallocT<byte>(num_bytes);
00310   }
00311 
00313   static FORCEINLINE void RawFree(CHdr *p)
00314   {
00315     /* Just to silence an unsilencable GCC 4.4+ warning. */
00316     assert(p != CBlobBaseSimple::hdrEmpty);
00317 
00318     /* In case GCC warns about the following, see GCC's PR38509 why it is bogus. */
00319     free(p);
00320   }
00322   FORCEINLINE void FixTail() const
00323   {
00324     if (MaxRawSize() > 0) {
00325       bitem_t *p = &ptr_u.m_pData[RawSize()];
00326       for (bsize_t i = 0; i < Ttail_reserve; i++) {
00327         p[i] = 0;
00328       }
00329     }
00330   }
00331 };
00332 
00340 template <class Titem_, class Tbase_ = CBlobBaseSimple>
00341 class CBlobT : public Tbase_ {
00342   /* make template arguments public: */
00343 public:
00344   typedef Titem_ Titem;
00345   typedef Tbase_ Tbase;
00346   typedef typename Tbase::bsize_t bsize_t;
00347 
00348   static const bsize_t Titem_size = sizeof(Titem);
00349 
00350   struct OnTransfer {
00351     typename Tbase_::CHdr *m_pHdr_1;
00352     OnTransfer(const OnTransfer& src) : m_pHdr_1(src.m_pHdr_1) {assert(src.m_pHdr_1 != NULL); *const_cast<typename Tbase_::CHdr**>(&src.m_pHdr_1) = NULL;}
00353     OnTransfer(CBlobT& src) : m_pHdr_1(src.ptr_u.m_pHdr_1) {src.InitEmpty();}
00354     ~OnTransfer() {assert(m_pHdr_1 == NULL);}
00355   };
00356 
00358   FORCEINLINE CBlobT()
00359     : Tbase()
00360   {}
00361 
00363   FORCEINLINE CBlobT(const Titem_ *p, bsize_t num_items)
00364     : Tbase((typename Tbase_::bitem_t*)p, num_items * Titem_size)
00365   {}
00366 
00368   FORCEINLINE CBlobT(const Tbase& src)
00369     : Tbase(src)
00370   {
00371     assert((Tbase::RawSize() % Titem_size) == 0);
00372   }
00373 
00375   FORCEINLINE CBlobT(const OnTransfer& ot)
00376     : Tbase(ot.m_pHdr_1)
00377   {}
00378 
00380   FORCEINLINE ~CBlobT()
00381   {
00382     Free();
00383   }
00384 
00386   FORCEINLINE void CheckIdx(bsize_t idx) const
00387   {
00388     assert(idx >= 0); assert(idx < Size());
00389   }
00390 
00392   FORCEINLINE Titem *Data()
00393   {
00394     return (Titem*)Tbase::RawData();
00395   }
00396 
00398   FORCEINLINE const Titem *Data() const
00399   {
00400     return (const Titem*)Tbase::RawData();
00401   }
00402 
00404   FORCEINLINE Titem *Data(bsize_t idx)
00405   {
00406     CheckIdx(idx);
00407     return (Data() + idx);
00408   }
00409 
00411   FORCEINLINE const Titem *Data(bsize_t idx) const
00412   {
00413     CheckIdx(idx);
00414     return (Data() + idx);
00415   }
00416 
00418   FORCEINLINE bsize_t Size() const
00419   {
00420     return (Tbase::RawSize() / Titem_size);
00421   }
00422 
00424   FORCEINLINE bsize_t MaxSize() const
00425   {
00426     return (Tbase::MaxRawSize() / Titem_size);
00427   }
00429   FORCEINLINE bsize_t GetReserve() const
00430   {
00431     return ((Tbase::MaxRawSize() - Tbase::RawSize()) / Titem_size);
00432   }
00433 
00435   FORCEINLINE void Free()
00436   {
00437     assert((Tbase::RawSize() % Titem_size) == 0);
00438     bsize_t old_size = Size();
00439     if (old_size > 0) {
00440       /* destroy removed items; */
00441       Titem *pI_last_to_destroy = Data(0);
00442       for (Titem *pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem_();
00443     }
00444     Tbase::Free();
00445   }
00446 
00448   FORCEINLINE Titem *GrowSizeNC(bsize_t num_items)
00449   {
00450     return (Titem*)Tbase::GrowRawSize(num_items * Titem_size);
00451   }
00452 
00454   FORCEINLINE Titem *GrowSizeC(bsize_t num_items)
00455   {
00456     Titem *pI = GrowSizeNC(num_items);
00457     for (bsize_t i = num_items; i > 0; i--, pI++) new (pI) Titem();
00458   }
00459 
00461   FORCEINLINE void ReduceSize(bsize_t num_items)
00462   {
00463     assert((Tbase::RawSize() % Titem_size) == 0);
00464     bsize_t old_size = Size();
00465     assert(num_items <= old_size);
00466     bsize_t new_size = (num_items <= old_size) ? (old_size - num_items) : 0;
00467     /* destroy removed items; */
00468     Titem *pI_last_to_destroy = Data(new_size);
00469     for (Titem *pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem();
00470     /* remove them */
00471     Tbase::ReduceRawSize(num_items * Titem_size);
00472   }
00473 
00475   FORCEINLINE Titem *AppendNew()
00476   {
00477     Titem& dst = *GrowSizeNC(1); // Grow size by one item
00478     Titem *pNewItem = new (&dst) Titem(); // construct the new item by calling in-place new operator
00479     return pNewItem;
00480   }
00481 
00483   FORCEINLINE Titem *Append(const Titem& src)
00484   {
00485     Titem& dst = *GrowSizeNC(1); // Grow size by one item
00486     Titem *pNewItem = new (&dst) Titem(src); // construct the new item by calling in-place new operator with copy ctor()
00487     return pNewItem;
00488   }
00489 
00491   FORCEINLINE Titem *Append(const Titem *pSrc, bsize_t num_items)
00492   {
00493     Titem *pDst = GrowSizeNC(num_items);
00494     Titem *pDstOrg = pDst;
00495     Titem *pDstEnd = pDst + num_items;
00496     while (pDst < pDstEnd) new (pDst++) Titem(*(pSrc++));
00497     return pDstOrg;
00498   }
00499 
00501   FORCEINLINE void RemoveBySwap(bsize_t idx)
00502   {
00503     CheckIdx(idx);
00504     /* destroy removed item */
00505     Titem *pRemoved = Data(idx);
00506     RemoveBySwap(pRemoved);
00507   }
00508 
00510   FORCEINLINE void RemoveBySwap(Titem *pItem)
00511   {
00512     Titem *pLast = Data(Size() - 1);
00513     assert(pItem >= Data() && pItem <= pLast);
00514     /* move last item to its new place */
00515     if (pItem != pLast) {
00516       pItem->~Titem_();
00517       new (pItem) Titem_(*pLast);
00518     }
00519     /* destroy the last item */
00520     pLast->~Titem_();
00521     /* and reduce the raw blob size */
00522     Tbase::ReduceRawSize(Titem_size);
00523   }
00524 
00527   FORCEINLINE Titem *MakeFreeSpace(bsize_t num_items)
00528   {
00529     return (Titem*)Tbase::MakeRawFreeSpace(num_items * Titem_size);
00530   }
00531 
00532   FORCEINLINE OnTransfer Transfer()
00533   {
00534     return OnTransfer(*this);
00535   };
00536 };
00537 
00538 
00539 #endif /* BLOB_HPP */

Generated on Tue Sep 14 17:06:49 2010 for OpenTTD by  doxygen 1.6.1