13 FORCEINLINE void MemCpyT(Titem_* d, const Titem_* s, int num_items = 1) |
13 FORCEINLINE void MemCpyT(Titem_* d, const Titem_* s, int num_items = 1) |
14 { |
14 { |
15 memcpy(d, s, num_items * sizeof(Titem_)); |
15 memcpy(d, s, num_items * sizeof(Titem_)); |
16 } |
16 } |
17 |
17 |
18 |
|
19 /** Base class for simple binary blobs. |
18 /** Base class for simple binary blobs. |
20 * Item is byte. |
19 * Item is byte. |
21 * The word 'simple' means: |
20 * The word 'simple' means: |
22 * - no configurable allocator type (always made from heap) |
21 * - no configurable allocator type (always made from heap) |
23 * - no smart deallocation - deallocation must be called from the same |
22 * - no smart deallocation - deallocation must be called from the same |
24 * module (DLL) where the blob was allocated |
23 * module (DLL) where the blob was allocated |
25 * - no configurable allocation policy (how big blocks should be allocated) |
24 * - no configurable allocation policy (how big blocks should be allocated) |
26 * - no extra ownership policy (i.e. 'copy on write') when blob is copied |
25 * - no extra ownership policy (i.e. 'copy on write') when blob is copied |
27 * - no thread synchronization at all |
26 * - no thread synchronization at all |
28 * |
27 * |
29 * Internal member layout: |
28 * Internal member layout: |
30 * 1. The only class member is pointer to the first item (see union ptr_u). |
29 * 1. The only class member is pointer to the first item (see union ptr_u). |
31 * 2. Allocated block contains the blob header (see CHdr) followed by the raw byte data. |
30 * 2. Allocated block contains the blob header (see CHdr) followed by the raw byte data. |
32 * Always, when it allocates memory the allocated size is: |
31 * Always, when it allocates memory the allocated size is: |
33 * sizeof(CHdr) + <data capacity> |
32 * sizeof(CHdr) + <data capacity> |
34 * 3. Two 'virtual' members (m_size and m_max_size) are stored in the CHdr at beginning |
33 * 3. Two 'virtual' members (m_size and m_max_size) are stored in the CHdr at beginning |
35 * of the alloated block. |
34 * of the alloated block. |
36 * 4. The pointer (in ptr_u) points behind the header (to the first data byte). |
35 * 4. The pointter (in ptr_u) pobsize_ts behind the header (to the first data byte). |
37 * When memory block is allocated, the sizeof(CHdr) it added to it. |
36 * When memory block is allocated, the sizeof(CHdr) it added to it. |
38 * 5. Benefits of this layout: |
37 * 5. Benefits of this layout: |
39 * - items are accessed in the simplest possible way - just dereferencing the pointer, |
38 * - items are accessed in the simplest possible way - just dereferencing the pointer, |
40 * which is good for performance (assuming that data are accessed most often). |
39 * which is good for performance (assuming that data are accessed most often). |
41 * - sizeof(blob) is the same as the size of any other pointer |
40 * - sizeof(blob) is the same as the size of any other pointer |
42 * 6. Drawbacks of this layout: |
41 * 6. Drawbacks of this layout: |
43 * - the fact, that pointer to the alocated block is adjusted by sizeof(CHdr) before |
42 * - the fact, that pointer to the alocated block is adjusted by sizeof(CHdr) before |
44 * it is stored can lead to several confusions: |
43 * it is stored can lead to several confusions: |
45 * - it is not common pattern so the implementation code is bit harder to read |
44 * - it is not common pattern so the implementation code is bit harder to read |
46 * - valgrind can generate warning that allocated block is lost (not accessible) |
45 * - valgrind can generate warning that allocated block is lost (not accessible) |
47 * */ |
46 * */ |
48 class CBlobBaseSimple { |
47 class CBlobBaseSimple { |
|
48 public: |
|
49 typedef ::ptrdiff_t bsize_t; |
|
50 typedef ::byte bitem_t; |
|
51 |
49 protected: |
52 protected: |
50 /** header of the allocated memory block */ |
53 /** header of the allocated memory block */ |
51 struct CHdr { |
54 struct CHdr { |
52 int m_size; ///< actual blob size in bytes |
55 bsize_t m_size; ///< actual blob size in bytes |
53 int m_max_size; ///< maximum (allocated) size in bytes |
56 bsize_t m_max_size; ///< maximum (allocated) size in bytes |
54 }; |
57 }; |
55 |
58 |
56 /** type used as class member */ |
59 /** type used as class member */ |
57 union { |
60 union { |
58 int8 *m_pData; ///< pointer to the first byte of data |
61 bitem_t *m_pData; ///< ptr to the first byte of data |
59 CHdr *m_pHdr_1; ///< pointer just after the CHdr holding m_size and m_max_size |
62 wchar_t *m_pwData; ///< ptr to the first byte of data |
|
63 CHdr *m_pHdr_1; ///< ptr just after the CHdr holding m_size and m_max_size |
60 } ptr_u; |
64 } ptr_u; |
61 |
65 |
62 public: |
66 public: |
63 static const int Ttail_reserve = 4; ///< four extra bytes will be always allocated and zeroed at the end |
67 static const bsize_t Ttail_reserve = 4; ///< four extra bytes will be always allocated and zeroed at the end |
64 |
68 |
65 /** default constructor - initializes empty blob */ |
69 /** default constructor - initializes empty blob */ |
66 FORCEINLINE CBlobBaseSimple() { InitEmpty(); } |
70 FORCEINLINE CBlobBaseSimple() { InitEmpty(); } |
|
71 /** constructor - create blob with data */ |
|
72 FORCEINLINE CBlobBaseSimple(const bitem_t *p, bsize_t num_bytes) |
|
73 { |
|
74 InitEmpty(); |
|
75 AppendRaw(p, num_bytes); |
|
76 } |
|
77 |
67 /** copy constructor */ |
78 /** copy constructor */ |
68 FORCEINLINE CBlobBaseSimple(const CBlobBaseSimple& src) |
79 FORCEINLINE CBlobBaseSimple(const CBlobBaseSimple& src) |
69 { |
80 { |
70 InitEmpty(); |
81 InitEmpty(); |
71 AppendRaw(src); |
82 AppendRaw(src); |
72 } |
83 } |
|
84 |
|
85 /** move constructor - take ownership of blob data */ |
|
86 FORCEINLINE CBlobBaseSimple(CHdr * const & pHdr_1) |
|
87 { |
|
88 assert(pHdr_1 != NULL); |
|
89 ptr_u.m_pHdr_1 = pHdr_1; |
|
90 *(CHdr**)&pHdr_1 = NULL; |
|
91 } |
|
92 |
73 /** destructor */ |
93 /** destructor */ |
74 FORCEINLINE ~CBlobBaseSimple() { Free(); } |
94 FORCEINLINE ~CBlobBaseSimple() |
|
95 { |
|
96 Free(); |
|
97 } |
|
98 |
75 protected: |
99 protected: |
76 /** initialize the empty blob by setting the ptr_u.m_pHdr_1 pointer to the static CHdr with |
100 /** initialize the empty blob by setting the ptr_u.m_pHdr_1 pointer to the static CHdr with |
77 * both m_size and m_max_size containing zero */ |
101 * both m_size and m_max_size containing zero */ |
78 FORCEINLINE void InitEmpty() { static CHdr hdrEmpty[] = {{0, 0}, {0, 0}}; ptr_u.m_pHdr_1 = &hdrEmpty[1]; } |
102 FORCEINLINE void InitEmpty() |
|
103 { |
|
104 static CHdr hdrEmpty[] = {{0, 0}, {0, 0}}; |
|
105 ptr_u.m_pHdr_1 = &hdrEmpty[1]; |
|
106 } |
|
107 |
79 /** initialize blob by attaching it to the given header followed by data */ |
108 /** initialize blob by attaching it to the given header followed by data */ |
80 FORCEINLINE void Init(CHdr* hdr) { ptr_u.m_pHdr_1 = &hdr[1]; } |
109 FORCEINLINE void Init(CHdr* hdr) |
|
110 { |
|
111 ptr_u.m_pHdr_1 = &hdr[1]; |
|
112 } |
|
113 |
81 /** blob header accessor - use it rather than using the pointer arithmetics directly - non-const version */ |
114 /** blob header accessor - use it rather than using the pointer arithmetics directly - non-const version */ |
82 FORCEINLINE CHdr& Hdr() { return ptr_u.m_pHdr_1[-1]; } |
115 FORCEINLINE CHdr& Hdr() |
|
116 { |
|
117 return ptr_u.m_pHdr_1[-1]; |
|
118 } |
|
119 |
83 /** blob header accessor - use it rather than using the pointer arithmetics directly - const version */ |
120 /** blob header accessor - use it rather than using the pointer arithmetics directly - const version */ |
84 FORCEINLINE const CHdr& Hdr() const { return ptr_u.m_pHdr_1[-1]; } |
121 FORCEINLINE const CHdr& Hdr() const |
|
122 { |
|
123 return ptr_u.m_pHdr_1[-1]; |
|
124 } |
|
125 |
85 /** return reference to the actual blob size - used when the size needs to be modified */ |
126 /** return reference to the actual blob size - used when the size needs to be modified */ |
86 FORCEINLINE int& RawSizeRef() { return Hdr().m_size; }; |
127 FORCEINLINE bsize_t& RawSizeRef() |
|
128 { |
|
129 return Hdr().m_size; |
|
130 }; |
87 |
131 |
88 public: |
132 public: |
89 /** return true if blob doesn't contain valid data */ |
133 /** return true if blob doesn't contain valid data */ |
90 FORCEINLINE bool IsEmpty() const { return RawSize() == 0; } |
134 FORCEINLINE bool IsEmpty() const |
|
135 { |
|
136 return RawSize() == 0; |
|
137 } |
|
138 |
91 /** return the number of valid data bytes in the blob */ |
139 /** return the number of valid data bytes in the blob */ |
92 FORCEINLINE int RawSize() const { return Hdr().m_size; }; |
140 FORCEINLINE bsize_t RawSize() const |
|
141 { |
|
142 return Hdr().m_size; |
|
143 }; |
|
144 |
93 /** return the current blob capacity in bytes */ |
145 /** return the current blob capacity in bytes */ |
94 FORCEINLINE int MaxRawSize() const { return Hdr().m_max_size; }; |
146 FORCEINLINE bsize_t MaxRawSize() const |
|
147 { |
|
148 return Hdr().m_max_size; |
|
149 }; |
|
150 |
95 /** return pointer to the first byte of data - non-const version */ |
151 /** return pointer to the first byte of data - non-const version */ |
96 FORCEINLINE int8* RawData() { return ptr_u.m_pData; } |
152 FORCEINLINE bitem_t* RawData() |
|
153 { |
|
154 return ptr_u.m_pData; |
|
155 } |
|
156 |
97 /** return pointer to the first byte of data - const version */ |
157 /** return pointer to the first byte of data - const version */ |
98 FORCEINLINE const int8* RawData() const { return ptr_u.m_pData; } |
158 FORCEINLINE const bitem_t* RawData() const |
99 #if 0 // reenable when needed |
159 { |
|
160 return ptr_u.m_pData; |
|
161 } |
|
162 |
100 /** return the 32 bit CRC of valid data in the blob */ |
163 /** return the 32 bit CRC of valid data in the blob */ |
101 FORCEINLINE uint32 Crc32() const {return CCrc32::Calc(RawData(), RawSize());} |
164 //FORCEINLINE bsize_t Crc32() const |
102 #endif //0 |
165 //{ |
|
166 // return CCrc32::Calc(RawData(), RawSize()); |
|
167 //} |
|
168 |
103 /** invalidate blob's data - doesn't free buffer */ |
169 /** invalidate blob's data - doesn't free buffer */ |
104 FORCEINLINE void Clear() { RawSizeRef() = 0; } |
170 FORCEINLINE void Clear() |
|
171 { |
|
172 RawSizeRef() = 0; |
|
173 } |
|
174 |
105 /** free the blob's memory */ |
175 /** free the blob's memory */ |
106 FORCEINLINE void Free() { if (MaxRawSize() > 0) {RawFree(&Hdr()); InitEmpty();} } |
176 FORCEINLINE void Free() |
|
177 { |
|
178 if (MaxRawSize() > 0) { |
|
179 RawFree(&Hdr()); |
|
180 InitEmpty(); |
|
181 } |
|
182 } |
|
183 |
107 /** copy data from another blob - replaces any existing blob's data */ |
184 /** copy data from another blob - replaces any existing blob's data */ |
108 FORCEINLINE void CopyFrom(const CBlobBaseSimple& src) { Clear(); AppendRaw(src); } |
185 FORCEINLINE void CopyFrom(const CBlobBaseSimple& src) |
|
186 { |
|
187 Clear(); |
|
188 AppendRaw(src); |
|
189 } |
|
190 |
109 /** overtake ownership of data buffer from the source blob - source blob will become empty */ |
191 /** overtake ownership of data buffer from the source blob - source blob will become empty */ |
110 FORCEINLINE void MoveFrom(CBlobBaseSimple& src) { Free(); ptr_u.m_pData = src.ptr_u.m_pData; src.InitEmpty(); } |
192 FORCEINLINE void MoveFrom(CBlobBaseSimple& src) |
|
193 { |
|
194 Free(); |
|
195 ptr_u.m_pData = src.ptr_u.m_pData; |
|
196 src.InitEmpty(); |
|
197 } |
|
198 |
111 /** swap buffers (with data) between two blobs (this and source blob) */ |
199 /** swap buffers (with data) between two blobs (this and source blob) */ |
112 FORCEINLINE void Swap(CBlobBaseSimple& src) { int8 *tmp = ptr_u.m_pData; ptr_u.m_pData = src.ptr_u.m_pData; src.ptr_u.m_pData = tmp; } |
200 FORCEINLINE void Swap(CBlobBaseSimple& src) |
|
201 { |
|
202 bitem_t *tmp = ptr_u.m_pData; ptr_u.m_pData = src.ptr_u.m_pData; |
|
203 src.ptr_u.m_pData = tmp; |
|
204 } |
113 |
205 |
114 /** append new bytes at the end of existing data bytes - reallocates if necessary */ |
206 /** append new bytes at the end of existing data bytes - reallocates if necessary */ |
115 FORCEINLINE void AppendRaw(int8 *p, int num_bytes) |
207 FORCEINLINE void AppendRaw(const void *p, bsize_t num_bytes) |
116 { |
208 { |
117 assert(p != NULL); |
209 assert(p != NULL); |
118 if (num_bytes > 0) { |
210 if (num_bytes > 0) { |
119 memcpy(GrowRawSize(num_bytes), p, num_bytes); |
211 memcpy(GrowRawSize(num_bytes), p, num_bytes); |
120 } else { |
212 } else { |
128 if (!src.IsEmpty()) |
220 if (!src.IsEmpty()) |
129 memcpy(GrowRawSize(src.RawSize()), src.RawData(), src.RawSize()); |
221 memcpy(GrowRawSize(src.RawSize()), src.RawData(), src.RawSize()); |
130 } |
222 } |
131 |
223 |
132 /** Reallocate if there is no free space for num_bytes bytes. |
224 /** Reallocate if there is no free space for num_bytes bytes. |
133 * @return pointer to the new data to be added */ |
225 * @return pointer to the new data to be added */ |
134 FORCEINLINE int8* MakeRawFreeSpace(int num_bytes) |
226 FORCEINLINE bitem_t* MakeRawFreeSpace(bsize_t num_bytes) |
135 { |
227 { |
136 assert(num_bytes >= 0); |
228 assert(num_bytes >= 0); |
137 int new_size = RawSize() + num_bytes; |
229 bsize_t new_size = RawSize() + num_bytes; |
138 if (new_size > MaxRawSize()) SmartAlloc(new_size); |
230 if (new_size > MaxRawSize()) SmartAlloc(new_size); |
139 FixTail(); |
|
140 return ptr_u.m_pData + RawSize(); |
231 return ptr_u.m_pData + RawSize(); |
141 } |
232 } |
142 |
233 |
143 /** Increase RawSize() by num_bytes. |
234 /** Increase RawSize() by num_bytes. |
144 * @return pointer to the new data added */ |
235 * @return pointer to the new data added */ |
145 FORCEINLINE int8* GrowRawSize(int num_bytes) |
236 FORCEINLINE bitem_t* GrowRawSize(bsize_t num_bytes) |
146 { |
237 { |
147 int8* pNewData = MakeRawFreeSpace(num_bytes); |
238 bitem_t* pNewData = MakeRawFreeSpace(num_bytes); |
148 RawSizeRef() += num_bytes; |
239 RawSizeRef() += num_bytes; |
149 return pNewData; |
240 return pNewData; |
150 } |
241 } |
151 |
242 |
152 /** Decrease RawSize() by num_bytes. */ |
243 /** Decrease RawSize() by num_bytes. */ |
153 FORCEINLINE void ReduceRawSize(int num_bytes) |
244 FORCEINLINE void ReduceRawSize(bsize_t num_bytes) |
154 { |
245 { |
155 if (MaxRawSize() > 0 && num_bytes > 0) { |
246 if (MaxRawSize() > 0 && num_bytes > 0) { |
156 assert(num_bytes <= RawSize()); |
247 assert(num_bytes <= RawSize()); |
157 if (num_bytes < RawSize()) RawSizeRef() -= num_bytes; |
248 if (num_bytes < RawSize()) RawSizeRef() -= num_bytes; |
158 else RawSizeRef() = 0; |
249 else RawSizeRef() = 0; |
159 } |
250 } |
160 } |
251 } |
|
252 |
161 /** reallocate blob data if needed */ |
253 /** reallocate blob data if needed */ |
162 void SmartAlloc(int new_size) |
254 void SmartAlloc(bsize_t new_size) |
163 { |
255 { |
164 int old_max_size = MaxRawSize(); |
256 bsize_t old_max_size = MaxRawSize(); |
165 if (old_max_size >= new_size) return; |
257 if (old_max_size >= new_size) return; |
166 // calculate minimum block size we need to allocate |
258 // calculate minimum block size we need to allocate |
167 int min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve; |
259 bsize_t min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve; |
168 // ask allocation policy for some reasonable block size |
260 // ask allocation policy for some reasonable block size |
169 int alloc_size = AllocPolicy(min_alloc_size); |
261 bsize_t alloc_size = AllocPolicy(min_alloc_size); |
170 // allocate new block |
262 // allocate new block |
171 CHdr* pNewHdr = RawAlloc(alloc_size); |
263 CHdr* pNewHdr = RawAlloc(alloc_size); |
172 // setup header |
264 // setup header |
173 pNewHdr->m_size = RawSize(); |
265 pNewHdr->m_size = RawSize(); |
174 pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve); |
266 pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve); |
199 min_alloc = (min_alloc | ((1 << 20) - 1)) + 1; |
292 min_alloc = (min_alloc | ((1 << 20) - 1)) + 1; |
200 return min_alloc; |
293 return min_alloc; |
201 } |
294 } |
202 |
295 |
203 /** all allocation should happen here */ |
296 /** all allocation should happen here */ |
204 static FORCEINLINE CHdr* RawAlloc(int num_bytes) { return (CHdr*)malloc(num_bytes); } |
297 static FORCEINLINE CHdr* RawAlloc(bsize_t num_bytes) |
|
298 { |
|
299 return (CHdr*)malloc(num_bytes); |
|
300 } |
|
301 |
205 /** all deallocations should happen here */ |
302 /** all deallocations should happen here */ |
206 static FORCEINLINE void RawFree(CHdr* p) { free(p); } |
303 static FORCEINLINE void RawFree(CHdr* p) |
|
304 { |
|
305 free(p); |
|
306 } |
207 /** fixing the four bytes at the end of blob data - useful when blob is used to hold string */ |
307 /** fixing the four bytes at the end of blob data - useful when blob is used to hold string */ |
208 FORCEINLINE void FixTail() |
308 FORCEINLINE void FixTail() const |
209 { |
309 { |
210 if (MaxRawSize() > 0) { |
310 if (MaxRawSize() > 0) { |
211 int8 *p = &ptr_u.m_pData[RawSize()]; |
311 bitem_t *p = &ptr_u.m_pData[RawSize()]; |
212 for (int i = 0; i < Ttail_reserve; i++) p[i] = 0; |
312 for (bsize_t i = 0; i < Ttail_reserve; i++) { |
|
313 p[i] = 0; |
|
314 } |
213 } |
315 } |
214 } |
316 } |
215 }; |
317 }; |
216 |
318 |
217 /** Blob - simple dynamic Titem_ array. Titem_ (template argument) is a placeholder for any type. |
319 /** Blob - simple dynamic Titem_ array. Titem_ (template argument) is a placeholder for any type. |
218 * Titem_ can be any integral type, pointer, or structure. Using Blob instead of just plain C array |
320 * Titem_ can be any integral type, pointer, or structure. Using Blob instead of just plain C array |
219 * simplifies the resource management in several ways: |
321 * simplifies the resource management in several ways: |
220 * 1. When adding new item(s) it automatically grows capacity if needed. |
322 * 1. When adding new item(s) it automatically grows capacity if needed. |
221 * 2. When variable of type Blob comes out of scope it automatically frees the data buffer. |
323 * 2. When variable of type Blob comes out of scope it automatically frees the data buffer. |
222 * 3. Takes care about the actual data size (number of used items). |
324 * 3. Takes care about the actual data size (number of used items). |
223 * 4. Dynamically constructs only used items (as opposite of static array which constructs all items) */ |
325 * 4. Dynamically constructs only used items (as opposite of static array which constructs all items) */ |
224 template <class Titem_, class Tbase_ = CBlobBaseSimple> |
326 template <class Titem_, class Tbase_ = CBlobBaseSimple> |
225 class CBlobT : public CBlobBaseSimple { |
327 class CBlobT : public Tbase_ { |
226 // make template arguments public: |
328 // make template arguments public: |
227 public: |
329 public: |
228 typedef Titem_ Titem; |
330 typedef Titem_ Titem; |
229 typedef Tbase_ Tbase; |
331 typedef Tbase_ Tbase; |
230 |
332 typedef typename Tbase::bsize_t bsize_t; |
231 static const int Titem_size = sizeof(Titem); |
333 |
|
334 static const bsize_t Titem_size = sizeof(Titem); |
|
335 |
|
336 struct OnTransfer { |
|
337 typename Tbase_::CHdr *m_pHdr_1; |
|
338 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;} |
|
339 OnTransfer(CBlobT& src) : m_pHdr_1(src.ptr_u.m_pHdr_1) {src.InitEmpty();} |
|
340 ~OnTransfer() {assert(m_pHdr_1 == NULL);} |
|
341 }; |
232 |
342 |
233 /** Default constructor - makes new Blob ready to accept any data */ |
343 /** Default constructor - makes new Blob ready to accept any data */ |
234 FORCEINLINE CBlobT() : Tbase() {} |
344 FORCEINLINE CBlobT() |
|
345 : Tbase() |
|
346 {} |
|
347 |
|
348 /** Constructor - makes new Blob with data */ |
|
349 FORCEINLINE CBlobT(const Titem_ *p, bsize_t num_items) |
|
350 : Tbase((typename Tbase_::bitem_t*)p, num_items * Titem_size) |
|
351 {} |
|
352 |
235 /** Copy constructor - make new blob to become copy of the original (source) blob */ |
353 /** Copy constructor - make new blob to become copy of the original (source) blob */ |
236 FORCEINLINE CBlobT(const Tbase& src) : Tbase(src) {assert((RawSize() % Titem_size) == 0);} |
354 FORCEINLINE CBlobT(const Tbase& src) |
|
355 : Tbase(src) |
|
356 { |
|
357 assert((Tbase::RawSize() % Titem_size) == 0); |
|
358 } |
|
359 |
|
360 /** Take ownership constructor */ |
|
361 FORCEINLINE CBlobT(const OnTransfer& ot) |
|
362 : Tbase(ot.m_pHdr_1) |
|
363 {} |
|
364 |
237 /** Destructor - ensures that allocated memory (if any) is freed */ |
365 /** Destructor - ensures that allocated memory (if any) is freed */ |
238 FORCEINLINE ~CBlobT() { Free(); } |
366 FORCEINLINE ~CBlobT() |
|
367 { |
|
368 Free(); |
|
369 } |
|
370 |
239 /** Check the validity of item index (only in debug mode) */ |
371 /** Check the validity of item index (only in debug mode) */ |
240 FORCEINLINE void CheckIdx(int idx) { assert(idx >= 0); assert(idx < Size()); } |
372 FORCEINLINE void CheckIdx(bsize_t idx) |
|
373 { |
|
374 assert(idx >= 0); assert(idx < Size()); |
|
375 } |
|
376 |
241 /** Return pointer to the first data item - non-const version */ |
377 /** Return pointer to the first data item - non-const version */ |
242 FORCEINLINE Titem* Data() { return (Titem*)RawData(); } |
378 FORCEINLINE Titem* Data() |
|
379 { |
|
380 return (Titem*)Tbase::RawData(); |
|
381 } |
|
382 |
243 /** Return pointer to the first data item - const version */ |
383 /** Return pointer to the first data item - const version */ |
244 FORCEINLINE const Titem* Data() const { return (const Titem*)RawData(); } |
384 FORCEINLINE const Titem* Data() const |
|
385 { |
|
386 return (const Titem*)Tbase::RawData(); |
|
387 } |
|
388 |
245 /** Return pointer to the idx-th data item - non-const version */ |
389 /** Return pointer to the idx-th data item - non-const version */ |
246 FORCEINLINE Titem* Data(int idx) { CheckIdx(idx); return (Data() + idx); } |
390 FORCEINLINE Titem* Data(bsize_t idx) |
|
391 { |
|
392 CheckIdx(idx); |
|
393 return (Data() + idx); |
|
394 } |
|
395 |
247 /** Return pointer to the idx-th data item - const version */ |
396 /** Return pointer to the idx-th data item - const version */ |
248 FORCEINLINE const Titem* Data(int idx) const { CheckIdx(idx); return (Data() + idx); } |
397 FORCEINLINE const Titem* Data(bsize_t idx) const |
|
398 { |
|
399 CheckIdx(idx); return (Data() + idx); |
|
400 } |
|
401 |
249 /** Return number of items in the Blob */ |
402 /** Return number of items in the Blob */ |
250 FORCEINLINE int Size() const { return (RawSize() / Titem_size); } |
403 FORCEINLINE bsize_t Size() const |
|
404 { |
|
405 return (Tbase::RawSize() / Titem_size); |
|
406 } |
|
407 |
|
408 /** Return total number of items that can fit in the Blob without buffer reallocation */ |
|
409 FORCEINLINE bsize_t MaxSize() const |
|
410 { |
|
411 return (Tbase::MaxRawSize() / Titem_size); |
|
412 } |
|
413 /** Return number of additional items that can fit in the Blob without buffer reallocation */ |
|
414 FORCEINLINE bsize_t GetReserve() const |
|
415 { |
|
416 return ((Tbase::MaxRawSize() - Tbase::RawSize()) / Titem_size); |
|
417 } |
|
418 |
251 /** Free the memory occupied by Blob destroying all items */ |
419 /** Free the memory occupied by Blob destroying all items */ |
252 FORCEINLINE void Free() |
420 FORCEINLINE void Free() |
253 { |
421 { |
254 assert((RawSize() % Titem_size) == 0); |
422 assert((Tbase::RawSize() % Titem_size) == 0); |
255 int old_size = Size(); |
423 bsize_t old_size = Size(); |
256 if (old_size > 0) { |
424 if (old_size > 0) { |
257 // destroy removed items; |
425 // destroy removed items; |
258 Titem* pI_last_to_destroy = Data(0); |
426 Titem* pI_last_to_destroy = Data(0); |
259 for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem_(); |
427 for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem_(); |
260 } |
428 } |
261 Tbase::Free(); |
429 Tbase::Free(); |
262 } |
430 } |
|
431 |
263 /** Grow number of data items in Blob by given number - doesn't construct items */ |
432 /** Grow number of data items in Blob by given number - doesn't construct items */ |
264 FORCEINLINE Titem* GrowSizeNC(int num_items) { return (Titem*)GrowRawSize(num_items * Titem_size); } |
433 FORCEINLINE Titem* GrowSizeNC(bsize_t num_items) |
|
434 { |
|
435 return (Titem*)Tbase::GrowRawSize(num_items * Titem_size); |
|
436 } |
|
437 |
265 /** Grow number of data items in Blob by given number - constructs new items (using Titem_'s default constructor) */ |
438 /** Grow number of data items in Blob by given number - constructs new items (using Titem_'s default constructor) */ |
266 FORCEINLINE Titem* GrowSizeC(int num_items) |
439 FORCEINLINE Titem* GrowSizeC(bsize_t num_items) |
267 { |
440 { |
268 Titem* pI = GrowSizeNC(num_items); |
441 Titem* pI = GrowSizeNC(num_items); |
269 for (int i = num_items; i > 0; i--, pI++) new (pI) Titem(); |
442 for (bsize_t i = num_items; i > 0; i--, pI++) new (pI) Titem(); |
270 } |
443 } |
|
444 |
271 /** Destroy given number of items and reduce the Blob's data size */ |
445 /** Destroy given number of items and reduce the Blob's data size */ |
272 FORCEINLINE void ReduceSize(int num_items) |
446 FORCEINLINE void ReduceSize(bsize_t num_items) |
273 { |
447 { |
274 assert((RawSize() % Titem_size) == 0); |
448 assert((Tbase::RawSize() % Titem_size) == 0); |
275 int old_size = Size(); |
449 bsize_t old_size = Size(); |
276 assert(num_items <= old_size); |
450 assert(num_items <= old_size); |
277 int new_size = (num_items <= old_size) ? (old_size - num_items) : 0; |
451 bsize_t new_size = (num_items <= old_size) ? (old_size - num_items) : 0; |
278 // destroy removed items; |
452 // destroy removed items; |
279 Titem* pI_last_to_destroy = Data(new_size); |
453 Titem* pI_last_to_destroy = Data(new_size); |
280 for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem(); |
454 for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem(); |
281 // remove them |
455 // remove them |
282 ReduceRawSize(num_items * Titem_size); |
456 Tbase::ReduceRawSize(num_items * Titem_size); |
283 } |
457 } |
|
458 |
284 /** Append one data item at the end (calls Titem_'s default constructor) */ |
459 /** Append one data item at the end (calls Titem_'s default constructor) */ |
285 FORCEINLINE Titem* AppendNew() |
460 FORCEINLINE Titem* AppendNew() |
286 { |
461 { |
287 Titem& dst = *GrowSizeNC(1); // Grow size by one item |
462 Titem& dst = *GrowSizeNC(1); // Grow size by one item |
288 Titem* pNewItem = new (&dst) Titem(); // construct the new item by calling in-place new operator |
463 Titem* pNewItem = new (&dst) Titem(); // construct the new item by calling in-place new operator |
289 return pNewItem; |
464 return pNewItem; |
290 } |
465 } |
|
466 |
291 /** Append the copy of given item at the end of Blob (using copy constructor) */ |
467 /** Append the copy of given item at the end of Blob (using copy constructor) */ |
292 FORCEINLINE Titem* Append(const Titem& src) |
468 FORCEINLINE Titem* Append(const Titem& src) |
293 { |
469 { |
294 Titem& dst = *GrowSizeNC(1); // Grow size by one item |
470 Titem& dst = *GrowSizeNC(1); // Grow size by one item |
295 Titem* pNewItem = new (&dst) Titem(src); // construct the new item by calling in-place new operator with copy ctor() |
471 Titem* pNewItem = new (&dst) Titem(src); // construct the new item by calling in-place new operator with copy ctor() |
296 return pNewItem; |
472 return pNewItem; |
297 } |
473 } |
|
474 |
298 /** Add given items (ptr + number of items) at the end of blob */ |
475 /** Add given items (ptr + number of items) at the end of blob */ |
299 FORCEINLINE Titem* Append(const Titem* pSrc, int num_items) |
476 FORCEINLINE Titem* Append(const Titem* pSrc, bsize_t num_items) |
300 { |
477 { |
301 Titem* pDst = GrowSizeNC(num_items); |
478 Titem* pDst = GrowSizeNC(num_items); |
302 Titem* pDstOrg = pDst; |
479 Titem* pDstOrg = pDst; |
303 Titem* pDstEnd = pDst + num_items; |
480 Titem* pDstEnd = pDst + num_items; |
304 while (pDst < pDstEnd) new (pDst++) Titem(*(pSrc++)); |
481 while (pDst < pDstEnd) new (pDst++) Titem(*(pSrc++)); |
305 return pDstOrg; |
482 return pDstOrg; |
306 } |
483 } |
|
484 |
307 /** Remove item with the given index by replacing it by the last item and reducing the size by one */ |
485 /** Remove item with the given index by replacing it by the last item and reducing the size by one */ |
308 FORCEINLINE void RemoveBySwap(int idx) |
486 FORCEINLINE void RemoveBySwap(bsize_t idx) |
309 { |
487 { |
310 CheckIdx(idx); |
488 CheckIdx(idx); |
311 // destroy removed item |
489 // destroy removed item |
312 Titem* pRemoved = Data(idx); |
490 Titem* pRemoved = Data(idx); |
313 RemoveBySwap(pRemoved); |
491 RemoveBySwap(pRemoved); |
314 } |
492 } |
|
493 |
315 /** Remove item given by pointer replacing it by the last item and reducing the size by one */ |
494 /** Remove item given by pointer replacing it by the last item and reducing the size by one */ |
316 FORCEINLINE void RemoveBySwap(Titem* pItem) |
495 FORCEINLINE void RemoveBySwap(Titem* pItem) |
317 { |
496 { |
318 Titem* pLast = Data(Size() - 1); |
497 Titem* pLast = Data(Size() - 1); |
319 assert(pItem >= Data() && pItem <= pLast); |
498 assert(pItem >= Data() && pItem <= pLast); |