//********************************************************
// The following code example is taken from the book
//  C++23 - The Complete Guide
//  by Nicolai M. Josuttis (www.josuttis.com)
//  https://www.cppstd23.com
//
// The code is licensed under a
//  Creative Commons Attribution 4.0 International License
//  https://creativecommons.org/licenses/by/4.0/
//********************************************************


#include <iostream>
#include <cstddef>    // for size_t

template<typename T>
class TracingAllocator {
 public:
  typedef T value_type;     // necessary type definition

  // constructors (nothing to do because the allocator has no state):
  TracingAllocator() noexcept {
  }
  template<typename T2>
  TracingAllocator (const TracingAllocator<T2>&) noexcept {
  }

  // allocate but don't initialize num elements of type T:
  T* allocate (std::size_t num) {
    std::cout << "\nALLOCATE " << num*sizeof(T) << " bytes\n";
    // allocate memory with global new
    return static_cast<T*>(::operator new(num*sizeof(T)));
  }

  // deallocate storage p of deleted elements:
  void deallocate (T* p, std::size_t num) {
    std::cout << "\nDEALLOCATE " << num*sizeof(T) << " bytes\n";
    // deallocate memory with global delete
    ::operator delete(p);
  }

  template<typename T2>
  bool operator== (const TracingAllocator<T2>&) noexcept {
    return true;  // all allocators of this type are interchangeable
  }    
};

