Skip to content

Commit 0d15ad8

Browse files
committed
More work on failure handlers. Add tests
1 parent 794d353 commit 0d15ad8

13 files changed

Lines changed: 216 additions & 46 deletions

include/MGIS/Behaviour/Behaviour.hxx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,11 @@ namespace mgis::behaviour {
169169
* \param[in] h: modelling hypothesis
170170
* \return the behaviour description
171171
*/
172-
MGIS_EXPORT [[nodiscard]] std::optional<Behaviour> load(Context &,
173-
const std::string &,
174-
const std::string &,
175-
const Hypothesis) noexcept;
172+
MGIS_EXPORT [[nodiscard]] std::optional<Behaviour> load(
173+
Context &,
174+
const std::string &,
175+
const std::string &,
176+
const Hypothesis) noexcept;
176177
/*!
177178
* \brief load the description of a finite strain behaviour from a library
178179
*

include/MGIS/Behaviour/MaterialStateManager.hxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ namespace mgis::behaviour {
457457
*/
458458
MGIS_EXPORT [[nodiscard]] std::optional<MaterialStateManagerRestoreOptions>
459459
getGreedyMaterialStateManagerRestoreOptions(Context&,
460-
const Behaviour&,
460+
const Behaviour&,
461461
const H5::Group&) noexcept;
462462
/*!
463463
* \brief restore a `MaterialStateManager` from a HDF5 group

include/MGIS/Context.hxx

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,34 @@ namespace mgis {
4343
enum FailureHandlerPolicy { ABORT, RAISE };
4444
template <FailureHandlerPolicy policy>
4545
struct FailureHandler {
46-
FailureHandler(Context &c) : ctx(c) {}
46+
explicit FailureHandler(Context &c) noexcept : ctx(c) {}
4747
template <typename T>
48-
constexpr T &&operator()(std::optional<T> &&v) const {
48+
decltype(auto) operator()(T &&v) const
49+
requires((internal::OptionalTraits<T>::isSpecialized) &&
50+
(std::is_rvalue_reference_v<decltype(v)>)) {
4951
if (isInvalid(v)) {
50-
raise(this->ctx.getErrorMessage());
52+
if (policy == FailureHandlerPolicy::RAISE) {
53+
raise(this->ctx.getErrorMessage());
54+
} else {
55+
this->ctx.abort();
56+
}
5157
}
52-
return std::move(*v);
58+
return internal::OptionalTraits<T>::deference(std::move(v));
5359
}
5460
template <typename T>
55-
constexpr T &operator()(OptionalReference<T> &&v) const {
61+
decltype(auto) operator()(T &&v) const
62+
requires((!internal::OptionalTraits<T>::isSpecialized) &&
63+
(std::is_rvalue_reference_v<decltype(v)>)) {
5664
if (isInvalid(v)) {
5765
raise(this->ctx.getErrorMessage());
5866
}
59-
return *v;
67+
return std::move(v);
6068
}
69+
template <typename T>
70+
friend decltype(auto) operator|(T &&v, const FailureHandler &h) requires(
71+
std::is_rvalue_reference_v<decltype(v)>) {
72+
return h(std::move(v));
73+
} // end of operator|
6174

6275
private:
6376
//! \brief reference to the context that created the failure handler
@@ -84,13 +97,19 @@ namespace mgis {
8497
void setVerbosityLevel(const VerbosityLevel) noexcept;
8598
/*!
8699
* \return a failure handler
87-
* \param[in] policy: policy used to treat a failure
100+
* \tparam policy: policy used to treat a failure
88101
* \note the context must outlive the failure hander
89102
*/
90103
template <FailureHandlerPolicy policy = FailureHandlerPolicy::RAISE>
91-
constexpr FailureHandler<policy> getFailureHandler() {
92-
return {*this};
104+
[[nodiscard]] FailureHandler<policy> getFailureHandler() {
105+
return FailureHandler<policy>{*this};
93106
}
107+
//! \return a failure handler throwing exception in case of failure
108+
[[nodiscard]] FailureHandler<FailureHandlerPolicy::RAISE>
109+
getThrowingFailureHandler() noexcept;
110+
//! \return a failure handler aborting the execution in case of failure
111+
[[nodiscard]] FailureHandler<FailureHandlerPolicy::ABORT>
112+
getFatalFailureHandler() noexcept;
94113
/*!
95114
* \brief set the current log stream.
96115
* \param[in] s: log stream
@@ -162,6 +181,9 @@ namespace mgis {
162181
Context(const Context &) = delete;
163182
Context &operator=(Context &&) = delete;
164183
Context &operator=(const Context &) = delete;
184+
//! \brief printing the error message on the log stream and abort the
185+
//! execution
186+
[[noreturn]] void abort();
165187
//! \brief current log stream
166188
std::variant<std::monostate, std::ostream *, std::shared_ptr<std::ostream>>
167189
log_stream;

include/MGIS/Context.ixx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*!
22
* \file MGIS/Context.ixx
3-
* \brief
3+
* \brief
44
* \author Thomas Helfer
55
* \date 24/02/2026
66
*/
@@ -32,6 +32,16 @@ namespace mgis {
3232
}
3333
} // end of debug
3434

35+
inline Context::FailureHandler<Context::FailureHandlerPolicy::RAISE>
36+
Context::getThrowingFailureHandler() noexcept {
37+
return this->getFailureHandler<FailureHandlerPolicy::RAISE>();
38+
}
39+
40+
inline Context::FailureHandler<Context::FailureHandlerPolicy::ABORT>
41+
Context::getFatalFailureHandler() noexcept {
42+
return this->getFailureHandler<FailureHandlerPolicy::ABORT>();
43+
}
44+
3545
} // end of namespace mgis
3646

