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{
24 if (N > 2 && input[0] == '"' && input[N - 2] == '"') {
25 thread_local char buffer[N - 1]{};
26 for (std::size_t i = 0; i < N - 3; ++i) buffer[i] = input[i + 1];
27 buffer[N - 3] = '\0';
28 return buffer;
29 }
30 return input;
31}
32
33// Concatenate multiple C-strings into a single thread-local buffer.
34template<typename... Parts>
35[[nodiscard]] inline const char*
36concat_cstr(const Parts*... parts)
37{
38 thread_local std::array<std::string, 4> buffers{};
39 thread_local std::size_t next = 0;
40 auto& buffer = buffers[next++ % buffers.size()];
41 buffer.clear();
42 std::size_t total = 0;
43 auto accumulate = [&](const char* part) { total += std::strlen(part); };
44 (accumulate(parts), ...);
45 buffer.reserve(total);
46 auto append = [&](const char* part) { buffer.append(part); };
47 (append(parts), ...);
48 return buffer.c_str();
49}
50
51} // anonymous namespace
52
62#define STRINGISE(s) stringise_literal(STRINGISE_IMPL(s))
63#define STRINGISE_IMPL(s) #s
64
75#define CONCAT(a, b) CONCAT_IMPL(a, b)
76#define CONCAT_IMPL(a, b) a##b
77
92#define VERSION_STRING(...) OVERLOAD(VERSION_STRING, __VA_ARGS__)
93
94// The actual one, two, and three argument versions of that macro.
95// In C++, contiguous strings are concatenated so "2" "." "3" is the same as "2.3"
96#define VERSION_STRING1(major) STRINGISE(major)
97#define VERSION_STRING2(major, minor) concat_cstr(STRINGISE(major), ".", STRINGISE(minor))
98#define VERSION_STRING3(major, minor, patch) concat_cstr(STRINGISE(major), ".", STRINGISE(minor), ".", STRINGISE(patch))
99
110#define RUN(...) OVERLOAD(RUN, __VA_ARGS__)
111
112// Concrete implementations for `RUN` called with 1, 2, or 3 arguments.
113#define RUN1(code) \
114 std::println("[CODE] {}", #code); \
115 code
116
117#define RUN2(code, val) \
118 RUN1(code); \
119 std::println("[RESULT] {}: {}", #val, val);
120
121#define RUN3(code, val1, val2) \
122 RUN1(code); \
123 std::println("[RESULT] {}: {} and {}: {}", #val1, val1, #val2, val2);
124
136#define OVERLOAD(macro, ...) CONCAT(macro, ARG_COUNT(__VA_ARGS__))(__VA_ARGS__)
137
138// ARG_COUNT(...) expands to the count of its arguments e.g. ARG_COUNT(x,y,z) will expands to 3.
139#define ARG_COUNT(...) ARG_COUNT_IMPL(__VA_ARGS__ __VA_OPT__(, ) 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
140#define ARG_COUNT_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, count, ...) count
141
147#if defined(_MSC_VER)
148 #define COMPILER_NAME concat_cstr("MSC ", STRINGISE(_MSC_FULL_VER))
149#elif defined(__clang__)
150 #define COMPILER_NAME concat_cstr("clang ", VERSION_STRING(__clang_major__, __clang_minor__, __clang_patchlevel__))
151#elif defined(__GNUC__)
152 #define COMPILER_NAME concat_cstr("gcc ", VERSION_STRING(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__))
153#else
154 #define COMPILER_NAME "Unidentified Compiler"
155#endif