/* * PROGRAM: Client/Server Common Code * MODULE: array.h * DESCRIPTION: dynamic array of simple elements * * The contents of this file are subject to the Interbase Public * License Version 1.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.Inprise.com/IPL.html * * Software distributed under the License is distributed on an * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express * or implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code was created by Inprise Corporation * and its predecessors. Portions created by Inprise Corporation are * Copyright (C) Inprise Corporation. * * Created by: Alex Peshkov * * All Rights Reserved. * Contributor(s): ______________________________________. */ #ifndef CLASSES_ARRAY_H #define CLASSES_ARRAY_H #include "../jrd/gdsassert.h" #include #include "../common/classes/alloc.h" namespace Firebird { // Static part of the array template class InlineStorage : public AutoStorage { public: explicit InlineStorage(MemoryPool& p) : AutoStorage(p) { } InlineStorage() : AutoStorage() { } protected: T* getStorage() { return buffer; } size_t getStorageSize() const { return Capacity; } private: T buffer[Capacity]; }; // Used when array doesn't have static part template class EmptyStorage : public AutoStorage { public: explicit EmptyStorage(MemoryPool& p) : AutoStorage(p) { } EmptyStorage() : AutoStorage() { } protected: T* getStorage() { return NULL; } size_t getStorageSize() const { return 0; } }; // Dynamic array of simple types template > class Array : protected Storage { public: explicit Array(MemoryPool& p) : Storage(p), count(0), capacity(this->getStorageSize()), data(this->getStorage()) { } Array(MemoryPool& p, size_t InitialCapacity) : Storage(p), count(0), capacity(this->getStorageSize()), data(this->getStorage()) { ensureCapacity(InitialCapacity); } Array() : count(0), capacity(this->getStorageSize()), data(this->getStorage()) { } explicit Array(size_t InitialCapacity) : count(0), capacity(this->getStorageSize()), data(this->getStorage()) { ensureCapacity(InitialCapacity); } ~Array() { freeData(); } void clear() { count = 0; } protected: const T& getElement(size_t index) const { fb_assert(index < count); return data[index]; } T& getElement(size_t index) { fb_assert(index < count); return data[index]; } void freeData() { if (data != this->getStorage()) this->getPool().deallocate(data); } public: typedef T* iterator; typedef const T* const_iterator; Array& operator =(const Array& L) { ensureCapacity(L.count); memcpy(data, L.data, sizeof(T) * L.count); count = L.count; return *this; } const T& operator[](size_t index) const { return getElement(index); } T& operator[](size_t index) { return getElement(index); } const T& front() const { fb_assert(count > 0); return *data; } const T& back() const { fb_assert(count > 0); return *(data + count - 1); } const T* begin() const { return data; } const T* end() const { return data + count; } T& front() { fb_assert(count > 0); return *data; } T& back() { fb_assert(count > 0); return *(data + count - 1); } T* begin() { return data; } T* end() { return data + count; } void insert(size_t index, const T& item) { fb_assert(index <= count); ensureCapacity(count + 1); memmove(data + index + 1, data + index, sizeof(T) * (count++ - index)); data[index] = item; } void insert(size_t index, const Array& L) { fb_assert(index <= count); ensureCapacity(count + L.count); memmove(data + index + L.count, data + index, sizeof(T) * (count - index)); memcpy(data + index, L.data, L.count); count += L.count; } void insert(size_t index, const T* items, size_t itemsSize) { fb_assert(index <= count); ensureCapacity(count + itemsSize); memmove(data + index + itemsSize, data + index, sizeof(T) * (count - index)); memcpy(data + index, items, sizeof(T) * itemsSize); count += itemsSize; } size_t add(const T& item) { ensureCapacity(count + 1); data[count++] = item; return count; } void remove(size_t index) { fb_assert(index < count); memmove(data + index, data + index + 1, sizeof(T) * (--count - index)); } void removeRange(size_t from, size_t to) { fb_assert(from <= to); fb_assert(to <= count); memmove(data + from, data + to, sizeof(T) * (count - to)); count -= (to - from); } void removeCount(size_t index, size_t n) { fb_assert(index + n <= count); memmove(data + index, data + index + n, sizeof(T) * (count - index - n)); count -= n; } void remove(T* itr) { const size_t index = itr - begin(); fb_assert(index < count); memmove(data + index, data + index + 1, sizeof(T) * (--count - index)); } void shrink(size_t newCount) { fb_assert(newCount <= count); count = newCount; } // Grow size of our array and zero-initialize new items void grow(size_t newCount) { fb_assert(newCount >= count); ensureCapacity(newCount); memset(data + count, 0, sizeof(T) * (newCount - count)); count = newCount; } // Resize array according to STL's vector::resize() rules void resize(size_t newCount, const T& val) { if (newCount > count) { ensureCapacity(newCount); while (count < newCount) { data[count++] = val; } } else { count = newCount; } } // Resize array according to STL's vector::resize() rules void resize(size_t newCount) { if (newCount > count) { grow(newCount); } else { count = newCount; } } void join(const Array& L) { ensureCapacity(count + L.count); memcpy(data + count, L.data, sizeof(T) * L.count); count += L.count; } size_t getCount() const { return count; } size_t getCapacity() const { return capacity; } void push(const T& item) { add(item); } void push(const T* items, size_t itemsSize) { ensureCapacity(count + itemsSize); memcpy(data + count, items, sizeof(T) * itemsSize); count += itemsSize; } T pop() { fb_assert(count > 0); count--; return data[count]; } // prepare array to be used as a buffer of capacity items T* getBuffer(size_t capacityL) { ensureCapacity(capacityL); count = capacityL; return data; } // clear array and release dinamically allocated memory void free() { clear(); freeData(); capacity = this->getStorageSize(); data = this->getStorage(); } protected: size_t count, capacity; T* data; void ensureCapacity(size_t newcapacity) { if (newcapacity > capacity) { if (newcapacity < capacity * 2) { newcapacity = capacity * 2; } T* newdata = reinterpret_cast (this->getPool().allocate(sizeof(T) * newcapacity #ifdef DEBUG_GDS_ALLOC , 1, __FILE__, __LINE__ #endif )); memcpy(newdata, data, sizeof(T) * count); freeData(); data = newdata; capacity = newcapacity; } } }; // Dynamic sorted array of simple objects template , typename Key = Value, typename KeyOfValue = DefaultKeyValue, typename Cmp = DefaultComparator > class SortedArray : public Array { public: SortedArray(MemoryPool& p, size_t s) : Array(p, s) {} explicit SortedArray(MemoryPool& p) : Array(p) {} explicit SortedArray(size_t s) : Array(s) {} SortedArray() : Array() {} bool find(const Key& item, size_t& pos) const { size_t highBound = this->count, lowBound = 0; while (highBound > lowBound) { const size_t temp = (highBound + lowBound) >> 1; if (Cmp::greaterThan(item, KeyOfValue::generate(this, this->data[temp]))) lowBound = temp + 1; else highBound = temp; } pos = lowBound; return highBound != this->count && !Cmp::greaterThan(KeyOfValue::generate(this, this->data[lowBound]), item); } size_t add(const Value& item) { size_t pos; find(KeyOfValue::generate(this, item), pos); insert(pos, item); return pos; } }; // Nice shorthand for arrays with static part template class HalfStaticArray : public Array > { public: explicit HalfStaticArray(MemoryPool& p) : Array > (p) {} HalfStaticArray(MemoryPool& p, size_t InitialCapacity) : Array > (p, InitialCapacity) {} HalfStaticArray() : Array > () {} explicit HalfStaticArray(size_t InitialCapacity) : Array > (InitialCapacity) {} }; } // namespace Firebird #endif // CLASSES_ARRAY_H