C++ Utilities
Loading...
Searching...
No Matches
macros.h
Go to the documentation of this file.
1#pragma once
2// Some useful commonly used macros.
3//
4// SPDX-FileCopyrightText: 2025 Nessan Fitzmaurice <nzznfitz+gh@icloud.com>
5// SPDX-License-Identifier: MIT
6
10
11#include <array>
12#include <cstring>
13#include <print>
14#include <string>
15#include <utility>
16
17namespace {
18
19// Remove surrounding quotes from a stringified literal when present.
20template <std::size_t N>
21[[nodiscard]] inline const char*
22stringise_literal(const char (&input)[N]) {
23 if (N > 2 && input[0] == '"' && input[N - 2] == '"') {
24 thread_local char buffer[N - 1]{};
25 for (std::size_t i = 0; i < N - 3; ++i) buffer[i] = input[i + 1];
26 buffer[N - 3] = '\0';
27 return buffer;
28 }
29 return input;
30}
31
32// Concatenate multiple C-strings into a single thread-local buffer.
33template <typename... Parts>
34[[nodiscard]] inline const char*
35concat_cstr(const Parts*... parts) {
36 thread_local std::array<std::string, 4> buffers{};
37 thread_local std::size_t next = 0;
38 auto& buffer = buffers[next++ % buffers.size()];
39 buffer.clear();
40 std::size_t total = 0;
41 auto accumulate = [&](const char* part) { total += std::strlen(part); };
42 (accumulate(parts), ...);
43 buffer.reserve(total);
44 auto append = [&](const char* part) { buffer.append(part); };
45 (append(parts), ...);
46 return buffer.c_str();
47}
48
49} // anonymous namespace
50
60#define STRINGISE(s) stringise_literal(STRINGISE_IMPL(s))
61#define STRINGISE_IMPL(s) #s
62
73#define CONCAT(a, b) CONCAT_IMPL(a, b)
74#define CONCAT_IMPL(a, b) a##b
75
90#define VERSION_STRING(...) OVERLOAD(VERSION_STRING, __VA_ARGS__)
91
92// The actual one, two, and three argument versions of that macro.
93// In C++, contiguous strings are concatenated so "2" "." "3" is the same as "2.3"
94#define VERSION_STRING1(major) STRINGISE(major)
95#define VERSION_STRING2(major, minor) concat_cstr(STRINGISE(major), ".", STRINGISE(minor))
96#define VERSION_STRING3(major, minor, patch) concat_cstr(STRINGISE(major), ".", STRINGISE(minor), ".", STRINGISE(patch))
97
108#define RUN(...) OVERLOAD(RUN, __VA_ARGS__)
109
110// Concrete implementations for `RUN` called with 1, 2, or 3 arguments.
111#define RUN1(code) \
112 std::println("[CODE] {}", #code); \
113 code
114
115#define RUN2(code, val) \
116 RUN1(code); \
117 std::println("[RESULT] {}: {}", #val, val);
118
119#define RUN3(code, val1, val2) \
120 RUN1(code); \
121 std::println("[RESULT] {}: {} and {}: {}", #val1, val1, #val2, val2);
122
134#define OVERLOAD(macro, ...) CONCAT(macro, ARG_COUNT(__VA_ARGS__))(__VA_ARGS__)
135
136// ARG_COUNT(...) expands to the count of its arguments e.g. ARG_COUNT(x,y,z) will expands to 3.
137#define ARG_COUNT(...) ARG_COUNT_IMPL(__VA_ARGS__ __VA_OPT__(, ) 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
138#define ARG_COUNT_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, count, ...) count
139
145#if defined(_MSC_VER)
146 #define COMPILER_NAME concat_cstr("MSC ", STRINGISE(_MSC_FULL_VER))
147#elif defined(__clang__)
148 #define COMPILER_NAME concat_cstr("clang ", VERSION_STRING(__clang_major__, __clang_minor__, __clang_patchlevel__))
149#elif defined(__GNUC__)
150 #define COMPILER_NAME concat_cstr("gcc ", VERSION_STRING(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__))
151#else
152 #define COMPILER_NAME "Unidentified Compiler"
153#endif