# 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 */