blob.hpp

Go to the documentation of this file.
00001 /* $Id: blob.hpp 11691 2007-12-25 09:48:53Z rubidium $ */
00002 
00005 #ifndef BLOB_HPP
00006 #define BLOB_HPP
00007 
00008 #include "../core/alloc_func.hpp"
00009 
00014 template <class Titem_>
00015 FORCEINLINE void MemCpyT(Titem_* d, const Titem_* s, int num_items = 1)
00016 {
00017   memcpy(d, s, num_items * sizeof(Titem_));
00018 }
00019 
00049 class CBlobBaseSimple {
00050 public:
00051   typedef ::ptrdiff_t bsize_t;
00052   typedef ::byte      bitem_t;
00053 
00054 protected:
00056   struct CHdr {
00057     bsize_t    m_size;      
00058     bsize_t    m_max_size;  
00059   };
00060 
00062   union {
00063     bitem_t    *m_pData;    
00064 #if defined(HAS_WCHAR)
00065     wchar_t    *m_pwData;   
00066 #endif /* HAS_WCHAR */
00067     CHdr       *m_pHdr_1;   
00068   } ptr_u;
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     *(CHdr**)&pHdr_1 = NULL;
00095   }
00096 
00098   FORCEINLINE ~CBlobBaseSimple()
00099   {
00100     Free();
00101   }
00102 
00103 protected:
00106   FORCEINLINE void InitEmpty()
00107   {
00108     static CHdr hdrEmpty[] = {{0, 0}, {0, 0}};
00109     ptr_u.m_pHdr_1 = &hdrEmpty[1];
00110   }
00111 
00113   FORCEINLINE void Init(CHdr* hdr)
00114   {
00115     ptr_u.m_pHdr_1 = &hdr[1];
00116   }
00117 
00119   FORCEINLINE CHdr& Hdr()
00120   {
00121     return ptr_u.m_pHdr_1[-1];
00122   }
00123 
00125   FORCEINLINE const CHdr& Hdr() const
00126   {
00127     return ptr_u.m_pHdr_1[-1];
00128   }
00129 
00131   FORCEINLINE bsize_t& RawSizeRef()
00132   {
00133     return Hdr().m_size;
00134   };
00135 
00136 public:
00138   FORCEINLINE bool IsEmpty() const
00139   {
00140     return RawSize() == 0;
00141   }
00142 
00144   FORCEINLINE bsize_t RawSize() const
00145   {
00146     return Hdr().m_size;
00147   };
00148 
00150   FORCEINLINE bsize_t MaxRawSize() const
00151   {
00152     return Hdr().m_max_size;
00153   };
00154 
00156   FORCEINLINE bitem_t* RawData()
00157   {
00158     return ptr_u.m_pData;
00159   }
00160 
00162   FORCEINLINE const bitem_t* RawData() const
00163   {
00164     return ptr_u.m_pData;
00165   }
00166 
00168   //FORCEINLINE bsize_t Crc32() const
00169   //{
00170   //  return CCrc32::Calc(RawData(), RawSize());
00171   //}
00172 
00174   FORCEINLINE void Clear()
00175   {
00176     RawSizeRef() = 0;
00177   }
00178 
00180   FORCEINLINE void Free()
00181   {
00182     if (MaxRawSize() > 0) {
00183       RawFree(&Hdr());
00184       InitEmpty();
00185     }
00186   }
00187 
00189   FORCEINLINE void CopyFrom(const CBlobBaseSimple& src)
00190   {
00191     Clear();
00192     AppendRaw(src);
00193   }
00194 
00196   FORCEINLINE void MoveFrom(CBlobBaseSimple& src)
00197   {
00198     Free();
00199     ptr_u.m_pData = src.ptr_u.m_pData;
00200     src.InitEmpty();
00201   }
00202 
00204   FORCEINLINE void Swap(CBlobBaseSimple& src)
00205   {
00206     bitem_t *tmp = ptr_u.m_pData; ptr_u.m_pData = src.ptr_u.m_pData;
00207     src.ptr_u.m_pData = tmp;
00208   }
00209 
00211   FORCEINLINE void AppendRaw(const void *p, bsize_t num_bytes)
00212   {
00213     assert(p != NULL);
00214     if (num_bytes > 0) {
00215       memcpy(GrowRawSize(num_bytes), p, num_bytes);
00216     } else {
00217       assert(num_bytes >= 0);
00218     }
00219   }
00220 
00222   FORCEINLINE void AppendRaw(const CBlobBaseSimple& src)
00223   {
00224     if (!src.IsEmpty())
00225       memcpy(GrowRawSize(src.RawSize()), src.RawData(), src.RawSize());
00226   }
00227 
00230   FORCEINLINE bitem_t* MakeRawFreeSpace(bsize_t num_bytes)
00231   {
00232     assert(num_bytes >= 0);
00233     bsize_t new_size = RawSize() + num_bytes;
00234     if (new_size > MaxRawSize()) SmartAlloc(new_size);
00235     return ptr_u.m_pData + RawSize();
00236   }
00237 
00240   FORCEINLINE bitem_t* GrowRawSize(bsize_t num_bytes)
00241   {
00242     bitem_t* pNewData = MakeRawFreeSpace(num_bytes);
00243     RawSizeRef() += num_bytes;
00244     return pNewData;
00245   }
00246 
00248   FORCEINLINE void ReduceRawSize(bsize_t num_bytes)
00249   {
00250     if (MaxRawSize() > 0 && num_bytes > 0) {
00251       assert(num_bytes <= RawSize());
00252       if (num_bytes < RawSize()) RawSizeRef() -= num_bytes;
00253       else RawSizeRef() = 0;
00254     }
00255   }
00256 
00258   void SmartAlloc(bsize_t new_size)
00259   {
00260     bsize_t old_max_size = MaxRawSize();
00261     if (old_max_size >= new_size) return;
00262     // calculate minimum block size we need to allocate
00263     bsize_t min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve;
00264     // ask allocation policy for some reasonable block size
00265     bsize_t alloc_size = AllocPolicy(min_alloc_size);
00266     // allocate new block
00267     CHdr* pNewHdr = RawAlloc(alloc_size);
00268     // setup header
00269     pNewHdr->m_size = RawSize();
00270     pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve);
00271     // copy existing data
00272     if (RawSize() > 0)
00273       memcpy(pNewHdr + 1, ptr_u.m_pData, pNewHdr->m_size);
00274     // replace our block with new one
00275     CHdr* pOldHdr = &Hdr();
00276     Init(pNewHdr);
00277     if (old_max_size > 0)
00278       RawFree(pOldHdr);
00279   }
00280 
00282   FORCEINLINE static bsize_t AllocPolicy(bsize_t min_alloc)
00283   {
00284     if (min_alloc < (1 << 9)) {
00285       if (min_alloc < (1 << 5)) return (1 << 5);
00286       return (min_alloc < (1 << 7)) ? (1 << 7) : (1 << 9);
00287     }
00288     if (min_alloc < (1 << 15)) {
00289       if (min_alloc < (1 << 11)) return (1 << 11);
00290       return (min_alloc < (1 << 13)) ? (1 << 13) : (1 << 15);
00291     }
00292     if (min_alloc < (1 << 20)) {
00293       if (min_alloc < (1 << 17)) return (1 << 17);
00294       return (min_alloc < (1 << 19)) ? (1 << 19) : (1 << 20);
00295     }
00296     min_alloc = (min_alloc | ((1 << 20) - 1)) + 1;
00297     return min_alloc;
00298   }
00299 
00301   static FORCEINLINE CHdr* RawAlloc(bsize_t num_bytes)
00302   {
00303     return (CHdr*)MallocT<byte>(num_bytes);
00304   }
00305 
00307   static FORCEINLINE void RawFree(CHdr* p)
00308   {
00309     free(p);
00310   }
00312   FORCEINLINE void FixTail() const
00313   {
00314     if (MaxRawSize() > 0) {
00315       bitem_t *p = &ptr_u.m_pData[RawSize()];
00316       for (bsize_t i = 0; i < Ttail_reserve; i++) {
00317         p[i] = 0;
00318       }
00319     }
00320   }
00321 };
00322 
00330 template <class Titem_, class Tbase_ = CBlobBaseSimple>
00331 class CBlobT : public Tbase_ {
00332   // make template arguments public:
00333 public:
00334   typedef Titem_ Titem;
00335   typedef Tbase_ Tbase;
00336   typedef typename Tbase::bsize_t bsize_t;
00337 
00338   static const bsize_t Titem_size = sizeof(Titem);
00339 
00340   struct OnTransfer {
00341     typename Tbase_::CHdr *m_pHdr_1;
00342     OnTransfer(const OnTransfer& src) : m_pHdr_1(src.m_pHdr_1) {assert(src.m_pHdr_1 != NULL); *(typename Tbase_::CHdr**)&src.m_pHdr_1 = NULL;}
00343     OnTransfer(CBlobT& src) : m_pHdr_1(src.ptr_u.m_pHdr_1) {src.InitEmpty();}
00344     ~OnTransfer() {assert(m_pHdr_1 == NULL);}
00345   };
00346 
00348   FORCEINLINE CBlobT()
00349     : Tbase()
00350   {}
00351 
00353   FORCEINLINE CBlobT(const Titem_ *p, bsize_t num_items)
00354     : Tbase((typename Tbase_::bitem_t*)p, num_items * Titem_size)
00355   {}
00356 
00358   FORCEINLINE CBlobT(const Tbase& src)
00359     : Tbase(src)
00360   {
00361     assert((Tbase::RawSize() % Titem_size) == 0);
00362   }
00363 
00365   FORCEINLINE CBlobT(const OnTransfer& ot)
00366     : Tbase(ot.m_pHdr_1)
00367   {}
00368 
00370   FORCEINLINE ~CBlobT()
00371   {
00372     Free();
00373   }
00374 
00376   FORCEINLINE void CheckIdx(bsize_t idx)
00377   {
00378     assert(idx >= 0); assert(idx < Size());
00379   }
00380 
00382   FORCEINLINE Titem* Data()
00383   {
00384     return (Titem*)Tbase::RawData();
00385   }
00386 
00388   FORCEINLINE const Titem* Data() const
00389   {
00390     return (const Titem*)Tbase::RawData();
00391   }
00392 
00394   FORCEINLINE Titem* Data(bsize_t idx)
00395   {
00396     CheckIdx(idx);
00397     return (Data() + idx);
00398   }
00399 
00401   FORCEINLINE const Titem* Data(bsize_t idx) const
00402   {
00403     CheckIdx(idx); return (Data() + idx);
00404   }
00405 
00407   FORCEINLINE bsize_t Size() const
00408   {
00409     return (Tbase::RawSize() / Titem_size);
00410   }
00411 
00413   FORCEINLINE bsize_t MaxSize() const
00414   {
00415     return (Tbase::MaxRawSize() / Titem_size);
00416   }
00418   FORCEINLINE bsize_t GetReserve() const
00419   {
00420     return ((Tbase::MaxRawSize() - Tbase::RawSize()) / Titem_size);
00421   }
00422 
00424   FORCEINLINE void Free()
00425   {
00426     assert((Tbase::RawSize() % Titem_size) == 0);
00427     bsize_t old_size = Size();
00428     if (old_size > 0) {
00429       // destroy removed items;
00430       Titem* pI_last_to_destroy = Data(0);
00431       for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem_();
00432     }
00433     Tbase::Free();
00434   }
00435 
00437   FORCEINLINE Titem* GrowSizeNC(bsize_t num_items)
00438   {
00439     return (Titem*)Tbase::GrowRawSize(num_items * Titem_size);
00440   }
00441 
00443   FORCEINLINE Titem* GrowSizeC(bsize_t num_items)
00444   {
00445     Titem* pI = GrowSizeNC(num_items);
00446     for (bsize_t i = num_items; i > 0; i--, pI++) new (pI) Titem();
00447   }
00448 
00450   FORCEINLINE void ReduceSize(bsize_t num_items)
00451   {
00452     assert((Tbase::RawSize() % Titem_size) == 0);
00453     bsize_t old_size = Size();
00454     assert(num_items <= old_size);
00455     bsize_t new_size = (num_items <= old_size) ? (old_size - num_items) : 0;
00456     // destroy removed items;
00457     Titem* pI_last_to_destroy = Data(new_size);
00458     for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem();
00459     // remove them
00460     Tbase::ReduceRawSize(num_items * Titem_size);
00461   }
00462 
00464   FORCEINLINE Titem* AppendNew()
00465   {
00466     Titem& dst = *GrowSizeNC(1); // Grow size by one item
00467     Titem* pNewItem = new (&dst) Titem(); // construct the new item by calling in-place new operator
00468     return pNewItem;
00469   }
00470 
00472   FORCEINLINE Titem* Append(const Titem& src)
00473   {
00474     Titem& dst = *GrowSizeNC(1); // Grow size by one item
00475     Titem* pNewItem = new (&dst) Titem(src); // construct the new item by calling in-place new operator with copy ctor()
00476     return pNewItem;
00477   }
00478 
00480   FORCEINLINE Titem* Append(const Titem* pSrc, bsize_t num_items)
00481   {
00482     Titem* pDst = GrowSizeNC(num_items);
00483     Titem* pDstOrg = pDst;
00484     Titem* pDstEnd = pDst + num_items;
00485     while (pDst < pDstEnd) new (pDst++) Titem(*(pSrc++));
00486     return pDstOrg;
00487   }
00488 
00490   FORCEINLINE void RemoveBySwap(bsize_t idx)
00491   {
00492     CheckIdx(idx);
00493     // destroy removed item
00494     Titem* pRemoved = Data(idx);
00495     RemoveBySwap(pRemoved);
00496   }
00497 
00499   FORCEINLINE void RemoveBySwap(Titem* pItem)
00500   {
00501     Titem* pLast = Data(Size() - 1);
00502     assert(pItem >= Data() && pItem <= pLast);
00503     // move last item to its new place
00504     if (pItem != pLast) {
00505       pItem->~Titem_();
00506       new (pItem) Titem_(*pLast);
00507     }
00508     // destroy the last item
00509     pLast->~Titem_();
00510     // and reduce the raw blob size
00511     Tbase::ReduceRawSize(Titem_size);
00512   }
00513 
00516   FORCEINLINE Titem* MakeFreeSpace(bsize_t num_items)
00517   {
00518     return (Titem*)Tbase::MakeRawFreeSpace(num_items * Titem_size);
00519   }
00520 
00521   FORCEINLINE OnTransfer Transfer()
00522   {
00523     return OnTransfer(*this);
00524   };
00525 };
00526 
00527 
00528 #endif /* BLOB_HPP */

Generated on Wed Oct 1 17:03:21 2008 for openttd by  doxygen 1.5.6