/* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef NDB_VECTOR_HPP #define NDB_VECTOR_HPP #include #include template class Vector { public: Vector(unsigned sz = 10, unsigned inc_sz = 0); int expand(unsigned sz); ~Vector(); T& operator[](unsigned i); const T& operator[](unsigned i) const; unsigned size() const { return m_size; }; int push_back(const T &); int push(const T&, unsigned pos); T& set(T&, unsigned pos, T& fill_obj); T& back(); void erase(unsigned index); void clear(); int fill(unsigned new_size, T & obj); Vector& operator=(const Vector&); /** Does deep copy.*/ Vector(const Vector&); /** * Shallow equal (i.e does memcmp) */ bool equal(const Vector& obj) const; int assign(const T*, unsigned cnt); int assign(const Vector& obj) { return assign(obj.getBase(), obj.size());} T* getBase() { return m_items;} const T* getBase() const { return m_items;} private: T * m_items; unsigned m_size; unsigned m_incSize; unsigned m_arraySize; }; /** * BEWARE: Constructing Vector with initial size > 0 is * unsafe wrt. catching 'out of memory' errors. * (C'tor doesn't return error code) * Instead construct Vector with size==0, and then * expand() it to the wanted initial size. */ template Vector::Vector(unsigned sz, unsigned inc_sz): m_items(NULL), m_size(0), m_incSize((inc_sz > 0) ? inc_sz : 50), m_arraySize(0) { if (sz == 0) return; m_items = new T[sz]; if (m_items == NULL) { errno = ENOMEM; return; } m_arraySize = sz; } template int Vector::expand(unsigned sz){ if (sz <= m_size) return 0; T * tmp = new T[sz]; if(tmp == NULL) { errno = ENOMEM; return -1; } for (unsigned i = 0; i < m_size; i++) tmp[i] = m_items[i]; delete[] m_items; m_items = tmp; m_arraySize = sz; return 0; } /** * BEWARE: Copy-constructing a Vector is * unsafe wrt. catching 'out of memory' errors. * (C'tor doesn't return error code) * Instead construct empty Vector (size==0), * and then assign() it the initial contents. */ template Vector::Vector(const Vector& src): m_items(NULL), m_size(0), m_incSize(src.m_incSize), m_arraySize(0) { const unsigned sz = src.m_size; if (sz == 0) return; m_items = new T[sz]; if (unlikely(m_items == NULL)){ errno = ENOMEM; return; } for(unsigned i = 0; i < sz; i++){ m_items[i] = src.m_items[i]; } m_arraySize = sz; m_size = sz; } template Vector::~Vector(){ delete[] m_items; // safety for placement new usage m_items = 0; m_size = 0; m_arraySize = 0; } template T & Vector::operator[](unsigned i){ if(i >= m_size) abort(); return m_items[i]; } template const T & Vector::operator[](unsigned i) const { if(i >= m_size) abort(); return m_items[i]; } template T & Vector::back(){ if(m_size==0) abort(); return (* this)[m_size - 1]; } template int Vector::push_back(const T & t){ if(m_size == m_arraySize){ const int err = expand(m_arraySize + m_incSize); if (unlikely(err)) return err; } m_items[m_size] = t; m_size++; return 0; } template int Vector::push(const T & t, unsigned pos) { const int err = push_back(t); if (unlikely(err)) return err; if (pos < m_size - 1) { for(unsigned i = m_size - 1; i > pos; i--) { m_items[i] = m_items[i-1]; } m_items[pos] = t; } return 0; } template T& Vector::set(T & t, unsigned pos, T& fill_obj) { if (fill(pos, fill_obj)) abort(); T& ret = m_items[pos]; m_items[pos] = t; return ret; } template void Vector::erase(unsigned i){ if(i >= m_size) abort(); for (unsigned k = i; k + 1 < m_size; k++) m_items[k] = m_items[k + 1]; m_size--; } template void Vector::clear(){ m_size = 0; } template int Vector::fill(unsigned new_size, T & obj){ const int err = expand(new_size); if (unlikely(err)) return err; while(m_size <= new_size) if (push_back(obj)) return -1; return 0; } /** * 'operator=' will 'abort()' on 'out of memory' errors. * You may prefer using ::assign()' which returns * an error code instead of aborting. */ template Vector& Vector::operator=(const Vector& obj){ if(this != &obj){ clear(); const int err = expand(obj.size()); if (unlikely(err)) abort(); for(unsigned i = 0; i int Vector::assign(const T* src, unsigned cnt) { if (getBase() == src) return 0; // Self-assign is a NOOP clear(); const int err = expand(cnt); if (unlikely(err)) return err; for (unsigned i = 0; i bool Vector::equal(const Vector& obj) const { if (size() != obj.size()) return false; return memcmp(getBase(), obj.getBase(), size() * sizeof(T)) == 0; } template class MutexVector : public NdbLockable { public: MutexVector(unsigned sz = 10, unsigned inc_sz = 0); int expand(unsigned sz); ~MutexVector(); T& operator[](unsigned i); const T& operator[](unsigned i) const; unsigned size() const { return m_size; }; int push_back(const T &); int push_back(const T &, bool lockMutex); T& back(); void erase(unsigned index); void erase(unsigned index, bool lockMutex); void clear(); void clear(bool lockMutex); int fill(unsigned new_size, T & obj); private: // Don't allow copy and assignment of MutexVector MutexVector(const MutexVector&); MutexVector& operator=(const MutexVector&); T * m_items; unsigned m_size; unsigned m_incSize; unsigned m_arraySize; }; /** * BEWARE: Constructing MutexVector with initial size > 0 is * unsafe wrt. catching 'out of memory' errors. * (C'tor doesn't return error code) * Instead construct MutexVector with size==0, and then * expand() it to the wanted initial size. */ template MutexVector::MutexVector(unsigned sz, unsigned inc_sz): m_items(NULL), m_size(0), m_incSize((inc_sz > 0) ? inc_sz : 50), m_arraySize(0) { if (sz == 0) return; m_items = new T[sz]; if (m_items == NULL) { errno = ENOMEM; return; } m_arraySize = sz; } template int MutexVector::expand(unsigned sz){ if (sz <= m_size) return 0; T * tmp = new T[sz]; if(tmp == NULL) { errno = ENOMEM; return -1; } for (unsigned i = 0; i < m_size; i++) tmp[i] = m_items[i]; delete[] m_items; m_items = tmp; m_arraySize = sz; return 0; } template MutexVector::~MutexVector(){ delete[] m_items; // safety for placement new usage m_items = 0; m_size = 0; m_arraySize = 0; } template T & MutexVector::operator[](unsigned i){ if(i >= m_size) abort(); return m_items[i]; } template const T & MutexVector::operator[](unsigned i) const { if(i >= m_size) abort(); return m_items[i]; } template T & MutexVector::back(){ if(m_size==0) abort(); return (* this)[m_size - 1]; } template int MutexVector::push_back(const T & t){ lock(); if(m_size == m_arraySize){ const int err = expand(m_arraySize + m_incSize); if (unlikely(err)) { unlock(); return err; } } m_items[m_size] = t; m_size++; unlock(); return 0; } template int MutexVector::push_back(const T & t, bool lockMutex){ if(lockMutex) lock(); if(m_size == m_arraySize){ const int err = expand(m_arraySize + m_incSize); if (unlikely(err)) { if(lockMutex) unlock(); return err; } } m_items[m_size] = t; m_size++; if(lockMutex) unlock(); return 0; } template void MutexVector::erase(unsigned i){ if(i >= m_size) abort(); lock(); for (unsigned k = i; k + 1 < m_size; k++) m_items[k] = m_items[k + 1]; m_size--; unlock(); } template void MutexVector::erase(unsigned i, bool _lock){ if(i >= m_size) abort(); if(_lock) lock(); for (unsigned k = i; k + 1 < m_size; k++) m_items[k] = m_items[k + 1]; m_size--; if(_lock) unlock(); } template void MutexVector::clear(){ lock(); m_size = 0; unlock(); } template void MutexVector::clear(bool l){ if(l) lock(); m_size = 0; if(l) unlock(); } template int MutexVector::fill(unsigned new_size, T & obj){ while(m_size <= new_size) if (push_back(obj)) return -1; return 0; } #endif