blob.hpp

Go to the documentation of this file.
00001 /* $Id: blob.hpp 18809 2010-01-15 16:41:15Z 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 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:
00068   static const CHdr hdrEmpty[];
00069 
00070 public:
00071   static const bsize_t Ttail_reserve = 4; 
00072 
00074   FORCEINLINE CBlobBaseSimple() { InitEmpty(); }
00076   FORCEINLINE CBlobBaseSimple(const bitem_t *p, bsize_t num_bytes)
00077   {
00078     InitEmpty();
00079     AppendRaw(p, num_bytes);
00080   }
00081 
00083   FORCEINLINE CBlobBaseSimple(const CBlobBaseSimple& src)
00084   {
00085     InitEmpty();
00086     AppendRaw(src);
00087   }
00088 
00090   FORCEINLINE CBlobBaseSimple(CHdr * const & pHdr_1)
00091   {
00092     assert(pHdr_1 != NULL);
00093     ptr_u.m_pHdr_1 = pHdr_1;
00094     *const_cast<CHdr**>(&pHdr_1) = NULL;
00095   }
00096 
00098   FORCEINLINE ~CBlobBaseSimple()
00099   {
00100     Free();
00101   }
00102 
00103 protected:
00106   FORCEINLINE void InitEmpty()
00107   {
00108     ptr_u.m_pHdr_1 = const_cast<CHdr *>(&CBlobBaseSimple::hdrEmpty[1]);
00109   }
00110 
00112   FORCEINLINE void Init(CHdr *hdr)
00113   {
00114     ptr_u.m_pHdr_1 = &hdr[1];
00115   }
00116 
00118   FORCEINLINE CHdr& Hdr()
00119   {
00120     return ptr_u.m_pHdr_1[-1];
00121   }
00122 
00124   FORCEINLINE const CHdr& Hdr() const
00125   {
00126     return ptr_u.m_pHdr_1[-1];
00127   }
00128 
00130   FORCEINLINE bsize_t& RawSizeRef()
00131   {
00132     return Hdr().m_size;
00133   };
00134 
00135 public:
00137   FORCEINLINE bool IsEmpty() const
00138   {
00139     return RawSize() == 0;
00140   }
00141 
00143   FORCEINLINE bsize_t RawSize() const
00144   {
00145     return Hdr().m_size;
00146   };
00147 
00149   FORCEINLINE bsize_t MaxRawSize() const
00150   {
00151     return Hdr().m_max_size;
00152   };
00153 
00155   FORCEINLINE bitem_t *RawData()
00156   {
00157     return ptr_u.m_pData;
00158   }
00159 
00161   FORCEINLINE const bitem_t *RawData() const
00162   {
00163     return ptr_u.m_pData;
00164   }
00165 
00167   //FORCEINLINE bsize_t Crc32() const
00168   //{
00169   //  return CCrc32::Calc(RawData(), RawSize());
00170   //}
00171 
00173   FORCEINLINE void Clear()
00174   {
00175     RawSizeRef() = 0;
00176   }
00177 
00179   FORCEINLINE void Free()
00180   {
00181     if (MaxRawSize() > 0) {
00182       RawFree(&Hdr());
00183       InitEmpty();
00184     }
00185   }
00186 
00188   FORCEINLINE void CopyFrom(const CBlobBaseSimple& src)
00189   {
00190     Clear();
00191     AppendRaw(src);
00192   }
00193 
00195   FORCEINLINE void MoveFrom(CBlobBaseSimple& src)
00196   {
00197     Free();
00198     ptr_u.m_pData = src.ptr_u.m_pData;
00199     src.InitEmpty();
00200   }
00201 
00203   FORCEINLINE void Swap(CBlobBaseSimple& src)
00204   {
00205     bitem_t *tmp = ptr_u.m_pData; ptr_u.m_pData = src.ptr_u.m_pData;
00206     src.ptr_u.m_pData = tmp;
00207   }
00208 
00210   FORCEINLINE void AppendRaw(const void *p, bsize_t num_bytes)
00211   {
00212     assert(p != NULL);
00213     if (num_bytes > 0) {
00214       memcpy(GrowRawSize(num_bytes), p, num_bytes);
00215     } else {
00216       assert(num_bytes >= 0);
00217     }
00218   }
00219 
00221   FORCEINLINE void AppendRaw(const CBlobBaseSimple& src)
00222   {
00223     if (!src.IsEmpty())
00224       memcpy(GrowRawSize(src.RawSize()), src.RawData(), src.RawSize());
00225   }
00226 
00229   FORCEINLINE bitem_t *MakeRawFreeSpace(bsize_t num_bytes)
00230   {
00231     assert(num_bytes >= 0);
00232     bsize_t new_size = RawSize() + num_bytes;
00233     if (new_size > MaxRawSize()) SmartAlloc(new_size);
00234     return ptr_u.m_pData + RawSize();
00235   }
00236 
00239   FORCEINLINE bitem_t *GrowRawSize(bsize_t num_bytes)
00240   {
00241     bitem_t *pNewData = MakeRawFreeSpace(num_bytes);
00242     RawSizeRef() += num_bytes;
00243     return pNewData;
00244   }
00245 
00247   FORCEINLINE void ReduceRawSize(bsize_t num_bytes)
00248   {
00249     if (MaxRawSize() > 0 && num_bytes > 0) {
00250       assert(num_bytes <= RawSize());
00251       if (num_bytes < RawSize()) {
00252         RawSizeRef() -= num_bytes;
00253       } else {
00254         RawSizeRef() = 0;
00255       }
00256     }
00257   }
00258 
00260   void SmartAlloc(bsize_t new_size)
00261   {
00262     bsize_t old_max_size = MaxRawSize();
00263     if (old_max_size >= new_size) return;
00264     /* calculate minimum block size we need to allocate */
00265     bsize_t min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve;
00266     /* ask allocation policy for some reasonable block size */
00267     bsize_t alloc_size = AllocPolicy(min_alloc_size);
00268     /* allocate new block */
00269     CHdr *pNewHdr = RawAlloc(alloc_size);
00270     /* setup header */
00271     pNewHdr->m_size = RawSize();
00272     pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve);
00273     /* copy existing data */
00274     if (RawSize() > 0)
00275       memcpy(pNewHdr + 1, ptr_u.m_pData, pNewHdr->m_size);
00276     /* replace our block with new one */
00277     CHdr *pOldHdr = &Hdr();
00278     Init(pNewHdr);
00279     if (old_max_size > 0)
00280       RawFree(pOldHdr);
00281   }
00282 
00284   FORCEINLINE static bsize_t AllocPolicy(bsize_t min_alloc)
00285   {
00286     if (min_alloc < (1 << 9)) {
00287       if (min_alloc < (1 << 5)) return (1 << 5);
00288       return (min_alloc < (1 << 7)) ? (1 << 7) : (1 << 9);
00289     }
00290     if (min_alloc < (1 << 15)) {
00291       if (min_alloc < (1 << 11)) return (1 << 11);
00292       return (min_alloc < (1 << 13)) ? (1 << 13) : (1 << 15);
00293     }
00294     if (min_alloc < (1 << 20)) {
00295       if (min_alloc < (1 << 17)) return (1 << 17);
00296       return (min_alloc < (1 << 19)) ? (1 << 19) : (1 << 20);
00297     }
00298     min_alloc = (min_alloc | ((1 << 20) - 1)) + 1;
00299     return min_alloc;
00300   }
00301 
00303   static FORCEINLINE CHdr *RawAlloc(bsize_t num_bytes)
00304   {
00305     return (CHdr*)MallocT<byte>(num_bytes);
00306   }
00307 
00309   static FORCEINLINE void RawFree(CHdr *p)
00310   {
00311     /* Just to silence an unsilencable GCC 4.4+ warning. */
00312     assert(p != CBlobBaseSimple::hdrEmpty);
00313 
00314     /* In case GCC warns about the following, see GCC's PR38509 why it is bogus. */
00315     free(p);
00316   }
00318   FORCEINLINE void FixTail() const
00319   {
00320     if (MaxRawSize() > 0) {
00321       bitem_t *p = &ptr_u.m_pData[RawSize()];
00322       for (bsize_t i = 0; i < Ttail_reserve; i++) {
00323         p[i] = 0;
00324       }
00325     }
00326   }
00327 };
00328 
00336 template <class Titem_, class Tbase_ = CBlobBaseSimple>
00337 class CBlobT : public Tbase_ {
00338   /* make template arguments public: */
00339 public:
00340   typedef Titem_ Titem;
00341   typedef Tbase_ Tbase;
00342   typedef typename Tbase::bsize_t bsize_t;
00343 
00344   static const bsize_t Titem_size = sizeof(Titem);
00345 
00346   struct OnTransfer {
00347     typename Tbase_::CHdr *m_pHdr_1;
00348     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;}
00349     OnTransfer(CBlobT& src) : m_pHdr_1(src.ptr_u.m_pHdr_1) {src.InitEmpty();}
00350     ~OnTransfer() {assert(m_pHdr_1 == NULL);}
00351   };
00352 
00354   FORCEINLINE CBlobT()
00355     : Tbase()
00356   {}
00357 
00359   FORCEINLINE CBlobT(const Titem_ *p, bsize_t num_items)
00360     : Tbase((typename Tbase_::bitem_t*)p, num_items * Titem_size)
00361   {}
00362 
00364   FORCEINLINE CBlobT(const Tbase& src)
00365     : Tbase(src)
00366   {
00367     assert((Tbase::RawSize() % Titem_size) == 0);
00368   }
00369 
00371   FORCEINLINE CBlobT(const OnTransfer& ot)
00372     : Tbase(ot.m_pHdr_1)
00373   {}
00374 
00376   FORCEINLINE ~CBlobT()
00377   {
00378     Free();
00379   }
00380 
00382   FORCEINLINE void CheckIdx(bsize_t idx) const
00383   {
00384     assert(idx >= 0); assert(idx < Size());
00385   }
00386 
00388   FORCEINLINE Titem *Data()
00389   {
00390     return (Titem*)Tbase::RawData();
00391   }
00392 
00394   FORCEINLINE const Titem *Data() const
00395   {
00396     return (const Titem*)Tbase::RawData();
00397   }
00398 
00400   FORCEINLINE Titem *Data(bsize_t idx)
00401   {
00402     CheckIdx(idx);
00403     return (Data() + idx);
00404   }
00405 
00407   FORCEINLINE const Titem *Data(bsize_t idx) const
00408   {
00409     CheckIdx(idx);
00410     return (Data() + idx);
00411   }
00412 
00414   FORCEINLINE bsize_t Size() const
00415   {
00416     return (Tbase::RawSize() / Titem_size);
00417   }
00418 
00420   FORCEINLINE bsize_t MaxSize() const
00421   {
00422     return (Tbase::MaxRawSize() / Titem_size);
00423   }
00425   FORCEINLINE bsize_t GetReserve() const
00426   {
00427     return ((Tbase::MaxRawSize() - Tbase::RawSize()) / Titem_size);
00428   }
00429 
00431   FORCEINLINE void Free()
00432   {
00433     assert((Tbase::RawSize() % Titem_size) == 0);
00434     bsize_t old_size = Size();
00435     if (old_size > 0) {
00436       /* destroy removed items; */
00437       Titem *pI_last_to_destroy = Data(0);
00438       for (Titem *pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem_();
00439     }
00440     Tbase::Free();
00441   }
00442 
00444   FORCEINLINE Titem *GrowSizeNC(bsize_t num_items)
00445   {
00446     return (Titem*)Tbase::GrowRawSize(num_items * Titem_size);
00447   }
00448 
00450   FORCEINLINE Titem *GrowSizeC(bsize_t num_items)
00451   {
00452     Titem *pI = GrowSizeNC(num_items);
00453     for (bsize_t i = num_items; i > 0; i--, pI++) new (pI) Titem();
00454   }
00455 
00457   FORCEINLINE void ReduceSize(bsize_t num_items)
00458   {
00459     assert((Tbase::RawSize() % Titem_size) == 0);
00460     bsize_t old_size = Size();
00461     assert(num_items <= old_size);
00462     bsize_t new_size = (num_items <= old_size) ? (old_size - num_items) : 0;
00463     /* destroy removed items; */
00464     Titem *pI_last_to_destroy = Data(new_size);
00465     for (Titem *pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem();
00466     /* remove them */
00467     Tbase::ReduceRawSize(num_items * Titem_size);
00468   }
00469 
00471   FORCEINLINE Titem *AppendNew()
00472   {
00473     Titem& dst = *GrowSizeNC(1); // Grow size by one item
00474     Titem *pNewItem = new (&dst) Titem(); // construct the new item by calling in-place new operator
00475     return pNewItem;
00476   }
00477 
00479   FORCEINLINE Titem *Append(const Titem& src)
00480   {
00481     Titem& dst = *GrowSizeNC(1); // Grow size by one item
00482     Titem *pNewItem = new (&dst) Titem(src); // construct the new item by calling in-place new operator with copy ctor()
00483     return pNewItem;
00484   }
00485 
00487   FORCEINLINE Titem *Append(const Titem *pSrc, bsize_t num_items)
00488   {
00489     Titem *pDst = GrowSizeNC(num_items);
00490     Titem *pDstOrg = pDst;
00491     Titem *pDstEnd = pDst + num_items;
00492     while (pDst < pDstEnd) new (pDst++) Titem(*(pSrc++));
00493     return pDstOrg;
00494   }
00495 
00497   FORCEINLINE void RemoveBySwap(bsize_t idx)
00498   {
00499     CheckIdx(idx);
00500     /* destroy removed item */
00501     Titem *pRemoved = Data(idx);
00502     RemoveBySwap(pRemoved);
00503   }
00504 
00506   FORCEINLINE void RemoveBySwap(Titem *pItem)
00507   {
00508     Titem *pLast = Data(Size() - 1);
00509     assert(pItem >= Data() && pItem <= pLast);
00510     /* move last item to its new place */
00511     if (pItem != pLast) {
00512       pItem->~Titem_();
00513       new (pItem) Titem_(*pLast);
00514     }
00515     /* destroy the last item */
00516     pLast->~Titem_();
00517     /* and reduce the raw blob size */
00518     Tbase::ReduceRawSize(Titem_size);
00519   }
00520 
00523   FORCEINLINE Titem *MakeFreeSpace(bsize_t num_items)
00524   {
00525     return (Titem*)Tbase::MakeRawFreeSpace(num_items * Titem_size);
00526   }
00527 
00528   FORCEINLINE OnTransfer Transfer()
00529   {
00530     return OnTransfer(*this);
00531   };
00532 };
00533 
00534 
00535 #endif /* BLOB_HPP */

Generated on Wed Jan 20 23:38:36 2010 for OpenTTD by  doxygen 1.5.6