HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
diagnosticContainer.h
Go to the documentation of this file.
1 //
2 // Copyright 2026 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_BASE_TF_DIAGNOSTIC_CONTAINER_H
8 #define PXR_BASE_TF_DIAGNOSTIC_CONTAINER_H
9 
10 /// \file tf/diagnosticContainer.h
11 
12 #include "pxr/pxr.h"
13 #include "pxr/base/tf/api.h"
14 #include "pxr/base/tf/error.h"
15 #include "pxr/base/tf/status.h"
16 #include "pxr/base/tf/tryInvoke.h"
17 #include "pxr/base/tf/warning.h"
18 
19 #include <functional>
20 #include <optional>
21 #include <string>
22 #include <type_traits>
23 #include <vector>
24 
26 
27 // Internal class that accumulates \c TfError, \c TfWarning, and \c TfStatus
28 // diagnostics in the order they were issued, and provides iteration,
29 // predicate-based query and erasure, and re-posting.
30 //
31 // This class is an implementation detail shared by \c TfDiagnosticTrap and \c
32 // TfDiagnosticTransport and is not intended for direct use.
34 {
35 public:
36  // A stateful cursor over the diagnostics in a \c Tf_DiagnosticContainer.
37  // Advance by calling \c Next() with a callable -- the iterator will advance
38  // to the next diagnostic the callable can accept, invoke it, and return the
39  // result. The callable may be changed between \c Next() calls, allowing
40  // different operations to be interleaved over a single pass.
41  //
42  // \c Next() returns a truthy value if it found and invoked the callable,
43  // and a falsy value when the container is exhausted. Specifically: - If
44  // the callable returns void, \c Next() returns \c bool - Otherwise, \c
45  // Next() returns \c std::optional<ReturnType>
46  struct Iterator {
47  explicit Iterator(Tf_DiagnosticContainer const &container)
48  : _container(container) {}
49 
50  template <class Fn>
51  auto Next(Fn &&fn)
52  {
53  using RetT = typename _IterNextReturnType<Fn>::Type;
54 
55  while (_orderIndex < _container._order.size()) {
56  char c = _container._order[_orderIndex++];
57  switch (c) {
58  case 'E':
59  if (auto r = TfTryInvoke<RetT>(
60  fn, _container._errors[_errorIndex++])) {
61  return r;
62  }
63  break;
64  case 'W':
65  if (auto r = TfTryInvoke<RetT>(
66  fn, _container._warnings[_warningIndex++])) {
67  return r;
68  }
69  break;
70  case 'S':
71  if (auto r = TfTryInvoke<RetT>(
72  fn, _container._statuses[_statusIndex++])) {
73  return r;
74  }
75  break;
76  }
77  }
78  return TfNotInvoked<RetT>();
79  }
80 
81  private:
82  Tf_DiagnosticContainer const &_container;
83  size_t _orderIndex = 0;
84  size_t _errorIndex = 0;
85  size_t _warningIndex = 0;
86  size_t _statusIndex = 0;
87  };
88 
89  // Return true if no diagnostics have been accumulated.
90  bool IsEmpty() const { return _order.empty(); }
91 
92  // Return the accumulated errors.
93  std::vector<TfError> const& GetErrors() const { return _errors; }
94 
95  // Return the accumulated warnings.
96  std::vector<TfWarning> const& GetWarnings() const { return _warnings; }
97 
98  // Return the accumulated status messages.
99  std::vector<TfStatus> const& GetStatuses() const { return _statuses; }
100 
101  // Mutation
102 
103  void Append(TfError const &e) {
104  _errors.push_back(e);
105  _order.push_back('E');
106  }
107 
108  void Append(TfWarning const &w) {
109  _warnings.push_back(w);
110  _order.push_back('W');
111  }
112 
113  void Append(TfStatus const &s) {
114  _statuses.push_back(s);
115  _order.push_back('S');
116  }
117 
118  // Discard all accumulated diagnostics.
119  void Clear() {
120  _errors.clear();
121  _warnings.clear();
122  _statuses.clear();
123  _order.clear();
124  }
125 
126  // Iteration
127 
128  // Return an iterator over this container's diagnostics.
130  return Iterator(*this);
131  }
132 
133  // Post all diagnostics in their original order then clear.
134  TF_API void Post();
135 
136 private:
137  // These are required to avoid instantiating invoke_result_t when Invocable
138  // is false. We can't use std::conditional_t because it always instantiates
139  // both branches of the condition.
140  template <class Fn, class Arg, bool Invocable>
141  struct _SafeInvokeResult {
142  using type = void;
143  };
144 
145  template <class Fn, class Arg>
146  struct _SafeInvokeResult<Fn, Arg, true> {
147  using type = std::invoke_result_t<Fn, Arg>;
148  };
149 
150  template <class Fn>
151  struct _IterNextReturnType {
152  static constexpr bool _ErrInvocable =
153  std::is_invocable_v<Fn, TfError const &>;
154  static constexpr bool _WarnInvocable =
155  std::is_invocable_v<Fn, TfWarning const &>;
156  static constexpr bool _StatInvocable =
157  std::is_invocable_v<Fn, TfStatus const &>;
158 
159  static_assert(_ErrInvocable || _WarnInvocable || _StatInvocable,
160  "Callable must be invocable with at least one of "
161  "TfError, TfWarning, or TfStatus");
162 
163  using _ErrResult = typename _SafeInvokeResult<
164  Fn, TfError const &, _ErrInvocable>::type;
165  using _WarnResult = typename _SafeInvokeResult<
166  Fn, TfWarning const &, _WarnInvocable>::type;
167  using _StatResult = typename _SafeInvokeResult<
168  Fn, TfStatus const &, _StatInvocable>::type;
169 
170  using Type = std::conditional_t<
171  _ErrInvocable, _ErrResult,
173  _WarnInvocable, _WarnResult, _StatResult>>;
174 
175  static_assert(!_ErrInvocable || !_WarnInvocable ||
176  std::is_same_v<_ErrResult, _WarnResult>,
177  "Callable must return the same type for all "
178  "invocable diagnostic types");
179  static_assert(!_ErrInvocable || !_StatInvocable ||
180  std::is_same_v<_ErrResult, _StatResult>,
181  "Callable must return the same type for all "
182  "invocable diagnostic types");
183  static_assert(!_WarnInvocable || !_StatInvocable ||
184  std::is_same_v<_WarnResult, _StatResult>,
185  "Callable must return the same type for all "
186  "invocable diagnostic types");
187  };
188 
189  std::vector<TfError> _errors;
190  std::vector<TfWarning> _warnings;
191  std::vector<TfStatus> _statuses;
192  std::string _order;
193 };
194 
196 
197 #endif // PXR_BASE_TF_DIAGNOSTIC_CONTAINER_H
type
Definition: core.h:556
#define TF_API
Definition: api.h:23
void
Definition: png.h:1083
typename std::conditional< B, T, F >::type conditional_t
Definition: core.h:266
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
std::vector< TfWarning > const & GetWarnings() const
GLdouble s
Definition: glad.h:3009
std::vector< TfStatus > const & GetStatuses() const
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
Iterator GetIterator() const
std::vector< TfError > const & GetErrors() const
Definition: error.h:32
void Append(TfStatus const &s)
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:857
void Append(TfError const &e)
GLboolean r
Definition: glcorearb.h:1222
Iterator(Tf_DiagnosticContainer const &container)
void Append(TfWarning const &w)