38class CachingMemoryResource :
public std::pmr::memory_resource {
40 explicit CachingMemoryResource(
41 std::pmr::memory_resource *upstream,
42 std::size_t minCacheBytes = 256u * 1024u,
43 std::size_t maxCachedBytes = 1024u * 1024u * 1024u)
45 : upstream_(upstream ? upstream : std::pmr::new_delete_resource()),
46 minCache_(minCacheBytes), maxCached_(maxCachedBytes) {}
48 ~CachingMemoryResource()
override { releaseCached(); }
50 CachingMemoryResource(
const CachingMemoryResource &) =
delete;
51 CachingMemoryResource &operator=(
const CachingMemoryResource &) =
delete;
54 void releaseCached() {
55 std::lock_guard<std::mutex> lk(mu_);
56 for (
auto &kv : free_)
57 for (
void *p : kv.second)
58 upstream_->deallocate(p, kv.first.first, kv.first.second);
64 using Key = std::pair<std::size_t, std::size_t>;
66 std::size_t operator()(
const Key &k)
const noexcept {
67 return k.first * 1000003u ^ (k.second << 1);
71 void *do_allocate(std::size_t bytes, std::size_t align)
override {
72 if (bytes >= minCache_) {
73 std::lock_guard<std::mutex> lk(mu_);
74 auto it = free_.find(Key{bytes, align});
75 if (it != free_.end() && !it->second.empty()) {
76 void *p = it->second.back();
77 it->second.pop_back();
78 cachedBytes_ -= bytes;
82 return upstream_->allocate(bytes, align);
85 void do_deallocate(
void *p, std::size_t bytes, std::size_t align)
override {
86 if (bytes >= minCache_) {
87 std::lock_guard<std::mutex> lk(mu_);
88 if (cachedBytes_ + bytes <= maxCached_) {
89 free_[Key{bytes, align}].push_back(p);
90 cachedBytes_ += bytes;
94 upstream_->deallocate(p, bytes, align);
97 bool do_is_equal(
const std::pmr::memory_resource &o)
const noexcept override {
101 std::pmr::memory_resource *upstream_;
102 std::size_t minCache_;
103 std::size_t maxCached_;
105 std::unordered_map<Key, std::vector<void *>, KeyHash> free_;
106 std::size_t cachedBytes_ = 0;