53struct Line { int32_t
id = -1; };
54struct Box { int32_t
id = -1; };
55struct Label { int32_t
id = -1; };
109 std::optional<std::int32_t>
id;
128struct DrawingBuiltinAccess;
129struct DrawingArenaTestAccess;
162 if constexpr (std::is_same_v<Rec, LineRec>) {
164 static_cast<XLoc>(-1),
false,
false,
false};
165 }
else if constexpr (std::is_same_v<Rec, BoxRec>) {
167 static_cast<XLoc>(-1),
false};
168 }
else if constexpr (std::is_same_v<Rec, LabelRec>) {
170 static_cast<YLoc>(-1), std::string{},
false};
171 }
else if constexpr (std::is_same_v<Rec, LinefillRec>) {
172 return {-1, -1,
false};
190 if constexpr (std::is_same_v<Rec, LineRec>)
return "line";
191 else if constexpr (std::is_same_v<Rec, BoxRec>)
return "box";
192 else if constexpr (std::is_same_v<Rec, LabelRec>)
return "label";
193 else if constexpr (std::is_same_v<Rec, LinefillRec>)
return "linefill";
194 else static_assert(!std::is_same_v<Rec, Rec>,
"name the drawing kind of this record");
204 {{
"object",
object}}, what);
207 const char* function,
const char* argument,
const char* rule,
const char* what) {
210 {{
"function", function}, {
"argument", argument}, {
"rule", rule}}, what);
215 static_cast<std::int64_t
>(std::numeric_limits<std::int32_t>::max());
222 if constexpr (std::is_same_v<Rec, LineRec>)
return "max_lines_count";
223 else if constexpr (std::is_same_v<Rec, BoxRec>)
return "max_boxes_count";
224 else if constexpr (std::is_same_v<Rec, LabelRec>)
return "max_labels_count";
225 else static_assert(!std::is_same_v<Rec, Rec>,
"name the declared-count field of this record");
240template <
class Rec,
bool Builtin = is_builtin_drawing_record_v<Rec>>
261 if (
this != &other) other.
reset();
270 if (
this != &other) other.reset();
277 while (
resetting.test_and_set(std::memory_order_acquire)) {}
278 if constexpr (std::is_same_v<Rec, LineRec>) {
287 }
else if constexpr (std::is_same_v<Rec, BoxRec>) {
294 }
else if constexpr (std::is_same_v<Rec, LabelRec>) {
299 std::string{}.swap(
value.text);
306 resetting.clear(std::memory_order_release);
329 static_assert(std::is_copy_constructible_v<Rec> && std::is_nothrow_move_constructible_v<Rec>,
330 "a drawing record must be copyable and nothrow move-constructible");
331 static constexpr unsigned kBits = 5;
332 static constexpr std::uint32_t kWidth = std::uint32_t{1} << kBits;
333 static constexpr std::uint32_t kMask = kWidth - 1;
343 std::uint32_t
used = 0;
347 Block(
const Block& other) {
349 for (;
used < other.used; ++
used) ::new (&slots[
used].rec) Rec(other.slots[
used].rec);
355 Block& operator=(
const Block&) =
delete;
356 ~Block() { clear(); }
358 void clear() noexcept {
359 while (used > 0) slots[--used].rec.~Rec();
361 void append(Rec&& rec)
noexcept {
362 ::new (&slots[used].rec) Rec(std::move(rec));
366 struct Node { std::array<std::shared_ptr<void>, kWidth> kids{}; };
368 std::vector<Rec> flat_;
369 std::shared_ptr<Node> root_;
370 std::shared_ptr<Block> tail_;
371 std::uint32_t size_ = 0;
372 std::uint32_t tail_first_ = 0;
373 unsigned shift_ = kBits;
374 bool blocks_ =
false;
378 mutable std::atomic<bool> shared_{
false};
386 T* own(std::shared_ptr<T>& slot) {
387 if (!shared_.load(std::memory_order_relaxed))
return slot.get();
388 if (slot.use_count() != 1) slot = std::make_shared<T>(*slot);
389 else std::atomic_thread_fence(std::memory_order_acquire);
393 T* own_as(std::shared_ptr<void>& slot) {
394 if (!shared_.load(std::memory_order_relaxed))
return static_cast<T*
>(slot.get());
395 if (slot.use_count() != 1) slot = std::make_shared<T>(*
static_cast<const T*
>(slot.get()));
396 else std::atomic_thread_fence(std::memory_order_acquire);
397 return static_cast<T*
>(slot.get());
401 static std::shared_ptr<void> path_to(
unsigned level,
const std::shared_ptr<Block>& block) {
402 std::shared_ptr<void> node = block;
403 for (; level > 0; level -= kBits) {
404 auto parent = std::make_shared<Node>();
405 parent->kids[0] = std::move(node);
406 node = std::move(parent);
414 [[gnu::noinline, gnu::cold]]
const Rec& read_blocks(std::uint32_t
id)
const {
415 if (
id >= tail_first_)
return tail_->slots[
id & kMask].rec;
416 const void* node = root_.get();
417 for (
unsigned level = shift_; level > 0; level -= kBits)
418 node =
static_cast<const Node*
>(node)->kids[(
id >> level) & kMask].get();
419 return static_cast<const Block*
>(node)->slots[
id & kMask].rec;
422 [[gnu::noinline, gnu::cold]] Rec& write_blocks(std::uint32_t
id) {
423 if (!shared_.load(std::memory_order_relaxed))
return const_cast<Rec&
>(read_blocks(
id));
424 if (
id >= tail_first_)
return own(tail_)->slots[
id & kMask].rec;
425 Node* node = own(root_);
426 for (
unsigned level = shift_; level > kBits; level -= kBits)
427 node = own_as<Node>(node->kids[(
id >> level) & kMask]);
428 return own_as<Block>(node->kids[(
id >> kBits) & kMask])->slots[
id & kMask].rec;
434 [[gnu::noinline, gnu::cold]]
void push_block(Rec&& rec) {
435 if (size_ != 0 && size_ - tail_first_ < kWidth) {
436 own(tail_)->append(std::move(rec));
440 auto block = std::make_shared<Block>();
441 block->append(std::move(rec));
442 if (size_ != 0) push_tail();
443 tail_ = std::move(block);
451 const std::uint32_t last = size_ - 1;
453 auto root = std::make_shared<Node>();
454 root->kids[0] = tail_;
455 root_ = std::move(root);
459 if ((std::uint64_t{size_} >> kBits) > (std::uint64_t{1} << shift_)) {
460 auto root = std::make_shared<Node>();
461 root->kids[1] = path_to(shift_, tail_);
462 root->kids[0] = std::move(root_);
463 root_ = std::move(root);
467 Node* node = own(root_);
468 for (
unsigned level = shift_; level > kBits; level -= kBits) {
469 std::shared_ptr<void>& kid = node->kids[(last >> level) & kMask];
471 kid = path_to(level - kBits, tail_);
474 node = own_as<Node>(kid);
476 node->kids[(last >> kBits) & kMask] = tail_;
484 if (!other.blocks_) {
485 for (const Rec& rec : other.flat_) push_block(Rec(rec));
488 other.shared_.store(
true, std::memory_order_relaxed);
492 tail_first_ = other.tail_first_;
493 shift_ = other.shift_;
494 shared_.store(
true, std::memory_order_relaxed);
502 : flat_(std::move(other.flat_)), root_(std::move(other.root_)),
503 tail_(std::move(other.tail_)), size_(std::exchange(other.size_, 0)),
504 tail_first_(std::exchange(other.tail_first_, 0)),
505 shift_(std::exchange(other.shift_, kBits)), blocks_(std::exchange(other.blocks_,
false)),
506 shared_(other.shared_.exchange(
false, std::memory_order_relaxed)) {
510 if (
this != &other) {
511 flat_ = std::move(other.flat_);
513 root_ = std::move(other.root_);
514 tail_ = std::move(other.tail_);
515 size_ = std::exchange(other.size_, 0);
516 tail_first_ = std::exchange(other.tail_first_, 0);
517 shift_ = std::exchange(other.shift_, kBits);
518 blocks_ = std::exchange(other.blocks_,
false);
519 shared_.store(other.shared_.exchange(
false, std::memory_order_relaxed),
520 std::memory_order_relaxed);
525 int32_t
size()
const {
return static_cast<int32_t
>(size_); }
528 const Rec&
read(std::uint32_t
id)
const {
529 if (!blocks_)
return flat_[id];
530 return read_blocks(
id);
533 if (!blocks_)
return flat_[id];
534 return write_blocks(
id);
539 flat_.push_back(std::move(rec));
543 push_block(std::move(rec));
562 std::uint32_t pending_creation_slots = 1) {
565 "drawing slot bound must be nonnegative");
566 return {slot_bound, pending_creation_slots};
581 std::int32_t declared_count = 50, std::uint32_t pending_creation_slots = 1) {
582 static_assert(std::is_same_v<Rec, LineRec> || std::is_same_v<Rec, BoxRec>
583 || std::is_same_v<Rec, LabelRec>,
584 "this default requires a declared count for line, box, or label");
588 if (declared_count < 0
592 "drawing declared count is outside the int32 domain");
594 pending_creation_slots};
603 std::uint32_t pending_creation_slots = 1) {
621 "drawing slot bound must be nonnegative");
622 const std::uint64_t total = std::min(
624 static_cast<std::uint64_t
>(std::numeric_limits<std::int32_t>::max()));
625 if (total > std::numeric_limits<std::size_t>::max())
627 "drawing slot storage size overflow");
628 return static_cast<std::size_t
>(total);
645 std::int32_t
slot_for(std::int32_t
id)
const noexcept {
646 const auto it = std::lower_bound(
649 return entry.logical_id < value;
651 if (it ==
directory.end() || it->logical_id !=
id)
return -1;
654 if (it->slot >=
slots.size()) std::terminate();
657 return static_cast<std::int32_t
>(it->slot);
661 for (std::size_t i = 0; i <
slots.size(); ++i)
671 std::int32_t declared_count = 50, std::uint32_t pending_creation_slots = 1) {
673 declared_count, pending_creation_slots);
678 std::uint32_t pending_creation_slots = 1) {
680 sampled_bound, pending_creation_slots);
692 friend struct detail::DrawingArenaTestAccess;
694 std::deque<int32_t> order_;
696 std::shared_ptr<detail::BoundDrawingState<Rec>> bound_;
697 std::optional<DrawingBoundConfig> bound_config_;
708 void ensure_bound_unique() {
709 if (bound_ && !bound_.unique())
710 bound_ = std::make_shared<detail::BoundDrawingState<Rec>>(*bound_);
713 const Rec& bound_read(int32_t
id)
const {
714 if (
id < 0 || !bound_ ||
static_cast<std::int64_t
>(
id) >= bound_->next_id)
716 "drawing access on na handle");
717 const std::int32_t slot = bound_->slot_for(
id);
719 return *bound_->slots[
static_cast<std::uint32_t
>(slot)].value;
722 template <
class Edit>
723 void bound_edit(int32_t
id, Edit&& edit) {
724 if (
id < 0 || !bound_ ||
static_cast<std::int64_t
>(
id) >= bound_->next_id)
726 "drawing access on na handle");
727 const std::int32_t slot = bound_->slot_for(
id);
728 if (slot < 0)
return;
729 if (!bound_->slots[
static_cast<std::uint32_t
>(slot)].value->alive)
return;
731 auto candidate = std::make_shared<detail::BoundDrawingState<Rec>>(*bound_);
732 const std::int32_t candidate_slot = candidate->slot_for(
id);
733 if (candidate_slot < 0) std::terminate();
734 std::forward<Edit>(edit)(
735 *candidate->slots[
static_cast<std::uint32_t
>(candidate_slot)].value);
737 bound_.swap(candidate);
744 "bounded arenas are only available for drawing records");
745 static_assert(!std::is_same_v<Rec, LinefillRec>,
746 "bounded linefill deletion lifetime is not yet specified");
749 "drawing slot bound must be nonnegative");
754 : recs_(other.recs_), order_(other.order_), cap_(other.cap_),
755 bound_(other.bound_), bound_config_(other.bound_config_),
756 stale_sink_(), last_allocation_diagnostic_(other.last_allocation_diagnostic_) {
757 other.stale_sink_.reset();
761 if (
this != &other) {
764 auto order = other.order_;
765 auto state = other.bound_;
766 recs_ = std::move(records);
770 bound_config_ = other.bound_config_;
771 last_allocation_diagnostic_ = other.last_allocation_diagnostic_;
772 other.stale_sink_.reset();
781 : recs_(
std::move(other.recs_)), order_(
std::move(other.order_)),
782 cap_(other.cap_), bound_(
std::move(other.bound_)),
783 bound_config_(other.bound_config_),
784 stale_sink_(
std::move(other.stale_sink_)),
785 last_allocation_diagnostic_(other.last_allocation_diagnostic_) {
786 other.order_.clear();
787 other.last_allocation_diagnostic_ = {};
791 if (
this != &other) {
792 recs_ = std::move(other.recs_);
793 order_ = std::move(other.order_);
794 bound_ = std::move(other.bound_);
795 bound_config_ = other.bound_config_;
796 stale_sink_ = std::move(other.stale_sink_);
797 last_allocation_diagnostic_ = other.last_allocation_diagnostic_;
798 other.order_.clear();
800 other.last_allocation_diagnostic_ = {};
814 "slot allocation requires a builtin drawing record");
817 "typed drawing allocation requires a slot arena");
820 diagnostic.configured_bound = bound_config_->slot_bound;
821 diagnostic.pending_creation_slots = bound_config_->pending_creation_slots;
822 const std::int64_t next_id = bound_ ? bound_->next_id : 0;
823 if (next_id >= kIdExclusive) {
825 return {diagnostic, std::nullopt};
827 const std::uint64_t required = (bound_ ? bound_->directory.size() : 0u) + 1u;
828 diagnostic.required_slots = required;
829 const std::uint64_t available =
830 static_cast<std::uint64_t
>(bound_config_->slot_bound)
831 + bound_config_->pending_creation_slots;
832 if (required > available) {
834 last_allocation_diagnostic_ = diagnostic;
835 return {diagnostic, std::nullopt};
837 auto candidate = bound_
838 ? std::make_shared<detail::BoundDrawingState<Rec>>(*bound_)
839 : std::make_shared<detail::BoundDrawingState<Rec>>(*bound_config_);
840 const std::size_t slot = candidate->free_slot();
841 if (slot >= candidate->slots.size()) std::terminate();
842 const std::int32_t
id =
static_cast<std::int32_t
>(next_id);
844 candidate->slots[slot].logical_id = id;
845 candidate->slots[slot].value.emplace(std::move(r));
846 candidate->directory.push_back({id,
static_cast<std::uint32_t
>(slot)});
847 candidate->order.push_back(
id);
848 candidate->next_id = next_id + 1;
850 last_allocation_diagnostic_ = diagnostic;
851 bound_.swap(candidate);
852 return {diagnostic,
id};
861 "slot drawing creation requires try_alloc");
862 if (
static_cast<std::int64_t
>(recs_.size()) >= kIdExclusive) {
869 while ((
int)order_.size() >= cap_) {
872 recs_.write(
static_cast<std::uint32_t
>(order_.front())).alive =
false;
875 int32_t
id = recs_.size();
877 recs_.push_back(std::move(r));
878 order_.push_back(
id);
884 if (
id < 0 ||
static_cast<std::int64_t
>(
id) >= bound_->next_id)
return;
885 const std::int32_t slot = bound_->slot_for(
id);
886 if (slot < 0)
return;
887 if (!bound_->slots[
static_cast<std::uint32_t
>(slot)].value->alive)
return;
889 auto candidate = std::make_shared<detail::BoundDrawingState<Rec>>(*bound_);
890 const std::int32_t candidate_slot = candidate->slot_for(
id);
891 if (candidate_slot < 0) std::terminate();
892 const auto dir = std::lower_bound(
893 candidate->directory.begin(), candidate->directory.end(),
id,
894 [](
const auto& entry, std::int32_t value) {
895 return entry.logical_id < value;
897 if (dir == candidate->directory.end() || dir->logical_id !=
id) std::terminate();
898 candidate->directory.erase(dir);
899 const auto it = std::find(candidate->order.begin(), candidate->order.end(),
id);
900 if (it != candidate->order.end()) candidate->order.erase(it);
901 candidate->slots[
static_cast<std::uint32_t
>(candidate_slot)].logical_id = -1;
902 candidate->slots[
static_cast<std::uint32_t
>(candidate_slot)].value.reset();
904 bound_.swap(candidate);
908 if (!
alive(
id))
return;
909 recs_.write(
static_cast<std::uint32_t
>(
id)).alive =
false;
910 const auto it = std::find(order_.begin(), order_.end(),
id);
911 if (it != order_.end()) order_.erase(it);
916 const std::int32_t slot = (
id >= 0) ? bound_->slot_for(
id) : -1;
918 && bound_->slots[
static_cast<std::uint32_t
>(slot)].value->alive;
920 return id >= 0 &&
id < recs_.size() && recs_.read(
static_cast<std::uint32_t
>(
id)).alive;
926 if (bound_)
return static_cast<int32_t
>(bound_->next_id);
933 if (
static_cast<std::int64_t
>(
id) >= bound_->next_id)
942 bool is_bound() const noexcept {
return bound_config_.has_value(); }
944 return bound_config_ ? bound_config_->slot_bound : 0;
947 return bound_config_ ? bound_config_->pending_creation_slots : 0;
950 return bound_ ? bound_->directory.size() : order_.size();
953 return last_allocation_diagnostic_;
959 Rec&
at(int32_t
id) {
962 if (
id < 0 || !bound_ ||
static_cast<std::int64_t
>(
id) >= bound_->next_id)
964 "drawing access on na handle");
965 if (bound_->slot_for(
id) < 0) {
967 return stale_sink_.value;
969 ensure_bound_unique();
971 const std::int32_t slot = bound_->slot_for(
id);
972 return *bound_->slots[
static_cast<std::uint32_t
>(slot)].value;
975 return recs_.write(
static_cast<std::uint32_t
>(
id));
978 const Rec&
at(int32_t
id)
const {
980 if (bound_config_)
return bound_read(
id);
982 return recs_.read(
static_cast<std::uint32_t
>(
id));
985 const std::deque<int32_t>&
order()
const {
986 return bound_ ? bound_->order : order_;
993template <
class Rec,
class Handle>
995 if (h.id < 0 || h.id >= a.
size())
999template <
class Rec,
class Handle>
1001 if (h.id < 0 || h.id >= a.
size())
1013 template <
class Rec,
class Handle>
1015 if (a.bound_config_) {
1016 if (!a.bound_)
return false;
1017 const auto slot = a.bound_->slot_for(h.id);
1019 || !a.bound_->slots[
static_cast<std::uint32_t
>(slot)].
value->alive;
1021 if constexpr (std::is_same_v<Rec, LinefillRec>)
return false;
1022 else return !a.alive(h.id);
1025 template <
class Rec,
class Handle>
1027 if (h.id < 0 || h.id >= a.
size())
1030 if (a.bound_config_)
return a.bound_read(h.id);
1031 const Rec& r = a.recs_.read(
static_cast<std::uint32_t
>(h.id));
1035 template <
class Rec,
class Handle,
class Edit>
1037 if (h.id < 0 || h.id >= a.
size())
1040 if (a.bound_config_) {
1041 a.bound_edit(h.id, std::forward<Edit>(apply));
1044 apply(a.recs_.write(
static_cast<std::uint32_t
>(h.id)));
1053template <
class Handle,
class Rec>
1055 if (!
arena.is_bound())
1056 return Handle{
arena.alloc(std::forward<Rec>(record))};
1061 if (!result.
id) std::terminate();
1062 return Handle{*result.
id};
1083 a,
LineRec{ x1, x2, y1, y2, xloc, el, er,
true });
1089 p1.
price, p2.
price, xloc,
false,
false,
true });
1124 "line.get_price requires xloc.bar_index");
1126 return r.y1 + (r.y2 - r.y1) / (
double)(r.x2 - r.x1) * (
double)(x - r.x1);
1141 a,
BoxRec{ left, right, top, bottom, xloc,
true });
1147 top_left.
price, bottom_right.
price, xloc,
true });
1193 a,
LabelRec{ x, y, xloc, yloc, std::move(text),
true });
1201 std::move(text),
true });
1251template <
class... A>
inline void pf_noop(A&&...) {}
const std::deque< int32_t > & order() const
DrawingAllocationResult try_alloc(Rec r)
DrawingAccessStatus access_status(int32_t id) const noexcept
std::int32_t slot_bound() const noexcept
DrawingArena(const DrawingArena &other)
std::uint32_t pending_creation_slots() const noexcept
DrawingArena(DrawingBoundConfig config)
DrawingArena & operator=(const DrawingArena &other)
bool is_bound() const noexcept
std::size_t occupied_slots() const noexcept
DrawingAllocationDiagnostic last_allocation_diagnostic() const noexcept
const Rec & at(int32_t id) const
DrawingArena & operator=(DrawingArena &&other) noexcept
bool alive(int32_t id) const
DrawingArena(DrawingArena &&other)
Base with a code: throw coded<std::invalid_argument>(code, {args}, text).
Rec & write(std::uint32_t id)
DrawingRecordStore & operator=(DrawingRecordStore &&other) noexcept
DrawingRecordStore()=default
DrawingRecordStore(DrawingRecordStore &&other) noexcept
DrawingRecordStore & operator=(const DrawingRecordStore &other)
const Rec & read(std::uint32_t id) const
DrawingRecordStore(const DrawingRecordStore &other)
void push_back(Rec &&rec)
constexpr bool is_builtin_drawing_record_v
void drawing_id_exhausted_error(const char *object)
constexpr const char * drawing_count_field() noexcept
Handle drawing_builtin_allocate(DrawingArena< Rec > &arena, Rec &&record)
constexpr std::int64_t kDrawingIdExclusive
void drawing_na_error(const char *object, const char *what)
void drawing_argument_error(const char *function, const char *argument, const char *rule, const char *what)
DrawingBoundConfig drawing_bound_from_linefill_sample(std::int32_t sampled_bound=kDrawingLinefillObservedBound, std::uint32_t pending_creation_slots=1)
constexpr std::int32_t kDrawingLinefillObservedBound
Rec drawing_missing_value() noexcept
constexpr const char * drawing_object_name() noexcept
DrawingBoundConfig drawing_bound_from_declared_count(std::int32_t declared_count=50, std::uint32_t pending_creation_slots=1)
constexpr DrawingKind drawing_kind_of() noexcept
constexpr std::int32_t kDrawingObservedSlack
const Rec & drawing_missing_record() noexcept
void pf_linefill_delete(DrawingArena< LinefillRec > &a, Linefill h)
void pf_line_set_xy1(DrawingArena< LineRec > &a, Line h, int64_t x, double y)
std::string pf_label_get_text(DrawingArena< LabelRec > &a, Label h)
void pf_label_delete(DrawingArena< LabelRec > &a, Label h)
void pf_line_set_xy2(DrawingArena< LineRec > &a, Line h, int64_t x, double y)
double pf_line_get_y1(DrawingArena< LineRec > &a, Line h)
void pf_box_set_bottom_right_point(DrawingArena< BoxRec > &a, Box h, ChartPoint p)
Line pf_linefill_get_line2(DrawingArena< LinefillRec > &a, Linefill h)
int64_t pf_point_x(const ChartPoint &p, XLoc xloc)
Line pf_line_copy(DrawingArena< LineRec > &a, Line h)
void pf_box_set_top(DrawingArena< BoxRec > &a, Box h, double v)
Box pf_box_new(DrawingArena< BoxRec > &a, int64_t left, double top, int64_t right, double bottom, XLoc xloc=XLoc::bar_index)
void pf_box_set_lefttop(DrawingArena< BoxRec > &a, Box h, int64_t left, double top)
void pf_label_set_point(DrawingArena< LabelRec > &a, Label h, ChartPoint p)
Box pf_box_new_pts(DrawingArena< BoxRec > &a, ChartPoint top_left, ChartPoint bottom_right, XLoc xloc=XLoc::bar_index)
void pf_box_set_right(DrawingArena< BoxRec > &a, Box h, int64_t v)
Line pf_line_new_pts(DrawingArena< LineRec > &a, ChartPoint p1, ChartPoint p2, XLoc xloc=XLoc::bar_index)
void pf_box_set_xloc(DrawingArena< BoxRec > &a, Box h, int64_t left, int64_t right, XLoc xloc)
void pf_box_set_top_left_point(DrawingArena< BoxRec > &a, Box h, ChartPoint p)
double pf_label_get_y(DrawingArena< LabelRec > &a, Label h)
Line pf_line_new(DrawingArena< LineRec > &a, int64_t x1, double y1, int64_t x2, double y2, XLoc xloc=XLoc::bar_index, bool el=false, bool er=false)
void pf_label_set_xy(DrawingArena< LabelRec > &a, Label h, int64_t x, double y)
void pf_line_set_y1(DrawingArena< LineRec > &a, Line h, double v)
Line pf_linefill_get_line1(DrawingArena< LinefillRec > &a, Linefill h)
Label pf_label_new(DrawingArena< LabelRec > &a, int64_t x, double y, std::string text, XLoc xloc=XLoc::bar_index, YLoc yloc=YLoc::price)
int64_t pf_box_get_left(DrawingArena< BoxRec > &a, Box h)
@ drawing_slot_bound_exceeded
@ pine_drawing_id_exhausted
void pf_box_set_rightbottom(DrawingArena< BoxRec > &a, Box h, int64_t right, double bottom)
int64_t pf_line_get_x2(DrawingArena< LineRec > &a, Line h)
int64_t pf_line_get_x1(DrawingArena< LineRec > &a, Line h)
void pf_line_set_x2(DrawingArena< LineRec > &a, Line h, int64_t v)
double pf_box_get_bottom(DrawingArena< BoxRec > &a, Box h)
Linefill pf_linefill_new(DrawingArena< LinefillRec > &a, Line l1, Line l2)
@ strategy_settings_rejected
void pf_label_set_x(DrawingArena< LabelRec > &a, Label h, int64_t v)
void pf_label_set_text(DrawingArena< LabelRec > &a, Label h, std::string text)
void pf_label_set_yloc(DrawingArena< LabelRec > &a, Label h, YLoc yloc)
bool is_na(const Line &h)
void pf_line_set_xloc(DrawingArena< LineRec > &a, Line h, int64_t x1, int64_t x2, XLoc xloc)
Rec & pf_require_live(DrawingArena< Rec > &a, Handle h)
void pf_line_set_first_point(DrawingArena< LineRec > &a, Line h, ChartPoint p)
double pf_box_get_top(DrawingArena< BoxRec > &a, Box h)
void pf_line_set_x1(DrawingArena< LineRec > &a, Line h, int64_t v)
Label pf_label_new_pt(DrawingArena< LabelRec > &a, ChartPoint point, std::string text, YLoc yloc=YLoc::price)
double pf_line_get_y2(DrawingArena< LineRec > &a, Line h)
int64_t pf_label_get_x(DrawingArena< LabelRec > &a, Label h)
DrawingBoundConfig drawing_bound(std::int32_t slot_bound, std::uint32_t pending_creation_slots=1)
void pf_box_delete(DrawingArena< BoxRec > &a, Box h)
DrawingBoundConfig drawing_bound_from_linefill_sample(std::int32_t sampled_bound=detail::kDrawingLinefillObservedBound, std::uint32_t pending_creation_slots=1)
void pf_line_set_second_point(DrawingArena< LineRec > &a, Line h, ChartPoint p)
void pf_line_delete(DrawingArena< LineRec > &a, Line h)
void pf_box_set_left(DrawingArena< BoxRec > &a, Box h, int64_t v)
int64_t pf_box_get_right(DrawingArena< BoxRec > &a, Box h)
double pf_line_get_price(DrawingArena< LineRec > &a, Line h, int64_t x)
void pf_line_set_y2(DrawingArena< LineRec > &a, Line h, double v)
void pf_label_set_y(DrawingArena< LabelRec > &a, Label h, double v)
Label pf_label_copy(DrawingArena< LabelRec > &a, Label h)
void pf_label_set_xloc(DrawingArena< LabelRec > &a, Label h, int64_t x, XLoc xloc)
void pf_box_set_bottom(DrawingArena< BoxRec > &a, Box h, double v)
DrawingBoundConfig drawing_bound_from_declared_count(std::int32_t declared_count=50, std::uint32_t pending_creation_slots=1)
Box pf_box_copy(DrawingArena< BoxRec > &a, Box h)
std::int32_t configured_bound
std::uint64_t required_slots
std::uint32_t pending_creation_slots
DrawingAllocationStatus status
std::optional< std::int32_t > id
DrawingAllocationDiagnostic diagnostic
std::uint32_t pending_creation_slots
std::optional< Rec > value
std::int32_t slot_for(std::int32_t id) const noexcept
std::vector< Slot > slots
std::size_t free_slot() const noexcept
std::vector< DirectoryEntry > directory
std::uint32_t pending_creation_slots
std::deque< std::int32_t > order
BoundDrawingState(DrawingBoundConfig config)
static std::size_t storage_slots(DrawingBoundConfig config)
static const Rec & read(const DrawingArena< Rec > &a, Handle h)
static void edit(DrawingArena< Rec > &a, Handle h, Edit &&apply)
static bool missing(const DrawingArena< Rec > &a, Handle h) noexcept
std::atomic_flag resetting
DrawingStaleSink & operator=(DrawingStaleSink &&other) noexcept
DrawingStaleSink & operator=(const DrawingStaleSink &other)
void reset() const noexcept
DrawingStaleSink(const DrawingStaleSink &other)
DrawingStaleSink(DrawingStaleSink &&other) noexcept
DrawingStaleSink() noexcept=default
void reset() const noexcept
static constexpr bool builtin
static constexpr DrawingKind kind
static constexpr bool builtin
static constexpr DrawingKind kind
static constexpr DrawingKind kind
static constexpr bool builtin
static constexpr DrawingKind kind
static constexpr bool builtin
static constexpr bool builtin
pine_drawing_error(const std::string &msg)
pine_drawing_id_exhausted(const char *object)