Friday, September 1, 2017

C++11: Scoped Allocators

C++11 added to ability to write allocators that can maintain state. Here is an example:

#include <iostream>
#include <vector>

class Arena
{
  void * mPointerToMemory;
  int    mMaxNumberOfBytes;
  int    mNextAvailableByte;

 public:
  Arena(void * pointerToMemory, int maxNumberOfBytes)
  : mPointerToMemory(pointerToMemory),
    mMaxNumberOfBytes(maxNumberOfBytes),
    mNextAvailableByte(0)
  {
    ;
  }

  void * getPointerToBlockOfBytes(int numberOfBytes)
  {
    void * pointerToBlockOfBytes  = nullptr;
    int    remainingNumberOfBytes = mMaxNumberOfBytes - mNextAvailableByte;

    if (numberOfBytes <= remainingNumberOfBytes)
    {
      pointerToBlockOfBytes  = (void*)((unsigned char*)mPointerToMemory +
                                                       mNextAvailableByte);
      mNextAvailableByte    += numberOfBytes;       
    }
    return pointerToBlockOfBytes;
  }
};

template <class T>
struct MyAllocator
{
  typedef T value_type;

  Arena * mArena;

  MyAllocator(Arena * arena) : mArena(arena)
  {
    ;
  }

  template <class U>
  constexpr MyAllocator(const MyAllocator<U> & rhs) noexcept
  : mArena(rhs.mArena)
  {
    ;
  }

  T * allocate(std::size_t n)
  {
    void * pointerToBlockOfBytes = mArena->getPointerToBlockOfBytes(n);
    if (!pointerToBlockOfBytes)
    {
      throw std::bad_alloc();
    }
    return (T *) pointerToBlockOfBytes;
  }

  void deallocate(T* p, std::size_t) noexcept
  {
    ;
  }
};

template <class T, class U>
bool operator==(const MyAllocator<T>&, const MyAllocator<U>&)
{
  return true;
}

template <class T, class U>
bool operator!=(const MyAllocator<T>&, const MyAllocator<U>&)
{
  return false;
}

int main()
{
  Arena myArena(new int[8], 8);

  std::vector<int, MyAllocator<int>> v1(MyAllocator<int>{&myArena});

  std::cout << sizeof(v1) << " ";
  try{v1.push_back(0);}catch(...){std::cout << "Exception0" <<  " ";}
  std::cout << v1[0] << " ";
  try{v1.push_back(1);}catch(...){std::cout << "Exception1" <<  " ";}
  std::cout << v1[1] << " ";
  try{v1.push_back(2);}catch(...){std::cout << "Exception2" <<  " ";}
  std::cout << v1[2] << " ";
  try{v1.push_back(3);}catch(...){std::cout << "Exception3" <<  " ";}
  std::cout << v1[3] << " ";
  try{v1.push_back(4);}catch(...){std::cout << "Exception4" <<  " ";}
  std::cout << v1[4] << " ";

  std::cout << std::endl;
  return 0;
}
// Output: 20 0 1 2 Exception3
Reference: https://isocpp.org/wiki/faq/cpp11-library#scoped-allocator

No comments:

Post a Comment