/***************************************************************************
**
**  This file is part of QGpCoreTools.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file 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 Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2009-05-13
**  Copyright: 2009-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifndef INCREASESTORAGE_H
#define INCREASESTORAGE_H

#include <stdlib.h>

#include "QGpCoreToolsDLLExport.h"

namespace QGpCoreTools {

class QGPCORETOOLS_EXPORT IncreaseStorage
{
public:
  inline IncreaseStorage(size_t defaultCapacity);
  inline IncreaseStorage(const IncreaseStorage& o);
  virtual ~IncreaseStorage() {}

  inline void reserve(size_t n);
  int size() const {return _size;}
  inline void add(size_t n=1);
  inline void clear();
  void downSize(size_t s) {_size=s;}
protected:
  virtual void reallocate()=0;
  inline void * allocateVector(size_t itemSize);
  inline void * reallocateVector(void * vect, size_t itemSize);

  double capacity() const {return _capacity;}
private:
  size_t _defaultCapacity;
  size_t _capacity;
  volatile size_t _size;
};

inline IncreaseStorage::IncreaseStorage(size_t defaultCapacity)
{
  _defaultCapacity=defaultCapacity;
  clear();
}

inline IncreaseStorage::IncreaseStorage(const IncreaseStorage& o)
{
  _defaultCapacity=o._defaultCapacity;
  _capacity=o._capacity;
  _size=o._size;
}

inline void * IncreaseStorage::allocateVector(size_t itemSize)
{
  return malloc(_capacity * itemSize);
}

inline void * IncreaseStorage::reallocateVector(void * vect, size_t itemSize)
{
  return realloc(vect, _capacity * itemSize);
}

inline void IncreaseStorage::reserve(size_t n)
{
  if(_size+n>=_capacity) {
    while(_size+n>=_capacity) {
      _capacity=_capacity << 1;
    }
    reallocate();
  }
}

inline void IncreaseStorage::add(size_t n)
{
  _size+=n;
  if(_size>=_capacity) {
    do {
      _capacity=_capacity << 1;
    } while(_size>=_capacity);
    reallocate();
  }
}

inline void IncreaseStorage::clear()
{
  _capacity=_defaultCapacity;
  _size=0;
}

} // namespace QGpCoreTools

#endif // INCREASESTORAGE_H
