VLink  2.0.0
A high-performance communication middleware
macros.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2026 by Thun Lu. All rights reserved.
3  * Author: Thun Lu <thun.lu@zohomail.cn>
4  * Repo: https://github.com/thun-res/vlink
5  * _ __ __ _ __
6  * | | / / / / (_) ____ / /__
7  * | | / / / / / / / __ \ / //_/
8  * | |/ / / /___ / / / / / / / ,<
9  * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 
24 /**
25  * @file macros.h
26  * @brief Cross-platform macros for visibility, branch hints, copy prevention, singletons and string helpers.
27  *
28  * @details
29  * Every header in VLink relies on this file for ABI export decoration, alignment, branch
30  * prediction hints, and class-level boilerplate. Macros that depend on compiler features
31  * gracefully degrade to no-ops on platforms that do not expose those features.
32  *
33  * @par Macro reference
34  *
35  * | Category | Macro | Purpose |
36  * | -------------------- | ---------------------------------------- | ---------------------------------------------- |
37  * | Visibility | @c VLINK_EXPORT | DLL / shared-object visibility |
38  * | Visibility + align | @c VLINK_EXPORT_AND_ALIGNED(n) | Combine export with byte alignment |
39  * | Branch hints (long) | @c VLINK_LIKELY(x), @c VLINK_UNLIKELY(x) | C++20 @c [[likely]] / @c __builtin_expect |
40  * | Branch hints (short) | @c VLIKELY(...), @c VUNLIKELY(...) | Aliases of @c VLINK_LIKELY / @c VLINK_UNLIKELY |
41  * | Class hygiene | @c VLINK_DISALLOW_COPY_AND_ASSIGN(class) | Delete copy ctor and assignment |
42  * | Singletons | @c VLINK_SINGLETON_CHECK(class) | Enforce one instance per process |
43  * | Singletons | @c VLINK_SINGLETON_DECLARE(class) | Add @c get accessor + check + no-copy |
44  * | Stringify | @c VLINK_MACRO_STRING_IFY(name) | Stringify a token directly |
45  * | Stringify (eval) | @c VLINK_MACRO_STRING_GET(name) | Stringify after macro expansion |
46  * | Constant check | @c VLINK_ASSERT_CONSTANT(msg) | @c static_assert message is a literal |
47  *
48  * @par Example
49  * @code
50  * class VLINK_EXPORT MyService final {
51  * VLINK_DISALLOW_COPY_AND_ASSIGN(MyService)
52  * public:
53  * MyService();
54  * };
55  *
56  * if VLIKELY (ptr != nullptr) {
57  * ptr->do_something();
58  * }
59  * @endcode
60  *
61  * @note @c VLINK_SINGLETON_CHECK enforces uniqueness at run time by tripping a
62  * @c std::atomic_flag the second time the constructor runs; the second
63  * instantiation throws @c std::runtime_error.
64  */
65 
66 #pragma once
67 
68 // export
69 #undef VLINK_EXPORT
70 #ifdef VLINK_LIBRARY_STATIC
71 #define VLINK_EXPORT
72 #elif defined(_WIN32) || defined(__CYGWIN__)
73 #ifdef VLINK_LIBRARY
74 /// @cond INTERNAL
75 #define VLINK_EXPORT __declspec(dllexport)
76 #else
77 #define VLINK_EXPORT __declspec(dllimport)
78 /// @endcond
79 #endif
80 #else
81 #define VLINK_EXPORT __attribute__((visibility("default")))
82 #endif
83 
84 // align
85 #undef VLINK_EXPORT_AND_ALIGNED
86 #ifdef _MSC_VER
87 #define VLINK_EXPORT_AND_ALIGNED(align_num) VLINK_EXPORT __declspec(align(align_num))
88 #else
89 /**
90  * @def VLINK_EXPORT_AND_ALIGNED(align_num)
91  * @brief Marks a class or variable as both exported and aligned to @p align_num bytes.
92  *
93  * @details
94  * Expands to @c __declspec(align(align_num)) on MSVC and to
95  * @c __attribute__((aligned(align_num))) on GCC / Clang.
96  *
97  * @param align_num Required alignment in bytes; must be a power of two.
98  */
99 #define VLINK_EXPORT_AND_ALIGNED(align_num) VLINK_EXPORT __attribute__((aligned(align_num)))
100 #endif
101 
102 // win32
103 #if defined(_WIN32) && !defined(WIN32_LEAN_AND_MEAN)
104 #define WIN32_LEAN_AND_MEAN
105 #endif
106 
107 // msvc
108 #ifdef _MSC_VER
109 #ifndef _CRT_SECURE_NO_WARNINGS
110 #define _CRT_SECURE_NO_WARNINGS // NOLINT(bugprone-reserved-identifier, readability-identifier-naming)
111 #endif
112 #pragma warning(disable : 4065)
113 #pragma warning(disable : 4251)
114 #pragma warning(disable : 4244)
115 #pragma warning(disable : 4267)
116 #pragma warning(disable : 4324)
117 #pragma warning(disable : 4702)
118 #pragma warning(disable : 4819)
119 #pragma warning(disable : 4840)
120 #pragma warning(disable : 4996)
121 #endif
122 
123 // __has_builtin
124 #ifndef __has_builtin
125 #define __has_builtin(x) 0
126 #endif
127 
128 #ifdef __cplusplus
129 #if __cplusplus >= 202002L
130 /**
131  * @def VLINK_LIKELY(x)
132  * @brief Hints to the compiler that @p x is very likely to evaluate to @c true.
133  *
134  * @details
135  * Expands to the C++20 @c [[likely]] attribute when available, @c __builtin_expect on older
136  * GCC / Clang, and is a no-op on MSVC.
137  *
138  * @param x Boolean expression to predict.
139  */
140 #define VLINK_LIKELY(x) (x) [[likely]]
141 /**
142  * @def VLINK_UNLIKELY(x)
143  * @brief Hints to the compiler that @p x is very unlikely to evaluate to @c true.
144  *
145  * @details
146  * Counterpart of @c VLINK_LIKELY with the opposite hint.
147  *
148  * @param x Boolean expression to predict.
149  */
150 #define VLINK_UNLIKELY(x) (x) [[unlikely]]
151 #else
152 #ifdef _WIN32
153 #define VLINK_LIKELY(x) (x)
154 #define VLINK_UNLIKELY(x) (x)
155 #else
156 #define VLINK_LIKELY(x) (__builtin_expect(!!(x), 1))
157 #define VLINK_UNLIKELY(x) (__builtin_expect(!!(x), 0))
158 #endif
159 #endif
160 #else
161 #define VLINK_LIKELY(x) (x)
162 #define VLINK_UNLIKELY(x) (x)
163 #endif
164 
165 /**
166  * @def VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
167  * @brief Deletes the copy constructor and copy-assignment operator of @p classname.
168  *
169  * @details
170  * Drop the macro inside the private section of a class to prevent accidental copying.
171  *
172  * @param classname Unqualified name of the enclosing class.
173  */
174 #define VLINK_DISALLOW_COPY_AND_ASSIGN(classname) \
175  classname(const classname&) = delete; \
176  classname& operator=(const classname&) = delete;
177 
178 /**
179  * @def VLINK_SINGLETON_CHECK(classname)
180  * @brief Embeds a static check that enforces one-instance-per-process for @p classname.
181  *
182  * @details
183  * Combines two safeguards:
184  * - Compile-time @c static_assert that @p classname is @c final and not externally
185  * default-constructible.
186  * - Run-time @c std::atomic_flag trip that throws @c std::runtime_error on the second
187  * instantiation.
188  *
189  * @param classname Unqualified name of the enclosing class.
190  * @note Place inside the @c private section of the class body.
191  */
192 #define VLINK_SINGLETON_CHECK(classname) \
193  private: \
194  struct ConstructorChecker { \
195  inline ConstructorChecker() { \
196  static_assert(std::is_final_v<classname>, "Constructor must be final."); \
197  static_assert(!std::is_default_constructible_v<classname>, "Constructor must be private."); \
198  \
199  static std::atomic_flag flag; \
200  \
201  if VLINK_UNLIKELY (flag.test_and_set(std::memory_order_seq_cst)) { \
202  throw std::runtime_error("Constructor has been instantiated."); \
203  } \
204  } \
205  }; \
206  \
207  ConstructorChecker constructor_checker_;
208 
209 /**
210  * @def VLINK_SINGLETON_DECLARE(classname)
211  * @brief Declares a Meyers singleton @c get and the matching uniqueness guards on @p classname.
212  *
213  * @details
214  * Expands to a public static @c get returning a reference to the single instance plus the
215  * @c VLINK_SINGLETON_CHECK and @c VLINK_DISALLOW_COPY_AND_ASSIGN macros.
216  *
217  * @param classname Unqualified name of the singleton class.
218  *
219  * @par Example
220  * @code
221  * class MyService final {
222  * VLINK_SINGLETON_DECLARE(MyService)
223  * public:
224  * void do_work();
225  * private:
226  * MyService() = default;
227  * };
228  *
229  * MyService::get().do_work();
230  * @endcode
231  */
232 #define VLINK_SINGLETON_DECLARE(classname) \
233  public: \
234  inline static classname& get() { \
235  static classname singleton = classname(); \
236  return singleton; \
237  } \
238  \
239  private: \
240  VLINK_SINGLETON_CHECK(classname) \
241  VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
242 
243 /**
244  * @def VLINK_MACRO_STRING_IFY(name)
245  * @brief Stringifies a token without performing macro expansion.
246  *
247  * @param name Token to stringify.
248  */
249 #define VLINK_MACRO_STRING_IFY(name) #name
250 
251 /**
252  * @def VLINK_MACRO_STRING_GET(name)
253  * @brief Stringifies the expanded value of a macro (two-step expansion).
254  *
255  * @details
256  * Use this form instead of @c VLINK_MACRO_STRING_IFY when @p name is itself a macro that should
257  * be expanded before stringification.
258  *
259  * @param name Macro whose expansion is stringified.
260  */
261 #define VLINK_MACRO_STRING_GET(name) VLINK_MACRO_STRING_IFY(name)
262 
263 #if __has_builtin(__builtin_constant_p)
264 /**
265  * @def VLINK_ASSERT_CONSTANT(msg)
266  * @brief Asserts at compile time that @p msg is a constant string literal.
267  *
268  * @details
269  * Expands to a @c static_assert on toolchains that expose @c __builtin_constant_p; otherwise
270  * the macro is a no-op.
271  *
272  * @param msg Expression checked for compile-time constancy.
273  */
274 #define VLINK_ASSERT_CONSTANT(msg) static_assert(__builtin_constant_p(msg), "Must be a constant string literal.");
275 #else
276 #define VLINK_ASSERT_CONSTANT(msg)
277 #endif
278 
279 #if !defined(VLIKELY) && !defined(VUNLIKELY)
280 /**
281  * @def VLIKELY(...)
282  * @brief Short alias for @c VLINK_LIKELY.
283  */
284 #define VLIKELY(...) VLINK_LIKELY(__VA_ARGS__)
285 /**
286  * @def VUNLIKELY(...)
287  * @brief Short alias for @c VLINK_UNLIKELY.
288  */
289 #define VUNLIKELY(...) VLINK_UNLIKELY(__VA_ARGS__)
290 #endif