Loading...
Searching...
No Matches
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
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"
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
25PXR_NAMESPACE_OPEN_SCOPE
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.
33class Tf_DiagnosticContainer
34{
35public:
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.
129 Iterator GetIterator() const {
130 return Iterator(*this);
131 }
132
133 // Post all diagnostics in their original order then clear.
134 TF_API void Post();
135
136private:
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,
172 std::conditional_t<
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
195PXR_NAMESPACE_CLOSE_SCOPE
196
197#endif // PXR_BASE_TF_DIAGNOSTIC_CONTAINER_H
Provide facilities for error handling in script.
Represents an object that contains error information.
Definition: error.h:32
Represents an object that contains information about a status message.
Definition: status.h:28
Represents an object that contains information about a warning.
Definition: warning.h:28