LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
computation_context.hpp
浏览该文件的文档.
1#pragma once
2
3#include <atomic>
4#include <cstddef>
5#include <functional>
6#include <memory>
7#include <new>
8#include <string>
9#include <thread>
10#include <utility>
11#include <vector>
12
13#include "result.hpp"
14#include "unit.hpp"
15
16namespace LMCAS {
17
18class AssumptionContext;
19
20/**
21 * Per-operation limits for APIs that accept a ComputationContext.
22 *
23 * Context-free BigInt and symbolic constructors are intentionally unbounded;
24 * use checked, context-aware entry points when processing untrusted input.
25 */
27 std::size_t max_ast_nodes = 1'000'000; ///< Reference-expanded nodes per AST or output forest.
28 std::size_t max_steps = 10'000'000; ///< Cumulative checked steps.
29 std::size_t max_recursion_depth = 256; ///< Simultaneous checked depth.
30 std::size_t max_integer_bits = 1'000'000; ///< One checked integer result.
31 std::size_t max_expansion_terms = 100'000; ///< One checked expansion.
32 std::size_t max_input_bytes = 1'048'576; ///< One checked input buffer.
33 std::size_t max_diagnostics = 10'000; ///< Stored diagnostics.
34};
35
37
43
45public:
46 using Consumer = std::function<void(const Diagnostic&)>;
47
48 explicit DiagnosticEngine(std::size_t limit, Consumer consumer = {})
49 : limit_(limit), consumer_(std::move(consumer)) {}
50
52 if (diagnostics_.size() >= limit_) {
54 "diagnostic budget exhausted",
55 diagnostic.operation);
56 }
57 bool inserted = false;
58 try {
59 diagnostics_.push_back(std::move(diagnostic));
60 inserted = true;
61 if (consumer_) consumer_(diagnostics_.back());
62 } catch (const std::bad_alloc&) {
63 if (inserted) diagnostics_.pop_back();
65 "diagnostic allocation failed");
66 } catch (...) {
67 if (inserted) diagnostics_.pop_back();
69 "diagnostic consumer failed");
70 }
71 return Result<void>::success();
72 }
73
74 void set_consumer(Consumer consumer) { consumer_ = std::move(consumer); }
75
76 const std::vector<Diagnostic>& diagnostics() const noexcept {
77 return diagnostics_;
78 }
79
80private:
81 std::size_t limit_;
83 std::vector<Diagnostic> diagnostics_;
84};
85
87public:
88 CancellationToken() : cancelled_(std::make_shared<std::atomic<bool>>(false)) {}
89
90 void cancel() const noexcept { cancelled_->store(true, std::memory_order_release); }
91 bool is_cancelled() const noexcept {
92 return cancelled_->load(std::memory_order_acquire);
93 }
94
95private:
96 std::shared_ptr<std::atomic<bool>> cancelled_;
97};
98
100public:
104 owner_thread_(std::this_thread::get_id()),
105 diagnostic_engine_(limits.max_diagnostics) {}
106
111
112 Result<void> consume_steps(std::size_t amount = 1,
113 const std::string& operation = {}) {
114 auto access = check_access(operation);
115 if (!access) return access;
117 amount > limits_.max_steps - steps_used_) {
119 "computation step budget exhausted", operation);
120 }
121 steps_used_ += amount;
122 return Result<void>::success();
123 }
124
125 Result<void> enter_recursion(const std::string& operation = {}) {
126 auto step = consume_steps(1, operation);
127 if (!step) return step;
130 "recursion depth limit exceeded", operation);
131 }
133 return Result<void>::success();
134 }
135
136 void leave_recursion() noexcept {
138 }
139
140 Result<void> require_ast_nodes(std::size_t amount,
141 const std::string& operation = {}) const {
142 auto access = check_access(operation);
143 if (!access) return access;
144 if (amount > limits_.max_ast_nodes) {
146 "AST node budget exhausted", operation);
147 }
148 return Result<void>::success();
149 }
150
152 std::size_t amount, const std::string& operation = {}) const {
153 auto access = check_access(operation);
154 if (!access) return access;
155 if (amount > limits_.max_integer_bits) {
158 "integer bit budget exceeded", operation);
159 }
160 return Result<void>::success();
161 }
162
164 std::size_t amount, const std::string& operation = {}) const {
165 auto access = check_access(operation);
166 if (!access) return access;
167 if (amount > limits_.max_expansion_terms) {
170 "expansion term budget exceeded", operation);
171 }
172 return Result<void>::success();
173 }
174
176 std::size_t amount, const std::string& operation = {}) const {
177 auto access = check_access(operation);
178 if (!access) return access;
179 if (amount > limits_.max_input_bytes) {
182 "input byte budget exceeded", operation);
183 }
184 return Result<void>::success();
185 }
186
188 auto access = check_access(diagnostic.operation);
189 if (!access) return access;
190 return diagnostic_engine_.emit(std::move(diagnostic));
191 }
192
193 const ResourceLimits& limits() const noexcept { return limits_; }
194 std::size_t steps_used() const noexcept { return steps_used_; }
195 std::size_t recursion_depth() const noexcept { return recursion_depth_; }
196 const std::vector<Diagnostic>& diagnostics() const noexcept {
198 }
199 const DiagnosticEngine& diagnostic_engine() const noexcept {
200 return diagnostic_engine_;
201 }
204 const std::string& operation = {}) {
205 auto access = check_access(operation);
206 if (!access) return access;
207 diagnostic_engine_.set_consumer(std::move(consumer));
208 return Result<void>::success();
209 }
210 const CancellationToken& cancellation() const noexcept { return cancellation_; }
211 UnitSystem& units() noexcept { return units_; }
212 const UnitSystem& units() const noexcept { return units_; }
213
215 std::shared_ptr<const AssumptionContext> assumptions,
216 const std::string& operation = {}) {
217 auto access = check_access(operation);
218 if (!access) return access;
219 assumptions_ = std::move(assumptions);
220 return Result<void>::success();
221 }
222 const std::shared_ptr<const AssumptionContext>& assumptions() const noexcept {
223 return assumptions_;
224 }
225
226private:
227 Result<void> check_access(const std::string& operation) const {
228 if (std::this_thread::get_id() != owner_thread_) {
231 "ComputationContext cannot be shared across threads",
232 operation);
233 }
236 "computation was cancelled", operation);
237 }
238 return Result<void>::success();
239 }
240
243 const std::thread::id owner_thread_;
244 std::shared_ptr<const AssumptionContext> assumptions_;
245 std::size_t steps_used_ = 0;
246 std::size_t recursion_depth_ = 0;
248 UnitSystem units_;
249};
250
251} // namespace LMCAS
std::shared_ptr< std::atomic< bool > > cancelled_
const std::shared_ptr< const AssumptionContext > & assumptions() const noexcept
std::shared_ptr< const AssumptionContext > assumptions_
ComputationContext(ComputationContext &&)=delete
Result< void > require_input_bytes(std::size_t amount, const std::string &operation={}) const
Result< void > set_assumptions(std::shared_ptr< const AssumptionContext > assumptions, const std::string &operation={})
ComputationContext(ResourceLimits limits={}, CancellationToken cancellation={})
Result< void > check_access(const std::string &operation) const
Result< void > add_diagnostic(Diagnostic diagnostic)
const std::vector< Diagnostic > & diagnostics() const noexcept
Result< void > consume_steps(std::size_t amount=1, const std::string &operation={})
ComputationContext & operator=(const ComputationContext &)=delete
Result< void > enter_recursion(const std::string &operation={})
const CancellationToken & cancellation() const noexcept
Result< void > require_ast_nodes(std::size_t amount, const std::string &operation={}) const
std::size_t recursion_depth() const noexcept
Result< void > require_integer_bits(std::size_t amount, const std::string &operation={}) const
const UnitSystem & units() const noexcept
const ResourceLimits & limits() const noexcept
Result< void > require_expansion_terms(std::size_t amount, const std::string &operation={}) const
Result< void > set_diagnostic_consumer(DiagnosticEngine::Consumer consumer, const std::string &operation={})
ComputationContext(const ComputationContext &)=delete
ComputationContext & operator=(ComputationContext &&)=delete
std::size_t steps_used() const noexcept
const DiagnosticEngine & diagnostic_engine() const noexcept
Result< void > emit(Diagnostic diagnostic)
DiagnosticEngine(std::size_t limit, Consumer consumer={})
std::function< void(const Diagnostic &)> Consumer
const std::vector< Diagnostic > & diagnostics() const noexcept
std::vector< Diagnostic > diagnostics_
void set_consumer(Consumer consumer)
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
std::size_t max_diagnostics
Stored diagnostics.
std::size_t max_steps
Cumulative checked steps.
std::size_t max_input_bytes
One checked input buffer.
std::size_t max_integer_bits
One checked integer result.
std::size_t max_recursion_depth
Simultaneous checked depth.
std::size_t max_ast_nodes
Reference-expanded nodes per AST or output forest.
std::size_t max_expansion_terms
One checked expansion.
Per-operation limits for APIs that accept a ComputationContext.