Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
state_tree.hpp
Go to the documentation of this file.
1#pragma once
2
3// StateTree — reactive hierarchical key-value store.
4// A tree of named properties with typed access, change listeners, RAII
5// transactions (coalesced notifications, abort, nesting) and undo recording:
6// a transaction begun with an UndoManager becomes one named undo/redo step.
7// Alternative to flat StateStore for complex nested state (presets, UI layout, etc.)
8
9#include <algorithm>
10#include <cstdint>
11#include <functional>
12#include <initializer_list>
13#include <map>
14#include <memory>
15#include <mutex>
16#include <optional>
17#include <string>
18#include <string_view>
19#include <variant>
20#include <vector>
21
23
24namespace pulp::state {
25
32struct PropertyArray;
33struct PropertyObject;
34
36 std::shared_ptr<const PropertyArray> storage;
37
38 PropertyArrayValue() = default;
39 explicit PropertyArrayValue(std::shared_ptr<const PropertyArray> s)
40 : storage(std::move(s)) {}
41
42 const PropertyArray* get() const noexcept { return storage.get(); }
43 explicit operator bool() const noexcept { return static_cast<bool>(storage); }
44};
45
47 std::shared_ptr<const PropertyObject> storage;
48
50 explicit PropertyObjectValue(std::shared_ptr<const PropertyObject> s)
51 : storage(std::move(s)) {}
52
53 const PropertyObject* get() const noexcept { return storage.get(); }
54 explicit operator bool() const noexcept { return static_cast<bool>(storage); }
55};
56
57bool operator==(const PropertyArrayValue& a, const PropertyArrayValue& b);
58bool operator!=(const PropertyArrayValue& a, const PropertyArrayValue& b);
59bool operator==(const PropertyObjectValue& a, const PropertyObjectValue& b);
60bool operator!=(const PropertyObjectValue& a, const PropertyObjectValue& b);
61
66using PropertyValue = std::variant<
67 std::monostate, // null/unset
68 bool,
69 int64_t,
70 double,
71 std::string,
74>;
75
77 std::vector<PropertyValue> values;
78
79 PropertyArray() = default;
80 explicit PropertyArray(std::vector<PropertyValue> v) : values(std::move(v)) {}
81 PropertyArray(std::initializer_list<PropertyValue> v) : values(v) {}
82};
83
85 using Member = std::pair<std::string, PropertyValue>;
86
87 std::map<std::string, PropertyValue, std::less<>> values;
88
89 PropertyObject() = default;
90 explicit PropertyObject(std::map<std::string, PropertyValue, std::less<>> v)
91 : values(std::move(v)) {}
92 PropertyObject(std::initializer_list<Member> v) {
93 for (const auto& [key, value] : v)
94 values.emplace(key, value);
95 }
96};
97
98inline bool operator==(const PropertyArray& a, const PropertyArray& b) {
99 return a.values == b.values;
100}
101
102inline bool operator!=(const PropertyArray& a, const PropertyArray& b) {
103 return !(a == b);
104}
105
106inline bool operator==(const PropertyObject& a, const PropertyObject& b) {
107 return a.values == b.values;
108}
109
110inline bool operator!=(const PropertyObject& a, const PropertyObject& b) {
111 return !(a == b);
112}
113
114inline bool operator==(const PropertyArrayValue& a, const PropertyArrayValue& b) {
115 if (a.storage == b.storage) return true;
116 if (!a.storage || !b.storage) return false;
117 return *a.storage == *b.storage;
118}
119
120inline bool operator!=(const PropertyArrayValue& a, const PropertyArrayValue& b) {
121 return !(a == b);
122}
123
124inline bool operator==(const PropertyObjectValue& a, const PropertyObjectValue& b) {
125 if (a.storage == b.storage) return true;
126 if (!a.storage || !b.storage) return false;
127 return *a.storage == *b.storage;
128}
129
130inline bool operator!=(const PropertyObjectValue& a, const PropertyObjectValue& b) {
131 return !(a == b);
132}
133
134inline PropertyValue make_property_array(std::vector<PropertyValue> values) {
135 return PropertyArrayValue{
136 std::make_shared<const PropertyArray>(PropertyArray{std::move(values)})};
137}
138
139inline PropertyValue make_property_array(std::initializer_list<PropertyValue> values) {
140 return PropertyArrayValue{
141 std::make_shared<const PropertyArray>(PropertyArray{values})};
142}
143
144inline PropertyValue make_property_object(std::map<std::string, PropertyValue, std::less<>> values) {
145 return PropertyObjectValue{
146 std::make_shared<const PropertyObject>(PropertyObject{std::move(values)})};
147}
148
150 std::initializer_list<PropertyObject::Member> values) {
151 return PropertyObjectValue{
152 std::make_shared<const PropertyObject>(PropertyObject{values})};
153}
154
155inline const PropertyArray* get_property_array(const PropertyValue& value) {
156 if (auto* ptr = std::get_if<PropertyArrayValue>(&value))
157 return ptr->get();
158 return nullptr;
159}
160
162 if (auto* ptr = std::get_if<PropertyObjectValue>(&value))
163 return ptr->get();
164 return nullptr;
165}
166
167class StateTree;
168class UndoManager;
169
171using TreeListener = std::function<void(StateTree& node, std::string_view property,
172 const PropertyValue& old_val, const PropertyValue& new_val)>;
173
177using ChildListener = std::function<void(StateTree& parent, StateTree& child, int index)>;
178
182 std::function<void(StateTree& parent, StateTree& child, int old_index, int new_index)>;
183
187using ParentChangedListener = std::function<void(StateTree& node, StateTree* old_parent)>;
188
191using AncestorChangedListener = std::function<void(StateTree& node)>;
192
207
222
228
231
234using PropertyValidator = std::function<std::optional<std::string>(
235 const StateTree& node, std::string_view name, const PropertyValue& value)>;
236
293class StateTree : public std::enable_shared_from_this<StateTree> {
294public:
295 using Ptr = std::shared_ptr<StateTree>;
296
297 class Transaction;
299
302 static Ptr create(std::string type_name) {
303 return Ptr(new StateTree(std::move(type_name)));
304 }
305
310 const std::string& type_name() const { return type_name_; }
311
312 // ── Properties ──────────────────────────────────────────────────────
313
318 void set(std::string_view name, PropertyValue value);
319
324 TreeEditResult set_checked(std::string_view name, PropertyValue value,
325 const PropertyValidator& validator = {});
326
330 PropertyValue get(std::string_view name) const;
331
334 bool get_bool(std::string_view name, bool default_val = false) const;
335 int64_t get_int(std::string_view name, int64_t default_val = 0) const;
336 double get_double(std::string_view name, double default_val = 0.0) const;
337 std::string get_string(std::string_view name, std::string_view default_val = "") const;
338
341 bool has(std::string_view name) const;
342
346 void remove(std::string_view name);
347
350 TreeEditResult remove_checked(std::string_view name);
351
356 std::vector<std::string> property_names() const;
357
358 // ── Children ────────────────────────────────────────────────────────
359
368
372
375 void insert_child(int index, Ptr child);
376
380
383 void remove_child(int index);
384
388
391 void remove_child(StateTree* child);
392
397
406 static bool move_child(StateTree& from_parent, int from_index, StateTree& to_parent,
407 int to_index);
408
411 static TreeEditResult move_child_checked(StateTree& from_parent, int from_index,
412 StateTree& to_parent, int to_index);
413
417 int child_count() const { return static_cast<int>(children_.size()); }
418
421 Ptr child(int index) const;
422
425 int index_of(const StateTree* node) const;
426
429 Ptr find_child(std::string_view type_name) const;
430
433 std::vector<Ptr> find_children(std::string_view type_name) const;
434
441 void for_each_descendant(const std::function<void(StateTree&)>& fn);
442
446 Ptr find_descendant(const std::function<bool(const StateTree&)>& predicate) const;
447
452 bool is_equivalent_to(const StateTree& other) const;
453
457 StateTree* parent() const { return parent_; }
458
459 // ── Transactions ────────────────────────────────────────────────────
460
465
472 [[nodiscard]] Transaction begin_transaction(UndoManager* undo, std::string_view name);
473
478 UndoManager* undo = nullptr,
479 std::string_view name = {});
480
483 bool in_transaction() const;
484
485 // ── Listeners ───────────────────────────────────────────────────────
486
493 void remove_listener(int id);
494
503
509
515
521
522 // ── Serialization ───────────────────────────────────────────────────
523
527 std::string to_json() const;
528
533 static Ptr from_json(std::string_view json);
534
535 // ── Deep copy ───────────────────────────────────────────────────────
536
540 Ptr deep_copy() const;
541
542 // ── Synchronized clone (single-process) ─────────────────────────────
543
568 class SyncedClone;
570
571private:
572 explicit StateTree(std::string type_name) : type_name_(std::move(type_name)) {}
573
574 struct TxState;
575 struct Edit;
576 struct Pending;
577 enum class Pass { kAll, kImmediate, kCoalesced };
578
579 template <typename Fn> struct Slot {
580 int id;
581 Fn fn;
582 ListenerDelivery delivery;
583 };
584
585 std::string type_name_;
586 std::map<std::string, PropertyValue, std::less<>> properties_;
587 std::vector<Ptr> children_;
588 StateTree* parent_ = nullptr;
589
590 std::vector<Slot<TreeListener>> listeners_;
591 std::vector<Slot<ChildListener>> child_added_listeners_;
592 std::vector<Slot<ChildListener>> child_removed_listeners_;
593 std::vector<Slot<ChildMovedListener>> child_moved_listeners_;
594 std::vector<Slot<ParentChangedListener>> parent_changed_listeners_;
595 std::vector<Slot<AncestorChangedListener>> ancestor_changed_listeners_;
596 int next_listener_id_ = 0;
597
598 // Open transaction owned by this node (when it is the tree it was begun
599 // on) or held by it (when it was detached while a transaction was open).
600 std::shared_ptr<TxState> tx_;
601 // Non-zero while this node's transaction is delivering its commit burst.
602 int flushing_ = 0;
603
604 template <typename Fn>
605 int add_slot(std::vector<Slot<Fn>>& slots, Fn fn, ListenerDelivery delivery);
606 template <typename Fn> static void remove_slot(std::vector<Slot<Fn>>& slots, int id);
607 template <typename Fn, typename... Args>
608 static void dispatch(std::vector<Slot<Fn>>& slots, Pass pass, Args&... args);
609
610 std::shared_ptr<TxState> active_tx() const;
611 bool flush_in_progress() const;
612 static TreeEditResult check_tx(const StateTree* a, const StateTree* b);
613
614 void apply_property(std::string_view name, std::optional<PropertyValue> value);
615 static void relocate(const Ptr& child, StateTree* to, int to_index, bool reorder_event);
616 static void place(const Ptr& child, StateTree* to, int to_index);
617 static void replay(const Edit& edit, bool forward);
618 static void replay_log(const std::vector<Edit>& log, const Ptr& owner, bool forward);
619 static void emit(Pending pending, TxState* tx);
620 static void deliver(const Pending& pending, Pass pass);
621 static void finish(std::shared_ptr<TxState> state);
622
623 // True if this node is `node` or one of its ancestors (walks `node`'s
624 // parent chain upward). Used by add_child / insert_child / move_child to
625 // reject parent/child cycles before they can form.
626 bool is_ancestor_of(const StateTree* node) const;
627};
628
637 public:
639 Transaction() = default;
640 Transaction(Transaction&& other) noexcept;
643 Transaction(const Transaction&) = delete;
646
650 void commit();
651
656 bool abort();
657
659 bool is_active() const {
660 return active_;
661 }
662
663 private:
664 friend class StateTree;
666 Transaction(std::shared_ptr<TxState> state, size_t edit_mark, size_t pending_mark)
667 : state_(std::move(state)), edit_mark_(edit_mark), pending_mark_(pending_mark),
668 active_(true) {}
669 void end();
670
671 std::shared_ptr<TxState> state_;
672 size_t edit_mark_ = 0;
673 size_t pending_mark_ = 0;
674 bool active_ = false;
675};
676
686 public:
687 ValidatedTransaction(ValidatedTransaction&& other) noexcept = default;
692
693 TreeEditResult set(StateTree& node, std::string_view name, PropertyValue value);
694 TreeEditResult remove(StateTree& node, std::string_view name);
698 TreeEditResult move_child(StateTree& from_parent, int from_index, StateTree& to_parent,
699 int to_index);
700
704
706 bool abort();
707
708 bool is_active() const {
709 return tx_.is_active();
710 }
711 bool has_error() const {
712 return first_error_.has_value();
713 }
714 const std::optional<TreeEditError>& first_error() const {
715 return first_error_;
716 }
717
718 private:
719 friend class StateTree;
720 ValidatedTransaction(Transaction tx, PropertyValidator validator, bool reentrant)
721 : tx_(std::move(tx)), validator_(std::move(validator)), reentrant_(reentrant) {}
722
723 TreeEditResult guard(std::initializer_list<const StateTree*> nodes) const;
724 TreeEditResult note(TreeEditResult result);
725
726 Transaction tx_;
727 PropertyValidator validator_;
728 std::optional<TreeEditError> first_error_;
729 bool reentrant_ = false;
730};
731
737public:
739 SyncedClone& operator=(SyncedClone&&) noexcept;
740 SyncedClone(const SyncedClone&) = delete;
741 SyncedClone& operator=(const SyncedClone&) = delete;
743
746 const StateTree::Ptr& clone() const { return clone_; }
747
750 void detach();
751
753 bool is_attached() const { return attached_; }
754
755private:
756 friend class StateTree;
757
759
760 void attach_recursive(StateTree& src, StateTree& dst);
761 void detach_recursive(StateTree& src);
762
763 // Weak handle to the source node. When the source subtree is
764 // removed via `remove_child` and no other shared_ptr keeps it
765 // alive, `lock()` returns null so `detach()` skips deregistration
766 // safely instead of dereferencing a dangling raw pointer.
767 // Pinned by the SyncedClone destructor-safety regression test.
768 struct WiringEntry {
769 std::weak_ptr<StateTree> source;
770 int prop_listener_id;
771 int child_added_listener_id;
772 int child_removed_listener_id;
773 int child_moved_listener_id;
774 };
775
776 StateTree::Ptr source_;
777 StateTree::Ptr clone_;
778 std::vector<WiringEntry> wiring_;
779 bool attached_ = true;
780};
781
787template<typename T>
789public:
790 ObservableValue() = default;
791 explicit ObservableValue(T initial) : value_(std::move(initial)) {}
792
793 const T& get() const { return value_; }
794 operator const T&() const { return value_; }
795
796 void set(T new_value) {
797 if (value_ != new_value) {
798 T old = std::move(value_);
799 value_ = std::move(new_value);
800 // Snapshot-then-dispatch with a liveness recheck, mirroring
801 // StateTree's listener fan-out: a callback may add or remove
802 // listeners on this same value while it runs, which would
803 // invalidate iterators into the live vector. A listener removed
804 // earlier in the same dispatch is skipped; one added during the
805 // dispatch is not invoked for the in-flight set. The single-
806 // listener fast path copies the callable before invoking so a
807 // self-removing sole listener can't free its own executing body.
808 if (listeners_.size() == 1) {
809 auto fn = listeners_.front().second;
810 if (fn) fn(old, value_);
811 return;
812 }
813 auto snapshot = listeners_;
814 for (auto& [id, fn] : snapshot) {
815 if (!fn) continue;
816 bool still_registered = std::any_of(
817 listeners_.begin(), listeners_.end(),
818 [id = id](const auto& e) { return e.first == id; });
819 if (still_registered) fn(old, value_);
820 }
821 }
822 }
823
825 set(std::move(new_value));
826 return *this;
827 }
828
829 using ChangeListener = std::function<void(const T& old_val, const T& new_val)>;
830
832 int id = next_id_++;
833 listeners_.push_back({id, std::move(fn)});
834 return id;
835 }
836
837 void remove_listener(int id) {
838 listeners_.erase(
839 std::remove_if(listeners_.begin(), listeners_.end(),
840 [id](auto& p) { return p.first == id; }),
841 listeners_.end());
842 }
843
844private:
845 T value_{};
846 std::vector<std::pair<int, ChangeListener>> listeners_;
847 int next_id_ = 0;
848};
849
850} // namespace pulp::state
Result<T, E> — either holds a T or an E, never both.
Definition result.hpp:76
ObservableValue(T initial)
Definition state_tree.hpp:791
int add_listener(ChangeListener fn)
Definition state_tree.hpp:831
ObservableValue & operator=(T new_value)
Definition state_tree.hpp:824
const T & get() const
Definition state_tree.hpp:793
void set(T new_value)
Definition state_tree.hpp:796
void remove_listener(int id)
Definition state_tree.hpp:837
std::function< void(const T &old_val, const T &new_val)> ChangeListener
Definition state_tree.hpp:829
Owns the listener wiring created by StateTree::clone_synced().
Definition state_tree.hpp:736
void detach()
Drop the listener subscriptions early.
const StateTree::Ptr & clone() const
The cloned tree.
Definition state_tree.hpp:746
bool is_attached() const
Whether the subscription is still active.
Definition state_tree.hpp:753
friend class StateTree
Definition state_tree.hpp:756
SyncedClone(SyncedClone &&) noexcept
RAII transaction on a StateTree.
Definition state_tree.hpp:636
Transaction(const Transaction &)=delete
Transaction & operator=(const Transaction &)=delete
bool is_active() const
Whether this object still holds an open transaction.
Definition state_tree.hpp:659
bool abort()
Revert every edit made since this transaction began, in reverse order, drop their pending notificatio...
void commit()
End this transaction and keep its edits.
friend class StateTree
Definition state_tree.hpp:664
Transaction()=default
An inert transaction (is_active() is false).
Transaction & operator=(Transaction &&other) noexcept
Commits the transaction currently held, then takes over other.
Transaction(Transaction &&other) noexcept
A transaction whose edits are checked and return TreeEditResult instead of being silently ignored.
Definition state_tree.hpp:685
ValidatedTransaction(const ValidatedTransaction &)=delete
const std::optional< TreeEditError > & first_error() const
Definition state_tree.hpp:714
ValidatedTransaction & operator=(ValidatedTransaction &&other) noexcept
bool abort()
Revert every edit and end the transaction. Returns false when inactive.
bool has_error() const
Definition state_tree.hpp:711
ValidatedTransaction & operator=(const ValidatedTransaction &)=delete
ValidatedTransaction(ValidatedTransaction &&other) noexcept=default
TreeEditResult remove(StateTree &node, std::string_view name)
TreeEditResult commit()
Commit when every edit succeeded; otherwise abort and return the first error.
bool is_active() const
Definition state_tree.hpp:708
TreeEditResult set(StateTree &node, std::string_view name, PropertyValue value)
friend class StateTree
Definition state_tree.hpp:719
TreeEditResult move_child(StateTree &from_parent, int from_index, StateTree &to_parent, int to_index)
TreeEditResult insert_child(StateTree &parent, int index, Ptr child)
TreeEditResult add_child(StateTree &parent, Ptr child)
TreeEditResult remove_child(StateTree &parent, int index)
Reactive tree node — each node has a type name, properties, and children.
Definition state_tree.hpp:293
int child_count() const
Number of children.
Definition state_tree.hpp:417
double get_double(std::string_view name, double default_val=0.0) const
Transaction begin_transaction(UndoManager *undo, std::string_view name)
Open (or join) a transaction that records inverse edits so the whole transaction becomes one named st...
void remove_listener(int id)
bool in_transaction() const
Whether a transaction is open that covers edits made through this node.
void for_each_descendant(const std::function< void(StateTree &)> &fn)
Visit every descendant (not this node) depth-first, parents before children.
static Ptr from_json(std::string_view json)
Deserialize from JSON string.
Ptr find_descendant(const std::function< bool(const StateTree &)> &predicate) const
First descendant (depth-first, parents before children, not this node) for which predicate returns tr...
bool get_bool(std::string_view name, bool default_val=false) const
Typed getters with defaults.
void remove_all_children()
Remove every child.
void remove_parent_changed_listener(int id)
TreeEditResult remove_child_checked(int index)
Checked remove_child(int).
void remove_child_added_listener(int id)
TreeEditResult insert_child_checked(int index, Ptr child)
Checked insert_child(): an out-of-range index is an error, not clamped.
Transaction begin_transaction()
Open (or join) a transaction on this node's tree.
StateTree * parent() const
Parent (may be null for root).
Definition state_tree.hpp:457
int add_child_removed_listener(ChildListener listener, ListenerDelivery delivery=ListenerDelivery::kCoalesced)
int add_child_moved_listener(ChildMovedListener listener, ListenerDelivery delivery=ListenerDelivery::kCoalesced)
Listen for reorders within this node (move_child with one parent).
int64_t get_int(std::string_view name, int64_t default_val=0) const
void add_child(Ptr child)
Add a child node (notifies child-added listeners).
PropertyValue get(std::string_view name) const
Get a property value (returns monostate if not set).
static Ptr create(std::string type_name)
Create a tree node with a type name.
Definition state_tree.hpp:302
int index_of(const StateTree *node) const
Index of node among this node's children, or -1.
bool has(std::string_view name) const
Whether a property exists.
std::vector< Ptr > find_children(std::string_view type_name) const
Find all children with matching type name.
Ptr find_child(std::string_view type_name) const
Find first child with matching type name.
Ptr child(int index) const
Get child by index.
void remove_child_moved_listener(int id)
int add_ancestor_changed_listener(AncestorChangedListener listener, ListenerDelivery delivery=ListenerDelivery::kCoalesced)
Listen for any ancestor link above this node changing.
Ptr deep_copy() const
Deep-copy this subtree (including properties and recursive children).
void remove_child_removed_listener(int id)
static bool move_child(StateTree &from_parent, int from_index, StateTree &to_parent, int to_index)
Move the child at from_index of from_parent to to_index of to_parent.
TreeEditResult set_checked(std::string_view name, PropertyValue value, const PropertyValidator &validator={})
Set a property, returning an error value instead of applying an invalid edit: an empty name,...
std::shared_ptr< StateTree > Ptr
Definition state_tree.hpp:295
int add_listener(TreeListener listener, ListenerDelivery delivery=ListenerDelivery::kCoalesced)
Listen for property changes.
int add_parent_changed_listener(ParentChangedListener listener, ListenerDelivery delivery=ListenerDelivery::kCoalesced)
Listen for this node's parent changing.
TreeEditResult add_child_checked(Ptr child)
Checked add_child(): returns an error instead of ignoring the edit.
static TreeEditResult move_child_checked(StateTree &from_parent, int from_index, StateTree &to_parent, int to_index)
Checked move_child().
std::vector< std::string > property_names() const
Get all property names (snapshot copy).
void remove_child(int index)
Remove a child by index (notifies child-removed listeners).
void remove(std::string_view name)
Remove a property.
void remove_ancestor_changed_listener(int id)
TreeEditResult remove_checked(std::string_view name)
Remove a property; kMissingProperty if it does not exist.
bool is_equivalent_to(const StateTree &other) const
Structural equality: same type name, equal properties (exact variant match, so int64 3 differs from d...
const std::string & type_name() const
Type name (e.g., "preset", "oscillator", "filter").
Definition state_tree.hpp:310
void set(std::string_view name, PropertyValue value)
Set a property value (notifies listeners).
std::string get_string(std::string_view name, std::string_view default_val="") const
ValidatedTransaction begin_validated_transaction(PropertyValidator validator={}, UndoManager *undo=nullptr, std::string_view name={})
Open (or join) a transaction whose edits are checked and return TreeEditResult.
void remove_child(StateTree *child)
Remove a specific child.
std::string to_json() const
Serialize to JSON string.
int add_child_added_listener(ChildListener listener, ListenerDelivery delivery=ListenerDelivery::kCoalesced)
Listen for child added/removed.
SyncedClone clone_synced()
void insert_child(int index, Ptr child)
Insert a child at a specific index (clamped to the valid range).
Manages undo/redo history with configurable depth.
Definition undo_manager.hpp:70
SequencerStateChannel is the audio-safe transport for a plugin's structured NON-parameter state: the ...
Definition audio_device_manager.hpp:48
std::function< std::optional< std::string >( const StateTree &node, std::string_view name, const PropertyValue &value)> PropertyValidator
Property validator used by checked edits.
Definition state_tree.hpp:234
ListenerDelivery
When a listener is told about edits made inside a StateTree::Transaction.
Definition state_tree.hpp:203
@ kImmediate
Definition state_tree.hpp:205
@ kCoalesced
Definition state_tree.hpp:204
bool operator==(const PropertyArrayValue &a, const PropertyArrayValue &b)
Definition state_tree.hpp:114
runtime::Result< std::monostate, TreeEditError > TreeEditResult
Result of a checked StateTree edit: success carries no value.
Definition state_tree.hpp:230
TreeEditErrorCode
Why a checked StateTree edit was refused.
Definition state_tree.hpp:210
@ kInvalidName
Empty property name.
Definition state_tree.hpp:211
@ kNotInTransaction
Node does not belong to this transaction's tree.
Definition state_tree.hpp:218
@ kReentrantTransaction
Transaction was begun from a listener during a commit burst.
Definition state_tree.hpp:219
@ kTransactionConflict
Edit spans two trees with different open transactions.
Definition state_tree.hpp:216
@ kWouldCreateCycle
Edit would make a node its own descendant.
Definition state_tree.hpp:215
@ kNullChild
Child pointer was null.
Definition state_tree.hpp:213
@ kIndexOutOfRange
Child index outside the valid range.
Definition state_tree.hpp:214
@ kTransactionClosed
Transaction already committed or aborted.
Definition state_tree.hpp:220
@ kRejectedByValidator
A PropertyValidator refused the value.
Definition state_tree.hpp:217
@ kMissingProperty
remove of a property that does not exist.
Definition state_tree.hpp:212
std::function< void(StateTree &node, StateTree *old_parent)> ParentChangedListener
Parent-changed listener — node's parent pointer changed.
Definition state_tree.hpp:187
PropertyValue make_property_array(std::vector< PropertyValue > values)
Definition state_tree.hpp:134
std::function< void(StateTree &node, std::string_view property, const PropertyValue &old_val, const PropertyValue &new_val)> TreeListener
Listener callback — receives the tree node, property name, old value, new value.
Definition state_tree.hpp:171
std::function< void(StateTree &node)> AncestorChangedListener
Ancestor-changed listener — some ancestor link above node changed (the node itself or one of its ance...
Definition state_tree.hpp:191
const PropertyArray * get_property_array(const PropertyValue &value)
Definition state_tree.hpp:155
std::function< void(StateTree &parent, StateTree &child, int old_index, int new_index)> ChildMovedListener
Reorder listener — a child moved within the same parent from old_index to new_index (both positions a...
Definition state_tree.hpp:181
std::function< void(StateTree &parent, StateTree &child, int index)> ChildListener
Child listener — receives parent, child, index.
Definition state_tree.hpp:177
PropertyValue make_property_object(std::map< std::string, PropertyValue, std::less<> > values)
Definition state_tree.hpp:144
const PropertyObject * get_property_object(const PropertyValue &value)
Definition state_tree.hpp:161
std::variant< std::monostate, bool, int64_t, double, std::string, PropertyArrayValue, PropertyObjectValue > PropertyValue
Property value — can hold scalar values plus immutable recursive arrays and string-keyed objects.
Definition state_tree.hpp:66
bool operator!=(const PropertyArrayValue &a, const PropertyArrayValue &b)
Definition state_tree.hpp:120
STL namespace.
Result<T, E> — success / failure union for fallible operations.
Definition state_tree.hpp:35
const PropertyArray * get() const noexcept
Definition state_tree.hpp:42
std::shared_ptr< const PropertyArray > storage
Definition state_tree.hpp:36
PropertyArrayValue(std::shared_ptr< const PropertyArray > s)
Definition state_tree.hpp:39
Definition state_tree.hpp:76
PropertyArray(std::vector< PropertyValue > v)
Definition state_tree.hpp:80
PropertyArray(std::initializer_list< PropertyValue > v)
Definition state_tree.hpp:81
std::vector< PropertyValue > values
Definition state_tree.hpp:77
Definition state_tree.hpp:46
const PropertyObject * get() const noexcept
Definition state_tree.hpp:53
std::shared_ptr< const PropertyObject > storage
Definition state_tree.hpp:47
PropertyObjectValue(std::shared_ptr< const PropertyObject > s)
Definition state_tree.hpp:50
Definition state_tree.hpp:84
PropertyObject(std::initializer_list< Member > v)
Definition state_tree.hpp:92
PropertyObject(std::map< std::string, PropertyValue, std::less<> > v)
Definition state_tree.hpp:90
std::map< std::string, PropertyValue, std::less<> > values
Definition state_tree.hpp:87
std::pair< std::string, PropertyValue > Member
Definition state_tree.hpp:85
Error value for a refused StateTree edit.
Definition state_tree.hpp:224
TreeEditErrorCode code
Definition state_tree.hpp:225
std::string message
Definition state_tree.hpp:226