62 #include <string_view>
63 #include <type_traits>
66 #if defined(__clang__)
67 #pragma clang diagnostic push
68 #pragma clang diagnostic ignored "-Wunknown-warning-option"
69 #pragma clang diagnostic ignored "-Wenum-constexpr-conversion"
70 #elif defined(__GNUC__)
71 #pragma GCC diagnostic push
72 #pragma GCC diagnostic ignored "-Wstringop-overflow"
73 #elif defined(_MSC_VER)
75 #pragma warning(disable : 26495)
76 #pragma warning(disable : 28020)
78 #pragma warning(disable : 26451)
79 #pragma warning(disable : 4514)
82 #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 7 || \
83 defined(_MSC_VER) && _MSC_VER >= 1910
84 #undef VLINK_NAME_DETECTOR_TYPE_SUPPORTED
85 #define VLINK_NAME_DETECTOR_TYPE_SUPPORTED 1
88 #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || \
89 defined(_MSC_VER) && _MSC_VER >= 1910
90 #undef VLINK_NAME_DETECTOR_ENUM_SUPPORTED
91 #define VLINK_NAME_DETECTOR_ENUM_SUPPORTED 1
94 #if !defined(VLINK_NAME_DETECTOR_ENUM_RANGE_MIN)
95 #define VLINK_NAME_DETECTOR_ENUM_RANGE_MIN -128
98 #if !defined(VLINK_NAME_DETECTOR_ENUM_RANGE_MAX)
99 #define VLINK_NAME_DETECTOR_ENUM_RANGE_MAX 128
108 namespace NameDetector {
116 template <
typename TypeT>
117 [[nodiscard]] constexpr
bool is_support() noexcept;
130 template <
typename TypeT>
131 [[nodiscard]] constexpr std::string_view
get() noexcept;
141 template <
typename EnumT>
142 [[nodiscard]] constexpr std::string_view
get_enum(EnumT value) noexcept;
152 namespace customize {
160 template <
typename EnumT>
162 static_assert(std::is_enum_v<EnumT>,
"vlink::NameDetector::customize::EnumRange requires enum type.");
165 static_assert(
kMax >
kMin,
"vlink::NameDetector::customize::EnumRange requires kMax > kMin.");
169 "VLINK_NAME_DETECTOR_ENUM_RANGE_MIN must be less or equals than 0.");
172 "VLINK_NAME_DETECTOR_ENUM_RANGE_MIN must be greater than INT16_MIN.");
177 "VLINK_NAME_DETECTOR_ENUM_RANGE_MAX must be less than INT16_MAX.");
180 "VLINK_NAME_DETECTOR_ENUM_RANGE_MAX must be greater than VLINK_NAME_DETECTOR_ENUM_RANGE_MIN.");
190 namespace NameDetector {
193 template <
typename TypeT>
195 #if defined(VLINK_NAME_DETECTOR_TYPE_SUPPORTED) && VLINK_NAME_DETECTOR_TYPE_SUPPORTED
203 template <
typename TypeT>
205 #if defined(VLINK_NAME_DETECTOR_ENUM_SUPPORTED) && VLINK_NAME_DETECTOR_ENUM_SUPPORTED
213 template <
typename TypeT>
214 inline constexpr
bool kIsEnum = std::is_enum_v<TypeT> && std::is_same_v<TypeT, std::decay_t<TypeT>>;
216 template <
typename TypeT>
219 template <u
int16_t SizeT>
222 constexpr
explicit CString(std::string_view str) noexcept
223 :
CString{str, std::make_integer_sequence<uint16_t, SizeT>{}} {
224 assert(str.size() == SizeT);
233 [[nodiscard]] constexpr const
char* data() const noexcept {
return chars_; }
234 [[nodiscard]] constexpr uint16_t
size() const noexcept {
return SizeT; }
235 [[nodiscard]] constexpr
bool empty() const noexcept {
return SizeT == 0; }
238 [[nodiscard]] constexpr
operator std::string_view() const noexcept {
return std::string_view{data(), size()}; }
241 template <uint16_t... IndexT>
242 constexpr
CString(std::string_view str, std::integer_sequence<uint16_t, IndexT...>) noexcept
243 : chars_{str[IndexT]...,
'\0'} {}
246 char chars_[
static_cast<size_t>(SizeT) + 1];
249 constexpr std::string_view
pretty_name(std::string_view name,
bool remove_suffix =
true) noexcept {
250 if (!name.empty() && (name[0] ==
'"' || name[0] ==
'\'')) {
252 }
else if (name.size() >= 2 && name[0] ==
'R' && (name[1] ==
'"' || name[1] ==
'\'')) {
254 }
else if (name.size() >= 2 && name[0] ==
'L' && (name[1] ==
'"' || name[1] ==
'\'')) {
256 }
else if (name.size() >= 2 && name[0] ==
'U' && (name[1] ==
'"' || name[1] ==
'\'')) {
258 }
else if (name.size() >= 2 && name[0] ==
'u' && (name[1] ==
'"' || name[1] ==
'\'')) {
260 }
else if (name.size() >= 3 && name[0] ==
'u' && name[1] ==
'8' && (name[2] ==
'"' || name[2] ==
'\'')) {
262 }
else if (!name.empty() && (name[0] >=
'0' && name[0] <=
'9')) {
266 for (
size_t i = name.size(), h = 0, s = 0; i > 0; --i) {
267 if (name[i - 1] ==
')') {
271 }
else if (name[i - 1] ==
'(') {
278 name.remove_suffix(s);
287 for (
size_t i = name.size(), h = 0; i > 0; --i) {
288 if (name[i - 1] ==
'>') {
292 }
else if (name[i - 1] ==
'<') {
306 for (
size_t i = name.size() - s; i > 0; --i) {
307 if (!((name[i - 1] >=
'0' && name[i - 1] <=
'9') || (name[i - 1] >=
'a' && name[i - 1] <=
'z') ||
308 (name[i - 1] >=
'A' && name[i - 1] <=
'Z') || (name[i - 1] ==
'_'))) {
309 name.remove_prefix(i);
315 name.remove_suffix(s);
318 if (!name.empty() && ((name[0] >=
'a' && name[0] <=
'z') || (name[0] >=
'A' && name[0] <=
'Z') || (name[0] ==
'_'))) {
325 #if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L
326 #define VLINK_NAME_DETECTOR_ARRAY_CONSTEXPR 1
328 template <
typename TypeT,
size_t SizeT,
size_t... IndexT>
329 constexpr std::array<std::remove_cv_t<TypeT>, SizeT>
to_array(TypeT (&a)[SizeT],
330 std::index_sequence<IndexT...>) noexcept {
331 return {{a[IndexT]...}};
335 template <
typename LeftT,
typename RightT>
336 constexpr
bool cmp_less(LeftT lhs, RightT rhs) noexcept {
337 static_assert(std::is_integral_v<LeftT> && std::is_integral_v<RightT>,
338 "vlink::NameDetector::detail::cmp_less requires integral type.");
340 if constexpr (std::is_signed_v<LeftT> == std::is_signed_v<RightT>) {
342 }
else if constexpr (std::is_same_v<LeftT, bool>) {
343 return static_cast<RightT
>(lhs) < rhs;
344 }
else if constexpr (std::is_same_v<RightT, bool>) {
345 return lhs < static_cast<LeftT>(rhs);
346 }
else if constexpr (std::is_signed_v<RightT>) {
347 return rhs > 0 && lhs < static_cast<std::make_unsigned_t<RightT>>(rhs);
349 return lhs < 0 || static_cast<std::make_unsigned_t<LeftT>>(lhs) < rhs;
353 template <
typename EnumT, EnumT ValueV>
355 static_assert(kIsEnum<EnumT>,
"vlink::NameDetector::detail::raw_enum_name requires enum type.");
358 #if defined(__clang__) || defined(__GNUC__)
359 constexpr
auto kName =
pretty_name({__PRETTY_FUNCTION__,
sizeof(__PRETTY_FUNCTION__) - 2});
360 #elif defined(_MSC_VER)
361 constexpr
auto kName =
pretty_name({__FUNCSIG__,
sizeof(__FUNCSIG__) - 17});
363 constexpr
auto kName = std::string_view{};
367 return std::string_view{};
371 template <
typename EnumT, EnumT ValueV>
373 constexpr
auto kName = raw_enum_name<EnumT, ValueV>();
377 template <
typename EnumT, EnumT ValueV>
379 inline constexpr
auto kEnumName = enum_name<EnumT, ValueV>();
381 template <
typename EnumT, auto ValueV>
383 #if defined(__clang__) && __clang_major__ >= 16
384 constexpr
auto kV = __builtin_bit_cast(EnumT, ValueV);
386 constexpr
auto kV =
static_cast<EnumT
>(ValueV);
388 return raw_enum_name<EnumT, kV>().size() != 0;
391 template <
typename EnumT,
int OffsetT,
typename UnderlyingT = std::underlying_type_t<EnumT>>
392 constexpr UnderlyingT
ualue(
size_t i) noexcept {
393 if constexpr (std::is_same_v<UnderlyingT, bool>) {
394 static_assert(OffsetT == 0,
"vlink::NameDetector::detail::ualue requires zero offset for bool.");
395 return static_cast<UnderlyingT
>(i);
397 return static_cast<UnderlyingT
>(
static_cast<int>(i) + OffsetT);
401 template <
typename EnumT,
int OffsetT,
typename UnderlyingT = std::underlying_type_t<EnumT>>
403 return static_cast<EnumT
>(ualue<EnumT, OffsetT>(i));
406 template <
typename EnumT,
typename UnderlyingT = std::underlying_type_t<EnumT>>
410 constexpr
auto kRhs = (std::numeric_limits<UnderlyingT>::min)();
413 if constexpr (
cmp_less(kRhs, kLhs)) {
420 template <
typename EnumT,
typename UnderlyingT = std::underlying_type_t<EnumT>>
424 constexpr
auto kRhs = (std::numeric_limits<UnderlyingT>::max)();
426 if constexpr (
cmp_less(kLhs, kRhs)) {
434 #define VLINK_NAME_DETECTOR_FOR_EACH_256(X) \
436 X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) \
437 X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31) X(32) X(33) X(34) X(35) X(36) X(37) X(38) X(39) X(40) \
438 X(41) X(42) X(43) X(44) X(45) X(46) X(47) X(48) X(49) X(50) X(51) X(52) X(53) X(54) X(55) X(56) X(57) X(58) X(59) \
439 X(60) X(61) X(62) X(63) X(64) X(65) X(66) X(67) X(68) X(69) X(70) X(71) X(72) X(73) X(74) X(75) X(76) X(77) X(78) \
440 X(79) X(80) X(81) X(82) X(83) X(84) X(85) X(86) X(87) X(88) X(89) X(90) X(91) X(92) X(93) X(94) X(95) X(96) X(97) \
441 X(98) X(99) X(100) X(101) X(102) X(103) X(104) X(105) X(106) X(107) X(108) X(109) X(110) X(111) X(112) X(113) \
442 X(114) X(115) X(116) X(117) X(118) X(119) X(120) X(121) X(122) X(123) X(124) X(125) X(126) X(127) X(128) X(129) \
443 X(130) X(131) X(132) X(133) X(134) X(135) X(136) X(137) X(138) X(139) X(140) X(141) X(142) X(143) X(144) X(145) \
444 X(146) X(147) X(148) X(149) X(150) X(151) X(152) X(153) X(154) X(155) X(156) X(157) X(158) X(159) X(160) X(161) \
445 X(162) X(163) X(164) X(165) X(166) X(167) X(168) X(169) X(170) X(171) X(172) X(173) X(174) X(175) X(176) X(177) \
446 X(178) X(179) X(180) X(181) X(182) X(183) X(184) X(185) X(186) X(187) X(188) X(189) X(190) X(191) X(192) X(193) \
447 X(194) X(195) X(196) X(197) X(198) X(199) X(200) X(201) X(202) X(203) X(204) X(205) X(206) X(207) X(208) X(209) \
448 X(210) X(211) X(212) X(213) X(214) X(215) X(216) X(217) X(218) X(219) X(220) X(221) X(222) X(223) X(224) X(225) \
449 X(226) X(227) X(228) X(229) X(230) X(231) X(232) X(233) X(234) X(235) X(236) X(237) X(238) X(239) X(240) X(241) \
450 X(242) X(243) X(244) X(245) X(246) X(247) X(248) X(249) X(250) X(251) X(252) X(253) X(254) X(255)
453 template <
typename EnumT,
size_t SizeT,
int MinT,
size_t IndexT>
456 #define VLINK_NAME_DETECTOR_ENUM_V(O) \
457 if constexpr ((IndexT + (O)) < SizeT) { \
458 if constexpr (is_valid<EnumT, ualue<EnumT, MinT>(IndexT + (O))>()) { \
459 valid[IndexT + (O)] = true; \
464 #undef VLINK_NAME_DETECTOR_ENUM_V
466 if constexpr ((IndexT + 256) < SizeT) {
467 valid_count_step<EnumT, SizeT, MinT, IndexT + 256>(valid, count);
471 template <
size_t SizeT>
477 template <
typename EnumT,
size_t SizeT,
int MinT>
480 valid_count_step<EnumT, SizeT, MinT, 0>(result.
valid, result.
count);
484 template <
typename EnumT,
size_t SizeT,
int MinT>
486 constexpr
auto kVc = valid_count<EnumT, SizeT, MinT>();
488 if constexpr (kVc.count > 0) {
489 #if defined(VLINK_NAME_DETECTOR_ARRAY_CONSTEXPR)
491 std::array<EnumT, kVc.count> result = {};
493 EnumT result[kVc.count] = {};
495 for (
size_t i = 0, v = 0; v < kVc.count; ++i) {
497 result[v++] = enum_value_at<EnumT, MinT>(i);
500 #if defined(VLINK_NAME_DETECTOR_ARRAY_CONSTEXPR)
503 return to_array(result, std::make_index_sequence<kVc.count>{});
506 return std::array<EnumT, 0>{};
510 template <
typename EnumT,
typename UnderlyingT = std::underlying_type_t<EnumT>>
512 constexpr
auto kMin = reflected_min<EnumT>();
513 constexpr
auto kMax = reflected_max<EnumT>();
514 constexpr
auto kRangeSize = kMax - kMin + 1;
515 static_assert(kRangeSize > 0,
"vlink::NameDetector enum range requires positive size.");
517 static_assert(kRangeSize < (std::numeric_limits<uint16_t>::max)(),
518 "vlink::NameDetector enum range exceeds supported size.");
520 return values_in_range<EnumT, kRangeSize, kMin>();
523 template <
typename EnumT>
524 inline constexpr
auto kValues = values<EnumT>();
526 template <
typename EnumT>
527 inline constexpr
auto kCount = kValues<EnumT>.size();
529 template <
typename EnumT,
typename UnderlyingT = std::underlying_type_t<EnumT>>
531 (kCount<EnumT> > 0) ?
static_cast<UnderlyingT
>(kValues<EnumT>.front()) : UnderlyingT{0};
533 template <
typename EnumT,
typename UnderlyingT = std::underlying_type_t<EnumT>>
535 (kCount<EnumT> > 0) ?
static_cast<UnderlyingT
>(kValues<EnumT>.back()) : UnderlyingT{0};
537 template <
typename EnumT,
size_t... IndexT>
538 constexpr
auto names_impl(std::index_sequence<IndexT...>) noexcept {
539 return std::array<std::string_view,
sizeof...(IndexT)>{{kEnumName<EnumT, kValues<EnumT>[IndexT]>...}};
542 template <
typename EnumT>
543 inline constexpr
auto kNames = names_impl<EnumT>(std::make_index_sequence<kCount<EnumT>>{});
545 template <
typename EnumT,
typename UnderlyingT = std::underlying_type_t<EnumT>>
547 if constexpr (kCount<EnumT> == 0) {
549 }
else if constexpr (std::is_same_v<UnderlyingT, bool>) {
552 constexpr
auto kMaxV = kMaxValue<EnumT>;
553 constexpr
auto kMinT = kMinTalue<EnumT>;
554 constexpr
auto kRangeSize = kMaxV - kMinT + 1;
555 return static_cast<size_t>(kRangeSize) != kCount<EnumT>;
559 template <
typename EnumT>
562 template <
typename EnumT,
typename UnderlyingT = std::underlying_type_t<EnumT>>
564 if constexpr (kIsSparse<EnumT>) {
565 return kValues<EnumT>[i];
567 constexpr
auto kMinT = kMinTalue<EnumT>;
568 return enum_value_at<EnumT, static_cast<int>(kMinT)>(i);
572 template <
typename TypeT>
575 #if defined(__clang__)
576 constexpr std::string_view kName{__PRETTY_FUNCTION__ + 59,
sizeof(__PRETTY_FUNCTION__) - 61};
577 #elif defined(__GNUC__)
578 constexpr std::string_view kName{__PRETTY_FUNCTION__ + 74,
sizeof(__PRETTY_FUNCTION__) - 76};
579 #elif defined(_MSC_VER)
580 constexpr std::string_view kName{__FUNCSIG__ + 56,
581 sizeof(__FUNCSIG__) - 73 - (__FUNCSIG__[
sizeof(__FUNCSIG__) - 18] ==
' ' ? 1 : 0)};
583 constexpr
auto kName = std::string_view{};
591 template <
typename TypeT>
592 inline constexpr
auto kTypeName = raw_type_name<TypeT>();
597 template <
typename TypeT>
602 template <
typename TypeT>
608 #if defined(_WIN32) || defined(__CYGWIN__)
609 std::string_view view = detail::kTypeName<DecayT>;
611 constexpr std::string_view kStructPrefix =
"struct ";
613 if (view.size() >= kStructPrefix.size() && view.substr(0, kStructPrefix.size()) == kStructPrefix) {
614 view.remove_prefix(kStructPrefix.size());
617 constexpr std::string_view kClassPrefix =
"class ";
619 if (view.size() >= kClassPrefix.size() && view.substr(0, kClassPrefix.size()) == kClassPrefix) {
620 view.remove_prefix(kClassPrefix.size());
625 return detail::kTypeName<DecayT>;
629 template <
typename EnumT>
631 static_assert(std::is_enum_v<EnumT>,
"vlink::NameDetector::get_enum requires enum type.");
633 using DecayT = std::decay_t<EnumT>;
634 using UnderlyingT = std::underlying_type_t<DecayT>;
637 "vlink::NameDetector::get_enum requires a supported compiler.");
638 static_assert(detail::kCount<DecayT> > 0,
639 "vlink::NameDetector::get_enum requires at least one enumerator within range.");
641 if constexpr (detail::kIsSparse<DecayT>) {
642 for (
size_t i = 0; i < detail::kCount<DecayT>; ++i) {
643 if (detail::enum_value<DecayT>(i) == value) {
644 return detail::kNames<DecayT>[i];
648 const auto v =
static_cast<UnderlyingT
>(value);
650 if (v >= detail::kMinTalue<DecayT> && v <= detail::kMaxValue<DecayT>) {
651 return detail::kNames<DecayT>[
static_cast<size_t>(v - detail::kMinTalue<DecayT>)];
660 #if defined(__clang__)
661 #pragma clang diagnostic pop
662 #elif defined(__GNUC__)
663 #pragma GCC diagnostic pop
664 #elif defined(_MSC_VER)
Definition: name_detector.h:220
constexpr uint16_t size() const noexcept
Definition: name_detector.h:234
constexpr bool empty() const noexcept
Definition: name_detector.h:235
constexpr CString(std::string_view str) noexcept
Definition: name_detector.h:222
constexpr CString(const CString &)=default
constexpr CString() noexcept
Definition: name_detector.h:226
constexpr CString(CString &&) noexcept=default
#define VLINK_NAME_DETECTOR_FOR_EACH_256(X)
Definition: name_detector.h:434
#define VLINK_NAME_DETECTOR_ENUM_V(O)
#define VLINK_NAME_DETECTOR_ENUM_RANGE_MAX
Definition: name_detector.h:99
#define VLINK_NAME_DETECTOR_ENUM_RANGE_MIN
Definition: name_detector.h:95
constexpr EnumT enum_value_at(size_t i) noexcept
Definition: name_detector.h:402
constexpr UnderlyingT kMaxValue
Definition: name_detector.h:534
constexpr auto valid_count() noexcept
Definition: name_detector.h:478
constexpr int reflected_max() noexcept
Definition: name_detector.h:421
constexpr UnderlyingT kMinTalue
Definition: name_detector.h:530
constexpr auto values_in_range() noexcept
Definition: name_detector.h:485
constexpr std::array< std::remove_cv_t< TypeT >, SizeT > to_array(TypeT(&a)[SizeT], std::index_sequence< IndexT... >) noexcept
Definition: name_detector.h:329
constexpr bool kIsSparse
Definition: name_detector.h:560
constexpr auto kEnumName
Definition: name_detector.h:379
constexpr auto enum_name() noexcept
Definition: name_detector.h:372
constexpr auto values() noexcept
Definition: name_detector.h:511
constexpr int reflected_min() noexcept
Definition: name_detector.h:407
constexpr bool cmp_less(LeftT lhs, RightT rhs) noexcept
Definition: name_detector.h:336
constexpr auto raw_enum_name() noexcept
Definition: name_detector.h:354
constexpr auto kTypeName
Definition: name_detector.h:592
constexpr bool kIsEnum
Definition: name_detector.h:214
constexpr auto kCount
Definition: name_detector.h:527
constexpr auto raw_type_name() noexcept
Definition: name_detector.h:573
constexpr UnderlyingT ualue(size_t i) noexcept
Definition: name_detector.h:392
constexpr auto names_impl(std::index_sequence< IndexT... >) noexcept
Definition: name_detector.h:538
constexpr auto kNames
Definition: name_detector.h:543
constexpr EnumT enum_value(size_t i) noexcept
Definition: name_detector.h:563
constexpr bool is_valid() noexcept
Definition: name_detector.h:382
constexpr bool is_sparse() noexcept
Definition: name_detector.h:546
constexpr auto kValues
Definition: name_detector.h:524
constexpr void valid_count_step(bool *valid, size_t &count) noexcept
Definition: name_detector.h:455
constexpr std::string_view pretty_name(std::string_view name, bool remove_suffix=true) noexcept
Definition: name_detector.h:249
std::remove_cv_t< std::remove_reference_t< TypeT > > RemoveCvrefT
Definition: name_detector.h:217
constexpr std::string_view get_enum(EnumT value) noexcept
Resolves the source identifier of an enumerator literal at compile time.
Definition: name_detector.h:630
constexpr bool is_support() noexcept
Reports whether the current toolchain can extract a textual name for TypeT.
Definition: name_detector.h:598
constexpr std::string_view get() noexcept
Returns the trimmed compile-time identifier for TypeT.
Definition: name_detector.h:603
Inclusive integer range scanned for EnumT enumerator labels.
Definition: name_detector.h:161
static constexpr int kMin
Inclusive lower scan bound.
Definition: name_detector.h:163
static constexpr int kMax
Inclusive upper scan bound.
Definition: name_detector.h:164
Definition: name_detector.h:209
Definition: name_detector.h:199
Definition: name_detector.h:472
size_t count
Definition: name_detector.h:473
bool valid[SizeT]
Definition: name_detector.h:474