Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
StdCompat.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Common_StdCompat_h_
5#define _Stroika_Foundation_Common_StdCompat_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <bit>
10#include <cmath>
11#include <compare>
12#include <cstdarg>
13#include <ranges>
14
15// Various kooky constraints
16// (1) clang++15/16 don't set __cpp_lib_format, so cannot check __cpp_lib_format >= 201907 instead check __has_include(<format>)
17// (2) has_include <format> false positives on some versions of XCode, and no reason to even build qStroika_HasComponent_fmtlib unless
18// its needed, so check it first
19
20#if qStroika_HasComponent_fmtlib
21#include <fmt/chrono.h>
22#include <fmt/format.h>
23#include <fmt/xchar.h>
24#elif __has_include(<format>)
25#include <format>
26#endif
27
28/**
29 * \file
30 *
31 * The purpose of this module is to define any std c++ functions/classes etc - which may not be provided by the
32 * current std c++ library (often because not compiled with appropriate --std=... flag) - and/or because its
33 * an old compiler.
34 *
35 * This doesn't strictly violate any rules about sticking stuff into namespace std - cuz we don't. That's why we use a
36 * separate namespace (that often just indirects to the namespace std - where the function/class is defined already).
37 *
38 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
39 *
40 */
41
42namespace Stroika::Foundation::Common::StdCompat {
43
44 /**
45 * By default include all of std, but throw in selected missing things from some implementations.
46 */
47 using namespace std;
48
49#if qStroika_HasComponent_fmtlib
50#define qStroika_Foundation_Characters_FMT_PREFIX_ fmt
51#elif __has_include(<format>)
52#define qStroika_Foundation_Characters_FMT_PREFIX_ std
53#else
54 static_assert (false, "Stroika v3 requires some std::format compatible library - if building with one lacking builtin std::format, "
55 "configure --fmtlib use");
56#endif
57
58 /**
59 * To allow interop between std::format and fmt(fmtlib)::format, publish the names into the namespace 'Stroika::Foundation::Common::StdCompat' and use those.
60 * Lose this once I can fully depend upon std::format... --LGP 2024-03-12
61 */
62 using qStroika_Foundation_Characters_FMT_PREFIX_::basic_format_parse_context;
63 using qStroika_Foundation_Characters_FMT_PREFIX_::format;
64 using qStroika_Foundation_Characters_FMT_PREFIX_::format_args;
65 using qStroika_Foundation_Characters_FMT_PREFIX_::format_error;
66 using qStroika_Foundation_Characters_FMT_PREFIX_::format_string;
67 using qStroika_Foundation_Characters_FMT_PREFIX_::format_to;
68 using qStroika_Foundation_Characters_FMT_PREFIX_::make_format_args;
69 using qStroika_Foundation_Characters_FMT_PREFIX_::make_wformat_args;
70 using qStroika_Foundation_Characters_FMT_PREFIX_::vformat;
71 using qStroika_Foundation_Characters_FMT_PREFIX_::wformat_args;
72 using qStroika_Foundation_Characters_FMT_PREFIX_::wformat_string;
73
74#if __cplusplus >= kStrokia_Foundation_Common_cplusplus_23 || _HAS_CXX23 /*vis studio uses _HAS_CXX23 */
75 template <class T, class CharT>
76 concept formattable = std::formattable<T, CharT>;
77#else
78 namespace Private_ {
79 template <class _CharT>
80 struct _Phony_fmt_iter_for {
81 using difference_type = ptrdiff_t;
82 _CharT& operator* () const;
83 _Phony_fmt_iter_for& operator++ ();
84 _Phony_fmt_iter_for operator++ (int);
85 };
86 // _Formatter = typename _Context needed for clang++-15 (compiler bug but no BWA declaration for now...BWA in middle of BWA ;-))
87 template <class _Ty, class _Context, class _Formatter = typename _Context::template formatter_type<remove_const_t<_Ty>>>
88 concept _Formattable_with = semiregular<_Formatter> && requires (_Formatter& __f, const _Formatter& __cf, _Ty&& __t, _Context __fc,
89 basic_format_parse_context<typename _Context::char_type> __pc) {
90 { __f.parse (__pc) } -> same_as<typename decltype (__pc)::iterator>;
91 { __cf.format (__t, __fc) } -> same_as<typename _Context::iterator>;
92 };
93 }
94 template <class T, class CharT>
95 concept formattable =
96 Private_::_Formattable_with<remove_reference_t<T>, qStroika_Foundation_Characters_FMT_PREFIX_::basic_format_context<Private_::_Phony_fmt_iter_for<CharT>, CharT>>;
97#endif
98
99 /**
100 * Workaround absence of bit_cast in MacOS XCode 14 (which we support with Stroika v3)
101 */
102#if __cpp_lib_bit_cast >= 201806L
103 using std::bit_cast;
104#else
105 template <class To, class From>
106 inline To bit_cast (const From& src) noexcept
107 requires (sizeof (To) == sizeof (From) && std::is_trivially_copyable_v<From> && std::is_trivially_copyable_v<To>)
108 {
109 static_assert (std::is_trivially_constructible_v<To>, "This implementation additionally requires "
110 "destination type to be trivially constructible");
111 To dst;
112 std::memcpy (&dst, &src, sizeof (To));
113 return dst;
114 }
115#endif
116
117 /**
118 * Workaround absence of byteswap gcc up to version 12, and clang (up to 14).
119 */
120#if __cpp_lib_byteswap >= 202110L
121 using std::byteswap;
122#else
123 template <class T>
124 inline T byteswap (T n) noexcept
125 {
126 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Warray-bounds\"");
127 static_assert (std::has_unique_object_representations_v<T>, "T may not have padding bits");
128 auto value_representation = bit_cast<array<byte, sizeof (T)>> (n);
129 for (size_t i = 0; i < value_representation.size () / 2; ++i) {
130 swap (value_representation[i], value_representation[value_representation.size () - i]);
131 }
132 return bit_cast<T> (value_representation);
133 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Warray-bounds\"");
134 }
135#endif
136
137 /**
138 * workaround qCompilerAndStdLib_fpclasifyEtcOfInteger_Buggy
139 */
140 template <typename T>
141#if __cplusplus >= kStrokia_Foundation_Common_cplusplus_23 || _MSVC_LANG >= kStrokia_Foundation_Common_cplusplus_23
142 constexpr
143#else
144 inline
145#endif
146 bool
147 isinf (T v) noexcept
148 {
149#if qCompilerAndStdLib_fpclasifyEtcOfInteger_Buggy
150 if constexpr (integral<T>) {
151 return false; // needed for vis stud
152 }
153 else
154#endif
155 return std::isinf (v);
156 }
157
158 /**
159 * workaround qCompilerAndStdLib_fpclasifyEtcOfInteger_Buggy
160 */
161 template <typename T>
162#if __cplusplus >= kStrokia_Foundation_Common_cplusplus_23
163 constexpr
164#else
165 inline
166#endif
167 bool
168 isnan (T v) noexcept
169 {
170#if qCompilerAndStdLib_fpclasifyEtcOfInteger_Buggy
171 if constexpr (integral<T>) {
172 return false; // needed for vis stud
173 }
174 else
175#endif
176 return std::isnan (v);
177 }
178
179#if qCompilerAndStdLib_stdlib_compare_three_way_present_but_Buggy
180 struct compare_three_way {
181 // NOTE - this workaround is GENERALLY INADEQUATE, but is adequate for my current use in Stroika -- LGP 2022-11-01
182 template <typename LT, typename RT>
183 constexpr auto operator() (LT&& lhs, RT&& rhs) const
184 {
185 using CT = common_type_t<LT, RT>;
186 if (equal_to<CT>{}(forward<LT> (lhs), forward<RT> (rhs))) {
187 return strong_ordering::equal;
188 }
189 return less<CT>{}(forward<LT> (lhs), forward<RT> (rhs)) ? strong_ordering::less : strong_ordering::greater;
190 }
191 using is_transparent = void;
192 };
193#else
194 using compare_three_way = std::compare_three_way;
195#endif
196
197}
198
199/*
200 ********************************************************************************
201 ***************************** Implementation Details ***************************
202 ********************************************************************************
203 */
204#include "StdCompat.inl"
205
206#endif /*_Stroika_Foundation_Common_StdCompat_h_*/
constexpr bool isnan(T v) noexcept
Definition StdCompat.h:168
To bit_cast(const From &src) noexcept
Definition StdCompat.h:106
constexpr bool isinf(T v) noexcept
Definition StdCompat.h:147
STL namespace.