Skip to content

Commit 3aeb5ea

Browse files
authored
Merge pull request #1043 from PowerGridModel/feature/more-constexpr
Internal improvements: more constexpr + unit tests
2 parents b84d2a3 + 9997f67 commit 3aeb5ea

File tree

6 files changed

+564
-253
lines changed

6 files changed

+564
-253
lines changed

power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp

Lines changed: 97 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,16 @@
1313
#include <string>
1414

1515
namespace power_grid_model {
16-
namespace detail {
17-
inline auto to_string(std::floating_point auto x) {
18-
std::ostringstream sstr{}; // NOLINT(misc-const-correctness) // https://github.com/llvm/llvm-project/issues/57297
19-
sstr << x;
20-
return sstr.str();
21-
}
22-
inline auto to_string(std::integral auto x) { return std::to_string(x); }
23-
} // namespace detail
24-
2516
class PowerGridError : public std::exception {
2617
public:
27-
void append_msg(std::string_view msg) { msg_ = std::format("{}{}", msg_, msg); }
2818
char const* what() const noexcept final { return msg_.c_str(); }
2919

20+
protected:
21+
PowerGridError() = default;
22+
PowerGridError(std::string msg) : msg_{std::move(msg)} {}
23+
24+
void append_msg(std::string_view msg) { msg_ = std::format("{} {}", msg_, msg); }
25+
3026
private:
3127
std::string msg_;
3228
};
@@ -38,203 +34,171 @@ class InvalidArguments : public PowerGridError {
3834
std::string value;
3935
};
4036

41-
template <std::same_as<TypeValuePair>... Options> InvalidArguments(std::string_view error_msg) {
42-
append_msg(error_msg);
43-
}
37+
template <std::same_as<TypeValuePair>... Options>
38+
InvalidArguments(std::string error_msg) : PowerGridError{std::move(error_msg)} {}
4439

4540
template <std::same_as<TypeValuePair>... Options>
46-
InvalidArguments(std::string_view method, std::string_view arguments) {
47-
append_msg(std::format("{} is not implemented for {}!\n", method, arguments));
48-
}
41+
InvalidArguments(std::string_view method, std::string_view arguments)
42+
: PowerGridError{std::format("{} is not implemented for {}!\n", method, arguments)} {}
4943

5044
template <class... Options>
51-
requires(std::same_as<std::remove_cvref_t<Options>, TypeValuePair> && ...)
45+
requires((std::same_as<std::remove_cvref_t<Options>, TypeValuePair> && ...) && sizeof...(Options) > 0)
5246
InvalidArguments(std::string_view method, Options const&... options)
5347
: InvalidArguments{method, "the following combination of options"} {
54-
(append_msg(std::format(" {}: {}\n", options.name, options.value)), ...);
48+
(append_msg(std::format("{}: {}\n", options.name, options.value)), ...);
5549
}
5650
};
5751

5852
class MissingCaseForEnumError : public InvalidArguments {
5953
public:
6054
template <typename T>
6155
MissingCaseForEnumError(std::string_view method, T const& value)
62-
: InvalidArguments{method,
63-
std::format("{} #{}", typeid(T).name(), detail::to_string(static_cast<IntS>(value)))} {}
56+
: InvalidArguments{method, std::format("{} #{:d}", typeid(T).name(), static_cast<IntS>(value))} {}
6457
};
6558

6659
class ConflictVoltage : public PowerGridError {
6760
public:
68-
ConflictVoltage(ID id, ID id1, ID id2, double u1, double u2) {
69-
append_msg(std::format(
70-
"Conflicting voltage for line {}\n voltage at from node {} is {}\n voltage at to node {} is {}\n",
71-
detail::to_string(id), detail::to_string(id1), detail::to_string(u1), detail::to_string(id2),
72-
detail::to_string(u2)));
73-
}
61+
ConflictVoltage(ID id, ID id1, ID id2, double u1, double u2)
62+
: PowerGridError{std::format(
63+
"Conflicting voltage for line {}\n voltage at from node {} is {}\n voltage at to node {} is {}\n", id,
64+
id1, u1, id2, u2)} {}
7465
};
7566

