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