Blender  V3.3
deg_builder_stack.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2022 Blender Foundation. All rights reserved. */
3 
8 #pragma once
9 
10 #include "BLI_utildefines.h"
11 #include "BLI_vector.hh"
12 
13 struct ID;
14 struct bConstraint;
15 struct bPoseChannel;
16 struct ModifierData;
17 
18 namespace 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_.checkIsBuiltAndTag(id)) {
28  * return;
29  * }
30  *
31  * const BuilderStack::ScopedEntry stack_entry = stack_.trace(*id);
32  *
33  * ...
34  * }
35  */
36 class BuilderStack {
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  }
46 
47  explicit Entry(const bConstraint &constraint) : constraint_(&constraint)
48  {
49  }
50 
51  explicit Entry(const bPoseChannel &pchan) : pchan_(&pchan)
52  {
53  }
54 
55  explicit Entry(const ModifierData &modifier_data) : modifier_data_(&modifier_data)
56  {
57  }
58 
59  private:
60  friend class BuilderStack;
61 
62  const ID *id_ = nullptr;
63  const bConstraint *constraint_ = nullptr;
64  const ModifierData *modifier_data_ = nullptr;
65  const bPoseChannel *pchan_ = nullptr;
66  };
67 
69 
70  /* A helper class to provide a RAII style of tracing. It is constructed by the
71  * `BuilderStack::trace` (which pushes entry to the stack), and upon destruction of this object
72  * the corresponding entry is popped from the stack.
73  *
74  * The goal of this `ScopedEntry` is to free developers from worrying about removing entries from
75  * the stack whenever leaving a builder step scope. */
76  class ScopedEntry {
77  public:
78  /* Delete copy constructor and operator: scoped entries are only supposed to be constructed
79  * once and never copied. */
80  ScopedEntry(const ScopedEntry &other) = delete;
81  ScopedEntry &operator=(const ScopedEntry &other) = delete;
82 
83  /* Move semantic. */
84  ScopedEntry(ScopedEntry &&other) noexcept : stack_(other.stack_)
85  {
86  other.stack_ = nullptr;
87  }
89  {
90  if (this == &other) {
91  return *this;
92  }
93 
94  stack_ = other.stack_;
95  other.stack_ = nullptr;
96 
97  return *this;
98  }
99 
101  {
102  /* Stack will become nullptr when the entry was moved somewhere else. */
103  if (stack_ != nullptr) {
104  BLI_assert(!stack_->is_empty());
105  stack_->pop_last();
106  }
107  }
108 
109  private:
110  friend BuilderStack;
111 
112  explicit ScopedEntry(Stack &stack) : stack_(&stack)
113  {
114  }
115 
116  Stack *stack_;
117  };
118 
119  BuilderStack() = default;
120  ~BuilderStack() = default;
121 
122  bool is_empty() const
123  {
124  return stack_.is_empty();
125  }
126 
127  void print_backtrace(std::ostream &stream);
128 
129  template<class... Args> ScopedEntry trace(const Args &...args)
130  {
131  stack_.append_as(args...);
132 
133  return ScopedEntry(stack_);
134  }
135 
136  private:
137  Stack stack_;
138 };
139 
140 } // namespace blender::deg
#define BLI_assert(a)
Definition: BLI_assert.h:46
bool is_empty() const
Definition: BLI_vector.hh:706
void append_as(ForwardValue &&...value)
Definition: BLI_vector.hh:442
Entry(const bPoseChannel &pchan)
Entry(const bConstraint &constraint)
Entry(const ModifierData &modifier_data)
ScopedEntry(const ScopedEntry &other)=delete
ScopedEntry & operator=(const ScopedEntry &other)=delete
ScopedEntry & operator=(ScopedEntry &&other)
ScopedEntry(ScopedEntry &&other) noexcept
void print_backtrace(std::ostream &stream)
ScopedEntry trace(const Args &...args)
Definition: DNA_ID.h:368