7667
class InvalidBranch : public PowerGridError {
7768
public:
78-
InvalidBranch(ID branch_id, ID node_id) {
79-
append_msg(std::format("Branch {} has the same from- and to-node {},\n This is not allowed!\n",
80-
detail::to_string(branch_id), detail::to_string(node_id)));
81-
}
69+
InvalidBranch(ID branch_id, ID node_id)
70+
: PowerGridError{std::format("Branch {} has the same from- and to-node {},\n This is not allowed!\n", branch_id,
71+
node_id)} {}
8272
};
8373

8474
class InvalidBranch3 : public PowerGridError {
8575
public:
86-
InvalidBranch3(ID branch3_id, ID node_1_id, ID node_2_id, ID node_3_id) {
87-
append_msg(std::format(
88-
"Branch3 {} is connected to the same node at least twice. Node 1/2/3: {}/{}/{},\n This is not allowed!\n",
89-
detail::to_string(branch3_id), detail::to_string(node_1_id), detail::to_string(node_2_id),
90-
detail::to_string(node_3_id)));
91-
}
76+
InvalidBranch3(ID branch3_id, ID node_1_id, ID node_2_id, ID node_3_id)
77+
: PowerGridError{std::format(
78+
"Branch3 {} is connected to the same node at least twice. Node 1/2/3: {}/{}/{},\n This is not allowed!\n",
79+
branch3_id, node_1_id, node_2_id, node_3_id)} {}
9280
};
9381

9482
class InvalidTransformerClock : public PowerGridError {
9583
public:
96-
InvalidTransformerClock(ID id, IntS clock) {
97-
append_msg(std::format("Invalid clock for transformer {}, clock {}\n", detail::to_string(id),
98-
detail::to_string(clock)));
99-
}
84+
InvalidTransformerClock(ID id, IntS clock)
85+
: PowerGridError{std::format("Invalid clock for transformer {}, clock {}\n", id, clock)} {}
10086
};
10187

10288
class SparseMatrixError : public PowerGridError {
10389
public:
104-
SparseMatrixError(Idx err, std::string_view msg = "") {
105-
append_msg(
106-
std::format("Sparse matrix error with error code #{} (possibly singular)\n", detail::to_string(err)));
107-
if (!msg.empty()) {
108-
append_msg(std::format("{}\n", msg));
109-
}
110-
append_msg("If you get this error from state estimation, ");
111-
append_msg("it usually means the system is not fully observable, i.e. not enough measurements.");
112-
}
113-
SparseMatrixError() {
114-
append_msg("Sparse matrix error, possibly singular matrix!\n"
115-
"If you get this error from state estimation, "
116-
"it might mean the system is not fully observable, i.e. not enough measurements.\n"
117-
"It might also mean that you are running into a corner case where PGM cannot resolve yet."
118-
"See https://github.com/PowerGridModel/power-grid-model/issues/864.");
119-
}
90+
SparseMatrixError(Idx err, std::string_view msg = "")
91+
: PowerGridError{std::format(
92+
"Sparse matrix error with error code #{} (possibly singular)\n{}If you get this error from state "
93+
"estimation, it usually means the system is not fully observable, i.e. not enough measurements.",
94+
err, msg.empty() ? "" : std::format("{}\n", msg))} {}
95+
SparseMatrixError()
96+
: PowerGridError{"Sparse matrix error, possibly singular matrix!\n"
97+
"If you get this error from state estimation, "
98+
"it might mean the system is not fully observable, i.e. not enough measurements.\n"
99+
"It might also mean that you are running into a corner case where PGM cannot resolve yet."
100+
"See https://github.com/PowerGridModel/power-grid-model/issues/864."} {}
120101
};
121102

122103
class NotObservableError : public PowerGridError {
123104
public:
124-
NotObservableError(std::string_view msg = "") {
125-
append_msg("Not enough measurements available for state estimation.\n");
126-
if (!msg.empty()) {
127-
append_msg(std::format("{}\n", msg));
128-
}
129-
}
105+
NotObservableError() : PowerGridError{"Not enough measurements available for state estimation.\n"} {}
106+
NotObservableError(std::string_view msg)
107+
: PowerGridError{std::format("Not enough measurements available for state estimation.\n{}\n", msg)} {}
130108
};
131109

