# blob.hpp

Go to the documentation of this file.

    00001 /* $Id: blob.hpp 17516 2009-09-12 20:44:12Z rubidium $ */
    00002
    00005 #ifndef BLOB_HPP
    00006 #define BLOB_HPP
    00007
    00008 #include "../core/alloc_func.hpp"
    00009 #include "../core/mem_func.hpp"
    00010
    00040 class CBlobBaseSimple {
    00041 public:
    00042   typedef ::ptrdiff_t bsize_t;
    00043   typedef ::byte      bitem_t;
    00044
    00045 protected:
    00047   struct CHdr {
    00048     bsize_t    m_size;
    00049     bsize_t    m_max_size;
    00050   };
    00051
    00053   union {
    00054     bitem_t    *m_pData;
    00055 #if defined(HAS_WCHAR)
    00056     wchar_t    *m_pwData;
    00057 #endif /* HAS_WCHAR */
    00058     CHdr       *m_pHdr_1;
    00059   } ptr_u;
    00060
    00061 public:
    00062   static const bsize_t Ttail_reserve = 4;
    00063
    00065   FORCEINLINE CBlobBaseSimple() { InitEmpty(); }
    00067   FORCEINLINE CBlobBaseSimple(const bitem_t *p, bsize_t num_bytes)
    00068   {
    00069     InitEmpty();
    00070     AppendRaw(p, num_bytes);
    00071   }
    00072
    00074   FORCEINLINE CBlobBaseSimple(const CBlobBaseSimple& src)
    00075   {
    00076     InitEmpty();
    00077     AppendRaw(src);
    00078   }
    00079
    00081   FORCEINLINE CBlobBaseSimple(CHdr * const & pHdr_1)
    00082   {
    00083     assert(pHdr_1 != NULL);
    00084     ptr_u.m_pHdr_1 = pHdr_1;
    00085     *(CHdr**)&pHdr_1 = NULL;
    00086   }
    00087
    00089   FORCEINLINE ~CBlobBaseSimple()
    00090   {
    00091     Free();
    00092   }
    00093
    00094 protected:
    00097   FORCEINLINE void InitEmpty()
    00098   {
    00099     static CHdr hdrEmpty[] = {{0, 0}, {0, 0}};
    00100     ptr_u.m_pHdr_1 = &hdrEmpty[1];
    00101   }
    00102
    00104   FORCEINLINE void Init(CHdr *hdr)
    00105   {
    00106     ptr_u.m_pHdr_1 = &hdr[1];
    00107   }
    00108
    00110   FORCEINLINE CHdr& Hdr()
    00111   {
    00112     return ptr_u.m_pHdr_1[-1];
    00113   }
    00114
    00116   FORCEINLINE const CHdr& Hdr() const
    00117   {
    00118     return ptr_u.m_pHdr_1[-1];
    00119   }
    00120
    00122   FORCEINLINE bsize_t& RawSizeRef()
    00123   {
    00124     return Hdr().m_size;
    00125   };
    00126
    00127 public:
    00129   FORCEINLINE bool IsEmpty() const
    00130   {
    00131     return RawSize() == 0;
    00132   }
    00133
    00135   FORCEINLINE bsize_t RawSize() const
    00136   {
    00137     return Hdr().m_size;
    00138   };
    00139
    00141   FORCEINLINE bsize_t MaxRawSize() const
    00142   {
    00143     return Hdr().m_max_size;
    00144   };
    00145
    00147   FORCEINLINE bitem_t *RawData()
    00148   {
    00149     return ptr_u.m_pData;
    00150   }
    00151
    00153   FORCEINLINE const bitem_t *RawData() const
    00154   {
    00155     return ptr_u.m_pData;
    00156   }
    00157
    00159   //FORCEINLINE bsize_t Crc32() const
    00160   //{
    00161   //  return CCrc32::Calc(RawData(), RawSize());
    00162   //}
    00163
    00165   FORCEINLINE void Clear()
    00166   {
    00167     RawSizeRef() = 0;
    00168   }
    00169
    00171   FORCEINLINE void Free()
    00172   {
    00173     if (MaxRawSize() > 0) {
    00174       RawFree(&Hdr());
    00175       InitEmpty();
    00176     }
    00177   }
    00178
    00180   FORCEINLINE void CopyFrom(const CBlobBaseSimple& src)
    00181   {
    00182     Clear();
    00183     AppendRaw(src);
    00184   }
    00185
    00187   FORCEINLINE void MoveFrom(CBlobBaseSimple& src)
    00188   {
    00189     Free();
    00190     ptr_u.m_pData = src.ptr_u.m_pData;
    00191     src.InitEmpty();
    00192   }
    00193
    00195   FORCEINLINE void Swap(CBlobBaseSimple& src)
    00196   {
    00197     bitem_t *tmp = ptr_u.m_pData; ptr_u.m_pData = src.ptr_u.m_pData;
    00198     src.ptr_u.m_pData = tmp;
    00199   }
    00200
    00202   FORCEINLINE void AppendRaw(const void *p, bsize_t num_bytes)
    00203   {
    00204     assert(p != NULL);
    00205     if (num_bytes > 0) {
    00206       memcpy(GrowRawSize(num_bytes), p, num_bytes);
    00207     } else {
    00208       assert(num_bytes >= 0);
    00209     }
    00210   }
    00211
    00213   FORCEINLINE void AppendRaw(const CBlobBaseSimple& src)
    00214   {
    00215     if (!src.IsEmpty())
    00216       memcpy(GrowRawSize(src.RawSize()), src.RawData(), src.RawSize());
    00217   }
    00218
    00221   FORCEINLINE bitem_t *MakeRawFreeSpace(bsize_t num_bytes)
    00222   {
    00223     assert(num_bytes >= 0);
    00224     bsize_t new_size = RawSize() + num_bytes;
    00225     if (new_size > MaxRawSize()) SmartAlloc(new_size);
    00226     return ptr_u.m_pData + RawSize();
    00227   }
    00228
    00231   FORCEINLINE bitem_t *GrowRawSize(bsize_t num_bytes)
    00232   {
    00233     bitem_t *pNewData = MakeRawFreeSpace(num_bytes);
    00234     RawSizeRef() += num_bytes;
    00235     return pNewData;
    00236   }
    00237
    00239   FORCEINLINE void ReduceRawSize(bsize_t num_bytes)
    00240   {
    00241     if (MaxRawSize() > 0 && num_bytes > 0) {
    00242       assert(num_bytes <= RawSize());
    00243       if (num_bytes < RawSize()) RawSizeRef() -= num_bytes;
    00244       else RawSizeRef() = 0;
    00245     }
    00246   }
    00247
    00249   void SmartAlloc(bsize_t new_size)
    00250   {
    00251     bsize_t old_max_size = MaxRawSize();
    00252     if (old_max_size >= new_size) return;
    00253     /* calculate minimum block size we need to allocate */
    00254     bsize_t min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve;
    00255     /* ask allocation policy for some reasonable block size */
    00256     bsize_t alloc_size = AllocPolicy(min_alloc_size);
    00257     /* allocate new block */
    00258     CHdr *pNewHdr = RawAlloc(alloc_size);
    00259     /* setup header */
    00260     pNewHdr->m_size = RawSize();
    00261     pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve);
    00262     /* copy existing data */
    00263     if (RawSize() > 0)
    00264       memcpy(pNewHdr + 1, ptr_u.m_pData, pNewHdr->m_size);
    00265     /* replace our block with new one */
    00266     CHdr *pOldHdr = &Hdr();
    00267     Init(pNewHdr);
    00268     if (old_max_size > 0)
    00269       RawFree(pOldHdr);
    00270   }
    00271
    00273   FORCEINLINE static bsize_t AllocPolicy(bsize_t min_alloc)
    00274   {
    00275     if (min_alloc < (1 << 9)) {
    00276       if (min_alloc < (1 << 5)) return (1 << 5);
    00277       return (min_alloc < (1 << 7)) ? (1 << 7) : (1 << 9);
    00278     }
    00279     if (min_alloc < (1 << 15)) {
    00280       if (min_alloc < (1 << 11)) return (1 << 11);
    00281       return (min_alloc < (1 << 13)) ? (1 << 13) : (1 << 15);
    00282     }
    00283     if (min_alloc < (1 << 20)) {
    00284       if (min_alloc < (1 << 17)) return (1 << 17);
    00285       return (min_alloc < (1 << 19)) ? (1 << 19) : (1 << 20);
    00286     }
    00287     min_alloc = (min_alloc | ((1 << 20) - 1)) + 1;
    00288     return min_alloc;
    00289   }
    00290
    00292   static FORCEINLINE CHdr *RawAlloc(bsize_t num_bytes)
    00293   {
    00294     return (CHdr*)MallocT<byte>(num_bytes);
    00295   }
    00296
    00298   static FORCEINLINE void RawFree(CHdr *p)
    00299   {
    00300     /* In case GCC warns about the following, see GCC's PR38509 why it is bogus. */
    00301     free(p);
    00302   }
    00304   FORCEINLINE void FixTail() const
    00305   {
    00306     if (MaxRawSize() > 0) {
    00307       bitem_t *p = &ptr_u.m_pData[RawSize()];
    00308       for (bsize_t i = 0; i < Ttail_reserve; i++) {
    00309         p[i] = 0;
    00310       }
    00311     }
    00312   }
    00313 };
    00314
    00322 template <class Titem_, class Tbase_ = CBlobBaseSimple>
    00323 class CBlobT : public Tbase_ {
    00324   /* make template arguments public: */
    00325 public:
    00326   typedef Titem_ Titem;
    00327   typedef Tbase_ Tbase;
    00328   typedef typename Tbase::bsize_t bsize_t;
    00329
    00330   static const bsize_t Titem_size = sizeof(Titem);
    00331
    00332   struct OnTransfer {
    00333     typename Tbase_::CHdr *m_pHdr_1;
    00334     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;}
    00335     OnTransfer(CBlobT& src) : m_pHdr_1(src.ptr_u.m_pHdr_1) {src.InitEmpty();}
    00336     ~OnTransfer() {assert(m_pHdr_1 == NULL);}
    00337   };
    00338
    00340   FORCEINLINE CBlobT()
    00341     : Tbase()
    00342   {}
    00343
    00345   FORCEINLINE CBlobT(const Titem_ *p, bsize_t num_items)
    00346     : Tbase((typename Tbase_::bitem_t*)p, num_items * Titem_size)
    00347   {}
    00348
    00350   FORCEINLINE CBlobT(const Tbase& src)
    00351     : Tbase(src)
    00352   {
    00353     assert((Tbase::RawSize() % Titem_size) == 0);
    00354   }
    00355
    00357   FORCEINLINE CBlobT(const OnTransfer& ot)
    00358     : Tbase(ot.m_pHdr_1)
    00359   {}
    00360
    00362   FORCEINLINE ~CBlobT()
    00363   {
    00364     Free();
    00365   }
    00366
    00368   FORCEINLINE void CheckIdx(bsize_t idx) const
    00369   {
    00370     assert(idx >= 0); assert(idx < Size());
    00371   }
    00372
    00374   FORCEINLINE Titem *Data()
    00375   {
    00376     return (Titem*)Tbase::RawData();
    00377   }
    00378
    00380   FORCEINLINE const Titem *Data() const
    00381   {
    00382     return (const Titem*)Tbase::RawData();
    00383   }
    00384
    00386   FORCEINLINE Titem *Data(bsize_t idx)
    00387   {
    00388     CheckIdx(idx);
    00389     return (Data() + idx);
    00390   }
    00391
    00393   FORCEINLINE const Titem *Data(bsize_t idx) const
    00394   {
    00395     CheckIdx(idx);
    00396     return (Data() + idx);
    00397   }
    00398
    00400   FORCEINLINE bsize_t Size() const
    00401   {
    00402     return (Tbase::RawSize() / Titem_size);
    00403   }
    00404
    00406   FORCEINLINE bsize_t MaxSize() const
    00407   {
    00408     return (Tbase::MaxRawSize() / Titem_size);
    00409   }
    00411   FORCEINLINE bsize_t GetReserve() const
    00412   {
    00413     return ((Tbase::MaxRawSize() - Tbase::RawSize()) / Titem_size);
    00414   }
    00415
    00417   FORCEINLINE void Free()
    00418   {
    00419     assert((Tbase::RawSize() % Titem_size) == 0);
    00420     bsize_t old_size = Size();
    00421     if (old_size > 0) {
    00422       /* destroy removed items; */
    00423       Titem *pI_last_to_destroy = Data(0);
    00424       for (Titem *pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem_();
    00425     }
    00426     Tbase::Free();
    00427   }
    00428
    00430   FORCEINLINE Titem *GrowSizeNC(bsize_t num_items)
    00431   {
    00432     return (Titem*)Tbase::GrowRawSize(num_items * Titem_size);
    00433   }
    00434
    00436   FORCEINLINE Titem *GrowSizeC(bsize_t num_items)
    00437   {
    00438     Titem *pI = GrowSizeNC(num_items);
    00439     for (bsize_t i = num_items; i > 0; i--, pI++) new (pI) Titem();
    00440   }
    00441
    00443   FORCEINLINE void ReduceSize(bsize_t num_items)
    00444   {
    00445     assert((Tbase::RawSize() % Titem_size) == 0);
    00446     bsize_t old_size = Size();
    00447     assert(num_items <= old_size);
    00448     bsize_t new_size = (num_items <= old_size) ? (old_size - num_items) : 0;
    00449     /* destroy removed items; */
    00450     Titem *pI_last_to_destroy = Data(new_size);
    00451     for (Titem *pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem();
    00452     /* remove them */
    00453     Tbase::ReduceRawSize(num_items * Titem_size);
    00454   }
    00455
    00457   FORCEINLINE Titem *AppendNew()
    00458   {
    00459     Titem& dst = *GrowSizeNC(1); // Grow size by one item
    00460     Titem *pNewItem = new (&dst) Titem(); // construct the new item by calling in-place new operator
    00461     return pNewItem;
    00462   }
    00463
    00465   FORCEINLINE Titem *Append(const Titem& src)
    00466   {
    00467     Titem& dst = *GrowSizeNC(1); // Grow size by one item
    00468     Titem *pNewItem = new (&dst) Titem(src); // construct the new item by calling in-place new operator with copy ctor()
    00469     return pNewItem;
    00470   }
    00471
    00473   FORCEINLINE Titem *Append(const Titem *pSrc, bsize_t num_items)
    00474   {
    00475     Titem *pDst = GrowSizeNC(num_items);
    00476     Titem *pDstOrg = pDst;
    00477     Titem *pDstEnd = pDst + num_items;
    00478     while (pDst < pDstEnd) new (pDst++) Titem(*(pSrc++));
    00479     return pDstOrg;
    00480   }
    00481
    00483   FORCEINLINE void RemoveBySwap(bsize_t idx)
    00484   {
    00485     CheckIdx(idx);
    00486     /* destroy removed item */
    00487     Titem *pRemoved = Data(idx);
    00488     RemoveBySwap(pRemoved);
    00489   }
    00490
    00492   FORCEINLINE void RemoveBySwap(Titem *pItem)
    00493   {
    00494     Titem *pLast = Data(Size() - 1);
    00495     assert(pItem >= Data() && pItem <= pLast);
    00496     /* move last item to its new place */
    00497     if (pItem != pLast) {
    00498       pItem->~Titem_();
    00499       new (pItem) Titem_(*pLast);
    00500     }
    00501     /* destroy the last item */
    00502     pLast->~Titem_();
    00503     /* and reduce the raw blob size */
    00504     Tbase::ReduceRawSize(Titem_size);
    00505   }
    00506
    00509   FORCEINLINE Titem *MakeFreeSpace(bsize_t num_items)
    00510   {
    00511     return (Titem*)Tbase::MakeRawFreeSpace(num_items * Titem_size);
    00512   }
    00513
    00514   FORCEINLINE OnTransfer Transfer()
    00515   {
    00516     return OnTransfer(*this);
    00517   };
    00518 };
    00519
    00520
    00521 #endif /* BLOB_HPP */