2 |
2 |
3 #ifndef BLOB_HPP |
3 #ifndef BLOB_HPP |
4 #define BLOB_HPP |
4 #define BLOB_HPP |
5 |
5 |
6 /** Type-safe version of memcpy(). |
6 /** Type-safe version of memcpy(). |
7 * @param d destination buffer |
7 * @param d destination buffer |
8 * @param s source buffer |
8 * @param s source buffer |
9 * @param num_items number of items to be copied (!not number of bytes!) */ |
9 * @param num_items number of items to be copied (!not number of bytes!) */ |
10 template <class Titem_> |
10 template <class Titem_> |
11 FORCEINLINE void MemCpyT(Titem_* d, const Titem_* s, int num_items = 1) |
11 FORCEINLINE void MemCpyT(Titem_* d, const Titem_* s, size_t num_items = 1) |
12 { |
12 { |
13 memcpy(d, s, num_items * sizeof(Titem_)); |
13 memcpy(d, s, num_items * sizeof(Titem_)); |
14 } |
14 } |
15 |
15 |
16 |
16 |
17 /** Base class for simple binary blobs. |
17 /** Base class for simple binary blobs. |
18 * Item is byte. |
18 * Item is byte. |
19 * The word 'simple' means: |
19 * The word 'simple' means: |
20 * - no configurable allocator type (always made from heap) |
20 * - no configurable allocator type (always made from heap) |
21 * - no smart deallocation - deallocation must be called from the same |
21 * - no smart deallocation - deallocation must be called from the same |
22 * module (DLL) where the blob was allocated |
22 * module (DLL) where the blob was allocated |
23 * - no configurable allocation policy (how big blocks should be allocated) |
23 * - no configurable allocation policy (how big blocks should be allocated) |
24 * - no extra ownership policy (i.e. 'copy on write') when blob is copied |
24 * - no extra ownership policy (i.e. 'copy on write') when blob is copied |
25 * - no thread synchronization at all |
25 * - no thread synchronization at all |
26 * |
26 * |
27 * Internal member layout: |
27 * Internal member layout: |
28 * 1. The only class member is pointer to the first item (see union ptr_u). |
28 * 1. The only class member is posize_ter to the first item (see union ptr_u). |
29 * 2. Allocated block contains the blob header (see CHdr) followed by the raw byte data. |
29 * 2. Allocated block contains the blob header (see CHdr) followed by the raw byte data. |
30 * Always, when it allocates memory the allocated size is: |
30 * Always, when it allocates memory the allocated size is: |
31 * sizeof(CHdr) + <data capacity> |
31 * sizeof(CHdr) + <data capacity> |
32 * 3. Two 'virtual' members (m_size and m_max_size) are stored in the CHdr at beginning |
32 * 3. Two 'virtual' members (m_size and m_max_size) are stored in the CHdr at beginning |
33 * of the alloated block. |
33 * of the alloated block. |
34 * 4. The pointer (in ptr_u) points behind the header (to the first data byte). |
34 * 4. The posize_ter (in ptr_u) posize_ts behind the header (to the first data byte). |
35 * When memory block is allocated, the sizeof(CHdr) it added to it. |
35 * When memory block is allocated, the sizeof(CHdr) it added to it. |
36 * 5. Benefits of this layout: |
36 * 5. Benefits of this layout: |
37 * - items are accessed in the simplest possible way - just dereferencing the pointer, |
37 * - items are accessed in the simplest possible way - just dereferencing the posize_ter, |
38 * which is good for performance (assuming that data are accessed most often). |
38 * which is good for performance (assuming that data are accessed most often). |
39 * - sizeof(blob) is the same as the size of any other pointer |
39 * - sizeof(blob) is the same as the size of any other posize_ter |
40 * 6. Drawbacks of this layout: |
40 * 6. Drawbacks of this layout: |
41 * - the fact, that pointer to the alocated block is adjusted by sizeof(CHdr) before |
41 * - the fact, that posize_ter to the alocated block is adjusted by sizeof(CHdr) before |
42 * it is stored can lead to several confusions: |
42 * it is stored can lead to several confusions: |
43 * - it is not common pattern so the implementation code is bit harder to read |
43 * - it is not common pattern so the implementation code is bit harder to read |
44 * - valgrind can generate warning that allocated block is lost (not accessible) |
44 * - valgrind can generate warning that allocated block is lost (not accessible) |
45 * */ |
45 * */ |
46 class CBlobBaseSimple { |
46 class CBlobBaseSimple { |
|
47 public: |
|
48 typedef ::ptrdiff_t size_t; |
47 protected: |
49 protected: |
48 /** header of the allocated memory block */ |
50 /** header of the allocated memory block */ |
49 struct CHdr { |
51 struct CHdr { |
50 int m_size; ///< actual blob size in bytes |
52 size_t m_size; ///< actual blob size in bytes |
51 int m_max_size; ///< maximum (allocated) size in bytes |
53 size_t m_max_size; ///< maximum (allocated) size in bytes |
52 }; |
54 }; |
53 |
55 |
54 /** type used as class member */ |
56 /** type used as class member */ |
55 union { |
57 union { |
56 int8 *m_pData; ///< pointer to the first byte of data |
58 int8 *m_pData; ///< ptr to the first byte of data |
57 CHdr *m_pHdr_1; ///< pointer just after the CHdr holding m_size and m_max_size |
59 wchar_t *m_pwData; ///< ptr to the first byte of data |
|
60 CHdr *m_pHdr_1; ///< ptr just after the CHdr holding m_size and m_max_size |
58 } ptr_u; |
61 } ptr_u; |
59 |
62 |
60 public: |
63 public: |
61 static const int Ttail_reserve = 4; ///< four extra bytes will be always allocated and zeroed at the end |
64 static const size_t Ttail_reserve = 4; ///< four extra bytes will be always allocated and zeroed at the end |
62 |
65 |
63 /** default constructor - initializes empty blob */ |
66 /** default constructor - initializes empty blob */ |
64 FORCEINLINE CBlobBaseSimple() { InitEmpty(); } |
67 FORCEINLINE CBlobBaseSimple() { InitEmpty(); } |
|
68 /** constructor - create blob with data */ |
|
69 FORCEINLINE CBlobBaseSimple(const int8 *p, size_t num_bytes) { InitEmpty(); AppendRaw(p, num_bytes);} |
65 /** copy constructor */ |
70 /** copy constructor */ |
66 FORCEINLINE CBlobBaseSimple(const CBlobBaseSimple& src) |
71 FORCEINLINE CBlobBaseSimple(const CBlobBaseSimple& src) |
67 { |
72 { |
68 InitEmpty(); |
73 InitEmpty(); |
69 AppendRaw(src); |
74 AppendRaw(src); |
70 } |
75 } |
|
76 /** move constructor - take ownership of blob data */ |
|
77 FORCEINLINE CBlobBaseSimple(CHdr*& pHdr_1) {assert(pHdr_1 != NULL); ptr_u.m_pHdr_1 = pHdr_1; pHdr_1 = NULL;} |
71 /** destructor */ |
78 /** destructor */ |
72 FORCEINLINE ~CBlobBaseSimple() { Free(); } |
79 FORCEINLINE ~CBlobBaseSimple() { Free(); } |
73 protected: |
80 protected: |
74 /** initialize the empty blob by setting the ptr_u.m_pHdr_1 pointer to the static CHdr with |
81 /** initialize the empty blob by setting the ptr_u.m_pHdr_1 posize_ter to the static CHdr with |
75 * both m_size and m_max_size containing zero */ |
82 * both m_size and m_max_size containing zero */ |
76 FORCEINLINE void InitEmpty() { static CHdr hdrEmpty[] = {{0, 0}, {0, 0}}; ptr_u.m_pHdr_1 = &hdrEmpty[1]; } |
83 FORCEINLINE void InitEmpty() { static CHdr hdrEmpty[] = {{0, 0}, {0, 0}}; ptr_u.m_pHdr_1 = &hdrEmpty[1]; } |
77 /** initialize blob by attaching it to the given header followed by data */ |
84 /** initialize blob by attaching it to the given header followed by data */ |
78 FORCEINLINE void Init(CHdr* hdr) { ptr_u.m_pHdr_1 = &hdr[1]; } |
85 FORCEINLINE void Init(CHdr* hdr) { ptr_u.m_pHdr_1 = &hdr[1]; } |
79 /** blob header accessor - use it rather than using the pointer arithmetics directly - non-const version */ |
86 /** blob header accessor - use it rather than using the posize_ter arithmetics directly - non-const version */ |
80 FORCEINLINE CHdr& Hdr() { return ptr_u.m_pHdr_1[-1]; } |
87 FORCEINLINE CHdr& Hdr() { return ptr_u.m_pHdr_1[-1]; } |
81 /** blob header accessor - use it rather than using the pointer arithmetics directly - const version */ |
88 /** blob header accessor - use it rather than using the posize_ter arithmetics directly - const version */ |
82 FORCEINLINE const CHdr& Hdr() const { return ptr_u.m_pHdr_1[-1]; } |
89 FORCEINLINE const CHdr& Hdr() const { return ptr_u.m_pHdr_1[-1]; } |
83 /** return reference to the actual blob size - used when the size needs to be modified */ |
90 /** return reference to the actual blob size - used when the size needs to be modified */ |
84 FORCEINLINE int& RawSizeRef() { return Hdr().m_size; }; |
91 FORCEINLINE size_t& RawSizeRef() { return Hdr().m_size; }; |
85 |
92 |
86 public: |
93 public: |
87 /** return true if blob doesn't contain valid data */ |
94 /** return true if blob doesn't contain valid data */ |
88 FORCEINLINE bool IsEmpty() const { return RawSize() == 0; } |
95 FORCEINLINE bool IsEmpty() const { return RawSize() == 0; } |
89 /** return the number of valid data bytes in the blob */ |
96 /** return the number of valid data bytes in the blob */ |
90 FORCEINLINE int RawSize() const { return Hdr().m_size; }; |
97 FORCEINLINE size_t RawSize() const { return Hdr().m_size; }; |
91 /** return the current blob capacity in bytes */ |
98 /** return the current blob capacity in bytes */ |
92 FORCEINLINE int MaxRawSize() const { return Hdr().m_max_size; }; |
99 FORCEINLINE size_t MaxRawSize() const { return Hdr().m_max_size; }; |
93 /** return pointer to the first byte of data - non-const version */ |
100 /** return posize_ter to the first byte of data - non-const version */ |
94 FORCEINLINE int8* RawData() { return ptr_u.m_pData; } |
101 FORCEINLINE int8* RawData() { return ptr_u.m_pData; } |
95 /** return pointer to the first byte of data - const version */ |
102 /** return posize_ter to the first byte of data - const version */ |
96 FORCEINLINE const int8* RawData() const { return ptr_u.m_pData; } |
103 FORCEINLINE const int8* RawData() const { return ptr_u.m_pData; } |
97 #if 0 // reenable when needed |
104 #if 0 // reenable when needed |
98 /** return the 32 bit CRC of valid data in the blob */ |
105 /** return the 32 bit CRC of valid data in the blob */ |
99 FORCEINLINE uint32 Crc32() const {return CCrc32::Calc(RawData(), RawSize());} |
106 FORCEINLINE usize_t32 Crc32() const {return CCrc32::Calc(RawData(), RawSize());} |
100 #endif //0 |
107 #endif //0 |
101 /** invalidate blob's data - doesn't free buffer */ |
108 /** invalidate blob's data - doesn't free buffer */ |
102 FORCEINLINE void Clear() { RawSizeRef() = 0; } |
109 FORCEINLINE void Clear() { RawSizeRef() = 0; } |
103 /** free the blob's memory */ |
110 /** free the blob's memory */ |
104 FORCEINLINE void Free() { if (MaxRawSize() > 0) {RawFree(&Hdr()); InitEmpty();} } |
111 FORCEINLINE void Free() { if (MaxRawSize() > 0) {RawFree(&Hdr()); InitEmpty();} } |
126 if (!src.IsEmpty()) |
133 if (!src.IsEmpty()) |
127 memcpy(GrowRawSize(src.RawSize()), src.RawData(), src.RawSize()); |
134 memcpy(GrowRawSize(src.RawSize()), src.RawData(), src.RawSize()); |
128 } |
135 } |
129 |
136 |
130 /** Reallocate if there is no free space for num_bytes bytes. |
137 /** Reallocate if there is no free space for num_bytes bytes. |
131 * @return pointer to the new data to be added */ |
138 * @return posize_ter to the new data to be added */ |
132 FORCEINLINE int8* MakeRawFreeSpace(int num_bytes) |
139 FORCEINLINE int8* MakeRawFreeSpace(size_t num_bytes) |
133 { |
140 { |
134 assert(num_bytes >= 0); |
141 assert(num_bytes >= 0); |
135 int new_size = RawSize() + num_bytes; |
142 size_t new_size = RawSize() + num_bytes; |
136 if (new_size > MaxRawSize()) SmartAlloc(new_size); |
143 if (new_size > MaxRawSize()) SmartAlloc(new_size); |
137 FixTail(); |
|
138 return ptr_u.m_pData + RawSize(); |
144 return ptr_u.m_pData + RawSize(); |
139 } |
145 } |
140 |
146 |
141 /** Increase RawSize() by num_bytes. |
147 /** Increase RawSize() by num_bytes. |
142 * @return pointer to the new data added */ |
148 * @return posize_ter to the new data added */ |
143 FORCEINLINE int8* GrowRawSize(int num_bytes) |
149 FORCEINLINE int8* GrowRawSize(size_t num_bytes) |
144 { |
150 { |
145 int8* pNewData = MakeRawFreeSpace(num_bytes); |
151 int8* pNewData = MakeRawFreeSpace(num_bytes); |
146 RawSizeRef() += num_bytes; |
152 RawSizeRef() += num_bytes; |
147 return pNewData; |
153 return pNewData; |
148 } |
154 } |
149 |
155 |
150 /** Decrease RawSize() by num_bytes. */ |
156 /** Decrease RawSize() by num_bytes. */ |
151 FORCEINLINE void ReduceRawSize(int num_bytes) |
157 FORCEINLINE void ReduceRawSize(size_t num_bytes) |
152 { |
158 { |
153 if (MaxRawSize() > 0 && num_bytes > 0) { |
159 if (MaxRawSize() > 0 && num_bytes > 0) { |
154 assert(num_bytes <= RawSize()); |
160 assert(num_bytes <= RawSize()); |
155 if (num_bytes < RawSize()) RawSizeRef() -= num_bytes; |
161 if (num_bytes < RawSize()) RawSizeRef() -= num_bytes; |
156 else RawSizeRef() = 0; |
162 else RawSizeRef() = 0; |
157 } |
163 } |
158 } |
164 } |
159 /** reallocate blob data if needed */ |
165 /** reallocate blob data if needed */ |
160 void SmartAlloc(int new_size) |
166 void SmartAlloc(size_t new_size) |
161 { |
167 { |
162 int old_max_size = MaxRawSize(); |
168 size_t old_max_size = MaxRawSize(); |
163 if (old_max_size >= new_size) return; |
169 if (old_max_size >= new_size) return; |
164 // calculate minimum block size we need to allocate |
170 // calculate minimum block size we need to allocate |
165 int min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve; |
171 size_t min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve; |
166 // ask allocation policy for some reasonable block size |
172 // ask allocation policy for some reasonable block size |
167 int alloc_size = AllocPolicy(min_alloc_size); |
173 size_t alloc_size = AllocPolicy(min_alloc_size); |
168 // allocate new block |
174 // allocate new block |
169 CHdr* pNewHdr = RawAlloc(alloc_size); |
175 CHdr* pNewHdr = RawAlloc(alloc_size); |
170 // setup header |
176 // setup header |
171 pNewHdr->m_size = RawSize(); |
177 pNewHdr->m_size = RawSize(); |
172 pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve); |
178 pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve); |
197 min_alloc = (min_alloc | ((1 << 20) - 1)) + 1; |
203 min_alloc = (min_alloc | ((1 << 20) - 1)) + 1; |
198 return min_alloc; |
204 return min_alloc; |
199 } |
205 } |
200 |
206 |
201 /** all allocation should happen here */ |
207 /** all allocation should happen here */ |
202 static FORCEINLINE CHdr* RawAlloc(int num_bytes) { return (CHdr*)malloc(num_bytes); } |
208 static FORCEINLINE CHdr* RawAlloc(size_t num_bytes) { return (CHdr*)malloc(num_bytes); } |
203 /** all deallocations should happen here */ |
209 /** all deallocations should happen here */ |
204 static FORCEINLINE void RawFree(CHdr* p) { free(p); } |
210 static FORCEINLINE void RawFree(CHdr* p) { free(p); } |
205 /** fixing the four bytes at the end of blob data - useful when blob is used to hold string */ |
211 /** fixing the four bytes at the end of blob data - useful when blob is used to hold string */ |
206 FORCEINLINE void FixTail() |
212 FORCEINLINE void FixTail() const |
207 { |
213 { |
208 if (MaxRawSize() > 0) { |
214 if (MaxRawSize() > 0) { |
209 int8 *p = &ptr_u.m_pData[RawSize()]; |
215 int8 *p = &ptr_u.m_pData[RawSize()]; |
210 for (int i = 0; i < Ttail_reserve; i++) p[i] = 0; |
216 for (size_t i = 0; i < Ttail_reserve; i++) p[i] = 0; |
211 } |
217 } |
212 } |
218 } |
213 }; |
219 }; |
214 |
220 |
215 /** Blob - simple dynamic Titem_ array. Titem_ (template argument) is a placeholder for any type. |
221 /** Blob - simple dynamic Titem_ array. Titem_ (template argument) is a placeholder for any type. |
216 * Titem_ can be any integral type, pointer, or structure. Using Blob instead of just plain C array |
222 * Titem_ can be any size_tegral type, posize_ter, or structure. Using Blob instead of just plain C array |
217 * simplifies the resource management in several ways: |
223 * simplifies the resource management in several ways: |
218 * 1. When adding new item(s) it automatically grows capacity if needed. |
224 * 1. When adding new item(s) it automatically grows capacity if needed. |
219 * 2. When variable of type Blob comes out of scope it automatically frees the data buffer. |
225 * 2. When variable of type Blob comes out of scope it automatically frees the data buffer. |
220 * 3. Takes care about the actual data size (number of used items). |
226 * 3. Takes care about the actual data size (number of used items). |
221 * 4. Dynamically constructs only used items (as opposite of static array which constructs all items) */ |
227 * 4. Dynamically constructs only used items (as opposite of static array which constructs all items) */ |
222 template <class Titem_, class Tbase_ = CBlobBaseSimple> |
228 template <class Titem_, class Tbase_ = CBlobBaseSimple> |
223 class CBlobT : public CBlobBaseSimple { |
229 class CBlobT : public Tbase_ { |
224 // make template arguments public: |
230 // make template arguments public: |
225 public: |
231 public: |
226 typedef Titem_ Titem; |
232 typedef Titem_ Titem; |
227 typedef Tbase_ Tbase; |
233 typedef Tbase_ Tbase; |
228 |
234 |
229 static const int Titem_size = sizeof(Titem); |
235 static const size_t Titem_size = sizeof(Titem); |
|
236 |
|
237 struct OnTransfer { |
|
238 typename Tbase_::CHdr *m_pHdr_1; |
|
239 OnTransfer(OnTransfer& src) : m_pHdr_1(src.m_pHdr_1) {assert(src.m_pHdr_1 != NULL); src.m_pHdr_1 = NULL;} |
|
240 OnTransfer(CBlobT& src) : m_pHdr_1(src.ptr_u.m_pHdr_1) {src.InitEmpty();} |
|
241 ~OnTransfer() {assert(m_pHdr_1 == NULL);} |
|
242 }; |
230 |
243 |
231 /** Default constructor - makes new Blob ready to accept any data */ |
244 /** Default constructor - makes new Blob ready to accept any data */ |
232 FORCEINLINE CBlobT() : Tbase() {} |
245 FORCEINLINE CBlobT() : Tbase() {} |
|
246 /** Constructor - makes new Blob with data */ |
|
247 FORCEINLINE CBlobT(const Titem_ *p, size_t num_items) : Tbase((int8*)p, num_items * Titem_size) {} |
233 /** Copy constructor - make new blob to become copy of the original (source) blob */ |
248 /** Copy constructor - make new blob to become copy of the original (source) blob */ |
234 FORCEINLINE CBlobT(const Tbase& src) : Tbase(src) {assert((RawSize() % Titem_size) == 0);} |
249 FORCEINLINE CBlobT(const Tbase& src) : Tbase(src) {assert((RawSize() % Titem_size) == 0);} |
|
250 /** Take ownership constructor */ |
|
251 FORCEINLINE CBlobT(OnTransfer& ot) : Tbase(ot.m_pHdr_1) {} |
235 /** Destructor - ensures that allocated memory (if any) is freed */ |
252 /** Destructor - ensures that allocated memory (if any) is freed */ |
236 FORCEINLINE ~CBlobT() { Free(); } |
253 FORCEINLINE ~CBlobT() { Free(); } |
237 /** Check the validity of item index (only in debug mode) */ |
254 /** Check the validity of item index (only in debug mode) */ |
238 FORCEINLINE void CheckIdx(int idx) { assert(idx >= 0); assert(idx < Size()); } |
255 FORCEINLINE void CheckIdx(size_t idx) { assert(idx >= 0); assert(idx < Size()); } |
239 /** Return pointer to the first data item - non-const version */ |
256 /** Return posize_ter to the first data item - non-const version */ |
240 FORCEINLINE Titem* Data() { return (Titem*)RawData(); } |
257 FORCEINLINE Titem* Data() { return (Titem*)RawData(); } |
241 /** Return pointer to the first data item - const version */ |
258 /** Return posize_ter to the first data item - const version */ |
242 FORCEINLINE const Titem* Data() const { return (const Titem*)RawData(); } |
259 FORCEINLINE const Titem* Data() const { return (const Titem*)RawData(); } |
243 /** Return pointer to the idx-th data item - non-const version */ |
260 /** Return posize_ter to the idx-th data item - non-const version */ |
244 FORCEINLINE Titem* Data(int idx) { CheckIdx(idx); return (Data() + idx); } |
261 FORCEINLINE Titem* Data(size_t idx) { CheckIdx(idx); return (Data() + idx); } |
245 /** Return pointer to the idx-th data item - const version */ |
262 /** Return posize_ter to the idx-th data item - const version */ |
246 FORCEINLINE const Titem* Data(int idx) const { CheckIdx(idx); return (Data() + idx); } |
263 FORCEINLINE const Titem* Data(size_t idx) const { CheckIdx(idx); return (Data() + idx); } |
247 /** Return number of items in the Blob */ |
264 /** Return number of items in the Blob */ |
248 FORCEINLINE int Size() const { return (RawSize() / Titem_size); } |
265 FORCEINLINE size_t Size() const { return (RawSize() / Titem_size); } |
|
266 /** Return total number of items that can fit in the Blob without buffer reallocation */ |
|
267 FORCEINLINE size_t MaxSize() const { return (MaxRawSize() / Titem_size); } |
|
268 /** Return number of additional items that can fit in the Blob without buffer reallocation */ |
|
269 FORCEINLINE size_t GetReserve() const { return ((MaxRawSize() - RawSize()) / Titem_size); } |
249 /** Free the memory occupied by Blob destroying all items */ |
270 /** Free the memory occupied by Blob destroying all items */ |
250 FORCEINLINE void Free() |
271 FORCEINLINE void Free() |
251 { |
272 { |
252 assert((RawSize() % Titem_size) == 0); |
273 assert((RawSize() % Titem_size) == 0); |
253 int old_size = Size(); |
274 size_t old_size = Size(); |
254 if (old_size > 0) { |
275 if (old_size > 0) { |
255 // destroy removed items; |
276 // destroy removed items; |
256 Titem* pI_last_to_destroy = Data(0); |
277 Titem* pI_last_to_destroy = Data(0); |
257 for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem_(); |
278 for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem_(); |
258 } |
279 } |
259 Tbase::Free(); |
280 Tbase::Free(); |
260 } |
281 } |
261 /** Grow number of data items in Blob by given number - doesn't construct items */ |
282 /** Grow number of data items in Blob by given number - doesn't construct items */ |
262 FORCEINLINE Titem* GrowSizeNC(int num_items) { return (Titem*)GrowRawSize(num_items * Titem_size); } |
283 FORCEINLINE Titem* GrowSizeNC(size_t num_items) { return (Titem*)GrowRawSize(num_items * Titem_size); } |
263 /** Grow number of data items in Blob by given number - constructs new items (using Titem_'s default constructor) */ |
284 /** Grow number of data items in Blob by given number - constructs new items (using Titem_'s default constructor) */ |
264 FORCEINLINE Titem* GrowSizeC(int num_items) |
285 FORCEINLINE Titem* GrowSizeC(size_t num_items) |
265 { |
286 { |
266 Titem* pI = GrowSizeNC(num_items); |
287 Titem* pI = GrowSizeNC(num_items); |
267 for (int i = num_items; i > 0; i--, pI++) new (pI) Titem(); |
288 for (size_t i = num_items; i > 0; i--, pI++) new (pI) Titem(); |
268 } |
289 } |
269 /** Destroy given number of items and reduce the Blob's data size */ |
290 /** Destroy given number of items and reduce the Blob's data size */ |
270 FORCEINLINE void ReduceSize(int num_items) |
291 FORCEINLINE void ReduceSize(size_t num_items) |
271 { |
292 { |
272 assert((RawSize() % Titem_size) == 0); |
293 assert((RawSize() % Titem_size) == 0); |
273 int old_size = Size(); |
294 size_t old_size = Size(); |
274 assert(num_items <= old_size); |
295 assert(num_items <= old_size); |
275 int new_size = (num_items <= old_size) ? (old_size - num_items) : 0; |
296 size_t new_size = (num_items <= old_size) ? (old_size - num_items) : 0; |
276 // destroy removed items; |
297 // destroy removed items; |
277 Titem* pI_last_to_destroy = Data(new_size); |
298 Titem* pI_last_to_destroy = Data(new_size); |
278 for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem(); |
299 for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem(); |
279 // remove them |
300 // remove them |
280 ReduceRawSize(num_items * Titem_size); |
301 ReduceRawSize(num_items * Titem_size); |
292 Titem& dst = *GrowSizeNC(1); // Grow size by one item |
313 Titem& dst = *GrowSizeNC(1); // Grow size by one item |
293 Titem* pNewItem = new (&dst) Titem(src); // construct the new item by calling in-place new operator with copy ctor() |
314 Titem* pNewItem = new (&dst) Titem(src); // construct the new item by calling in-place new operator with copy ctor() |
294 return pNewItem; |
315 return pNewItem; |
295 } |
316 } |
296 /** Add given items (ptr + number of items) at the end of blob */ |
317 /** Add given items (ptr + number of items) at the end of blob */ |
297 FORCEINLINE Titem* Append(const Titem* pSrc, int num_items) |
318 FORCEINLINE Titem* Append(const Titem* pSrc, size_t num_items) |
298 { |
319 { |
299 Titem* pDst = GrowSizeNC(num_items); |
320 Titem* pDst = GrowSizeNC(num_items); |
300 Titem* pDstOrg = pDst; |
321 Titem* pDstOrg = pDst; |
301 Titem* pDstEnd = pDst + num_items; |
322 Titem* pDstEnd = pDst + num_items; |
302 while (pDst < pDstEnd) new (pDst++) Titem(*(pSrc++)); |
323 while (pDst < pDstEnd) new (pDst++) Titem(*(pSrc++)); |
303 return pDstOrg; |
324 return pDstOrg; |
304 } |
325 } |
305 /** Remove item with the given index by replacing it by the last item and reducing the size by one */ |
326 /** Remove item with the given index by replacing it by the last item and reducing the size by one */ |
306 FORCEINLINE void RemoveBySwap(int idx) |
327 FORCEINLINE void RemoveBySwap(size_t idx) |
307 { |
328 { |
308 CheckIdx(idx); |
329 CheckIdx(idx); |
309 // destroy removed item |
330 // destroy removed item |
310 Titem* pRemoved = Data(idx); |
331 Titem* pRemoved = Data(idx); |
311 RemoveBySwap(pRemoved); |
332 RemoveBySwap(pRemoved); |
312 } |
333 } |
313 /** Remove item given by pointer replacing it by the last item and reducing the size by one */ |
334 /** Remove item given by posize_ter replacing it by the last item and reducing the size by one */ |
314 FORCEINLINE void RemoveBySwap(Titem* pItem) |
335 FORCEINLINE void RemoveBySwap(Titem* pItem) |
315 { |
336 { |
316 Titem* pLast = Data(Size() - 1); |
337 Titem* pLast = Data(Size() - 1); |
317 assert(pItem >= Data() && pItem <= pLast); |
338 assert(pItem >= Data() && pItem <= pLast); |
318 // move last item to its new place |
339 // move last item to its new place |