3747
#endif /* LIB_MGIS_CONTEXT_IXX */

include/MGIS/InvalidResult.hxx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#define LIB_MGIS_INVALIDRESULT_HXX 1
99

1010
#include <memory>
11+
#include <cassert>
1112
#include <optional>
1213

1314
namespace mgis::internal {
@@ -30,6 +31,43 @@ namespace mgis::internal {
3031
static constexpr bool isSpecialized = false;
3132
};
3233

34+
/*!
35+
* \brief metafunction allowing returning a value from an optional-like type
36+
* or void for boolean values
37+
*
38+
* - a public static constexpr data member named `isSpecialized` egal to true.
39+
* - a public static constexpr method named `deference` taking an r-value
40+
* reference to an optional-like and returning its value.
41+
*/
42+
template <typename Type>
43+
struct OptionalTraits {
44+
//
45+
static constexpr bool isSpecialized = false;
46+
};
47+
48+
//! \brief partial specialisation for boolean values
49+
template <>
50+
struct OptionalTraits<bool> {
51+
static constexpr bool isSpecialized = true;
52+
static constexpr void deference(const bool) noexcept {}
53+
};
54+
55+
//! \brief partial specialisation for std::optional values
56+
template <typename T>
57+
struct OptionalTraits<std::optional<T>> {
58+
static constexpr bool isSpecialized = true;
59+
static constexpr T &&deference(std::optional<T> &&v) noexcept
60+
requires(!std::is_pointer_v<T>) {
61+
assert(v.has_value());
62+
return std::move(*v);
63+
}
64+
static constexpr T deference(std::optional<T> &&v) noexcept
65+
requires(std::is_pointer_v<T>) {
66+
assert(v.has_value());
67+
return *v;
68+
}
69+
};
70+
3371
} // end of namespace mgis::internal
3472

