Fix union member access for EXEC_INQUIRE.
[gcc.git] / libstdc++-v3 / src / c++20 / format.cc
blob1a24fcab7f76f1e84696cca7dfc425d46490be22
1 // Definitions for <chrono> formatting -*- C++ -*-
3 // Copyright The GNU Toolchain Authors.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
25 #define _GLIBCXX_USE_CXX11_ABI 1
26 #include "../c++26/text_encoding.cc"
28 #ifdef _GLIBCXX_USE_NL_LANGINFO_L
29 # include <format>
30 # include <chrono>
31 # include <memory> // make_unique
32 # include <mutex> // mutex, lock_guard
33 # include <string.h> // strlen, strcpy
34 # ifdef _GLIBCXX_HAVE_ICONV
35 # include <iconv.h>
36 # include <errno.h>
37 # endif
38 #endif
40 namespace std
42 _GLIBCXX_BEGIN_NAMESPACE_VERSION
43 namespace __format
45 // Helpers for P2419R2
46 // (Clarify handling of encodings in localized formatting of chrono types)
47 // Convert a string from the locale's charset to UTF-8.
49 #if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8
50 namespace
52 #ifndef _GLIBCXX_HAS_GTHREADS
53 // Dummy mutex
54 struct mutex
56 void lock() const { }
57 void unlock() const { }
59 #endif
61 // A non-standard locale::facet that caches the locale's std::text_encoding
62 // and an iconv descriptor for converting from that encoding to UTF-8.
63 struct __encoding : locale::facet
65 static locale::id id;
67 explicit
68 __encoding(const text_encoding& enc, size_t refs = 0)
69 : facet(refs), _M_enc(enc)
71 #ifdef _GLIBCXX_HAVE_ICONV
72 using enum text_encoding::id;
73 switch (_M_enc.mib())
75 case UTF8:
76 case ASCII:
77 break;
78 default:
79 _M_cd = ::iconv_open("UTF-8", _M_enc.name());
81 #endif
84 ~__encoding()
86 #ifdef _GLIBCXX_HAVE_ICONV
87 if (_M_cd != (::iconv_t)-1)
88 ::iconv_close(_M_cd);
89 #endif
92 text_encoding _M_enc;
93 #ifdef _GLIBCXX_HAVE_ICONV
94 ::iconv_t _M_cd = (::iconv_t)-1;
95 mutable mutex mx;
96 #endif
98 // Convert `input` to UTF-8, using `out` to hold the result.
99 codecvt_base::result
100 conv(string_view input, string& out) const
102 if (input.empty()) [[unlikely]]
103 return codecvt_base::noconv;
105 #ifdef _GLIBCXX_HAVE_ICONV
106 if (_M_cd == (::iconv_t)-1)
107 return codecvt_base::error;
109 size_t inbytesleft = input.size();
110 size_t written = 0;
111 bool done = false;
113 auto overwrite = [&](char* p, size_t n) {
114 auto inbytes
115 = const_cast<char*>(input.data()) + input.size() - inbytesleft;
116 char* outbytes = p + written;
117 size_t outbytesleft = n - written;
118 size_t res = ::iconv(_M_cd, &inbytes, &inbytesleft,
119 &outbytes, &outbytesleft);
120 if (res == (size_t)-1)
122 if (errno != E2BIG)
124 ::iconv(_M_cd, nullptr, 0, nullptr, 0); // reset
125 done = true;
126 return 0zu;
129 else
130 done = true;
131 written = outbytes - p;
132 return written;
135 size_t mult = 1;
136 lock_guard<mutex> lock(mx);
139 // Estimate that we need 1.5 UTF-8 code units per char, but increase
140 // that every time the conversion fails due to insufficient space.
141 out.resize_and_overwrite((inbytesleft * 3 / 2) * mult, overwrite);
142 ++mult;
144 while (!done);
146 return out.empty() ? codecvt_base::error : codecvt_base::ok;
147 #else
148 return codecvt_base::error;
149 #endif
153 locale::id __encoding::id;
155 inline const __encoding*
156 __get_encoding_facet(const locale& loc)
158 // Don't need to use __try_use_facet with its dynamic_cast<const __encoding*>
159 // because we know there are no types derived from __encoding. We have the
160 // facet if the id is within the array bounds and the element is non-null.
161 const auto id = __encoding::id._M_id();
162 if (id >= loc._M_impl->_M_facets_size)
163 return nullptr;
164 return static_cast<const __encoding*>(loc._M_impl->_M_facets[id]);
167 } // namespace
169 locale
170 __with_encoding_conversion(const locale& loc)
172 if (__get_encoding_facet(loc))
173 return loc;
175 string name = loc.name();
176 if (name == "C" || name == "*")
177 return loc;
179 text_encoding locenc = __locale_encoding(name.c_str());
181 if (locenc == text_encoding::UTF8 || locenc == text_encoding::ASCII
182 || locenc == text_encoding::unknown)
183 return loc;
185 auto facetp = std::make_unique<__encoding>(locenc);
186 locale loc2(loc, facetp.get()); // FIXME: PR libstdc++/113704
187 facetp.release();
188 // FIXME: Ideally we wouldn't need to reallocate this string again,
189 // just don't delete[] it in the locale(locale, Facet*) constructor.
190 if (const char* name = loc._M_impl->_M_names[0])
192 loc2._M_impl->_M_names[0] = new char[strlen(name) + 1];
193 strcpy(loc2._M_impl->_M_names[0], name);
195 return loc2;
198 string_view
199 __locale_encoding_to_utf8(const locale& loc, string_view str, void* poutbuf)
201 string& outbuf = *static_cast<string*>(poutbuf);
202 if (auto enc_facet = __get_encoding_facet(loc))
204 auto result = enc_facet->conv(str, outbuf);
205 if (result == codecvt_base::ok)
206 str = outbuf; // UTF-8 output was written to outbuf.
207 // else result was noconv or error, return str unchanged.
209 return str;
211 #else
212 locale
213 __with_encoding_conversion(const locale& loc)
214 { return loc; }
216 string_view
217 __locale_encoding_to_utf8(const locale&, string_view str, void*)
218 { return str; }
219 #endif // USE_NL_LANGINFO_L && CHAR_BIT == 8
220 } // namespace __format
221 _GLIBCXX_END_NAMESPACE_VERSION
222 } // namespace std