MeshLib
 
Loading...
Searching...
No Matches
MRCanonicalTypedefs.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRMesh/MRMacros.h"
4
5// This helper macro is used to declare canonical typedefs. For example, if you have this:
6// template <typename T> struct MRMESH_CLASS Vector3; // `MRMESH_CLASS` isn't necessary, just to demonstrate that it's supported.
7// using Vector3f = Vector3<float>;
8// using Vector3i = Vector3<int>;
9// You should rewrite it as following:
10// MR_CANONICAL_TYPEDEFS( (template <typename T> struct MRMESH_CLASS), Vector3,
11// ( Vector3f, Vector3<float> )
12// ( Vector3i, Vector3<int> )
13// )
14//
15// WHAT THIS ACHIEVES?
16// This macro only has effect on Clang.
17// It primarily affects the error messages, using those typedefs instead of the full type when possible.
18// It also helps when parsing our code with libclang to automatically generate Python bindings.
19//
20// NOTE:
21// * Only non-template `using`s can be declared like this. If you want to add additional templated ones, add them below the macro manually.
22
23#define MR_CANONICAL_TYPEDEFS(type_, name_, aliases_) \
24 MR_IDENTITY type_ name_; \
25 MR_END(DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_USING_A aliases_) \
26 DETAIL_MR_CANONICAL_TYPEDEFS(type_, name_, aliases_)
27
28#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_USING_BODY(name_, ...) using name_ = __VA_ARGS__;
29// `MR_IDENTITY` here keeps the legacy MSVC preprocessor happy.
30#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_USING_A(...) DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_USING_BODY MR_IDENTITY()(__VA_ARGS__) DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_USING_B
31#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_USING_B(...) DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_USING_BODY MR_IDENTITY()(__VA_ARGS__) DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_USING_A
32#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_USING_A_END
33#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_USING_B_END
34
35#if defined(__has_attribute)
36#if __has_attribute(__preferred_name__)
37#define DETAIL_MR_CANONICAL_TYPEDEFS(type_, name_, aliases_) \
38 MR_IDENTITY type_ \
39 MR_END(DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_ATTR_A aliases_) \
40 name_; \
41 DETAIL_MR_CANONICAL_TYPEDEFS_CLANG_WORKAROUND(aliases_)
42
43#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_ATTR_BODY(name_, ...) __attribute__((__preferred_name__(name_)))
44#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_ATTR_A(...) DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_ATTR_BODY(__VA_ARGS__) DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_ATTR_B
45#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_ATTR_B(...) DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_ATTR_BODY(__VA_ARGS__) DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_ATTR_A
46#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_ATTR_A_END
47#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_ATTR_B_END
48
49#ifdef __clang__ // Workaround for bug: https://github.com/llvm/llvm-project/issues/106358
50
51#define DETAIL_MR_CANONICAL_TYPEDEFS_CLANG_WORKAROUND(aliases_) \
52 MR_END(DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_TOUCH_A aliases_)
53
54namespace MR::detail::CanonicalTypedefs
55{
56template <typename> struct RegisterType {};
57}
58
59#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_TOUCH_BODY(name_, ...) static_assert((void(::MR::detail::CanonicalTypedefs::RegisterType<__VA_ARGS__>{}), true));
60#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_TOUCH_A(...) DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_TOUCH_BODY(__VA_ARGS__) DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_TOUCH_B
61#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_TOUCH_B(...) DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_TOUCH_BODY(__VA_ARGS__) DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_TOUCH_A
62#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_TOUCH_A_END
63#define DETAIL_MR_CANONICAL_TYPEDEFS_LOOP_TOUCH_B_END
64
65#else // no workaround needed
66#define DETAIL_MR_CANONICAL_TYPEDEFS_CLANG_WORKAROUND(aliases_)
67#endif
68
69#else // this attribute is not supported
70#define DETAIL_MR_CANONICAL_TYPEDEFS(type_, name_, aliases_)
71#endif
72
73#else // no __has_attribute
74#define DETAIL_MR_CANONICAL_TYPEDEFS(type_, name_, aliases_)
75#endif