3573
namespace mgis {

include/MGIS/LogStream.hxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ namespace mgis {
8585
* \param[out] out: output stream
8686
* \param[in] l: verbosity level
8787
*/
88-
MGIS_EXPORT bool resetStreamColor(std::ostream&) noexcept;
88+
MGIS_EXPORT bool resetStreamColor(std::ostream &) noexcept;
8989
/*!
9090
* \brief print a warning message
9191
*

include/MGIS/LogStream.ixx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*!
22
* \file MGIS/LogStream.ixx
3-
* \brief
3+
* \brief
44
* \author Thomas Helfer
55
* \date 24/02/2026
66
*/

include/MGIS/Utilities/OptionalReference.hxx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,15 @@ namespace mgis::internal {
168168
template <typename ValueType>
169169
struct InvalidValueTraits<mgis::OptionalReference<ValueType>> {
170170
static constexpr bool isSpecialized = true;
171-
static mgis::OptionalReference<ValueType> getValue() noexcept {
172-
return {};
171+
static mgis::OptionalReference<ValueType> getValue() noexcept { return {}; }
172+
};
173+
174+
//! \brief partial specialisation for optional reference
175+
template <typename T>
176+
struct OptionalTraits<OptionalReference<T>> {
177+
static constexpr bool isSpecialized = true;
178+
static constexpr T& deference(OptionalReference<T>&& v) noexcept {
179+
return *v;
173180
}
174181
};
175182

src/Context.cxx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ namespace mgis {
2525
this->verbosity = l;
2626
} // end of setVerbosityLevel
2727

28-
void Context::setLogStream(std::ostream& s) noexcept {
28+
void Context::setLogStream(std::ostream &s) noexcept {
2929
this->log_stream = &s;
3030
} // end of setLogStream
3131

@@ -37,7 +37,7 @@ namespace mgis {
3737
this->log_stream = s;
3838
} // end of setLogStream
3939

40-
void Context::resetLogStream() noexcept{
40+
void Context::resetLogStream() noexcept {
4141
this->log_stream = std::monostate{};
4242
}
4343

@@ -74,7 +74,17 @@ namespace mgis {
7474
return *ptr;
7575
}
7676
return ::mgis::getDefaultLogStream();
77-
} // end of log
77+
} // end of log
78+
79+
void Context::abort() {
80+
const auto msg = this->getErrorMessage();
81+
if (!msg.empty()) {
82+
this->log() << msg << std::endl;
83+
} else {
84+
this->log() << "fatal error" << std::endl;
85+
}
86+
std::abort();
87+
} // end of abort
7888

7989
Context::~Context() noexcept = default;
8090

src/LogStream.cxx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*!
22
* \file LogStream.cxx
3-
* \brief
3+
* \brief
44
* \author Thomas Helfer
55
* \date 24/02/2026
66
*/
@@ -25,7 +25,7 @@ namespace mgis {
2525
std::ostream &getDefaultLogStream() noexcept {
2626
auto &os = getGlobalLogStream();
2727
if (std::holds_alternative<std::ostream *>(os)) {
28-
auto* const ptr = std::get<std::ostream *>(os);
28+
auto *const ptr = std::get<std::ostream *>(os);
2929
if (ptr == nullptr) {
3030
return std::cout;
3131
}
@@ -51,7 +51,7 @@ namespace mgis {
5151
return {true, ""};
5252
} // end of setDefaultLogStream
5353

54-
void setDefaultLogStream(std::ostream & os) noexcept{
54+
void setDefaultLogStream(std::ostream &os) noexcept {
5555
getGlobalLogStream() = &os;
5656
} // end of setDefaultLogStream
5757

@@ -84,7 +84,6 @@ namespace mgis {
8484
setDefaultLogStream(null_stream);
8585
} // end of disableDefaultLogStream
8686

87-
8887
/*!
8988
* \class TerminalColors
9089
* \brief This class contains char sequence corresponding to colors.
@@ -167,7 +166,7 @@ namespace mgis {
167166
os.write(TerminalColors::LightBlue, sizeof(TerminalColors::LightBlue));
168167
}
169168

170-
void resetOutputColor(std::ostream & os) noexcept {
169+
void resetOutputColor(std::ostream &os) noexcept {
171170
os.write(TerminalColors::Reset, sizeof(TerminalColors::Reset));
172171
}
173172

0 commit comments

Comments
 (0)