17 return a.sequence ==
b.sequence && a.checkpoint ==
b.checkpoint &&
18 a.bar ==
b.bar && a.target_command ==
b.target_command;
21 return a.sequence ==
b.sequence && a.cause_fill ==
b.cause_fill &&
22 a.bar ==
b.bar && a.target_command ==
b.target_command;
28void require_origin(
const std::shared_ptr<const CommandObservation>& origin,
29 uint64_t target, uint64_t event,
int bar) {
30 if (!origin || target != origin->command || event <= origin->command ||
33 "admission receipt requires its exact earlier command");
39 "market draft requires one original command observation");
43 require_origin(observation_, receipt.target_command, receipt.sequence, receipt.bar);
44 if (!known_checkpoint(receipt.checkpoint))
46 "review requires a known checkpoint");
48 if (same(*review_, receipt))
return;
50 "first admission review cannot be replaced");
55 require_origin(observation_, receipt.target_command, receipt.sequence, receipt.bar);
56 if (receipt.cause_fill == 0)
58 "sizing revision requires committed cause");
59 if (sizing_revision_) {
60 if (same(*sizing_revision_, receipt))
return;
61 if (receipt.sequence <= sizing_revision_->sequence ||
62 receipt.bar < sizing_revision_->bar || receipt.cause_fill < sizing_revision_->cause_fill)
64 "sizing revision cannot rewrite or precede its latest cause");
66 sizing_revision_ = receipt;
69 return std::visit([](
const auto& value)->uint64_t {
70 using T=std::decay_t<
decltype(value)>;
71 if constexpr(std::is_same_v<T,CommandEvent>) {
72 if(!value.observation) {
74 "command event requires an observation");
76 return value.observation->command;
78 else return value.receipt.sequence;
83 mutable std::vector<std::byte> page;
84 std::uint64_t count = 0;
88 std::uint64_t abandoned = 0;
89 std::uint64_t failed_sequence = 0;
90 mutable bool snapshot_valid =
false;
101 "admission journal codec invalid storage");
103 detail::ScratchBuffer buffer()
const {
return {page.data(),page.size()}; }
104 void retire_through(std::uint64_t
sequence) {
105 auto status = store.begin();
109 std::array<std::byte,8>
key{};
112 std::uint64_t
id = 0;
113 for (
unsigned i=0;i!=8;++i)
114 id |= std::uint64_t(std::to_integer<unsigned>(key[i])) << (8*i);
116 status = store.erase(handle);
122 std::size_t page_size() const noexcept
override {
return store.page_size(); }
123 std::uint64_t record_count() const noexcept
override {
return count; }
124 const detail::ReportScratchIoError* carried_failure() const noexcept
override {
125 return store.carried_failure();
128 detail::ScratchRecordInfo& info)
const noexcept override {
129 detail::ScratchRecordInfo actual;
130 const auto status = store.point(handle,actual);
137 std::uint64_t offset, detail::ScratchBuffer out)
const noexcept override {
138 detail::ScratchRecordInfo info;
139 const auto status = point(handle,info);
144 if (!buffer.data || buffer.size != page_size() || !visitor)
146 detail::ScratchRecordInfo info;
147 const auto status = point(handle,info);
154 detail::ScratchRecordVisitor visitor;
156 static bool row(
void* self,
const detail::ScratchRecordView& value)
noexcept {
157 auto& walk = *
static_cast<Walk*
>(self);
158 return !
value.info.value_bytes || walk.visitor(walk.context,value);
160 } walk{visitor,context};
161 return store.for_each(buffer,&Walk::row,&walk);
171 if (journal.next_sequence_ != 1 || journal.event_count() || journal.has_unfinished_events()
173 || store.record_count() || store.transaction_active())
175 "journal codec requires an empty committed store");
176 journal.codec_ = std::make_unique<Journal::CodecState>(store);
182 "journal codec is not bound");
183 return *journal.codec_;
190 if (!journal.codec_)
return Status::programming_error;
191 auto& codec = *journal.codec_;
192 if (codec.failure != Status::ok)
return codec.failure;
195 if (status != Status::ok)
return status;
197 || summary.
sequence <= journal.retired_prefix_.last_sequence
198 || summary.
sequence == codec.abandoned)
199 return Status::programming_error;
201 status = jc::find(codec.store,summary.
sequence,existing);
202 if (status == Status::ok)
return Status::programming_error;
203 if (status != Status::not_found)
return status;
204 status = codec.store.begin();
205 if (status != Status::ok)
return status;
207 if (codec.abandoned && codec.abandoned > journal.retired_prefix_.last_sequence) {
208 const jc::WordSource abandoned(codec.abandoned);
210 status = codec.store.put(abandoned,empty,handle);
212 if (status == Status::ok) {
213 const jc::WordSource key(summary.
sequence);
214 status = codec.store.put(key,
source,handle);
216 status = jc::finish(codec.store,status);
217 if (status == Status::ok) {
219 codec.failed_sequence = 0;
221 --journal.outstanding_count_;
222 codec.snapshot_valid =
false;
223 std::vector<Event>().swap(journal.events_);
224 if (summary.
sequence <= journal.folded_window_.last_sequence) journal.fold_valid_ =
false;
225 if (summary.
rejected && journal.rejection_gate_.valid
226 && summary.
sequence > journal.rejection_gate_.sequence)
228 }
else codec.failed_sequence = summary.
sequence;
233 return retired_prefix_.count + (codec_ ?
static_cast<std::size_t
>(codec_->count) : events_.size());
237 if (!codec_ || codec_->snapshot_valid)
return events_;
238 std::vector<Event> result;
240 auto status = codec_->store.first(handle);
243 CodecState::check(codec_->store.point(handle,info), codec_.get());
248 result.push_back(std::move(event));
250 status = codec_->store.next(handle,handle);
253 events_.swap(result);
254 codec_->snapshot_valid =
true;
262 if (filtered_ && retired_prefix_.count == 0)
264 "admission filter cannot rewrite folded lifetime history");
265 if (codec_) CodecState::check(codec_->failure, codec_.get());
266 if (fold_valid_ && !filtered_ && folded_window_.count ==
event_count())
267 return folded_window_;
268 Prefix result = fold_valid_ && !filtered_ ? folded_window_ : retired_prefix_;
269 auto gate = rejection_gate_.valid ? rejection_gate_
270 : RejectionGate{retired_prefix_.last_sequence,retired_prefix_.last_rejected_command_bar,
true};
274 std::optional<detail::ReportScratchIoError> failure;
279 CodecState::check(status, codec_.get());
281 if (result.
count == std::numeric_limits<std::size_t>::max())
283 "admission event count exhausted");
288 if (summary.
sequence > gate.sequence)
292 if (summary.
sequence <= folded_window_.last_sequence)
301 auto status = codec_->store.lower_bound(frontier,handle);
304 CodecState::check(codec_->store.point(handle,info), codec_.get());
305 std::array<std::byte,8> key{};
307 {key.data(),key.size()}), codec_.get());
308 std::uint64_t
id = 0;
309 for (
unsigned i=0;i!=8;++i)
310 id |= std::uint64_t(std::to_integer<unsigned>(key[i])) << (8*i);
315 status = codec_->store.next(handle,handle);
319 std::array<std::byte,512> page{};
320 const auto first = std::upper_bound(events_.begin(),events_.end(),result.
last_sequence,
321 [](uint64_t
id,
const auto& event){return id < sequence(event);});
322 for (
auto at = first; at != events_.end(); ++at) {
327 if (filtered_ && retained_rejected_bar != folded_window_.last_rejected_command_bar)
329 "admission filter cannot rewrite the rejection gate");
330 folded_window_ = result;
333 rejection_gate_ = gate;
339 if (codec_) CodecState::check(codec_->failure, codec_.get());
341 return rejection_gate_.bar;
345 if (other.active_allocations_ != 0)
347 "cannot copy admission journal with active captures");
348 next_sequence_ = other.next_sequence_;
349 outstanding_sequences_ = other.outstanding_sequences_;
351 for (
auto id = other.retired_prefix_.
last_sequence + 1;
id < other.next_sequence_; ++
id) {
355 if (
id != other.codec_->abandoned) outstanding_sequences_.push_back(
id);
357 else CodecState::check(status, other.codec_.get());
360 outstanding_count_ = other.outstanding_count_;
361 retired_prefix_ = other.retired_prefix_;
362 folded_window_ = other.folded_window_;
363 fold_valid_ = other.fold_valid_;
364 filtered_ = other.filtered_;
365 rejection_gate_ = other.rejection_gate_;
366 retain_full_observation_history_ = other.retain_full_observation_history_;
369 if (
this == &other)
return *
this;
370 if (active_allocations_ != 0)
372 "cannot replace admission journal with active captures");
374 std::swap(next_sequence_, copy.next_sequence_);
375 codec_.swap(copy.codec_);
376 std::swap(outstanding_count_, copy.outstanding_count_);
377 outstanding_sequences_.swap(copy.outstanding_sequences_);
378 events_.swap(copy.events_);
379 std::swap(retired_prefix_, copy.retired_prefix_);
380 std::swap(folded_window_, copy.folded_window_);
381 std::swap(fold_valid_, copy.fold_valid_);
382 std::swap(filtered_, copy.filtered_);
383 std::swap(rejection_gate_, copy.rejection_gate_);
384 std::swap(retain_full_observation_history_, copy.retain_full_observation_history_);
388 if (other.active_allocations_ != 0)
390 "cannot move admission journal with active captures");
391 next_sequence_ = other.next_sequence_;
392 codec_ = std::move(other.codec_);
393 outstanding_count_ = std::exchange(other.outstanding_count_,0);
394 outstanding_sequences_ = std::move(other.outstanding_sequences_);
395 events_ = std::move(other.events_);
396 retired_prefix_ = other.retired_prefix_;
397 folded_window_ = other.folded_window_;
398 fold_valid_ = other.fold_valid_;
399 filtered_ = other.filtered_;
400 rejection_gate_ = other.rejection_gate_;
401 retain_full_observation_history_ = other.retain_full_observation_history_;
402 other.outstanding_sequences_.clear();
403 other.events_.clear();
404 other.next_sequence_ = 1;
405 other.retired_prefix_ = {};
406 other.folded_window_ = {};
407 other.fold_valid_ =
false;
408 other.filtered_ =
false;
409 other.rejection_gate_ = {};
410 other.retain_full_observation_history_ =
false;
413 if (
this == &other)
return *
this;
414 if (active_allocations_ != 0)
416 "cannot replace admission journal with active captures");
417 Journal moved(std::move(other));
418 std::swap(next_sequence_, moved.next_sequence_);
419 codec_.swap(moved.codec_);
420 std::swap(outstanding_count_, moved.outstanding_count_);
421 outstanding_sequences_.swap(moved.outstanding_sequences_);
422 events_.swap(moved.events_);
423 std::swap(retired_prefix_, moved.retired_prefix_);
424 std::swap(folded_window_, moved.folded_window_);
425 std::swap(fold_valid_, moved.fold_valid_);
426 std::swap(filtered_, moved.filtered_);
427 std::swap(rejection_gate_, moved.rejection_gate_);
428 std::swap(retain_full_observation_history_, moved.retain_full_observation_history_);
432 if(next_sequence_==std::numeric_limits<uint64_t>::max()) {
434 "admission event sequence exhausted");
436 if (codec_) CodecState::check(codec_->failure, codec_.get());
437 else outstanding_sequences_.push_back(next_sequence_);
438 ++outstanding_count_;
439 return next_sequence_++;
443 ++active_allocations_;
448 if (!
id ||
id >= next_sequence_ ||
id <= retired_prefix_.last_sequence)
return;
449 if (
id == codec_->abandoned)
return;
455 if (codec_->abandoned && codec_->abandoned > retired_prefix_.last_sequence) {
460 codec_->abandoned = id;
461 codec_->failed_sequence = 0;
462 --outstanding_count_;
465 codec_->failure = status;
468 const auto at = std::find(outstanding_sequences_.begin(), outstanding_sequences_.end(),
id);
469 if (at != outstanding_sequences_.end()) {
470 outstanding_sequences_.erase(at);
471 --outstanding_count_;
475 : journal_(other.journal_), sequence_(other.sequence_) {
476 other.journal_ =
nullptr;
479void Journal::release_allocation(uint64_t
sequence)
noexcept {
481 --active_allocations_;
487 if (!
id ||
id >= next_sequence_ ||
id <= retired_prefix_.last_sequence)
489 "admission event has no outstanding allocation");
490 if (
id == codec_->abandoned)
492 "admission event has no outstanding allocation");
497 "admission event has no outstanding allocation");
503 const auto pending = std::find(outstanding_sequences_.begin(), outstanding_sequences_.end(),
id);
504 if (pending == outstanding_sequences_.end())
506 "admission event has no outstanding allocation");
507 const auto* command = std::get_if<CommandEvent>(&event);
509 const int rejected_bar = rejected ? command->observation->bar : -1;
510 auto at=std::lower_bound(events_.begin(),events_.end(),
id,[](
const auto& e,uint64_t n){return sequence(e)<n;});
511 events_.insert(at,std::move(event));
514 outstanding_sequences_.erase(pending);
515 --outstanding_count_;
516 if (
id <= folded_window_.last_sequence) fold_valid_ =
false;
517 if (rejected && rejection_gate_.valid &&
id > rejection_gate_.sequence)
518 rejection_gate_ = {id,rejected_bar,
true};
522 auto& store = codec_->store;
523 auto status = store.begin();
524 CodecState::check(status, codec_.get());
525 auto removed = std::uint64_t{0};
527 status = store.first(handle);
530 const auto following = store.next(handle,next);
532 status = following;
break;
535 status = store.point(handle,info);
538 std::array<std::byte,8> key{};
541 std::uint64_t
id = 0;
542 for (
unsigned i=0;i!=8;++i)
543 id |= std::uint64_t(std::to_integer<unsigned>(key[i])) << (8*i);
544 if (std::find(retained.begin(),retained.end(),
id)==retained.end()) {
548 status = store.put(probe,empty,same);
553 handle = next; status = following;
558 codec_->count -= removed;
559 codec_->snapshot_valid =
false;
560 std::vector<Event>().swap(events_);
561 filtered_ = filtered_ || fold_valid_;
562 rejection_gate_.valid =
false;
566 const auto before = events_.size();
567 events_.erase(std::remove_if(events_.begin(),events_.end(),[&](
const auto& e){
568 return std::find(retained.begin(),retained.end(),sequence(e))==retained.end();
570 if (events_.size() != before) {
571 if (fold_valid_) filtered_ =
true;
572 rejection_gate_.valid =
false;
578 "cannot reset admission journal with unfinished events");
580 CodecState::check(codec_->failure, codec_.get());
582 codec_->count = 0; codec_->snapshot_valid =
false;
583 codec_->abandoned = codec_->failed_sequence = 0;
585 std::vector<Event>().swap(events_);
586 std::vector<uint64_t>().swap(outstanding_sequences_);
587 next_sequence_=1;retired_prefix_={};folded_window_={};fold_valid_=
false;filtered_=
false;
588 rejection_gate_ = {};
592 || retired_prefix_.count != 0)
594 "full admission observation requires a fresh journal");
595 retain_full_observation_history_ =
true;
600 "cannot retire admission journal with unfinished events");
602 if (count != expected.count || last_sequence != expected.last_sequence
603 || digest != expected.digest || count !=
event_count())
605 "admission retirement requires the exact folded window");
606 if (retain_full_observation_history_)
return;
608 codec_->retire_through(expected.last_sequence);
609 codec_->count = 0; codec_->snapshot_valid =
false;
610 if (codec_->abandoned <= expected.last_sequence) codec_->abandoned = 0;
612 retired_prefix_ = expected;
615 std::vector<Event>().swap(events_);
618 std::function<
void(
CommandEvent)> complete):allocation_(
std::move(allocation)),input_(
std::move(
input)),before_(
std::move(before)),complete_(
std::move(complete)) {
619 if (input_.command != allocation_.sequence())
621 "command capture requires its allocated event");
626 if (std::uncaught_exceptions() != 0)
return;
627 complete_({std::make_shared<const CommandObservation>(input_),outcome_,0,std::move(before_),{}});
630 input_.original_sizing=std::move(sizing);input_.explicit_equity=equity;input_.explicit_price=
price;
631 draft.
bind(std::make_shared<const CommandObservation>(input_));
636 : allocation_(
std::move(allocation)),event_(
std::move(event)),complete_(
std::move(complete)) {
637 if (event_.receipt.sequence != allocation_.sequence() || event_.receipt.target_command != 0 ||
638 !known_checkpoint(event_.receipt.checkpoint))
640 "review capture requires an allocated batch checkpoint");
643 if (std::uncaught_exceptions() != 0)
return;
644 complete_(std::move(event_));
648 if (!origin || std::none_of(event_.reviewed.begin(), event_.reviewed.end(), [&](
const auto& order) {
649 return order.draft.observation() && order.draft.observation()->command == origin->command;
652 "draft does not belong to this admission review");
653 auto receipt = event_.receipt;
654 receipt.target_command = origin->command;
655 require_origin(origin, receipt.target_command, receipt.sequence, receipt.bar);
662 template<
class T>
void field(
const std::string& path,
const char* name,
const T& value)
const {
663 if constexpr(std::is_same_v<T,bool>)visit({path+
"."+name,uint64_t(value?1:0)});
664 else if constexpr(std::is_enum_v<T>||std::is_same_v<T,int>)visit({path+
"."+name,int64_t(value)});
665 else visit({path+
"."+name,value});
667 void birth(
const OrderBirth& o,
const std::string& p)
const {
668 field(p,
"cause",o.cause());field(p,
"bar",o.bar());field(p,
"timestamp",o.timestamp());
669 field(p,
"cursor_domain",o.cursor().domain());field(p,
"cursor_position",o.cursor().position());
670 field(p,
"cursor_index",o.cursor().index());field(p,
"cursor_count",o.cursor().count());
671 field(p,
"cursor_price",o.cursor_price());field(p,
"first_fill",o.first_fill());
672 field(p,
"last_fill",o.last_fill());field(p,
"evaluation_ordinal",o.evaluation_ordinal());
674 void config(
const Configuration& o,
const std::string& p)
const {
675#define F(name) field(p,#name,o.name)
676 F(process_on_close);
F(calc_on_fills);
F(magnifier);
F(fill_recalculation);
F(scheduler);
677 F(slippage);
F(pyramiding);
F(default_quantity_type);
F(default_quantity_value);
678 F(long_margin);
F(short_margin);
F(commission_value);
F(commission_type);
F(pointvalue);
F(fx);
F(quantity_step);
F(mintick);
F(risk_direction);
F(loss_days_limit);
679 F(drawdown_limit);
F(intraday_loss_limit);
F(position_limit);
F(fill_cap_active);
F(risk_halted);
682 void sizing(
const SizingObservation& o,
const std::string& p)
const {
683#define F(name) field(p,#name,o.name)
684 F(quantity);
F(equity);
F(price);
F(mark);
F(fx);
687 void command(
const CommandObservation& o,
const std::string& p)
const {
688#define F(name) field(p,#name,o.name)
689 F(command);
F(kind);birth(o.birth,p+
".birth");
F(
id);
F(requested_quantity);
F(quantity_type);
F(buy);
690 field(p+
".prices",
"limit",o.prices.limit);field(p+
".prices",
"stop",o.prices.stop);
691 F(oca_name);
F(oca_type);config(o.configuration,p+
".configuration");
F(bar);
F(placement_side);
F(placement_cycle);
692 F(prior_close_quantity);
F(held_quantity);
F(held_entries);
F(realized_equity);
F(placement_equity);
F(signal_close);
F(quantized_fixed_quantity);
693 field(p,
"original_sizing_present",o.original_sizing.has_value());
694 if(o.original_sizing)sizing(*o.original_sizing,p+
".original_sizing");
695 F(explicit_equity);
F(explicit_price);
698 void review(
const ReviewReceipt& o,
const std::string& p)
const {
699 field(p,
"sequence",o.sequence);field(p,
"checkpoint",o.checkpoint);field(p,
"bar",o.bar);
700 field(p,
"target_command",o.target_command);
702 void revision(
const SizingRevision& o,
const std::string& p)
const {
703 field(p,
"sequence",o.sequence);field(p,
"cause_fill",o.cause_fill);field(p,
"bar",o.bar);
704 field(p,
"target_command",o.target_command);
706 void draft(
const Draft& o,
const std::string& p)
const {
707 field(p,
"observation_present",
bool(o.observation()));
708 if(o.observation())
command(*o.observation(),p+
".observation");
709 field(p,
"review_present",o.review().has_value());
if(o.review())review(*o.review(),p+
".review");
710 field(p,
"sizing_revision_present",o.sizing_revision().has_value());
if(o.sizing_revision())revision(*o.sizing_revision(),p+
".sizing_revision");
712 void book(
const BookObservation& o,
const std::string& p)
const {
713 field(p,
"incarnation",o.incarnation);field(p,
"priority",o.priority);field(p,
"bar",o.bar);
714 field(p,
"type",o.type);field(p,
"placement_side",o.placement_side);field(p,
"buy",o.buy);field(p,
"id",o.id);
715 field(p,
"oca_name",o.oca_name);field(p,
"oca_type",o.oca_type);birth(o.birth,p+
".birth");
716 field(p+
".prices",
"limit",o.prices.limit);field(p+
".prices",
"stop",o.prices.stop);
717 field(p+
".prices",
"trail_points",o.prices.trail_points);field(p+
".prices",
"trail_price",o.prices.trail_price);
718 field(p+
".prices",
"trail_offset",o.prices.trail_offset);draft(o.draft,p+
".draft");
720 void resolution(
const InstructionResolution& o,
const std::string& p)
const {
721 field(p,
"incarnation",o.incarnation);field(p,
"kind",o.kind);field(p,
"peer_incarnation",o.peer_incarnation);
722 field(p,
"own_priority",o.own_priority);field(p,
"peer_priority",o.peer_priority);field(p,
"transaction_quantity",o.transaction_quantity);
724 template<
class T,
class Fn>
void array(
const std::vector<T>& values,
const std::string& p,Fn fn)
const {
725 field(p,
"size",uint64_t(values.size()));
for(
size_t i=0;i<values.size();++i)fn(values[i],p+
"["+std::to_string(i)+
"]");
727 void event(
const Event& value,
const std::string& p)
const {
728 field(p,
"kind",uint64_t(
value.index()));
729 std::visit([&](
const auto& o){
using T=std::decay_t<
decltype(o)>;
730 if constexpr(std::is_same_v<T,CommandEvent>){
731 command(*o.observation,p+
".observation");field(p,
"outcome",o.outcome);field(p,
"admitted_incarnation",o.admitted_incarnation);
732 array(o.before,p+
".before",[&](
const auto& x,
const auto& q){book(x,q);});
733 array(o.removed,p+
".removed",[&](
auto x,
const auto& q){field(q,
"incarnation",x);});
734 }
else if constexpr(std::is_same_v<T,ReviewEvent>){
735 review(o.receipt,p+
".receipt");config(o.configuration,p+
".configuration");field(p,
"open_price",o.open_price);field(p,
"position_side",o.position_side);field(p,
"position_cycle",o.position_cycle);array(o.book,p+
".book",[&](
const auto& x,
const auto& q){book(x,q);});array(o.reviewed,p+
".reviewed",[&](
const auto& x,
const auto& q){book(x,q);});
736 array(o.resolutions,p+
".resolutions",[&](
const auto& x,
const auto& q){resolution(x,q);});
737 array(o.causes,p+
".causes",[&](
auto x,
const auto& q){field(q,
"sequence",x);});
739 revision(o.receipt,p+
".receipt");field(p,
"incarnation",o.incarnation);
740 sizing(o.before,p+
".before");sizing(o.after,p+
".after");
741 field(p,
"affordability_equity_before",o.affordability_equity_before);field(p,
"affordability_equity_after",o.affordability_equity_after);
750 Reflect r{visit};r.field(path,
"next_sequence",next_sequence_);
751 r.field(path,
"active_allocations",active_allocations_);
753 r.field(path+
".outstanding_sequences",
"size",outstanding_count_);
754 std::size_t rank = 0;
755 for (
auto id = retired_prefix_.last_sequence + 1;
id < next_sequence_; ++
id) {
756 if (
id == codec_->abandoned)
continue;
760 r.field(path+
".outstanding_sequences["+std::to_string(rank++)+
"]",
"sequence",
id);
761 else CodecState::check(status, codec_.get());
763 }
else r.array(outstanding_sequences_,path+
".outstanding_sequences",[&](
auto sequence,
const auto& p){r.field(p,
"sequence",
sequence);});
764 r.array(
events(),path+
".events",[&](
const auto& event,
const auto& p){r.event(event,p);});
767 if (retired_prefix_.count != 0) {
768 r.field(path+
".base",
"count",uint64_t(retired_prefix_.count));
769 r.field(path+
".base",
"digest",retired_prefix_.digest);
770 r.field(path+
".base",
"last_sequence",retired_prefix_.last_sequence);
771 r.field(path+
".base",
"last_rejected_command_bar",retired_prefix_.last_rejected_command_bar);
775 std::vector<Field> result;
reflect(draft,
"draft",[&](
const auto& field){result.push_back(field);});
return result;
778template<
class T>T read_field(
const std::vector<Field>&
fields,
const std::string& path) {
779 for(
const auto& field:
fields)
if(field.path==path)
return std::get<T>(field.value);
783uint64_t
read_unsigned(
const std::vector<Field>& f,
const std::string& p){
return read_field<uint64_t>(f,p);}
784int64_t
read_integer(
const std::vector<Field>& f,
const std::string& p){
return read_field<int64_t>(f,p);}
785double read_double(
const std::vector<Field>& f,
const std::string& p){
return read_field<double>(f,p);}
786std::string
read_string(
const std::vector<Field>& f,
const std::string& p){
return read_field<std::string>(f,p);}
Allocation(const Allocation &)=delete
CommandCapture(Allocation allocation, CommandObservation input, std::vector< BookObservation > before, std::function< void(CommandEvent)> complete)
void bind(Draft &draft, std::optional< SizingObservation > sizing, double explicit_equity, double explicit_price)
~CommandCapture() noexcept(false)
const CommandObservation & input() const
const std::shared_ptr< const CommandObservation > & observation() const
void reviewed(ReviewReceipt receipt)
void bind(std::shared_ptr< const CommandObservation > observation)
void sizing_revised(SizingRevision receipt)
void retain_full_observation_history()
std::size_t event_count() const
void abandon(uint64_t sequence) noexcept
int last_rejected_command_bar() const
Journal & operator=(const Journal &other)
bool has_unfinished_events() const
const std::vector< Event > & events() const
friend detail::ScratchStatus append_journal_record(Journal &, const detail::ScratchByteSource &) noexcept
void reflect(const std::string &path, const FieldVisitor &visit) const
friend void bind_journal_codec(Journal &, detail::CommandScratchStore &)
void retire_prefix(std::size_t count, uint64_t digest, uint64_t last_sequence)
void retain(const std::vector< uint64_t > &sequences)
Prefix folded_window() const
~ReviewCapture() noexcept(false)
ReviewCapture(Allocation allocation, ReviewEvent event, std::function< void(ReviewEvent)> complete)
ReviewReceipt receipt_for(const Draft &draft) const
Base with a code: throw coded<std::invalid_argument>(code, {args}, text).
JournalRecordSource encode_journal_record(const Event &) noexcept
bool rejected_command(Outcome outcome) noexcept
uint64_t read_unsigned(const std::vector< Field > &fields, const std::string &path)
std::string read_string(const std::vector< Field > &fields, const std::string &path)
int64_t read_integer(const std::vector< Field > &fields, const std::string &path)
detail::ScratchStatus scan_journal_record(const detail::ScratchByteSource &source, detail::ScratchBuffer page, JournalRecordSummary &summary) noexcept
std::vector< Field > fields(const Draft &draft)
std::function< void(const Field &)> FieldVisitor
uint64_t sequence(const Event &event)
detail::ScratchStatus decode_journal_record(const detail::ScratchByteSource &, detail::ScratchBuffer, Event &)
double read_double(const std::vector< Field > &fields, const std::string &path)
const detail::ScratchReadback & journal_readback(const Journal &)
void reflect(const Draft &value, const std::string &path, const FieldVisitor &visit)
std::variant< CommandEvent, ReviewEvent, SizingEvent > Event
@ OpeningRejectedReductionAdmitted
detail::ScratchStatus fold_validated_journal_record(const detail::ScratchByteSource &source, detail::ScratchBuffer page, JournalRecordSummary &summary, std::uint64_t &digest, std::uint64_t after_sequence, std::optional< detail::ReportScratchIoError > *failure) noexcept
detail::ScratchStatus append_journal_record(Journal &, const detail::ScratchByteSource &) noexcept
ScratchStatus find(CommandScratchStore &store, std::uint64_t key, ScratchRecordInfo &out) noexcept
ScratchStatus finish(CommandScratchStore &store, ScratchStatus status) noexcept
ScratchStatus clear(CommandScratchStore &store) noexcept
ScratchStatus put(CommandScratchStore &store, std::uint64_t key, const ScratchByteSource &value) noexcept
bool(*)(void *, const ScratchChunkView &) noexcept ScratchChunkVisitor
std::uint64_t ScratchHandle
constexpr ScratchHandle scratch_no_handle
void rethrow_carried_scratch_failure(const ReportScratchIoError *failure)
void raise_scratch_io_error(int error, const char *operation)
bool(*)(void *, const ScratchRecordView &) noexcept ScratchRecordVisitor
int last_rejected_command_bar
std::uint64_t value_bytes