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


#include <iostream>
#include <generator>
#include <memory_resource>

// PMR memory resource that traces allocations
class TracingPMR : public std::pmr::memory_resource
{
  std::pmr::memory_resource* upstream;  // wrapped memory resource
 public:
  // we wrap the passed or the default resource:
  explicit TracingPMR(std::pmr::memory_resource* us
                       = std::pmr::get_default_resource())
   : upstream{us} {
  }
 private:
  // trace allocations:
  void* do_allocate(std::size_t bytes, std::size_t alignment) override {
    std::cout << "allocate " << bytes << " Bytes\n";    // trace
    void* ret = upstream->allocate(bytes, alignment);   // delegate to upstream
    return ret;
  }

  // trace deallocations:
  void do_deallocate(void* ptr, std::size_t bytes, std::size_t alignment) override {
    std::cout << "deallocate " << bytes << " Bytes\n";  // trace
    upstream->deallocate(ptr, bytes, alignment);        // delegate to upstream
  }

  // interchangeability of objects of this resource type:
  bool do_is_equal(const std::pmr::memory_resource& r2) const noexcept override {
    return this == &r2 ||                                    // same object or
           (dynamic_cast<const TracingPMR*>(&r2) != nullptr  // same type and
             && upstream->is_equal(r2));                     // same upstream
  }
};

