core/indigo-core/common/base_cpp/array.h (467 lines of code) (raw):

/**************************************************************************** * Copyright (C) from 2009 to Present EPAM Systems. * * This file is part of Indigo toolkit. * * 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 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ***************************************************************************/ #ifndef __array_h__ #define __array_h__ #include <cctype> #include <cstdarg> #include <cstdio> #include <cstdlib> #include <cstring> #include <new> #include <utility> #include <vector> #include "base_c/defs.h" #include "base_cpp/exception.h" namespace indigo { DECL_EXCEPTION(ArrayError); template <typename T> class Array { public: DECL_TPL_ERROR(ArrayError); explicit Array() : _reserved(0), _length(0), _array(nullptr) { } Array(Array&& other) : _reserved(other._reserved), _length(other._length), _array(other._array) { other._array = nullptr; other._length = 0; other._reserved = 0; } ~Array() { if (_array != nullptr) { std::free(static_cast<void*>(_array)); _array = nullptr; _length = 0; _reserved = 0; } } void clear() { _length = 0; } void reserve(int to_reserve) { if (to_reserve < 0) throw Error("to_reserve = %d", to_reserve); if (to_reserve > _reserved) { if (_length < 1) { if (_array != nullptr) { std::free(static_cast<void*>(_array)); _array = nullptr; _length = 0; _reserved = 0; } } T* oldptr = _array; _array = static_cast<T*>(std::realloc(static_cast<void*>(_array), sizeof(T) * to_reserve)); if (_array == nullptr) { _array = oldptr; throw std::bad_alloc(); } _reserved = to_reserve; } } void zerofill() { if (_length > 0) memset(_array, 0, _length * sizeof(T)); } void fffill() { if (_length > 0) memset(_array, 0xFF, _length * sizeof(T)); } void fill(const T& value) { for (int i = 0; i < size(); i++) _array[i] = value; } const T* ptr() const { return _array; } T* ptr() { return _array; } const T& operator[](int index) const { if (index < 0 || _length - index <= 0) throw Error("invalid index %d (size=%d)", index, _length); return _array[index]; } T& operator[](int index) { if (index < 0 || _length - index <= 0) throw Error("invalid index %d (size=%d)", index, _length); return _array[index]; } const T& at(int index) const { if (index < 0 || _length - index <= 0) throw Error("invalid index %d (size=%d)", index, _length); return (*this)[index]; } T& at(int index) { if (index < 0 || _length - index <= 0) throw Error("invalid index %d (size=%d)", index, _length); return (*this)[index]; } int size() const { return _length; } int sizeInBytes() const { return _length * sizeof(T); } void copy(const std::vector<T> other) { copy(other.data(), static_cast<int>(other.size())); } void copy(const Array<T>& other) { copy(other._array, other._length); } void copy(const T* other, int count) { if (count > 0) { clear_resize(count); memcpy(_array, other, count * sizeof(T)); } else { _length = 0; } } void copy(const T* other, std::size_t count) { copy(other, static_cast<int>(count)); } void concat(const Array<T>& other) { concat(other._array, other.size()); } void concat(const T* other, int count) { if (count > 0) { int length = _length; resize(length + count); memcpy(_array + length, other, count * sizeof(T)); } } int memcmp(const Array<T>& other) const { if (_length < other._length) return -1; if (_length > other._length) return -1; if (_length == 0) return 0; return ::memcmp(_array, other._array, _length * sizeof(T)); } void remove(int idx, int span = 1) { if (idx < 0 || idx - _length - span + 1 >= 0) throw Error("remove(): invalid index %d with span %d (size=%d)", idx, span, _length); memmove(_array + idx, _array + idx + span, sizeof(T) * (_length - idx - span)); _length -= span; } void remove_replace(int idx) { if (idx < 0 || idx >= _length) throw Error("remove_replace(): invalid index %d (size=%d)", idx, _length); if (idx < _length - 1) _array[idx] = _array[_length - 1]; _length--; } int find(const T& value) const { return find(0, _length, value); } int find(int from, int to, const T& value) const { for (int i = from; i < to; i++) if (_array[i] == value) return i; return -1; } int count(const T& value) const { return count(0, _length, value); } int count(int from, int to, const T& value) const { int cnt = 0; for (int i = from; i < to; i++) if (_array[i] == value) cnt++; return cnt; } void swap(int idx1, int idx2) { if (idx1 < 0 || idx1 >= _length) throw Error("swap(): invalid index %d (size=%d)", idx1, _length); if (idx2 < 0 || idx2 >= _length) throw Error("swap(): invalid index %d (size=%d)", idx2, _length); if (idx1 == idx2) return; std::swap(_array[idx1], _array[idx2]); } void push(T elem) { resize(_length + 1); _array[_length - 1] = elem; } T& push() { resize(_length + 1); return _array[_length - 1]; } T& pop() { if (_length <= 0) throw Error("stack underflow"); return _array[--_length]; } T& top() { if (_length <= 0) throw Error("stack underflow"); return _array[_length - 1]; } const T& top() const { if (_length <= 0) throw Error("stack underflow"); return _array[_length - 1]; } T& top(int offset) { if (_length - offset <= 0) throw Error("stack underflow"); return _array[_length - 1 - offset]; } const T& top(int offset) const { if (_length - offset <= 0) throw Error("stack underflow"); return _array[_length - 1 - offset]; } void resize(int newsize) { if (newsize > _reserved) reserve((newsize + 1) * 2); _length = newsize; } void expand(int newsize) { if (_length < newsize) resize(newsize); } void expandFill(int newsize, const T& value) { while (_length < newsize) push(value); } void clear_resize(int newsize) { if (_reserved < newsize) { _length = 0; reserve((newsize + 1) * 2); } _length = newsize; } void swap(Array<T>& other) { std::swap(_array, other._array); std::swap(_reserved, other._reserved); std::swap(_length, other._length); } T* begin() { return _array; } T* end() { return _array + _length; } T* begin() const { return _array; } T* end() const { return _array + _length; } // CMP_FUNCTOR has two arguments and returns sign of comparation template <typename CmpFunctor> void insertionSort(int start, int end, CmpFunctor cmp) { int i, j; char tmp[sizeof(T)]; // can't use T directly because it may have destructor for (i = start + 1; i <= end; i++) { j = i; while (j > start && cmp(_array[j - 1], _array[j]) > 0) { T* a1 = _array + j - 1; T* a2 = a1 + 1; memcpy(&tmp, a1, sizeof(T)); memcpy(a1, a2, sizeof(T)); memcpy(a2, &tmp, sizeof(T)); j--; } } } // CMP_FUNCTOR has two arguments and returns sign of comparation template <typename CmpFunctor> void qsort(int start, int end, CmpFunctor cmp) { // Sort elements from start to end if (start >= end) return; if (end - start < 10) insertionSort(start, end, cmp); struct { T *lo, *hi; } stack[32], *sp; char tmp[sizeof(T)]; // can't use T directly because it may have destructor sp = stack; // push our initial values onto the stack sp->lo = _array + start; sp->hi = _array + end + 1; sp++; while (sp > stack) { // pop lo and hi off the stack sp--; T *high = sp->hi, *low = sp->lo; T* hi = high - 1; T* lo = low; T* pivot = low; while (1) { while (lo < high && lo != pivot && cmp(*lo, *pivot) < 0) lo++; while (hi > low && (hi == pivot || cmp(*hi, *pivot) >= 0)) hi--; if (lo < hi) { memcpy(&tmp, lo, sizeof(T)); memcpy(lo, hi, sizeof(T)); memcpy(hi, &tmp, sizeof(T)); if (lo == pivot) pivot = hi; else if (hi == pivot) pivot = lo; hi--; } else { hi++; if (hi == high) // done with this segment break; // push the larger segment onto the stack and continue // sorting the smaller segment. if ((hi - low) > (high - hi)) { sp->lo = low; sp->hi = hi; sp++; hi = high; low = lo; } else { sp->hi = high; sp->lo = hi; sp++; high = hi; lo = low; } pivot = lo; hi--; } } } } template <typename T1, typename T2> void qsort(int start, int end, int (*cmp)(T1, T2, void*), void* context) { this->qsort(start, end, _CmpFunctorCaller<T1, T2>(cmp, context)); } template <typename T1, typename T2> void qsort(int (*cmp)(T1, T2, void*), void* context) { this->qsort(0, _length - 1, cmp, context); } // Array<char>-specific void appendString(const char* str, bool keep_zero) { int len = (int)strlen(str); int initial_size = _length; if (initial_size > 0 && _array[initial_size - 1] == 0) initial_size--; resize(initial_size + len); memcpy(_array + initial_size, str, len); if (keep_zero) push(0); } void readString(const char* str, bool keep_zero) { clear(); appendString(str, keep_zero); } void upper(const char* source) { clear(); while (*source != 0) push(::toupper(*source++)); push(0); } void lower(const char* source) { clear(); while (*source != 0) push(::tolower(*source++)); push(0); } void toupper() { for (int i = 0; i < _length; i++) _array[i] = ::toupper(_array[i]); } void tolower() { for (int i = 0; i < _length; i++) _array[i] = ::tolower(_array[i]); } protected: T* _array; int _reserved; int _length; private: Array(const Array&); // no implicit copy Array<int>& operator=(const Array<int>& right); // no copy constructor template <typename T1, typename T2> class _CmpFunctorCaller { public: _CmpFunctorCaller(int (*cmp)(T1, T2, void*), void* context) : _context(context), _cmp(cmp) { } int operator()(T1 arg1, T2 arg2) const { return _cmp(arg1, arg2, _context); } private: void* _context; int (*_cmp)(T1, T2, void*); }; }; } // namespace indigo #endif