| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | //================================================================================================== | ||
| 2 | /* | ||
| 3 | SPY - C++ Informations Broker | ||
| 4 | Copyright : SPY Project Contributors | ||
| 5 | SPDX-License-Identifier: BSL-1.0 | ||
| 6 | */ | ||
| 7 | //================================================================================================== | ||
| 8 | #pragma once | ||
| 9 | |||
| 10 | // Make sure the proper header is included to detect libstd | ||
| 11 | #include <spy/detail.hpp> | ||
| 12 | |||
| 13 | #include <cstddef> | ||
| 14 | |||
| 15 | namespace spy::_ | ||
| 16 | { | ||
| 17 | enum class stdlib | ||
| 18 | { | ||
| 19 | undefined_ = -1, | ||
| 20 | libcpp_, | ||
| 21 | gnucpp_ | ||
| 22 | }; | ||
| 23 | |||
| 24 | template<stdlib Lib, int M, int N, int P> struct stdlib_info | ||
| 25 | { | ||
| 26 | static constexpr stdlib vendor = Lib; | ||
| 27 | static constexpr version_id<M, N, P> version = {}; | ||
| 28 | |||
| 29 | inline constexpr explicit operator bool() const noexcept; | ||
| 30 | |||
| 31 | template<stdlib C2> constexpr bool operator==(stdlib_info<C2, -1, 0, 0> const&) const noexcept | ||
| 32 | { | ||
| 33 | return C2 == vendor; | ||
| 34 | } | ||
| 35 | |||
| 36 | template<stdlib C2, int M2, int N2, int P2> | ||
| 37 | constexpr bool operator==(stdlib_info<C2, M2, N2, P2> const& c2) const noexcept | ||
| 38 | { | ||
| 39 | return C2 == vendor && version == c2.version; | ||
| 40 | } | ||
| 41 | |||
| 42 | template<stdlib C2, int M2, int N2, int P2> | ||
| 43 | constexpr std::partial_ordering | ||
| 44 | operator<=>(stdlib_info<C2, M2, N2, P2> const& c2) const noexcept | ||
| 45 | { | ||
| 46 | if constexpr(vendor == C2) return version <=> c2.version; | ||
| 47 | else return std::partial_ordering::unordered; | ||
| 48 | } | ||
| 49 | }; | ||
| 50 | |||
| 51 | template<_::stream OS, stdlib SLib, int M, int N, int P> | ||
| 52 | 1 | auto& operator<<(OS& os, stdlib_info<SLib, M, N, P> const& p) | |
| 53 | { | ||
| 54 | if(SLib == stdlib::libcpp_) return os << "libc++ Standard C++ Library " << p.version; | ||
| 55 | 1 | if(SLib == stdlib::gnucpp_) return os << "GNU Standard C++ Library " << p.version; | |
| 56 | |||
| 57 | return os << "Undefined Standard C++ Library"; | ||
| 58 | } | ||
| 59 | |||
| 60 | template<int M, int N, int P> using libcpp_t = stdlib_info<stdlib::libcpp_, M, N, P>; | ||
| 61 | template<int M, int N, int P> using gnucpp_t = stdlib_info<stdlib::gnucpp_, M, N, P>; | ||
| 62 | } | ||
| 63 | |||
| 64 | namespace spy | ||
| 65 | { | ||
| 66 | #if defined(_LIBCPP_VERSION) | ||
| 67 | #define SPY_STDLIB_IS_LIBCPP | ||
| 68 | using stdlib_type = _::libcpp_t<(_LIBCPP_VERSION / 1000) % 10, 0, _LIBCPP_VERSION % 1000>; | ||
| 69 | #elif defined(__GLIBCXX__) | ||
| 70 | #define SPY_STDLIB_IS_GLIBCXX | ||
| 71 | #define SPY0 (__GLIBCXX__ / 100) | ||
| 72 | using stdlib_type = _::gnucpp_t<(SPY0 / 100) % 10000, SPY0 % 100, __GLIBCXX__ % 100>; | ||
| 73 | #undef SPY0 | ||
| 74 | #else | ||
| 75 | #define SPY_STDLIB_IS_UNKNOWN | ||
| 76 | using stdlib_type = _::stdlib_info<_::stdlib::undefined_, -1, 0, 0>; | ||
| 77 | #endif | ||
| 78 | |||
| 79 | //================================================================================================ | ||
| 80 | //! @ingroup spy_standards | ||
| 81 | //! @brief C++ Standard Library version reporting value | ||
| 82 | //! | ||
| 83 | //! The `spy::stdlib` object can be compared to any other stdlib related value to verify | ||
| 84 | //! if the code being compiled with a specific version of the C++ standard library. | ||
| 85 | //! | ||
| 86 | //! Any stdlib related value can be checked for equality or ordering for a given version. The | ||
| 87 | //! targeted version is then specified using a stdlib-dependent literal. | ||
| 88 | //! | ||
| 89 | //! Additionally, any of the stdlib related value are convertible to `bool`. They evaluates to | ||
| 90 | //! `true` if they matches the correct standard library currently used. | ||
| 91 | //! | ||
| 92 | //! @groupheader{Supported Value} | ||
| 93 | //! | ||
| 94 | //! Name | Vendor | ||
| 95 | //! ----------------- | ------------- | ||
| 96 | //! `spy::libcpp_` | Clang libcpp | ||
| 97 | //! `spy::gnucpp_` | GNU C++ standard library | ||
| 98 | //! | ||
| 99 | //! @groupheader{Example} | ||
| 100 | //! @godbolt{samples/stdlib.cpp} | ||
| 101 | //================================================================================================ | ||
| 102 | constexpr inline auto stdlib = stdlib_type {}; | ||
| 103 | } | ||
| 104 | |||
| 105 | namespace spy::_ | ||
| 106 | { | ||
| 107 | template<stdlib SLib, int M, int N, int P> | ||
| 108 | inline constexpr stdlib_info<SLib, M, N, P>::operator bool() const noexcept | ||
| 109 | { | ||
| 110 | return spy::stdlib == *this; | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | namespace spy | ||
| 115 | { | ||
| 116 | //================================================================================================ | ||
| 117 | // STDLIBs detector stand-alone instances | ||
| 118 | //================================================================================================ | ||
| 119 | constexpr inline auto libcpp_ = _::libcpp_t<-1, 0, 0> {}; | ||
| 120 | constexpr inline auto gnucpp_ = _::gnucpp_t<-1, 0, 0> {}; | ||
| 121 | } | ||
| 122 | |||
| 123 | namespace spy::literal | ||
| 124 | { | ||
| 125 | template<char... c> constexpr auto operator""_libcpp() | ||
| 126 | { | ||
| 127 | return _::literal_wrap<_::libcpp_t, c...>(); | ||
| 128 | } | ||
| 129 | |||
| 130 | template<char... c> constexpr auto operator""_gnucpp() | ||
| 131 | { | ||
| 132 | return _::literal_wrap<_::gnucpp_t, c...>(); | ||
| 133 | } | ||
| 134 | } | ||
| 135 |