1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
13 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
18 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 mike 1.1 **==============================================================================
23 */
24
|
25 mike 1.2 #include "array.h"
26
27 #include <assert.h>
28 #include <new>
29 #include <common.h>
|
30 krisbash 1.4 #include <pal/atomic.h>
|
31 mike 1.2 #include "types.h"
32 #include "instance.h"
33
34 MI_BEGIN_NAMESPACE
35
36 struct header
37 {
|
38 krisbash 1.4 volatile ptrdiff_t m_refCounter;
|
39 mike 1.2 MI_Uint32 m_capacity;
40 };
41
42 struct Array_data
43 {
44 void* p;
45 MI_Uint32 size;
46 };
47
48 //==============================================================================
49 //
50 // Traits for 'raw' types.
51 //
52 //==============================================================================
53
54 static ArrayTraits _uint8Traits =
55 {
56 sizeof(Uint8), 0, 0,
57 };
58
59 static ArrayTraits _uint16Traits =
60 mike 1.2 {
61 sizeof(Uint16), 0, 0,
62 };
63
64 static ArrayTraits _uint32Traits =
65 {
66 sizeof(Uint32), 0, 0,
67 };
68
69 static ArrayTraits _uint64Traits =
70 {
71 sizeof(Uint64), 0, 0,
72 };
73
74 static ArrayTraits _datetimeTraits =
75 {
76 sizeof(Datetime), 0, 0,
77 };
78
79 static void _stringCtor(void* dest_, const void* src_, MI_Uint32 size)
80 {
81 mike 1.2 String* dest = (String*)dest_;
82 const String* src = (const String*)src_;
83
84 while(size--)
85 new(dest++) String(*src++);
86 }
87
88 static void _stringDtor(void* data_, MI_Uint32 size)
89 {
90 String* data = (String*)data_;
91
92 while (size--)
93 data++->~String();
94 }
95
96 static ArrayTraits _stringTraits =
97 {
98 sizeof(String), _stringCtor, _stringDtor,
99 };
100
101 static void _instanceCtor(void* dest_, const void* src_, MI_Uint32 size)
102 mike 1.2 {
103 Instance* dest = (Instance*)dest_;
104 const Instance* src = (const Instance*)src_;
105
106 while(size--)
107 new(dest++) Instance(*src++);
108 }
109
110 static void _instanceDtor(void* data_, MI_Uint32 size)
111 {
112 Instance* data = (Instance*)data_;
113
114 while (size--)
115 data++->~Instance();
116 }
117
118 static ArrayTraits _instanceTraits =
119 {
120 sizeof(Instance), _instanceCtor, _instanceDtor,
121 };
122
123 mike 1.2 /* Indexable by scalar type */
124 const ArrayTraits* __traits[16] =
125 {
126 &_uint8Traits, /* boolean */
127 &_uint8Traits, /* uint8 */
128 &_uint8Traits, /* sint8 */
129 &_uint16Traits, /* uint16 */
130 &_uint16Traits, /* sint64 */
131 &_uint32Traits, /* uint32 */
132 &_uint32Traits, /* sint32 */
133 &_uint64Traits, /* uint64 */
134 &_uint64Traits, /* sint64 */
135 &_uint32Traits, /* real32 */
136 &_uint64Traits, /* real64 */
137 &_uint16Traits, /* char16 */
138 &_datetimeTraits, /* datetime */
139 &_stringTraits, /* string */
140 &_instanceTraits, /* reference */
141 &_instanceTraits, /* instance */
142 };
143
144 mike 1.2 //==============================================================================
145 //
146 // Array
147 //
148 //==============================================================================
149
150 enum { CAPACITY_ALIGMENT = 16 };
151 // returns 0 - for 0; 16 for 1-6; 32 for 17-32 etc
152 inline static MI_Uint32 AlignCapacity(MI_Uint32 size) {return ((size + CAPACITY_ALIGMENT -1) / CAPACITY_ALIGMENT) * CAPACITY_ALIGMENT;}
153
154 static void* Allocate(MI_Uint32 size, const ArrayTraits* v_traits)
155 {
156 MI_Uint32 capacity = AlignCapacity(size);
157
158 // allocate new buffer
159 header* chunk = (header*)operator new(sizeof(header) + capacity * v_traits->size);
160
161 chunk->m_capacity = capacity;
|
162 krisbash 1.4 Atomic_Swap(&chunk->m_refCounter, 0);
|
163 mike 1.2
164 return (chunk + 1);
165 }
166
167 inline static header* GetHeader(void* buf)
168 {
169 return reinterpret_cast<header*>(reinterpret_cast<char*>(buf) - sizeof(header));
170 }
171
172 inline static void AddRef(void* data)
173 {
174 if ( data )
|
175 krisbash 1.4 Atomic_Inc(&GetHeader(data)->m_refCounter);
|
176 mike 1.2 }
177
178 static void Release(void* v_this, const ArrayTraits* v_traits)
179 {
180 Array_data* v = (Array_data*)v_this;
181 if ( v->p &&
|
182 krisbash 1.4 Atomic_Dec(&GetHeader(v->p)->m_refCounter) == 0)
|
183 mike 1.2 {
184 if (v_traits->dtor)
185 v_traits->dtor(v->p,v->size);
186
187 operator delete(GetHeader(v->p));
188 v->p = 0;
189 v->size = 0;
190 }
191 }
192
193 // Array class implementation - taken out to reduce code size
194 void __ArrayCopyCtor(void* v_this, const ArrayTraits* v_traits, const void* v_obj, MI_Uint32 count)
195 {
196 Array_data* v = (Array_data*)v_this;
197
198 v->p = Allocate(count,v_traits);
199 v->size = count;
200 AddRef(v->p);
201
202 if(v_traits->copy_ctor)
203 v_traits->copy_ctor(v->p,v_obj,count);
204 mike 1.2 else
205 memcpy(v->p,v_obj,count*v_traits->size);
206 }
207
208 void __ArrayAssign(void* v_this, const ArrayTraits* v_traits, const void* v_other)
209 {
210 Array_data* v = (Array_data*)v_this;
211 const Array_data* v_x = (const Array_data*)v_other;
212
|
213 krisbash 1.4 Release(v_this, v_traits);
|
214 mike 1.2
215 if (v_x)
216 {
|
217 krisbash 1.4 *v = *v_x;
|
218 mike 1.2 AddRef(v->p);
219 }
220 }
221
222 void __ArrayCOW(void* v_this, const ArrayTraits* v_traits)
223 {
224 Array_data* v = (Array_data*)v_this;
|
225 krisbash 1.4 if ( v->p && Atomic_Read(&GetHeader(v->p)->m_refCounter) != 1 )
|
226 mike 1.2 {
227 void* new_data = Allocate(v->size,v_traits);
228
229 if (v_traits->copy_ctor)
230 v_traits->copy_ctor(new_data,v->p,v->size);
231 else
232 memcpy(new_data,v->p,v->size*v_traits->size);
233
|
234 krisbash 1.4 Release(v_this,v_traits);
235 v->p = new_data;
236 AddRef(v->p);
|
237 mike 1.2 }
238 }
239
240 void __ArrayResize(void* v_this, const ArrayTraits* v_traits, const void* v_obj, MI_Uint32 new_size)
241 {
242 Array_data* v = (Array_data*)v_this;
243
244 // special case - remove all
245 if (!new_size)
246 {
|
247 krisbash 1.4 Release(v_this,v_traits);
|
248 mike 1.2 v->p = 0;
249 v->size = 0;
250 return;
251 }
252
253 // assumptions:
254 // size > 0
255 // if size < m_size, buffer stays the same
256 // actions:
257 // cow()
258 // re-alloc
259
260 // make own copy
261 __ArrayCOW(v_this,v_traits);
262
263
264 // see if we need to re-alloc
265 if ( !v->p || GetHeader(v->p)->m_capacity < new_size)
266 {
|
267 krisbash 1.4 void* new_data = Allocate(new_size,v_traits);
268 if (v->size)
|
269 mike 1.2 memcpy(new_data,v->p,v->size * v_traits->size);
270
|
271 krisbash 1.4 if (v->p)
272 operator delete(GetHeader(v->p));
|
273 mike 1.2
|
274 krisbash 1.4 v->p = new_data;
275 AddRef(v->p);
|
276 mike 1.2 }
277
278 // delete extra
279 if ( v->size > new_size && v_traits->dtor )
280 {
281 v_traits->dtor(((char*)v->p) + new_size*v_traits->size, v->size-new_size);
282 }
283
284 // create missing
285 if ( v->size < new_size )
286 {
287 // copy elements one-by-one
288 for( ;v->size < new_size; v->size++)
289 {
290 if ( v_traits->copy_ctor )
291 {
292 v_traits->copy_ctor(((char*)v->p) + v->size*v_traits->size,v_obj,1);
293 }
294 else
295 {
296 memcpy(((char*)v->p) + v->size*v_traits->size,v_obj,v_traits->size);
297 mike 1.2 }
298 }
299 }
300
301 v->size = new_size;
302 }
303
304 void __ArrayDelete(void* v_this, const ArrayTraits* v_traits, MI_Uint32 index)
305 {
306 Array_data* v = (Array_data*)v_this;
307
308 __ArrayCOW(v_this,v_traits);
309
310 // destroy item
311 if ( v_traits->dtor )
312 {
313 v_traits->dtor(((char*)v->p) + index*v_traits->size,1);
314 }
315
316 // move the rest
317 memmove(((char*)v->p) +index*v_traits->size, ((char*)v->p) + (index+1)*v_traits->size, (v->size - index - 1)*v_traits->size);
318 mike 1.2
319 // dec size
320 v->size --;
321 }
322
323
324 MI_END_NAMESPACE
|