Skip to content

Commit 4bd0915

Browse files
committed
Add simple support for log messages. Start working the a failure handler
1 parent d4c11d8 commit 4bd0915

6 files changed

Lines changed: 177 additions & 3 deletions

File tree

include/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
mgis_header(MGIS Config-c.h)
22
mgis_header(MGIS Config.hxx)
3+
mgis_header(MGIS LogStream.hxx)
4+
mgis_header(MGIS LogStream.ixx)
35
mgis_header(MGIS AbstractErrorHandler.hxx)
46
mgis_header(MGIS Contract.hxx)
57
mgis_header(MGIS Contract.ixx)
68
mgis_header(MGIS Context.hxx)
9+
mgis_header(MGIS Context.ixx)
710
mgis_header(MGIS ErrorBacktrace.hxx)
811
mgis_header(MGIS InvalidResult.hxx)
912
mgis_header(MGIS InvalidResult.ixx)

include/MGIS/Context.hxx

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77
#ifndef LIB_MGIS_CONTEXT_HXX
88
#define LIB_MGIS_CONTEXT_HXX 1
99

10+
#include <memory>
11+
#include <variant>
1012
#include <ostream>
1113
#include "MGIS/Config.hxx"
14+
#include "MGIS/Raise.hxx"
15+
#include "MGIS/LogStream.hxx"
1216
#include "MGIS/VerbosityLevel.hxx"
1317
#include "MGIS/ErrorBacktrace.hxx"
1418

