4#ifndef _Stroika_Foundation_Common_StdCompat_h_
5#define _Stroika_Foundation_Common_StdCompat_h_ 1
7#include "Stroika/Foundation/StroikaPreComp.h"
27#if qStroika_HasComponent_fmtlib
28#include <fmt/chrono.h>
29#include <fmt/format.h>
31#elif __has_include(<format>)
51namespace Stroika::Foundation::Common::StdCompat {
66 { lo.lock () } -> std::same_as<void>;
68 { lo.unlock () } -> std::same_as<void>;
78 { lo.try_lock () } -> std::same_as<bool>;
83 concept _Boolean_testable_impl = convertible_to<_Ty, bool>;
92 concept Boolean_testable = Private_::_Boolean_testable_impl<_Ty> &&
requires (_Ty&& __t) {
93 { !
static_cast<_Ty&&
> (__t) } -> Private_::_Boolean_testable_impl;
101 template <
class FROM,
class TO>
104#if qStroika_HasComponent_fmtlib
105#define qStroika_Foundation_Characters_FMT_PREFIX_ fmt
106#elif __has_include(<format>)
107#define qStroika_Foundation_Characters_FMT_PREFIX_ std
109 static_assert (
false,
"Stroika v3 requires some std::format compatible library - if building with one lacking builtin std::format, "
110 "configure --fmtlib use");
117 using qStroika_Foundation_Characters_FMT_PREFIX_::basic_format_parse_context;
118 using qStroika_Foundation_Characters_FMT_PREFIX_::format;
119 using qStroika_Foundation_Characters_FMT_PREFIX_::format_args;
120 using qStroika_Foundation_Characters_FMT_PREFIX_::format_error;
121 using qStroika_Foundation_Characters_FMT_PREFIX_::format_string;
122 using qStroika_Foundation_Characters_FMT_PREFIX_::format_to;
123 using qStroika_Foundation_Characters_FMT_PREFIX_::make_format_args;
124 using qStroika_Foundation_Characters_FMT_PREFIX_::make_wformat_args;
125 using qStroika_Foundation_Characters_FMT_PREFIX_::vformat;
126 using qStroika_Foundation_Characters_FMT_PREFIX_::wformat_args;
127 using qStroika_Foundation_Characters_FMT_PREFIX_::wformat_string;
129#if __cplusplus >= kStrokia_Foundation_Common_cplusplus_23 || _HAS_CXX23
130 template <
class T,
class CharT>
131 concept formattable = std::formattable<T, CharT>;
134 template <
class _CharT>
135 struct _Phony_fmt_iter_for {
136 using difference_type = ptrdiff_t;
137 _CharT& operator* ()
const;
138 _Phony_fmt_iter_for& operator++ ();
139 _Phony_fmt_iter_for operator++ (
int);
142 template <
class _Ty,
class _Context,
class _Formatter =
typename _Context::
template formatter_type<remove_const_t<_Ty>>>
143 concept _Formattable_with = semiregular<_Formatter> &&
requires (_Formatter& __f,
const _Formatter& __cf, _Ty&& __t, _Context __fc,
144 basic_format_parse_context<typename _Context::char_type> __pc) {
145 { __f.parse (__pc) } -> same_as<
typename decltype (__pc)::iterator>;
146 { __cf.format (__t, __fc) } -> same_as<typename _Context::iterator>;
149 template <
class T,
class CharT>
150 concept formattable =
151 Private_::_Formattable_with<remove_reference_t<T>, qStroika_Foundation_Characters_FMT_PREFIX_::basic_format_context<Private_::_Phony_fmt_iter_for<CharT>, CharT>>;
157#if __cpp_lib_bit_cast >= 201806L
160 template <
class To,
class From>
162 requires (
sizeof (To) ==
sizeof (From) && std::is_trivially_copyable_v<From> && std::is_trivially_copyable_v<To>)
164 static_assert (std::is_trivially_constructible_v<To>,
"This implementation additionally requires "
165 "destination type to be trivially constructible");
167 std::memcpy (&dst, &src,
sizeof (To));
175#if __cpp_lib_byteswap >= 202110L
181 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Warray-bounds\"");
182 static_assert (std::has_unique_object_representations_v<T>,
"T may not have padding bits");
183 auto value_representation =
bit_cast<array<byte,
sizeof (T)>> (n);
184 for (
size_t i = 0; i < value_representation.size () / 2; ++i) {
185 swap (value_representation[i], value_representation[value_representation.size () - i]);
187 return bit_cast<T> (value_representation);
188 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Warray-bounds\"");
195 template <
typename T>
196#if __cplusplus >= kStrokia_Foundation_Common_cplusplus_23 || _MSVC_LANG >= kStrokia_Foundation_Common_cplusplus_23
204#if qCompilerAndStdLib_fpclasifyEtcOfInteger_Buggy
205 if constexpr (integral<T>) {
210 return std::isinf (v);
216 template <
typename T>
217#if __cplusplus >= kStrokia_Foundation_Common_cplusplus_23
225#if qCompilerAndStdLib_fpclasifyEtcOfInteger_Buggy
226 if constexpr (integral<T>) {
231 return std::isnan (v);
234#if qCompilerAndStdLib_stdlib_compare_three_way_present_but_Buggy
235 struct compare_three_way {
237 template <
typename LT,
typename RT>
238 constexpr auto operator() (LT&& lhs, RT&& rhs)
const
240 using CT = common_type_t<LT, RT>;
241 if (equal_to<CT>{}(forward<LT> (lhs), forward<RT> (rhs))) {
242 return strong_ordering::equal;
244 return less<CT>{}(forward<LT> (lhs), forward<RT> (rhs)) ? strong_ordering::less : strong_ordering::greater;
246 using is_transparent = void;
249 using compare_three_way = std::compare_three_way;
255#if __cpp_lib_expected
256 template <
typename T>
257 using unexpected = std::unexpected<T>;
258 template <
typename T,
typename E>
259 using expected = std::expected<T, E>;
261 template <
typename T>
264 template <
typename _UError = T>
265 requires (!is_same_v<remove_cvref_t<_UError>,
unexpected> && !is_same_v<remove_cvref_t<_UError>, in_place_t> && is_constructible_v<T, _UError>)
266 constexpr explicit unexpected (_UError&& _Unex)
267 : _Unexpected (forward<_UError> (_Unex))
270 template <
typename... _Args>
271 requires is_constructible_v<T, _Args...>
272 constexpr explicit unexpected (in_place_t, _Args&&... _Vals)
273 : _Unexpected (forward<_Args> (_Vals)...)
276 template <
typename _Uty,
typename... _Args>
277 requires is_constructible_v<T, initializer_list<_Uty>&, _Args...>
278 constexpr explicit unexpected (in_place_t, initializer_list<_Uty> _Ilist, _Args&&... _Vals)
279 : _Unexpected (_Ilist, forward<_Args> (_Vals)...)
283 constexpr const T& error ()
const&
noexcept
287 constexpr T& error () &
noexcept
291 constexpr const T&& error ()
const&&
noexcept
293 return std::move (_Unexpected);
295 constexpr T&& error () &&
noexcept
297 return std::move (_Unexpected);
303 swap (_Unexpected, _Other._Unexpected);
307 requires is_swappable<T>::value
312 template <
class _UErr>
315 return _Left._Unexpected == _Right.error ();
321 template <
typename T>
330 template <
typename T,
typename E>
332 template <
typename T,
typename E>
335 using value_type = T;
336 using error_type = E;
339 constexpr expected ()
noexcept =
default;
349 template <
typename T1,
typename E1>
359 explicit operator bool ()
const noexcept
361 return std::get_if<T> (&fData_) !=
nullptr;
369 return get<T> (fData_);
373 return get<E> (fData_);
377 variant<T, E> fData_;
392#if __has_cpp_attribute(indeterminate)
393#define qStroika_ATTRIBUTE_INDETERMINATE [[indeterminate]]
395#define qStroika_ATTRIBUTE_INDETERMINATE
404#if __has_cpp_attribute(assume)
405#define qStroika_ATTRIBUTE_ASSUME(X) [[assume (X)]];
410#define qStroika_ATTRIBUTE_ASSUME(X) __assume (X);
412#define qStroika_ATTRIBUTE_ASSUME(X)
415#if qCompilerAndStdLib_AssumeWarningSpamming_Buggy
417 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wassume\"");
426#if qCompilerAndStdLib_NO_UNIQUE_ADDR_IgnoredAndMustUseMSVCNOUNIQUE_Buggy && defined(_MSC_VER)
427#if qCompilerAndStdLib_NO_UNIQUE_ADDR_REALLYREALLY_Buggy
428#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS
430#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
432#elif __has_cpp_attribute(no_unique_address)
433#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS [[no_unique_address]]
435#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS
442#if qCompilerAndStdLib_NO_UNIQUE_ADDR_REALLYREALLY_Buggy
443#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS_VCFORCE [[msvc::no_unique_address]]
445#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS_VCFORCE qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS
454#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS_VCBUGGY qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS
463#include "StdCompat.inl"
constexpr bool isnan(T v) noexcept
To bit_cast(const From &src) noexcept
constexpr bool isinf(T v) noexcept
Logically the C++ standard BasicLockable named requirement, but that was not included in std c++ libr...
handy re-usable concept, with the obvious meaning, and strangely omitted from std-c++ (though used in...
Logically the C++ standard Lockable named requirement, but that was not included in std c++ library.
like convertible_to, but also handling cases where T has an explicit CTOR taking From