MCPcopy Create free account
hub / github.com/bitcoin/bitcoin / TreeEvalMaybe

Method TreeEvalMaybe

src/script/miniscript.h:652–713  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

650 */
651 template<typename Result, typename State, typename DownFn, typename UpFn>
652 std::optional<Result> TreeEvalMaybe(State root_state, DownFn downfn, UpFn upfn) const
653 {
654 /** Entries of the explicit stack tracked in this algorithm. */
655 struct StackElem
656 {
657 const Node& node; //!< The node being evaluated.
658 size_t expanded; //!< How many children of this node have been expanded.
659 State state; //!< The state for that node.
660
661 StackElem(const Node& node_, size_t exp_, State&& state_) :
662 node(node_), expanded(exp_), state(std::move(state_)) {}
663 };
664 /* Stack of tree nodes being explored. */
665 std::vector<StackElem> stack;
666 /* Results of subtrees so far. Their order and mapping to tree nodes
667 * is implicitly defined by stack. */
668 std::vector<Result> results;
669 stack.emplace_back(*this, 0, std::move(root_state));
670
671 /* Here is a demonstration of the algorithm, for an example tree A(B,C(D,E),F).
672 * State variables are omitted for simplicity.
673 *
674 * First: stack=[(A,0)] results=[]
675 * stack=[(A,1),(B,0)] results=[]
676 * stack=[(A,1)] results=[B]
677 * stack=[(A,2),(C,0)] results=[B]
678 * stack=[(A,2),(C,1),(D,0)] results=[B]
679 * stack=[(A,2),(C,1)] results=[B,D]
680 * stack=[(A,2),(C,2),(E,0)] results=[B,D]
681 * stack=[(A,2),(C,2)] results=[B,D,E]
682 * stack=[(A,2)] results=[B,C]
683 * stack=[(A,3),(F,0)] results=[B,C]
684 * stack=[(A,3)] results=[B,C,F]
685 * Final: stack=[] results=[A]
686 */
687 while (stack.size()) {
688 const Node& node = stack.back().node;
689 if (stack.back().expanded < node.subs.size()) {
690 /* We encounter a tree node with at least one unexpanded child.
691 * Expand it. By the time we hit this node again, the result of
692 * that child (and all earlier children) will be at the end of `results`. */
693 size_t child_index = stack.back().expanded++;
694 State child_state = downfn(stack.back().state, node, child_index);
695 stack.emplace_back(node.subs[child_index], 0, std::move(child_state));
696 continue;
697 }
698 // Invoke upfn with the last node.subs.size() elements of results as input.
699 assert(results.size() >= node.subs.size());
700 std::optional<Result> result{upfn(std::move(stack.back().state), node,
701 std::span<Result>{results}.last(node.subs.size()))};
702 // If evaluation returns std::nullopt, abort immediately.
703 if (!result) return {};
704 // Replace the last node.subs.size() elements of results with the new result.
705 results.erase(results.end() - node.subs.size(), results.end());
706 results.push_back(std::move(*result));
707 stack.pop_back();
708 }
709 // The final remaining results element is the root result, return it.

Callers

nothing calls this directly

Calls 7

emplace_backMethod · 0.45
sizeMethod · 0.45
backMethod · 0.45
eraseMethod · 0.45
endMethod · 0.45
push_backMethod · 0.45
pop_backMethod · 0.45

Tested by

no test coverage detected