blob.hpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
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:
00072 static CHdr hdrEmpty[];
00073
00074 public:
00075 static const bsize_t Ttail_reserve = 4;
00076
00078 FORCEINLINE CBlobBaseSimple() { InitEmpty(); }
00080 FORCEINLINE CBlobBaseSimple(const bitem_t *p, bsize_t num_bytes)
00081 {
00082 InitEmpty();
00083 AppendRaw(p, num_bytes);
00084 }
00085
00087 FORCEINLINE CBlobBaseSimple(const CBlobBaseSimple& src)
00088 {
00089 InitEmpty();
00090 AppendRaw(src);
00091 }
00092
00094 FORCEINLINE CBlobBaseSimple(CHdr * const & pHdr_1)
00095 {
00096 assert(pHdr_1 != NULL);
00097 ptr_u.m_pHdr_1 = pHdr_1;
00098 *const_cast<CHdr**>(&pHdr_1) = NULL;
00099 }
00100
00102 FORCEINLINE ~CBlobBaseSimple()
00103 {
00104 Free();
00105 }
00106
00107 protected:
00110 FORCEINLINE void InitEmpty()
00111 {
00112 ptr_u.m_pHdr_1 = const_cast<CHdr *>(&CBlobBaseSimple::hdrEmpty[1]);
00113 }
00114
00116 FORCEINLINE void Init(CHdr *hdr)
00117 {
00118 ptr_u.m_pHdr_1 = &hdr[1];
00119 }
00120
00122 FORCEINLINE CHdr& Hdr()
00123 {
00124 return *(ptr_u.m_pHdr_1 - 1);
00125 }
00126
00128 FORCEINLINE const CHdr& Hdr() const
00129 {
00130 return *(ptr_u.m_pHdr_1 - 1);
00131 }
00132
00134 FORCEINLINE bsize_t& RawSizeRef()
00135 {
00136 return Hdr().m_size;
00137 };
00138
00139 public:
00141 FORCEINLINE bool IsEmpty() const
00142 {
00143 return RawSize() == 0;
00144 }
00145
00147 FORCEINLINE bsize_t RawSize() const
00148 {
00149 return Hdr().m_size;
00150 };
00151
00153 FORCEINLINE bsize_t MaxRawSize() const
00154 {
00155 return Hdr().m_max_size;
00156 };
00157
00159 FORCEINLINE bitem_t *RawData()
00160 {
00161 return ptr_u.m_pData;
00162 }
00163
00165 FORCEINLINE const bitem_t *RawData() const
00166 {
00167 return ptr_u.m_pData;
00168 }
00169
00171
00172
00173
00174
00175
00177 FORCEINLINE void Clear()
00178 {
00179 RawSizeRef() = 0;
00180 }
00181
00183 FORCEINLINE void Free()
00184 {
00185 if (MaxRawSize() > 0) {
00186 RawFree(&Hdr());
00187 InitEmpty();
00188 }
00189 }
00190
00192 FORCEINLINE void CopyFrom(const CBlobBaseSimple& src)
00193 {
00194 Clear();
00195 AppendRaw(src);
00196 }
00197
00199 FORCEINLINE void MoveFrom(CBlobBaseSimple& src)
00200 {
00201 Free();
00202 ptr_u.m_pData = src.ptr_u.m_pData;
00203 src.InitEmpty();
00204 }
00205
00207 FORCEINLINE void Swap(CBlobBaseSimple& src)
00208 {
00209 bitem_t *tmp = ptr_u.m_pData; ptr_u.m_pData = src.ptr_u.m_pData;
00210 src.ptr_u.m_pData = tmp;
00211 }
00212
00214 FORCEINLINE void AppendRaw(const void *p, bsize_t num_bytes)
00215 {
00216 assert(p != NULL);
00217 if (num_bytes > 0) {
00218 memcpy(GrowRawSize(num_bytes), p, num_bytes);
00219 } else {
00220 assert(num_bytes >= 0);
00221 }
00222 }
00223
00225 FORCEINLINE void AppendRaw(const CBlobBaseSimple& src)
00226 {
00227 if (!src.IsEmpty())
00228 memcpy(GrowRawSize(src.RawSize()), src.RawData(), src.RawSize());
00229 }
00230
00233 FORCEINLINE bitem_t *MakeRawFreeSpace(bsize_t num_bytes)
00234 {
00235 assert(num_bytes >= 0);
00236 bsize_t new_size = RawSize() + num_bytes;
00237 if (new_size > MaxRawSize()) SmartAlloc(new_size);
00238 return ptr_u.m_pData + RawSize();
00239 }
00240
00243 FORCEINLINE bitem_t *GrowRawSize(bsize_t num_bytes)
00244 {
00245 bitem_t *pNewData = MakeRawFreeSpace(num_bytes);
00246 RawSizeRef() += num_bytes;
00247 return pNewData;
00248 }
00249
00251 FORCEINLINE void ReduceRawSize(bsize_t num_bytes)
00252 {
00253 if (MaxRawSize() > 0 && num_bytes > 0) {
00254 assert(num_bytes <= RawSize());
00255 if (num_bytes < RawSize()) {
00256 RawSizeRef() -= num_bytes;
00257 } else {
00258 RawSizeRef() = 0;
00259 }
00260 }
00261 }
00262
00264 void SmartAlloc(bsize_t new_size)
00265 {
00266 bsize_t old_max_size = MaxRawSize();
00267 if (old_max_size >= new_size) return;
00268
00269 bsize_t min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve;
00270
00271 bsize_t alloc_size = AllocPolicy(min_alloc_size);
00272
00273 CHdr *pNewHdr = RawAlloc(alloc_size);
00274
00275 pNewHdr->m_size = RawSize();
00276 pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve);
00277
00278 if (RawSize() > 0)
00279 memcpy(pNewHdr + 1, ptr_u.m_pData, pNewHdr->m_size);
00280
00281 CHdr *pOldHdr = &Hdr();
00282 Init(pNewHdr);
00283 if (old_max_size > 0)
00284 RawFree(pOldHdr);
00285 }
00286
00288 FORCEINLINE static bsize_t AllocPolicy(bsize_t min_alloc)
00289 {
00290 if (min_alloc < (1 << 9)) {
00291 if (min_alloc < (1 << 5)) return (1 << 5);
00292 return (min_alloc < (1 << 7)) ? (1 << 7) : (1 << 9);
00293 }
00294 if (min_alloc < (1 << 15)) {
00295 if (min_alloc < (1 << 11)) return (1 << 11);
00296 return (min_alloc < (1 << 13)) ? (1 << 13) : (1 << 15);
00297 }
00298 if (min_alloc < (1 << 20)) {
00299 if (min_alloc < (1 << 17)) return (1 << 17);
00300 return (min_alloc < (1 << 19)) ? (1 << 19) : (1 << 20);
00301 }
00302 min_alloc = (min_alloc | ((1 << 20) - 1)) + 1;
00303 return min_alloc;
00304 }
00305
00307 static FORCEINLINE CHdr *RawAlloc(bsize_t num_bytes)
00308 {
00309 return (CHdr*)MallocT<byte>(num_bytes);
00310 }
00311
00313 static FORCEINLINE void RawFree(CHdr *p)
00314 {
00315
00316 assert(p != CBlobBaseSimple::hdrEmpty);
00317
00318
00319 free(p);
00320 }
00322 FORCEINLINE void FixTail() const
00323 {
00324 if (MaxRawSize() > 0) {
00325 bitem_t *p = &ptr_u.m_pData[RawSize()];
00326 for (bsize_t i = 0; i < Ttail_reserve; i++) {
00327 p[i] = 0;
00328 }
00329 }
00330 }
00331 };
00332
00340 template <class Titem_, class Tbase_ = CBlobBaseSimple>
00341 class CBlobT : public Tbase_ {
00342
00343 public:
00344 typedef Titem_ Titem;
00345 typedef Tbase_ Tbase;
00346 typedef typename Tbase::bsize_t bsize_t;
00347
00348 static const bsize_t Titem_size = sizeof(Titem);
00349
00350 struct OnTransfer {
00351 typename Tbase_::CHdr *m_pHdr_1;
00352 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;}
00353 OnTransfer(CBlobT& src) : m_pHdr_1(src.ptr_u.m_pHdr_1) {src.InitEmpty();}
00354 ~OnTransfer() {assert(m_pHdr_1 == NULL);}
00355 };
00356
00358 FORCEINLINE CBlobT()
00359 : Tbase()
00360 {}
00361
00363 FORCEINLINE CBlobT(const Titem_ *p, bsize_t num_items)
00364 : Tbase((typename Tbase_::bitem_t*)p, num_items * Titem_size)
00365 {}
00366
00368 FORCEINLINE CBlobT(const Tbase& src)
00369 : Tbase(src)
00370 {
00371 assert((Tbase::RawSize() % Titem_size) == 0);
00372 }
00373
00375 FORCEINLINE CBlobT(const OnTransfer& ot)
00376 : Tbase(ot.m_pHdr_1)
00377 {}
00378
00380 FORCEINLINE ~CBlobT()
00381 {
00382 Free();
00383 }
00384
00386 FORCEINLINE void CheckIdx(bsize_t idx) const
00387 {
00388 assert(idx >= 0); assert(idx < Size());
00389 }
00390
00392 FORCEINLINE Titem *Data()
00393 {
00394 return (Titem*)Tbase::RawData();
00395 }
00396
00398 FORCEINLINE const Titem *Data() const
00399 {
00400 return (const Titem*)Tbase::RawData();
00401 }
00402
00404 FORCEINLINE Titem *Data(bsize_t idx)
00405 {
00406 CheckIdx(idx);
00407 return (Data() + idx);
00408 }
00409
00411 FORCEINLINE const Titem *Data(bsize_t idx) const
00412 {
00413 CheckIdx(idx);
00414 return (Data() + idx);
00415 }
00416
00418 FORCEINLINE bsize_t Size() const
00419 {
00420 return (Tbase::RawSize() / Titem_size);
00421 }
00422
00424 FORCEINLINE bsize_t MaxSize() const
00425 {
00426 return (Tbase::MaxRawSize() / Titem_size);
00427 }
00429 FORCEINLINE bsize_t GetReserve() const
00430 {
00431 return ((Tbase::MaxRawSize() - Tbase::RawSize()) / Titem_size);
00432 }
00433
00435 FORCEINLINE void Free()
00436 {
00437 assert((Tbase::RawSize() % Titem_size) == 0);
00438 bsize_t old_size = Size();
00439 if (old_size > 0) {
00440
00441 Titem *pI_last_to_destroy = Data(0);
00442 for (Titem *pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem_();
00443 }
00444 Tbase::Free();
00445 }
00446
00448 FORCEINLINE Titem *GrowSizeNC(bsize_t num_items)
00449 {
00450 return (Titem*)Tbase::GrowRawSize(num_items * Titem_size);
00451 }
00452
00454 FORCEINLINE Titem *GrowSizeC(bsize_t num_items)
00455 {
00456 Titem *pI = GrowSizeNC(num_items);
00457 for (bsize_t i = num_items; i > 0; i--, pI++) new (pI) Titem();
00458 }
00459
00461 FORCEINLINE void ReduceSize(bsize_t num_items)
00462 {
00463 assert((Tbase::RawSize() % Titem_size) == 0);
00464 bsize_t old_size = Size();
00465 assert(num_items <= old_size);
00466 bsize_t new_size = (num_items <= old_size) ? (old_size - num_items) : 0;
00467
00468 Titem *pI_last_to_destroy = Data(new_size);
00469 for (Titem *pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem();
00470
00471 Tbase::ReduceRawSize(num_items * Titem_size);
00472 }
00473
00475 FORCEINLINE Titem *AppendNew()
00476 {
00477 Titem& dst = *GrowSizeNC(1);
00478 Titem *pNewItem = new (&dst) Titem();
00479 return pNewItem;
00480 }
00481
00483 FORCEINLINE Titem *Append(const Titem& src)
00484 {
00485 Titem& dst = *GrowSizeNC(1);
00486 Titem *pNewItem = new (&dst) Titem(src);
00487 return pNewItem;
00488 }
00489
00491 FORCEINLINE Titem *Append(const Titem *pSrc, bsize_t num_items)
00492 {
00493 Titem *pDst = GrowSizeNC(num_items);
00494 Titem *pDstOrg = pDst;
00495 Titem *pDstEnd = pDst + num_items;
00496 while (pDst < pDstEnd) new (pDst++) Titem(*(pSrc++));
00497 return pDstOrg;
00498 }
00499
00501 FORCEINLINE void RemoveBySwap(bsize_t idx)
00502 {
00503 CheckIdx(idx);
00504
00505 Titem *pRemoved = Data(idx);
00506 RemoveBySwap(pRemoved);
00507 }
00508
00510 FORCEINLINE void RemoveBySwap(Titem *pItem)
00511 {
00512 Titem *pLast = Data(Size() - 1);
00513 assert(pItem >= Data() && pItem <= pLast);
00514
00515 if (pItem != pLast) {
00516 pItem->~Titem_();
00517 new (pItem) Titem_(*pLast);
00518 }
00519
00520 pLast->~Titem_();
00521
00522 Tbase::ReduceRawSize(Titem_size);
00523 }
00524
00527 FORCEINLINE Titem *MakeFreeSpace(bsize_t num_items)
00528 {
00529 return (Titem*)Tbase::MakeRawFreeSpace(num_items * Titem_size);
00530 }
00531
00532 FORCEINLINE OnTransfer Transfer()
00533 {
00534 return OnTransfer(*this);
00535 };
00536 };
00537
00538
00539 #endif