text: #pragma once
  
  #include <limits>   // std::numeric_limits
  #include <utility>  // std::forward
  #include <cstddef>
  
  #include "libipc/pool_alloc.h"
  
  namespace ipc {
  namespace mem {
  
  ////////////////////////////////////////////////////////////////
  /// The allocator wrapper class for STL
  ////////////////////////////////////////////////////////////////
  
  namespace detail {
  
  template <typename T, typename AllocP>
  struct rebind {
      template <typename U>
      using alloc_t = AllocP;
  };
  
  template <typename T, template <typename> class AllocT>
  struct rebind<T, AllocT<T>> {
      template <typename U>
      using alloc_t = AllocT<U>;
  };
  
  } // namespace detail
  
  template <typename T, typename AllocP>
  class allocator_wrapper {
  
      template <typename U, typename AllocU>
      friend class allocator_wrapper;
  
  public:
      // type definitions
      typedef T                 value_type;
      typedef value_type*       pointer;
      typedef const value_type* const_pointer;
      typedef value_type&       reference;
      typedef const value_type& const_reference;
      typedef std::size_t       size_type;
      typedef std::ptrdiff_t    difference_type;
      typedef AllocP            alloc_policy;
  
  private:
      alloc_policy alloc_;
  
  public:
      allocator_wrapper() noexcept {}
  
      // construct by copying (do nothing)
      allocator_wrapper           (const allocator_wrapper<T, AllocP>&) noexcept {}
      allocator_wrapper& operator=(const allocator_wrapper<T, AllocP>&) noexcept { return *this; }
  	
      // construct from a related allocator (do nothing)
      template <typename U, typename AllocU> allocator_wrapper           (const allocator_wrapper<U, AllocU>&) noexcept {}
      template <typename U, typename AllocU> allocator_wrapper& operator=(const allocator_wrapper<U, AllocU>&) noexcept { return *this; }
  
      allocator_wrapper           (allocator_wrapper && rhs) noexcept : alloc_ ( std::move(rhs.alloc_) ) {}
      allocator_wrapper& operator=(allocator_wrapper && rhs) noexcept { alloc_ = std::move(rhs.alloc_); return *this; }
  
  public:
      // the other type of std_allocator
      template <typename U>
      struct rebind { 
          using other = allocator_wrapper< U, typename detail::rebind<T, AllocP>::template alloc_t<U> >;
      };
  
      constexpr size_type max_size(void) const noexcept {
          return (std::numeric_limits<size_type>::max)() / sizeof(value_type);
      }
  
  public:
      pointer allocate(size_type count) noexcept {
          if (count == 0) return nullptr;
          if (count > this->max_size()) return nullptr;
          return static_cast<pointer>(alloc_.alloc(count * sizeof(value_type)));
      }
  
      void deallocate(pointer p, size_type count) noexcept {
          alloc_.free(p, count * sizeof(value_type));
      }
  
      template <typename... P>
      static void construct(pointer p, P && ... params) {
          ipc::mem::construct(p, std::forward<P>(params)...);
      }
  
      static void destroy(pointer p) {
          ipc::mem::destruct(p);
      }
  };
  
  template <class AllocP>
  class allocator_wrapper<void, AllocP> {
  public:
      // type definitions
      typedef void              value_type;
      typedef value_type*       pointer;
      typedef const value_type* const_pointer;
      typedef std::size_t       size_type;
      typedef std::ptrdiff_t    difference_type;
      typedef AllocP            alloc_policy;
  };
  
  template <typename T, typename U, class AllocP>
  constexpr bool operator==(const allocator_wrapper<T, AllocP>&, const allocator_wrapper<U, AllocP>&) noexcept {
      return true;
  }
  
  template <typename T, typename U, class AllocP>
  constexpr bool operator!=(const allocator_wrapper<T, AllocP>&, const allocator_wrapper<U, AllocP>&) noexcept {
      return false;
  }
  
  } // namespace mem
  } // namespace ipc
  