36 std::array<RegionLayout, kScratchRegionCount>
regions{};
41inline std::uint64_t
add(std::uint64_t left, std::uint64_t right) {
42 if (right > std::numeric_limits<std::uint64_t>::max() - left)
46inline std::uint64_t
multiply(std::uint64_t left, std::uint64_t right) {
47 if (left != 0 && right > std::numeric_limits<std::uint64_t>::max() / left)
51inline std::uint64_t
slots(std::uint64_t keys) {
52 if (keys == 0)
return 0;
53 const auto minimum = std::max(std::uint64_t{64},
multiply(2, keys));
54 std::uint64_t result = 64;
55 while (result < minimum) result =
multiply(result, 2);
58inline std::uint64_t
page(std::uint64_t bytes) {
63template<
class HostSize>
64inline bool fits(std::uint64_t bytes)
noexcept {
65 if constexpr (std::numeric_limits<HostSize>::digits
66 < std::numeric_limits<std::uint64_t>::digits)
67 return bytes <=
static_cast<std::uint64_t
>(std::numeric_limits<HostSize>::max());
79 const std::array<std::uint64_t, kScratchRegionCount> capacities{{
80 add(multiply(40, manifest.
K_q), manifest.
B_q),
81 multiply(16, slots(manifest.
K_q)),
82 add(multiply(40, manifest.
K_e), manifest.
B_e),
83 multiply(16, slots(manifest.
K_e)),
84 add(multiply(40, manifest.
K_c), manifest.
B_c),
85 multiply(16, slots(manifest.
K_c)),
86 manifest.
U == 0 ? 0 : add(add(1, multiply(96, manifest.
U)), manifest.
B_U),
87 manifest.
V == 0 ? 0 : add(add(1, multiply(60, manifest.
V)), manifest.
B_V),
88 multiply(16, manifest.
R),
91 std::uint64_t offset = 0;
92 for (std::size_t i = 0; i < capacities.size(); ++i) {
93 const auto span = page(capacities[i]);
96 offset = add(offset, span);
99 if (!fits<std::size_t>(
layout.slab_size) || !fits<off_t>(
layout.slab_size))
114 allocation_(static_cast<
std::uint8_t*>(::operator new(
115 static_cast<
std::size_t>(layout_.slab_size),
117 for (std::size_t i = 0; i < regions_.size(); ++i) {
118 const auto& item = layout_.regions[i];
119 regions_[i] = {allocation_ +
static_cast<std::size_t
>(item.offset),
120 item.capacity, 0, item.resource};
125 ::operator
delete(allocation_,
135 const std::array<Region, kScratchRegionCount>&
regions() const noexcept {
return regions_; }
141 const auto word =
static_cast<std::uint32_t
>(
resource);
143 && new_extent <= regions_[word - 1].capacity;
161 auto& item = regions_[index(
resource)];
162 item.logical_extent = std::max(item.logical_extent, new_extent);
170 void* destination, std::size_t length)
const {
172 if (offset > item.capacity || length > item.capacity - offset
173 || offset > item.logical_extent || length > item.logical_extent - offset)
175 if (length == 0)
return;
177 std::memcpy(destination, item.base +
static_cast<std::size_t
>(offset), length);
180 void* destination, std::size_t length)
const {
185 const void*
source, std::size_t length) {
186 auto& item = regions_[index(
resource)];
187 if (offset > item.capacity || length > item.capacity - offset)
189 if (length == 0)
return;
191 std::memcpy(item.base +
static_cast<std::size_t
>(offset),
source, length);
192 item.logical_extent = std::max(item.logical_extent,
193 offset +
static_cast<std::uint64_t
>(length));
196 const void*
source, std::size_t length) {
204 std::memset(allocation_, 0,
static_cast<std::size_t
>(layout_.slab_size));
207 auto& item = regions_[index(
resource)];
208 if (item.capacity != 0)
209 std::memset(item.base, 0,
static_cast<std::size_t
>(item.capacity));
213 for (
auto& item : regions_) item.logical_extent = 0;
217 regions_[index(
resource)].logical_extent = 0;
222 const auto word =
static_cast<std::uint32_t
>(
resource);
225 return static_cast<std::size_t
>(word - 1);
227 void validate(
const Region& item)
const {
228 if (&item != ®ions_[index(item.resource)])
230 "scratch region belongs to another slab");
232 const ScratchManifest manifest_;
233 const Layout layout_;
234 std::uint8_t*
const allocation_;
235 std::array<Region, kScratchRegionCount> regions_{};
void read_at(ScratchResource resource, std::uint64_t offset, void *destination, std::size_t length) const
ScratchSlab & operator=(const ScratchSlab &)=delete
void require_extend(const Region &item, std::uint64_t new_extent) const
void read_at(const Region &item, std::uint64_t offset, void *destination, std::size_t length) const
ScratchSlab & operator=(ScratchSlab &&)=delete
void reset(ScratchResource resource)
bool can_extend(ScratchResource resource, std::uint64_t new_extent) const noexcept
void require_extend(ScratchResource resource, std::uint64_t new_extent) const
const Layout & layout() const noexcept
ScratchSlab(ScratchSlab &&)=delete
void extend(ScratchResource resource, std::uint64_t new_extent)
ScratchSlab(const ScratchManifest &manifest)
ScratchSlab(const ScratchSlab &)=delete
const Region & region(ScratchResource resource) const
const std::array< Region, kScratchRegionCount > & regions() const noexcept
void zero(ScratchResource resource)
bool can_extend(const Region &item, std::uint64_t new_extent) const
void write_at(ScratchResource resource, std::uint64_t offset, const void *source, std::size_t length)
const ScratchManifest & manifest() const noexcept
void write_at(const Region &item, std::uint64_t offset, const void *source, std::size_t length)
bool fits(std::uint64_t bytes) noexcept
std::uint64_t slots(std::uint64_t keys)
std::uint64_t add(std::uint64_t left, std::uint64_t right)
std::uint64_t multiply(std::uint64_t left, std::uint64_t right)
std::uint64_t page(std::uint64_t bytes)
Layout compute_layout(const ScratchManifest &manifest)
constexpr std::uint64_t kScratchPageSize
constexpr std::size_t kScratchRegionCount
std::array< RegionLayout, kScratchRegionCount > regions
std::uint64_t logical_extent