nk
1.0.0
C++ Numerical Computing Runtime
Toggle main menu visibility
Loading...
Searching...
No Matches
scratch.hpp
1
// core/include/nk/value/scratch.hpp
2
//
3
// nk memory layer — two thin classes over std::pmr.
4
//
5
// `std::pmr::memory_resource*` is the single allocation primitive across
6
// the codebase. Public APIs accept it directly. Embedders supply their
7
// own memory_resource (subclass it, or use one of the std::pmr-provided
8
// resources like get_default_resource(), pool resources, etc.).
9
//
10
// ── ScratchArena ──────────────────────────────────────────────────────
11
//
12
// Per-call bump arena. IS-A std::pmr::monotonic_buffer_resource —
13
// pass `&arena` directly to anything pmr-aware (pmr containers, the
14
// nested ScratchVec, etc.). 64 KiB inline storage absorbs the typical
15
// scratch footprint of every public toolboxes/builtin and toolboxes/signal
16
// function (incl. set-op hash maps at small N and tridiagonal scratches
17
// in interp1Spline). Spillover paths still work for inputs that exceed
18
// this. Stack burden +60 KiB per arena is fine on every supported
19
// target (Windows 1 MB main, emcc 5 MB main / 1 MB worker) since
20
// arenas are scope-confined to a single public function call (no
21
// nesting / no recursion).
22
//
23
// Lifetime: the upstream memory_resource MUST outlive every ScratchArena
24
// built on it, AND every Value/DataBuffer that flowed through that
25
// memory_resource. In practice the upstream comes from Engine and
26
// outlives all Values it produced — standard pmr lifetime contract.
27
//
28
// ── ScratchVec<T> ─────────────────────────────────────────────────────
29
//
30
// std::pmr::vector<T> with two structural footgun closures:
31
//
32
// #a Implicit copy ctor + copy-assignment DELETED.
33
// `auto X = other_scratchvec;` is a compile error. Without the
34
// deletion it would have silently allocated X off-arena via pmr's
35
// select_on_container_copy_construction → default_resource. Use
36
// the alloc-aware copy ctor (inherited from base) explicitly when
37
// a duplicate is genuinely intended:
38
// ScratchVec<T> dup(other_scratchvec, mr);
39
//
40
// #b bool rejected at compile time via static_assert.
41
// MSVC's pmr::vector<bool> bit-packed proxy has an init-state
42
// miscompilation that bit us on the primes() sieve. Use
43
// ScratchVec<std::uint8_t> for boolean masks.
44
//
45
// Move stays defaulted (same resource → O(1) buffer transfer; cross-
46
// resource degrades to element-wise — same as plain pmr::vector).
47
//
48
// All other base ctors are inherited via `using base_type::base_type`.
49
// The standard pmr ctor `ScratchVec<T>(n, memory_resource*)` is the
50
// canonical way to construct.
51
//
52
// Slicing-to-base (`pmr::vector<T> X(scratch_vec);`) bypasses the
53
// deletions. Don't do it.
54
55
#pragma once
56
57
#include <array>
58
#include <cstddef>
59
#include <memory_resource>
60
#include <type_traits>
61
#include <vector>
62
63
namespace
nk {
64
65
template
<
class
T>
66
class
ScratchVec :
public
std::pmr::vector<T>
67
{
68
static_assert
(!std::is_same_v<T, bool>,
69
"ScratchVec<bool> miscompiles on MSVC (bit-packed proxy "
70
"init bug); use ScratchVec<std::uint8_t> for masks."
);
71
public
:
72
using
base_type = std::pmr::vector<T>;
73
using
base_type::base_type;
74
using
base_type::operator=;
75
76
ScratchVec(
const
ScratchVec &) =
delete
;
77
ScratchVec &operator=(
const
ScratchVec &) =
delete
;
78
79
ScratchVec(ScratchVec &&)
noexcept
=
default
;
80
ScratchVec &operator=(ScratchVec &&)
noexcept
=
default
;
81
};
82
83
namespace
detail {
84
// Holds the inline scratch buffer. It is listed as the FIRST base of
85
// ScratchArena so it is constructed BEFORE the monotonic_buffer_resource
86
// base that points into it (base-from-member idiom). If the buffer were a
87
// plain member, the resource base — initialised with storage_.data()/size()
88
// — would run first and read a member whose lifetime has not begun, which
89
// clang flags as -Wuninitialized.
90
struct
ScratchStorage
{
91
static
constexpr
std::size_t kInlineBytes = 65536;
92
alignas
(std::max_align_t) std::array<std::byte, kInlineBytes> bytes;
93
};
94
}
// namespace detail
95
96
class
ScratchArena :
private
detail::ScratchStorage
,
97
public
std::pmr::monotonic_buffer_resource
98
{
99
public
:
100
explicit
ScratchArena(std::pmr::memory_resource *upstream)
101
: std::pmr::monotonic_buffer_resource(
102
bytes.data(), bytes.size(),
103
upstream ? upstream : std::pmr::get_default_resource()) {}
104
105
ScratchArena(
const
ScratchArena &) =
delete
;
106
ScratchArena &operator=(
const
ScratchArena &) =
delete
;
107
ScratchArena(ScratchArena &&) =
delete
;
108
ScratchArena &operator=(ScratchArena &&) =
delete
;
109
};
110
111
}
// namespace nk
nk::detail::ScratchStorage
Definition
scratch.hpp:90
src
value
include
nk
value
scratch.hpp
Generated by
1.17.0