Blender V5.0
deg_builder_stack.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#pragma once
10
11#include "BLI_vector.hh"
12
13struct ID;
14struct bConstraint;
15struct bPoseChannel;
16struct ModifierData;
17
18namespace blender::deg {
19
20/* This class keeps track of the builder calls nesting, allowing to unroll them back and provide a
21 * clue about how the builder made it to its current state.
22 *
23 * The tracing is based on the builder giving a trace clues to the stack. Typical usage is:
24 *
25 * void DepsgraphRelationBuilder::my_id_builder(ID *id)
26 * {
27 * if (built_map_.check_is_built_and_tag(id)) {
28 * return;
29 * }
30 *
31 * const BuilderStack::ScopedEntry stack_entry = stack_.trace(*id);
32 *
33 * ...
34 * }
35 */
37 public:
38 /* Entry of the backtrace.
39 * A cheap-to-construct wrapper which allows to gather a proper string representation whenever
40 * the stack is printed. */
41 class Entry {
42 public:
43 explicit Entry(const ID &id) : id_(&id) {}
44
45 explicit Entry(const bConstraint &constraint) : constraint_(&constraint) {}
46
47 explicit Entry(const bPoseChannel &pchan) : pchan_(&pchan) {}
48
49 explicit Entry(const ModifierData &modifier_data) : modifier_data_(&modifier_data) {}
50
51 private:
52 friend class BuilderStack;
53
54 const ID *id_ = nullptr;
55 const bConstraint *constraint_ = nullptr;
56 const ModifierData *modifier_data_ = nullptr;
57 const bPoseChannel *pchan_ = nullptr;
58 };
59
61
62 /* A helper class to provide a RAII style of tracing. It is constructed by the
63 * `BuilderStack::trace` (which pushes entry to the stack), and upon destruction of this object
64 * the corresponding entry is popped from the stack.
65 *
66 * The goal of this `ScopedEntry` is to free developers from worrying about removing entries from
67 * the stack whenever leaving a builder step scope. */
69 public:
70 /* Delete copy constructor and operator: scoped entries are only supposed to be constructed
71 * once and never copied. */
72 ScopedEntry(const ScopedEntry &other) = delete;
73 ScopedEntry &operator=(const ScopedEntry &other) = delete;
74
75 /* Move semantic. */
76 ScopedEntry(ScopedEntry &&other) noexcept : stack_(other.stack_)
77 {
78 other.stack_ = nullptr;
79 }
81 {
82 if (this == &other) {
83 return *this;
84 }
85
86 stack_ = other.stack_;
87 other.stack_ = nullptr;
88
89 return *this;
90 }
91
93 {
94 /* Stack will become nullptr when the entry was moved somewhere else. */
95 if (stack_ != nullptr) {
96 BLI_assert(!stack_->is_empty());
97 stack_->pop_last();
98 }
99 }
100
101 private:
102 friend BuilderStack;
103
104 explicit ScopedEntry(Stack &stack) : stack_(&stack) {}
105
106 Stack *stack_;
107 };
108
109 BuilderStack() = default;
110 ~BuilderStack() = default;
111
112 bool is_empty() const
113 {
114 return stack_.is_empty();
115 }
116
117 void print_backtrace(std::ostream &stream);
118
119 template<class... Args> ScopedEntry trace(const Args &...args)
120 {
121 stack_.append_as(args...);
122
123 return ScopedEntry(stack_);
124 }
125
126 private:
127 Stack stack_;
128};
129
130} // namespace blender::deg
#define BLI_assert(a)
Definition BLI_assert.h:46
Entry(const bPoseChannel &pchan)
Entry(const bConstraint &constraint)
Entry(const ModifierData &modifier_data)
ScopedEntry(const ScopedEntry &other)=delete
ScopedEntry(ScopedEntry &&other) noexcept
ScopedEntry & operator=(ScopedEntry &&other)
ScopedEntry & operator=(const ScopedEntry &other)=delete
void print_backtrace(std::ostream &stream)
ScopedEntry trace(const Args &...args)
Definition DNA_ID.h:414