blob.hpp
Go to the documentation of this file.00001
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
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
00169
00170
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
00263 bsize_t min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve;
00264
00265 bsize_t alloc_size = AllocPolicy(min_alloc_size);
00266
00267 CHdr* pNewHdr = RawAlloc(alloc_size);
00268
00269 pNewHdr->m_size = RawSize();
00270 pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve);
00271
00272 if (RawSize() > 0)
00273 memcpy(pNewHdr + 1, ptr_u.m_pData, pNewHdr->m_size);
00274
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
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
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
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
00460 Tbase::ReduceRawSize(num_items * Titem_size);
00461 }
00462
00464 FORCEINLINE Titem* AppendNew()
00465 {
00466 Titem& dst = *GrowSizeNC(1);
00467 Titem* pNewItem = new (&dst) Titem();
00468 return pNewItem;
00469 }
00470
00472 FORCEINLINE Titem* Append(const Titem& src)
00473 {
00474 Titem& dst = *GrowSizeNC(1);
00475 Titem* pNewItem = new (&dst) Titem(src);
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
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
00504 if (pItem != pLast) {
00505 pItem->~Titem_();
00506 new (pItem) Titem_(*pLast);
00507 }
00508
00509 pLast->~Titem_();
00510
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