132110
class IterationDiverge : public PowerGridError {
133111
public:
134-
IterationDiverge() = default;
135-
IterationDiverge(Idx num_iter, double max_dev, double err_tol) {
136-
append_msg(
137-
std::format("Iteration failed to converge after {} iterations! Max deviation: {}, error tolerance: {}.\n",
138-
detail::to_string(num_iter), detail::to_string(max_dev), detail::to_string(err_tol)));
139-
}
112+
IterationDiverge(std::string msg) : PowerGridError{std::move(msg)} {}
113+
IterationDiverge(Idx num_iter, double max_dev, double err_tol)
114+
: PowerGridError{
115+
std::format("Iteration failed to converge after {} iterations! Max deviation: {}, error tolerance: {}.\n",
116+
num_iter, max_dev, err_tol)} {}
140117
};
141118

142119
class MaxIterationReached : public IterationDiverge {
143120
public:
144-
MaxIterationReached(std::string const& msg = "") {
145-
append_msg(std::format("Maximum number of iterations reached {}\n", msg));
146-
}
121+
MaxIterationReached(std::string_view msg = "")
122+
: IterationDiverge{std::format("Maximum number of iterations reached! {}\n", msg)} {}
147123
};
148124

149125
class ConflictID : public PowerGridError {
150126
public:
151-
explicit ConflictID(ID id) { append_msg(std::format("Conflicting id detected: {}\n", detail::to_string(id))); }
127+
explicit ConflictID(ID id) : PowerGridError{std::format("Conflicting id detected: {}\n", id)} {}
152128
};
153129

154130
class IDNotFound : public PowerGridError {
155131
public:
156-
explicit IDNotFound(ID id) { append_msg(std::format("The id cannot be found: {}\n", detail::to_string(id))); }
132+
explicit IDNotFound(ID id) : PowerGridError{std::format("The id cannot be found: {}\n", id)} {}
157133
};
158134
class Idx2DNotFound : public PowerGridError {
159135
public:
160-
explicit Idx2DNotFound(Idx2D id) {
161-
append_msg(std::format("The idx 2d cannot be found: {{{}, {}}}.\n", detail::to_string(id.group),
162-
detail::to_string(id.pos)));
163-
}
136+
explicit Idx2DNotFound(Idx2D id)
137+
: PowerGridError{std::format("The idx 2d cannot be found: {{{}, {}}}.\n", id.group, id.pos)} {}
164138
};
165139

166140
class InvalidMeasuredObject : public PowerGridError {
167141
public:
168-
InvalidMeasuredObject(std::string_view object, std::string_view sensor) {
169-
append_msg(std::format("{} measurement is not supported for object of type {}", sensor, object));
170-
}
142+
InvalidMeasuredObject(std::string_view object, std::string_view sensor)
143+
: PowerGridError{std::format("{} measurement is not supported for object of type {}", sensor, object)} {}
171144
};
172145

173146
class InvalidMeasuredTerminalType : public PowerGridError {
174147
public:
175-
InvalidMeasuredTerminalType(MeasuredTerminalType const terminal_type, std::string_view sensor) {
176-
append_msg(std::format("{} measurement is not supported for object of type {}", sensor,
177-
detail::to_string(static_cast<IntS>(terminal_type))));
178-
}
148+
InvalidMeasuredTerminalType(MeasuredTerminalType const terminal_type, std::string_view sensor)
149+
: PowerGridError{std::format("{} measurement is not supported for object of type {}", sensor,
150+
static_cast<IntS>(terminal_type))} {}
179151
};
180152

181153
class InvalidRegulatedObject : public PowerGridError {
182154
public:
183-
InvalidRegulatedObject(std::string_view object, std::string_view regulator) {
184-
append_msg(std::format("{} regulator is not supported for object of type {}", regulator, object));
185-
}
186-
InvalidRegulatedObject(ID id, std::string_view regulator) {
187-
append_msg(
188-
std::format("{} regulator is not supported for object with ID {}", regulator, detail::to_string(id)));
189-
}
155+
InvalidRegulatedObject(std::string_view object, std::string_view regulator)
156+
: PowerGridError{std::format("{} regulator is not supported for object of type {}", regulator, object)} {}
157+
InvalidRegulatedObject(ID id, std::string_view regulator)
158+
: PowerGridError{std::format("{} regulator is not supported for object with ID {}", regulator, id)} {}
190159
};
191160

