1//! @file macro.hpp
2//! @author ryftchen
3//! @brief The declarations (macro) in the utility module.
4//! @version 0.1.0
5//! @copyright Copyright (c) 2022-2025 ryftchen. All rights reserved.
6
7#pragma once
8
9#include <cstdio>
10#include <cstdlib>
11#include <utility>
12
13//! @brief Do stringification.
14#define MACRO_STRINGIFY(x) MACRO_STRINGIFY_OP(x)
15//! @brief The stringification operator.
16#define MACRO_STRINGIFY_OP(x) #x
17
18//! @brief Do concatenation.
19#define MACRO_CONCAT(x, y) MACRO_CONCAT_OP(x, y)
20//! @brief The concatenation operator.
21#define MACRO_CONCAT_OP(x, y) x##y
22
23//! @brief Mark to ignore.
24#define MACRO_IGNORE(...) \
25 do \
26 { \
27 utility::macro::ignoreAll(__VA_ARGS__); \
28 } \
29 while (false)
30
31//! @brief Always assert.
32#define MACRO_ASSERT(expr) \
33 (static_cast<bool>(expr) ? static_cast<void>(0) : utility::macro::assertFail(#expr, __FILE__, __LINE__, __func__))
34
35//! @brief Defer process.
36#define MACRO_DEFER(call) \
37 [[maybe_unused]] const auto MACRO_CONCAT(_deferGuard, __LINE__) = utility::macro::makeDeferral(call)
38
39//! @brief The utility module.
40namespace utility // NOLINT(modernize-concat-nested-namespaces)
41{
42//! @brief Public-macro-related functions in the utility module.
43namespace macro
44{
45//! @brief Brief function description.
46//! @return function description (module_function)
47inline static const char* description() noexcept
48{
49 return "UTIL_MACRO";
50}
51extern const char* version() noexcept;
52
53//! @brief Safely ignore all provided arguments.
54//! @tparam Args - type of all provided arguments
55template <typename... Args>
56constexpr void ignoreAll(Args&&... /*args*/) noexcept
57{
58}
59
60//! @brief Assertion failed.
61//! @param assertion - assertion expression
62//! @param file - file path
63//! @param line - line number
64//! @param function - function name
65[[noreturn]] inline void assertFail(
66 const char* const assertion, const char* const file, const unsigned int line, const char* const function) noexcept
67{
68 std::fprintf(stream: ::stderr, format: "%s:%d: %s: Assertion `%s` failed.\n", file, line, function, assertion);
69 std::abort();
70}
71
72//! @brief Defer the execution of the callable until it is out of scope.
73//! @tparam Call - type of deferred callable
74template <typename Call>
75class Defer
76{
77public:
78 //! @brief Construct a new Defer object.
79 //! @tparam Func - type of deferred callable
80 //! @param deferred - deferred callable
81 template <typename Func>
82 explicit Defer(Func&& deferred) noexcept(noexcept(Call(std::forward<Func>(deferred)))) :
83 deferred{std::forward<Func>(deferred)}
84 {
85 }
86 //! @brief Destroy the Defer object.
87 virtual ~Defer() noexcept(noexcept(deferred()));
88 //! @brief Construct a new Defer object.
89 Defer(const Defer&) = delete;
90 //! @brief Construct a new Defer object.
91 Defer(Defer&&) = delete;
92 //! @brief The operator (=) overloading of Defer class.
93 //! @return reference of the Defer object
94 Defer& operator=(const Defer&) = delete;
95 //! @brief The operator (=) overloading of Defer class.
96 //! @return reference of the Defer object
97 Defer& operator=(Defer&&) = delete;
98
99private:
100 //! @brief The deferred callable.
101 const Call deferred{};
102};
103
104template <typename Call>
105Defer<Call>::~Defer() noexcept(noexcept(deferred()))
106{
107 deferred();
108}
109
110//! @brief Create the deferral from a callable.
111//! @tparam Call - type of deferred callable
112//! @param deferred - deferred callable
113//! @return deferral
114template <typename Call>
115constexpr auto makeDeferral(Call&& deferred) noexcept(noexcept(Defer<std::decay_t<Call>>(std::forward<Call>(deferred))))
116{
117 return Defer<std::decay_t<Call>>(std::forward<Call>(deferred));
118}
119} // namespace macro
120} // namespace utility
121