/* **============================================================================== ** ** Open Management Infrastructure (OMI) ** ** Copyright (c) Microsoft Corporation ** ** Licensed under the Apache License, Version 2.0 (the "License"); you may not ** use this file except in compliance with the License. You may obtain a copy ** of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABLITY OR NON-INFRINGEMENT. ** ** See the Apache 2 License for the specific language governing permissions ** and limitations under the License. ** **============================================================================== */ #include "array.h" #include #include #include #include "types.h" #include "instance.h" MI_BEGIN_NAMESPACE struct header { AtomicType m_refCounter; MI_Uint32 m_capacity; }; struct Array_data { void* p; MI_Uint32 size; }; //============================================================================== // // Traits for 'raw' types. // //============================================================================== static ArrayTraits _uint8Traits = { sizeof(Uint8), 0, 0, }; static ArrayTraits _uint16Traits = { sizeof(Uint16), 0, 0, }; static ArrayTraits _uint32Traits = { sizeof(Uint32), 0, 0, }; static ArrayTraits _uint64Traits = { sizeof(Uint64), 0, 0, }; static ArrayTraits _datetimeTraits = { sizeof(Datetime), 0, 0, }; static void _stringCtor(void* dest_, const void* src_, MI_Uint32 size) { String* dest = (String*)dest_; const String* src = (const String*)src_; while(size--) new(dest++) String(*src++); } static void _stringDtor(void* data_, MI_Uint32 size) { String* data = (String*)data_; while (size--) data++->~String(); } static ArrayTraits _stringTraits = { sizeof(String), _stringCtor, _stringDtor, }; static void _instanceCtor(void* dest_, const void* src_, MI_Uint32 size) { Instance* dest = (Instance*)dest_; const Instance* src = (const Instance*)src_; while(size--) new(dest++) Instance(*src++); } static void _instanceDtor(void* data_, MI_Uint32 size) { Instance* data = (Instance*)data_; while (size--) data++->~Instance(); } static ArrayTraits _instanceTraits = { sizeof(Instance), _instanceCtor, _instanceDtor, }; /* Indexable by scalar type */ const ArrayTraits* __traits[16] = { &_uint8Traits, /* boolean */ &_uint8Traits, /* uint8 */ &_uint8Traits, /* sint8 */ &_uint16Traits, /* uint16 */ &_uint16Traits, /* sint64 */ &_uint32Traits, /* uint32 */ &_uint32Traits, /* sint32 */ &_uint64Traits, /* uint64 */ &_uint64Traits, /* sint64 */ &_uint32Traits, /* real32 */ &_uint64Traits, /* real64 */ &_uint16Traits, /* char16 */ &_datetimeTraits, /* datetime */ &_stringTraits, /* string */ &_instanceTraits, /* reference */ &_instanceTraits, /* instance */ }; //============================================================================== // // Array // //============================================================================== enum { CAPACITY_ALIGMENT = 16 }; // returns 0 - for 0; 16 for 1-6; 32 for 17-32 etc inline static MI_Uint32 AlignCapacity(MI_Uint32 size) {return ((size + CAPACITY_ALIGMENT -1) / CAPACITY_ALIGMENT) * CAPACITY_ALIGMENT;} static void* Allocate(MI_Uint32 size, const ArrayTraits* v_traits) { MI_Uint32 capacity = AlignCapacity(size); // allocate new buffer header* chunk = (header*)operator new(sizeof(header) + capacity * v_traits->size); chunk->m_capacity = capacity; AtomicSet(chunk->m_refCounter, 0); return (chunk + 1); } inline static header* GetHeader(void* buf) { return reinterpret_cast(reinterpret_cast(buf) - sizeof(header)); } inline static void AddRef(void* data) { if ( data ) AtomicInc(GetHeader(data)->m_refCounter); } static void Release(void* v_this, const ArrayTraits* v_traits) { Array_data* v = (Array_data*)v_this; if ( v->p && AtomicDec(GetHeader(v->p)->m_refCounter)) { if (v_traits->dtor) v_traits->dtor(v->p,v->size); operator delete(GetHeader(v->p)); v->p = 0; v->size = 0; } } // Array class implementation - taken out to reduce code size void __ArrayCopyCtor(void* v_this, const ArrayTraits* v_traits, const void* v_obj, MI_Uint32 count) { Array_data* v = (Array_data*)v_this; v->p = Allocate(count,v_traits); v->size = count; AddRef(v->p); if(v_traits->copy_ctor) v_traits->copy_ctor(v->p,v_obj,count); else memcpy(v->p,v_obj,count*v_traits->size); } void __ArrayAssign(void* v_this, const ArrayTraits* v_traits, const void* v_other) { Array_data* v = (Array_data*)v_this; const Array_data* v_x = (const Array_data*)v_other; Release(v_this, v_traits); if (v_x) { *v = *v_x; AddRef(v->p); } } void __ArrayCOW(void* v_this, const ArrayTraits* v_traits) { Array_data* v = (Array_data*)v_this; if ( v->p && AtomicGet(GetHeader(v->p)->m_refCounter) != 1 ) { void* new_data = Allocate(v->size,v_traits); if (v_traits->copy_ctor) v_traits->copy_ctor(new_data,v->p,v->size); else memcpy(new_data,v->p,v->size*v_traits->size); Release(v_this,v_traits); v->p = new_data; AddRef(v->p); } } void __ArrayResize(void* v_this, const ArrayTraits* v_traits, const void* v_obj, MI_Uint32 new_size) { Array_data* v = (Array_data*)v_this; // special case - remove all if (!new_size) { Release(v_this,v_traits); v->p = 0; v->size = 0; return; } // assumptions: // size > 0 // if size < m_size, buffer stays the same // actions: // cow() // re-alloc // make own copy __ArrayCOW(v_this,v_traits); // see if we need to re-alloc if ( !v->p || GetHeader(v->p)->m_capacity < new_size) { void* new_data = Allocate(new_size,v_traits); if (v->size) memcpy(new_data,v->p,v->size * v_traits->size); if (v->p) operator delete(GetHeader(v->p)); v->p = new_data; AddRef(v->p); } // delete extra if ( v->size > new_size && v_traits->dtor ) { v_traits->dtor(((char*)v->p) + new_size*v_traits->size, v->size-new_size); } // create missing if ( v->size < new_size ) { // copy elements one-by-one for( ;v->size < new_size; v->size++) { if ( v_traits->copy_ctor ) { v_traits->copy_ctor(((char*)v->p) + v->size*v_traits->size,v_obj,1); } else { memcpy(((char*)v->p) + v->size*v_traits->size,v_obj,v_traits->size); } } } v->size = new_size; } void __ArrayDelete(void* v_this, const ArrayTraits* v_traits, MI_Uint32 index) { Array_data* v = (Array_data*)v_this; __ArrayCOW(v_this,v_traits); // destroy item if ( v_traits->dtor ) { v_traits->dtor(((char*)v->p) + index*v_traits->size,1); } // move the rest memmove(((char*)v->p) +index*v_traits->size, ((char*)v->p) + (index+1)*v_traits->size, (v->size - index - 1)*v_traits->size); // dec size v->size --; } MI_END_NAMESPACE