192161
class DuplicativelyRegulatedObject : public PowerGridError {
193162
public:
194-
DuplicativelyRegulatedObject() {
195-
append_msg("There are objects regulated by more than one regulator. Maximum one regulator is allowed.");
196-
}
163+
DuplicativelyRegulatedObject()
164+
: PowerGridError{"There are objects regulated by more than one regulator. Maximum one regulator is allowed."} {}
197165
};
198166

199167
class AutomaticTapCalculationError : public PowerGridError {
200168
public:
201-
AutomaticTapCalculationError(ID id) {
202-
append_msg(
203-
std::format("Automatic tap changing regulator with tap_side at LV side is not supported. Found at id {}",
204-
detail::to_string(id)));
205-
}
169+
AutomaticTapCalculationError(ID id)
170+
: PowerGridError{std::format(
171+
"Automatic tap changing regulator with tap_side at LV side is not supported. Found at id {}", id)} {}
206172
};
207173

208174
class AutomaticTapInputError : public PowerGridError {
209175
public:
210-
AutomaticTapInputError(std::string_view msg) {
211-
append_msg(std::format("Automatic tap changer has invalid configuration. {}", msg));
212-
}
176+
AutomaticTapInputError(std::string_view msg)
177+
: PowerGridError{std::format("Automatic tap changer has invalid configuration. {}", msg)} {}
213178
};
214179

215180
class IDWrongType : public PowerGridError {
216181
public:
217-
explicit IDWrongType(ID id) {
218-
append_msg(std::format("Wrong type for object with id {}\n", detail::to_string(id)));
219-
}
182+
explicit IDWrongType(ID id) : PowerGridError{std::format("Wrong type for object with id {}\n", id)} {}
220183
};
221184

222185
class ConflictingAngleMeasurementType : public PowerGridError {
223186
public:
224-
ConflictingAngleMeasurementType(std::string_view msg) {
225-
append_msg(std::format("Conflicting angle measurement type. {}", msg));
226-
}
187+
ConflictingAngleMeasurementType(std::string_view msg)
188+
: PowerGridError{std::format("Conflicting angle measurement type. {}", msg)} {}
227189
};
228190

229191
class CalculationError : public PowerGridError {
230192
public:
231-
explicit CalculationError(std::string_view msg) { append_msg(msg); }
193+
explicit CalculationError(std::string msg) : PowerGridError{std::move(msg)} {}
232194
};
233195

