Everett
Loading...
Searching...
No Matches
output_budget.h
Go to the documentation of this file.
1
12#pragma once
13
14#include <atomic>
15#include <cstddef>
16#include <memory>
17#include <optional>
18#include <stdexcept>
19#include <utility>
20
21namespace everett {
22 // This accounts for caller-declared allocation capacities. It does not
23 // measure allocations or bound cursor workspace and user callbacks. Builders
24 // acquire before retaining output; finished owners keep the lease until the
25 // last reference is gone, possibly on a different thread from the builder.
27 private:
28 struct state {
29 std::size_t const limit;
30 std::atomic<std::size_t> used{0};
31 explicit state(std::size_t bytes) noexcept : limit(bytes) {}
32 };
33 public:
34 struct lease {
35 lease() = default;
36 lease(lease const &) = delete;
37 lease & operator=(lease const &) = delete;
38 lease(lease && other) noexcept
39 : state_(std::move(other.state_)), bytes_(std::exchange(other.bytes_, 0)) {}
40 lease & operator=(lease && other) noexcept {
41 if (this != &other) {
42 reset(); state_ = std::move(other.state_); bytes_ = std::exchange(other.bytes_, 0);
43 }
44 return *this;
45 }
46 ~lease() { reset(); }
47 std::size_t bytes() const noexcept { return bytes_; }
48 void reset() noexcept {
49 if (state_) state_->used.fetch_sub(bytes_, std::memory_order_relaxed);
50 bytes_ = 0; state_.reset();
51 }
52 // Finalization can return conservative staging slack without briefly
53 // releasing the allowance covering the finished object's allocations.
54 void shrink(std::size_t bytes) {
55 if (bytes > bytes_) throw std::invalid_argument("output lease cannot grow");
56 if (state_) state_->used.fetch_sub(bytes_ - bytes, std::memory_order_relaxed);
57 bytes_ = bytes;
58 }
59 private:
60 friend struct output_budget;
61 std::shared_ptr<state> state_;
62 std::size_t bytes_ = 0;
63 lease(std::shared_ptr<state> value, std::size_t bytes) noexcept
64 : state_(std::move(value)), bytes_(bytes) {}
65 };
66
67 explicit output_budget(std::size_t limit) : state_(std::make_shared<state>(limit)) {}
68 // Copies deliberately share one allowance, including across context owners.
69 std::size_t limit() const noexcept { return state_->limit; }
70 std::size_t used() const noexcept { return state_->used.load(std::memory_order_relaxed); }
71 std::optional<lease> try_acquire(std::size_t bytes) const noexcept {
72 auto used = state_->used.load(std::memory_order_relaxed);
73 for (;;) {
74 if (bytes > state_->limit - used) return std::nullopt;
75 if (state_->used.compare_exchange_weak(used, used + bytes, std::memory_order_relaxed))
76 return lease(state_, bytes);
77 }
78 }
79
80 // The alias owns both value and allowance without changing the array's
81 // representation. Destroy the value before returning its charge. If the
82 // holder allocation or value construction throws, the lease is returned.
83 template <class T> static std::shared_ptr<T const> attach(T value, lease allocation) {
84 auto owner = std::make_shared<retained<T>>(std::move(allocation), std::move(value));
85 auto address = &owner->value;
86 return std::shared_ptr<T const>(std::move(owner), address);
87 }
88 private:
89 template <class T> struct retained {
92 retained(lease && charge, T && item) : allocation(std::move(charge)), value(std::move(item)) {}
93 };
94 std::shared_ptr<state> state_;
95 };
96}
Definition active_engine.h:18
Definition output_budget.h:34
std::size_t bytes_
Definition output_budget.h:62
lease(lease &&other) noexcept
Definition output_budget.h:38
void reset() noexcept
Definition output_budget.h:48
lease(std::shared_ptr< state > value, std::size_t bytes) noexcept
Definition output_budget.h:63
lease & operator=(lease &&other) noexcept
Definition output_budget.h:40
std::shared_ptr< state > state_
Definition output_budget.h:61
lease(lease const &)=delete
~lease()
Definition output_budget.h:46
std::size_t bytes() const noexcept
Definition output_budget.h:47
void shrink(std::size_t bytes)
Definition output_budget.h:54
lease & operator=(lease const &)=delete
Definition output_budget.h:89
retained(lease &&charge, T &&item)
Definition output_budget.h:92
T value
Definition output_budget.h:91
lease allocation
Definition output_budget.h:90
Definition output_budget.h:28
state(std::size_t bytes) noexcept
Definition output_budget.h:31
std::atomic< std::size_t > used
Definition output_budget.h:30
std::size_t const limit
Definition output_budget.h:29
Definition output_budget.h:26
std::size_t limit() const noexcept
Definition output_budget.h:69
std::shared_ptr< state > state_
Definition output_budget.h:94
std::size_t used() const noexcept
Definition output_budget.h:70
std::optional< lease > try_acquire(std::size_t bytes) const noexcept
Definition output_budget.h:71
static std::shared_ptr< T const > attach(T value, lease allocation)
Definition output_budget.h:83
output_budget(std::size_t limit)
Definition output_budget.h:67