https://github.com/wilkeraziz/mosesdecoder
Raw File
Tip revision: 2ec5207db1493a3580a4c2dc3aab4fc65ed528d5 authored by Hieu Hoang on 16 September 2015, 12:31:36 UTC
int warnings
Tip revision: 2ec5207
ObjectPool.h
// $Id$

/* ---------------------------------------------------------------- */
/* Copyright 2005 (c) by RWTH Aachen - Lehrstuhl fuer Informatik VI */
/* Richard Zens                                                     */
/* ---------------------------------------------------------------- */

#ifndef moses_ObjectPool_h
#define moses_ObjectPool_h

#include <vector>
#include <deque>
#include <string>
#include <iostream>
#include <iterator>
#include "Util.h"

/***
 * template class for pool of objects
 * - useful if many small objects are frequently created and destroyed
 * - allocates memory for N objects at a time
 * - separates memory allocation from constructor/destructor calls
 * - prevents memory leaks
 */
template<typename T> class ObjectPool
{
public:
  typedef T Object;
private:
  std::string name;
  size_t idx,dIdx,N;
  std::vector<Object*> data;
  std::vector<size_t> dataSize;
  std::deque<Object*> freeObj;
  int mode;
public:
  static const int cleanUpOnDestruction=1;
  static const int hasTrivialDestructor=2;

  // constructor arguments:
  //   N: initial number of objects to allocate memory at a time
  //   m & cleanUpOnDestruction = clean up objects in destructor
  //   m & hasTrivialDestructor = the object type has a trivial destructor,
  //            i.e. no sub-object uses dynamically allocated memory
  //            note: not equivalent to empty destructor
  //         -> more efficient (destructor calls can be omitted),
  //            note: looks like memory leak, but is not
  ObjectPool(std::string name_="T",size_t N_=100000,int m=cleanUpOnDestruction)
    : name(name_),idx(0),dIdx(0),N(N_),mode(m) {
    allocate();
  }

  // main accesss functions:
  // get pointer to object via default or copy constructor
  Object* get() {
    return new (getPtr()) Object;
  }
  Object* get(const Object& x) {
    return new (getPtr()) Object(x);
  }

  // get pointer to uninitialized memory,
  // WARNING: use only if you know what you are doing !
  // useful for non-default constructors, you have to use placement new
  Object* getPtr() {
    if(freeObj.size()) {
      Object* rv=freeObj.back();
      freeObj.pop_back();
      rv->~Object();
      return rv;
    }
    if(idx==dataSize[dIdx]) {
      idx=0;
      if(++dIdx==data.size()) allocate();
    }
    return data[dIdx]+idx++;
  }

  // return object(s) to pool for reuse
  // note: objects are not destroyed here, but in 'getPtr'/'destroyObjects',
  //       otherwise 'destroyObjects' would have to check the freeObj-stack
  //       before each destructor call
  void freeObject(Object* x) {
    freeObj.push_back(x);
  }
  template<class fwiter> void freeObjects(fwiter b,fwiter e) {
    for(; b!=e; ++b) this->free(*b);
  }

  // destroy all objects, but do not free memory
  void reset() {
    destroyObjects();
    idx=0;
    dIdx=0;
    freeObj.clear();
  }
  // destroy all objects and free memory
  void cleanUp() {
    reset();
    for(size_t i=0; i<data.size(); ++i) free(data[i]);
    data.clear();
    dataSize.clear();
  }

  ~ObjectPool() {
    if(mode & cleanUpOnDestruction) cleanUp();
  }

  void printInfo(std::ostream& out) const {
    out<<"OPOOL ("<<name<<") info: "<<data.size()<<" "<<dataSize.size()<<" "
       <<freeObj.size()<<"\n"<<idx<<" "<<dIdx<<" "<<N<<"\n";
    std::copy(dataSize.begin(),dataSize.end(),
              std::ostream_iterator<size_t>(out," "));
    out<<"\n\n";
  }


private:
  void destroyObjects() {
    if(mode & hasTrivialDestructor) return;
    for(size_t i=0; i<=dIdx; ++i) {
      size_t lastJ= (i<dIdx ? dataSize[i] : idx);
      for(size_t j=0; j<lastJ; ++j) (data[i]+j)->~Object();
    }
  }
  // allocate memory for a N objects, for follow-up allocations,
  // the block size is doubled every time
  // if allocation fails, block size is reduced by 1/4
  void allocate() {
    try {
      if(dataSize.empty()) dataSize.push_back(N);
      else dataSize.push_back(dataSize.back()*2);
      void *m=malloc(sizeof(Object)*dataSize.back());
      while(!m) {
        dataSize.back()=static_cast<size_t>(dataSize.back()*0.75);
        m=malloc(sizeof(Object)*dataSize.back());
      }
      data.push_back(static_cast<Object*>(m));
    } catch (const std::exception& e) {
      TRACE_ERR("caught std::exception: "<<e.what()
                <<" in ObjectPool::allocate(), name: "<<name<<", last size: "
                <<dataSize.back()<<"\n");
      TRACE_ERR("OPOOL info: "<<data.size()<<" "<<dataSize.size()<<" "
                <<freeObj.size()<<"\n"<<idx<<" "<<dIdx<<" "<<N<<"\n");
      std::copy(dataSize.begin(),dataSize.end(),
                std::ostream_iterator<size_t>(std::cerr," "));
      TRACE_ERR("\n");
      throw;
    }
  }
};

#endif
back to top