234196
class BatchCalculationError : public CalculationError {
235197
public:
236-
BatchCalculationError(std::string_view msg, IdxVector failed_scenarios, std::vector<std::string> err_msgs)
237-
: CalculationError(msg), failed_scenarios_{std::move(failed_scenarios)}, err_msgs_(std::move(err_msgs)) {}
198+
BatchCalculationError(std::string msg, IdxVector failed_scenarios, std::vector<std::string> err_msgs)
199+
: CalculationError{std::move(msg)},
200+
failed_scenarios_{std::move(failed_scenarios)},
201+
err_msgs_(std::move(err_msgs)) {}
238202

239203
IdxVector const& failed_scenarios() const { return failed_scenarios_; }
240204

@@ -247,46 +211,40 @@ class BatchCalculationError : public CalculationError {
247211

248212
class InvalidCalculationMethod : public CalculationError {
249213
public:
250-
InvalidCalculationMethod() : CalculationError("The calculation method is invalid for this calculation!") {}
214+
InvalidCalculationMethod() : CalculationError{"The calculation method is invalid for this calculation!"} {}
251215
};
252216

253217
class InvalidShortCircuitType : public PowerGridError {
254218
public:
255-
explicit InvalidShortCircuitType(FaultType short_circuit_type) {
256-
append_msg(std::format("The short circuit type ({}) is invalid!\n",
257-
detail::to_string(static_cast<IntS>(short_circuit_type))));
258-
}
259-
InvalidShortCircuitType(bool sym, FaultType short_circuit_type) {
260-
append_msg(std::format("The short circuit type ({}) does not match the calculation type (symmetric={})\n",
261-
detail::to_string(static_cast<IntS>(short_circuit_type)),
262-
detail::to_string(static_cast<int>(sym))));
263-
}
219+
explicit InvalidShortCircuitType(FaultType short_circuit_type)
220+
: PowerGridError{
221+
std::format("The short circuit type ({}) is invalid!\n", static_cast<IntS>(short_circuit_type))} {}
222+
InvalidShortCircuitType(bool sym, FaultType short_circuit_type)
223+
: PowerGridError{std::format("The short circuit type ({}) does not match the calculation type (symmetric={})\n",
224+
static_cast<IntS>(short_circuit_type), static_cast<int>(sym))} {}
264225
};
265226

266227
class InvalidShortCircuitPhases : public PowerGridError {
267228
public:
268-
InvalidShortCircuitPhases(FaultType short_circuit_type, FaultPhase short_circuit_phases) {
269-
append_msg(std::format("The short circuit phases ({}) do not match the short circuit type ({})\n",
270-
detail::to_string(static_cast<IntS>(short_circuit_phases)),
271-
detail::to_string(static_cast<IntS>(short_circuit_type))));
272-
}
229+
InvalidShortCircuitPhases(FaultType short_circuit_type, FaultPhase short_circuit_phases)
230+
: PowerGridError{std::format("The short circuit phases ({}) do not match the short circuit type ({})\n",
231+
static_cast<IntS>(short_circuit_phases), static_cast<IntS>(short_circuit_type))} {}
273232
};
274233

275234
class InvalidShortCircuitPhaseOrType : public PowerGridError {
276235
public:
277-
InvalidShortCircuitPhaseOrType() {
278-
append_msg("During one calculation the short circuit types phases should be similar for all faults\n");
279-
}
236+
InvalidShortCircuitPhaseOrType()
237+
: PowerGridError{"During one calculation the short circuit types phases should be similar for all faults\n"} {}
280238
};
281239

282240
class SerializationError : public PowerGridError {
283241
public:
284-
explicit SerializationError(std::string_view msg) { append_msg(msg); }
242+
explicit SerializationError(std::string msg) : PowerGridError{std::move(msg)} {}
285243
};
286244

287245
class DatasetError : public PowerGridError {
288246
public:
289-
explicit DatasetError(std::string_view msg) { append_msg(std::format("Dataset error: {}", msg)); }
247+
explicit DatasetError(std::string_view msg) : PowerGridError{std::format("Dataset error: {}", msg)} {}
290248
};
291249

292250
class ExperimentalFeature : public InvalidArguments {
@@ -295,25 +253,24 @@ class ExperimentalFeature : public InvalidArguments {
295253

296254
class NotImplementedError : public PowerGridError {
297255
public:
298-
NotImplementedError() { append_msg("Function not yet implemented"); }
256+
NotImplementedError() : PowerGridError{"Function not yet implemented"} {}
299257
};
300258

301259
class UnreachableHit : public PowerGridError {
302260
public:
303-
UnreachableHit(std::string_view method, std::string_view reason_for_assumption) {
304-
append_msg(std::format("Unreachable code hit when executing {}.\n The following assumption for unreachability "
305-
"was not met: {}.\n This may be a bug in the library\n",
306-
method, reason_for_assumption));
307-
}
261+
UnreachableHit(std::string_view method, std::string_view reason_for_assumption)
262+
: PowerGridError{
263+
std::format("Unreachable code hit when executing {}.\n The following assumption for unreachability "
264+
"was not met: {}.\n This may be a bug in the library\n",
265+
method, reason_for_assumption)} {}
308266
};
309267

310268
class TapSearchStrategyIncompatibleError : public InvalidArguments {
311269
public:
312270
template <typename T1, typename T2>
313271
TapSearchStrategyIncompatibleError(std::string_view method, T1 const& value1, T2 const& value2)
314-
: InvalidArguments{method, std::format("{} #{} and {} #{}", typeid(T1).name(),
315-
detail::to_string(static_cast<IntS>(value1)), typeid(T2).name(),
316-
detail::to_string(static_cast<IntS>(value2)))} {}
272+
: InvalidArguments{method, std::format("{} #{} and {} #{}", typeid(T1).name(), static_cast<IntS>(value1),
273+
typeid(T2).name(), static_cast<IntS>(value2))} {}
317274
};
318275

319276
} // namespace power_grid_model

0 commit comments

Comments
 (0)