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
203#if qCompilerAndStdLib_fpclasifyEtcOfInteger_Buggy
204 if constexpr (integral<T>) {
209 return std::isinf (v);
215 template <
typename T>
216#if __cplusplus >= kStrokia_Foundation_Common_cplusplus_23
223#if qCompilerAndStdLib_fpclasifyEtcOfInteger_Buggy
224 if constexpr (integral<T>) {
229 return std::isnan (v);
232#if qCompilerAndStdLib_stdlib_compare_three_way_present_but_Buggy
233 struct compare_three_way {
235 template <
typename LT,
typename RT>
236 constexpr auto operator() (LT&& lhs, RT&& rhs)
const
238 using CT = common_type_t<LT, RT>;
239 if (equal_to<CT>{}(forward<LT> (lhs), forward<RT> (rhs))) {
240 return strong_ordering::equal;
242 return less<CT>{}(forward<LT> (lhs), forward<RT> (rhs)) ? strong_ordering::less : strong_ordering::greater;
244 using is_transparent = void;
247 using compare_three_way = std::compare_three_way;
253#if __cpp_lib_expected
254 template <
typename T>
255 using unexpected = std::unexpected<T>;
256 template <
typename T,
typename E>
257 using expected = std::expected<T, E>;
259 template <
typename T>
262 template <
typename _UError = T>
263 requires (!is_same_v<remove_cvref_t<_UError>,
unexpected> && !is_same_v<remove_cvref_t<_UError>, in_place_t> && is_constructible_v<T, _UError>)
264 constexpr explicit unexpected (_UError&& _Unex)
265 : _Unexpected (forward<_UError> (_Unex))
268 template <
typename... _Args>
269 requires is_constructible_v<T, _Args...>
270 constexpr explicit unexpected (in_place_t, _Args&&... _Vals)
271 : _Unexpected (forward<_Args> (_Vals)...)
274 template <
typename _Uty,
typename... _Args>
275 requires is_constructible_v<T, initializer_list<_Uty>&, _Args...>
276 constexpr explicit unexpected (in_place_t, initializer_list<_Uty> _Ilist, _Args&&... _Vals)
277 : _Unexpected (_Ilist, forward<_Args> (_Vals)...)
281 constexpr const T& error ()
const&
noexcept
285 constexpr T& error () &
noexcept
289 constexpr const T&& error ()
const&&
noexcept
291 return std::move (_Unexpected);
293 constexpr T&& error () &&
noexcept
295 return std::move (_Unexpected);
301 swap (_Unexpected, _Other._Unexpected);
305 requires is_swappable<T>::value
310 template <
class _UErr>
313 return _Left._Unexpected == _Right.error ();
319 template <
typename T>
328 template <
typename T,
typename E>
330 template <
typename T,
typename E>
333 using value_type = T;
334 using error_type = E;
337 constexpr expected ()
noexcept =
default;
347 template <
typename T1,
typename E1>
357 explicit operator bool ()
const noexcept
359 return std::get_if<T> (&fData_) !=
nullptr;
367 return get<T> (fData_);
371 return get<E> (fData_);
375 variant<T, E> fData_;
390#if __has_cpp_attribute(indeterminate)
391#define qStroika_ATTRIBUTE_INDETERMINATE [[indeterminate]]
393#define qStroika_ATTRIBUTE_INDETERMINATE
402#if __has_cpp_attribute(assume)
403#define qStroika_ATTRIBUTE_ASSUME(X) [[assume (X)]];
408#define qStroika_ATTRIBUTE_ASSUME(X) __assume (X);
410#define qStroika_ATTRIBUTE_ASSUME(X)
413#if qCompilerAndStdLib_AssumeWarningSpamming_Buggy
415 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wassume\"");
424#if qCompilerAndStdLib_NO_UNIQUE_ADDR_IgnoredAndMustUseMSVCNOUNIQUE_Buggy && defined(_MSC_VER)
425#if qCompilerAndStdLib_NO_UNIQUE_ADDR_REALLYREALLY_Buggy
426#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS
428#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
430#elif __has_cpp_attribute(no_unique_address)
431#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS [[no_unique_address]]
433#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS
440#if qCompilerAndStdLib_NO_UNIQUE_ADDR_REALLYREALLY_Buggy
441#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS_VCFORCE [[msvc::no_unique_address]]
443#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS_VCFORCE qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS
452#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS_VCBUGGY qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS
461#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