@@ -33,9 +37,32 @@ namespace mgis {
3337
* to debug a specific rm.
3438
*
3539
* The default logging stream is the one returned by the
36-
* `mgis::getLogStream` free function.
40+
* `mgis::getDefaultLogStream` free function.
3741
*/
3842
struct MGIS_EXPORT Context final : public ErrorBacktrace {
43+
enum FailureHandlerPolicy { ABORT, RAISE };
44+
template <FailureHandlerPolicy policy>
45+
struct FailureHandler {
46+
FailureHandler(Context &c) : ctx(c) {}
47+
template <typename T>
48+
constexpr T &&operator()(std::optional<T> &&v) const {
49+
if (isInvalid(v)) {
50+
raise(this->ctx.getErrorMessage());
51+
}
52+
return std::move(*v);
53+
}
54+
template <typename T>
55+
constexpr T &operator()(OptionalReference<T> &&v) const {
56+
if (isInvalid(v)) {
57+
raise(this->ctx.getErrorMessage());
58+
}
59+
return *v;
60+
}
61+
62+
private:
63+
//! \brief reference to the context that created the failure handler
64+
Context &ctx;
65+
};
3966
/*!
4067
* \brief default constructor
4168
*
@@ -55,6 +82,77 @@ namespace mgis {
5582
* \param[in] l: the new verbose level
5683
*/
5784
void setVerbosityLevel(const VerbosityLevel) noexcept;
85+
/*!
86+
* \return a failure handler
87+
* \param[in] policy: policy used to treat a failure
88+
* \note the context must outlive the failure hander
89+
*/
90+
template <FailureHandlerPolicy policy = FailureHandlerPolicy::RAISE>
91+
constexpr FailureHandler<policy> getFailureHandler() {
92+
return {*this};
93+
}
94+
/*!
95+
* \brief set the current log stream.
96+
* \param[in] s: log stream
97+
* \note the user is responsible for ensuring that the given object is alive
98+
*/
99+
void setLogStream(std::ostream &) noexcept;
100+
/*!
101+
* \brief set the current log stream.
102+
* \param[in] s: log stream
103+
* \note if an empty shared pointer is given, the log stream is reset to the
104+
* default one, i.e. the one returned by the `mgis::getDefaultLogStream`
105+
* free function.
106+
*/
107+
void setLogStream(std::shared_ptr<std::ostream>) noexcept;
108+
//! \brief reset the default log stream
109+
void resetLogStream() noexcept;
110+
/*!
111+
* \brief disable the default log stream
112+
*
113+
* \note logging is disable by creating a no-op output stream
114+
*/
115+
void disableLogStream() noexcept;
116+
/*!
117+
* \return the current log stream
118+
*
119+
* \note if no log stream is set, the default one is returned. See
120+
* `getDefaultLogStream` for details.
121+
*/
122+
[[nodiscard]] std::ostream &log() noexcept;
123+
/*!
124+
* \brief display the given arguments in the log stream if the current
125+
* verbosity level (as returned by the `getVerbosityLevel` method) is
126+
* greater than a minimal one.
127+
*
128+
* \tparam Args: types of the arguments
129+
* \return the current log stream
130+
* \param[in] l: minimal verbosity level
131+
* \param[in] args: streamed object
132+
* \note note nothing is displayed if the current verbositiy
133+
* level is below the first argument
134+
*/
135+
template <typename... Args>
136+
std::ostream &log(const VerbosityLevel, Args &&...) noexcept;
137+
/*!
138+
* \brief a simple wrapper around the `log` method to print a warning
139+
*
140+
* \tparam Args: types of the arguments
141+
* \param[in] args: streamed object
142+
*/
143+
template <typename... Args>
144+
void warning(Args &&...) noexcept;
145+
/*!
146+
* \brief a simple wrapper around the `log` method which sets the minimun
147+
* verbosity level to `verboseDebug`
148+
*
149+
* \tparam Args: types of the arguments
150+
* \param[in] args: streamed object
151+
* \note note nothing is displayed if the current verbositiy level is below
152+
* `verboseDebug`
153+
*/
154+
template <typename... Args>
155+
void debug(Args &&...) noexcept;
58156
//! \brief destructor
59157
~Context() noexcept override;
60158

@@ -64,13 +162,19 @@ namespace mgis {
64162
Context(const Context &) = delete;
65163
Context &operator=(Context &&) = delete;
66164
Context &operator=(const Context &) = delete;
165+
//! \brief current log stream
166+
std::variant<std::monostate, std::ostream *, std::shared_ptr<std::ostream>>
167+
log_stream;
67168
/*!
68-
* \brief local level of verbosity, initialize by the global option
69-
* returned by the `getVerbosityLevel` function
169+
* \brief local level of verbosity, initialize by the
170+
* global option returned by the `getVerbosityLevel`
171+
* function
70172
*/
71173
VerbosityLevel verbosity;
72174
}; // end of class Context
73175

74176
} // end of namespace mgis
75177

178+
#include "MGIS/Context.ixx"
179+
76180
#endif /* LIB_MGIS_CONTEXT_HXX */

include/MGIS/VerbosityLevel.hxx

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

1010
#include <string>
11+
#include <iosfwd>
1112
#include <optional>
1213
#include <string_view>
1314
#include "MGIS/Config.hxx"

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ set(MFrontGenericInterface_SOURCES)
22
list(APPEND MFrontGenericInterface_SOURCES
33
Raise.cxx
44
VerbosityLevel.cxx
5+
LogStream.cxx
56
ErrorBacktrace.cxx
67
Context.cxx
78
Contract.cxx

src/Context.cxx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
* \date 08/02/2023
55
*/
66

7+
#include <fstream>
8+
#include "MGIS/LogStream.hxx"
79
#include "MGIS/Context.hxx"
810

911
namespace mgis {
@@ -23,6 +25,57 @@ namespace mgis {
2325
this->verbosity = l;
2426
} // end of setVerbosityLevel
2527

28+
void Context::setLogStream(std::ostream& s) noexcept {
29+
this->log_stream = &s;
30+
} // end of setLogStream
31+
32+
void Context::setLogStream(std::shared_ptr<std::ostream> s) noexcept {
33+
if (s.get() == nullptr) {
34+
this->resetLogStream();
35+
return;
36+
}
37+
this->log_stream = s;
38+
} // end of setLogStream
39+
40+
void Context::resetLogStream() noexcept{
41+
this->log_stream = std::monostate{};
42+
}
43+
44+
void Context::disableLogStream() noexcept {
45+
/*!
46+
* \brief a buffer which allows to create no-op output streams, i.e. streams
47+
* that does not nothing.
48+
*
49+
* see
50+
* https://stackoverflow.com/questions/11826554/standard-no-op-output-stream
51+
* for details
52+
*/
53+
struct NullBuffer : public std::streambuf {
54+
int overflow(int c) override { return c; }
55+
};
56+
static NullBuffer null_buffer;
57+
static std::ostream null_stream(&null_buffer);
58+
this->setLogStream(null_stream);
59+
}
60+
61+
std::ostream &Context::log() noexcept {
62+
if (std::holds_alternative<std::ostream *>(this->log_stream)) {
63+
auto *const ptr = std::get<std::ostream *>(this->log_stream);
64+
if (ptr == nullptr) {
65+
return ::mgis::getDefaultLogStream();
66+
}
67+
return *ptr;
68+
} else if (std::holds_alternative<std::shared_ptr<std::ostream>>(
69+
this->log_stream)) {
70+
auto ptr = std::get<std::shared_ptr<std::ostream>>(this->log_stream);
71+
if (ptr.get() == nullptr) {
72+
return ::mgis::getDefaultLogStream();
73+
}
74+
return *ptr;
75+
}
76+
return ::mgis::getDefaultLogStream();
77+
} // end of log
78+
2679
Context::~Context() noexcept = default;
2780

2881
} // end of namespace mgis

tests/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,18 @@ if((CMAKE_HOST_WIN32) AND (NOT MSYS))
457457
PROPERTY ENVIRONMENT "PATH=$<TARGET_FILE_DIR:MFrontGenericInterface>\;${MGIS_PATH_STRING}")
458458
endif((CMAKE_HOST_WIN32) AND (NOT MSYS))
459459

460+
add_executable(ContextTest
461+
EXCLUDE_FROM_ALL
462+
ContextTest.cxx)
463+
target_link_libraries(ContextTest
464+
PRIVATE MFrontGenericInterface)
465+
add_test(NAME ContextTest COMMAND ContextTest)
466+
add_dependencies(check ContextTest)
467+
if((CMAKE_HOST_WIN32) AND (NOT MSYS))
468+
set_property(TEST ContextTest
469+
PROPERTY ENVIRONMENT "PATH=$<TARGET_FILE_DIR:MFrontGenericInterface>\;${MGIS_PATH_STRING}")
470+
endif((CMAKE_HOST_WIN32) AND (NOT MSYS))
471+
460472
if(enable-mgis-function)
461473

462474
if(MGIS_HAVE_TFEL)

0 commit comments

Comments
 (0)