//COTD Entry by James Johnson [kmeson@telocity.com]
///////////////////////////////////////////////////////////////////////////////
// Class:           aligned_BlockAlloc
// Base Classes:    std::allocator<T>
// Type:            template class
// Inheritance:     public
// Desc:            implements a block aligned allocator. Allocation occurs on
//                  T_ALIGNMENT boundary. This boundary must be a power of 2.
//                  The minimum block size allocated is T_BLOCKSIZE and must be
//                  non-ZERO. Allocations smaller than	T_BLOCKSIZE are rounded
//                  up to the nears multiple of T_BLOCKSIZE.
//
//                  Default alignment is 16 bytes
//                  Default block size is 8 bytes
//
// Usage:
//
//    std::vector<float,aligned_BlockAlloc<float> >	vecFloatAlign16by8;
//    vecFloatAlign16by8.resize(1024,1.0f)
//
///////////////////////////////////////////////////////////////////////////////
template <typename T,
           unsigned long T_ALIGNMENT=16,
           unsigned long T_BLOCKSIZE=8>
class aligned_BlockAlloc : public std::allocator<T>
{
private:
     typedef std::allocator<T>  BASE_TYPE;

public:
     aligned_BlockAlloc() {}
     aligned_BlockAlloc& operator=(const aligned_Alloc &r){
         BASE_TYPE::operator=(r);
         return *this;
     }

     pointer allocate(size_type n, const void *hint){
         pointer p = NULL;
         unsigned long byteCount = sizeof(T) * n;
         unsigned long byteCountLeft = byteCount % T_BLOCKSIZE;
         if(byteCountLeft){
             byteCount += T_BLOCKSIZE -  byteCountLeft;
         }
         if(!hint){
             p = reinterpret_cast<pointer>(_aligned_malloc(byteCount,T_ALIGNMENT));
         }else{
             p = reinterpret_cast<pointer>(_aligned_realloc((void*)hint,byteCount,T_ALIGNMENT));
         }
         return p;
     }

     void deallocate(pointer p, size_type n){
         _aligned_free(p);
     }

     void construct(pointer p, const T &val){
         new(p) T(val);
     }

     void destroy(pointer p){
         p->~T();
     }
};
