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