xref: /freebsd/contrib/llvm-project/libcxx/src/locale.cpp (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
1349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
95f757f3fSDimitry Andric #include <__utility/no_destroy.h>
1081ad6265SDimitry Andric #include <algorithm>
1181ad6265SDimitry Andric #include <clocale>
1281ad6265SDimitry Andric #include <codecvt>
135f757f3fSDimitry Andric #include <cstddef>
1481ad6265SDimitry Andric #include <cstdio>
1581ad6265SDimitry Andric #include <cstdlib>
1681ad6265SDimitry Andric #include <cstring>
1781ad6265SDimitry Andric #include <locale>
185f757f3fSDimitry Andric #include <new>
1981ad6265SDimitry Andric #include <string>
2081ad6265SDimitry Andric #include <type_traits>
2181ad6265SDimitry Andric #include <typeinfo>
225f757f3fSDimitry Andric #include <utility>
2381ad6265SDimitry Andric #include <vector>
24349cc55cSDimitry Andric 
25349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2681ad6265SDimitry Andric #  include <cwctype>
27349cc55cSDimitry Andric #endif
28349cc55cSDimitry Andric 
29349cc55cSDimitry Andric #if defined(_AIX)
30349cc55cSDimitry Andric #  include <sys/localedef.h> // for __lc_ctype_ptr
31349cc55cSDimitry Andric #endif
32349cc55cSDimitry Andric 
330b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT)
340b57cec5SDimitry Andric #  define _CTYPE_DISABLE_MACROS
350b57cec5SDimitry Andric #endif
36349cc55cSDimitry Andric 
370b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
38d409305fSDimitry Andric #  include "__support/win32/locale_win32.h"
39e8d8bef9SDimitry Andric #elif !defined(__BIONIC__) && !defined(__NuttX__)
400b57cec5SDimitry Andric #  include <langinfo.h>
410b57cec5SDimitry Andric #endif
42349cc55cSDimitry Andric 
430b57cec5SDimitry Andric #include "include/atomic_support.h"
44fe6060f1SDimitry Andric #include "include/sso_allocator.h"
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric // On Linux, wint_t and wchar_t have different signed-ness, and this causes
470b57cec5SDimitry Andric // lots of noise in the build log, but no bugs that I know of.
4881ad6265SDimitry Andric _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wsign-conversion")
4981ad6265SDimitry Andric 
5081ad6265SDimitry Andric _LIBCPP_PUSH_MACROS
5181ad6265SDimitry Andric #include <__undef_macros>
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric struct __libcpp_unique_locale {
560b57cec5SDimitry Andric   __libcpp_unique_locale(const char* nm) : __loc_(newlocale(LC_ALL_MASK, nm, 0)) {}
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   ~__libcpp_unique_locale() {
590b57cec5SDimitry Andric     if (__loc_)
600b57cec5SDimitry Andric       freelocale(__loc_);
610b57cec5SDimitry Andric   }
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   explicit operator bool() const { return __loc_; }
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric   locale_t& get() { return __loc_; }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   locale_t __loc_;
68*cb14a3feSDimitry Andric 
690b57cec5SDimitry Andric private:
700b57cec5SDimitry Andric   __libcpp_unique_locale(__libcpp_unique_locale const&);
710b57cec5SDimitry Andric   __libcpp_unique_locale& operator=(__libcpp_unique_locale const&);
720b57cec5SDimitry Andric };
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric #ifdef __cloc_defined
750b57cec5SDimitry Andric locale_t __cloc() {
760b57cec5SDimitry Andric   // In theory this could create a race condition. In practice
770b57cec5SDimitry Andric   // the race condition is non-fatal since it will just create
780b57cec5SDimitry Andric   // a little resource leak. Better approach would be appreciated.
790b57cec5SDimitry Andric   static locale_t result = newlocale(LC_ALL_MASK, "C", 0);
800b57cec5SDimitry Andric   return result;
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric #endif // __cloc_defined
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric namespace {
850b57cec5SDimitry Andric 
865f757f3fSDimitry Andric struct releaser {
870b57cec5SDimitry Andric   void operator()(locale::facet* p) { p->__release_shared(); }
880b57cec5SDimitry Andric };
890b57cec5SDimitry Andric 
90349cc55cSDimitry Andric template <class T, class... Args>
91*cb14a3feSDimitry Andric T& make(Args... args) {
925f757f3fSDimitry Andric   alignas(T) static std::byte buf[sizeof(T)];
93349cc55cSDimitry Andric   auto* obj = ::new (&buf) T(args...);
940b57cec5SDimitry Andric   return *obj;
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric template <typename T, size_t N>
98*cb14a3feSDimitry Andric inline constexpr size_t countof(const T (&)[N]) {
990b57cec5SDimitry Andric   return N;
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric template <typename T>
103*cb14a3feSDimitry Andric inline constexpr size_t countof(const T* const begin, const T* const end) {
1040b57cec5SDimitry Andric   return static_cast<size_t>(end - begin);
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric 
107*cb14a3feSDimitry Andric } // namespace
1080b57cec5SDimitry Andric 
109*cb14a3feSDimitry Andric string build_name(const string& other, const string& one, locale::category c) {
11006c3fb27SDimitry Andric   if (other == "*" || one == "*")
11106c3fb27SDimitry Andric     return "*";
11206c3fb27SDimitry Andric   if (c == locale::none || other == one)
11306c3fb27SDimitry Andric     return other;
11406c3fb27SDimitry Andric 
11506c3fb27SDimitry Andric   // FIXME: Handle the more complicated cases, such as when the locale has
11606c3fb27SDimitry Andric   // different names for different categories.
11706c3fb27SDimitry Andric   return "*";
11806c3fb27SDimitry Andric }
11906c3fb27SDimitry Andric 
1200b57cec5SDimitry Andric const locale::category locale::none;
1210b57cec5SDimitry Andric const locale::category locale::collate;
1220b57cec5SDimitry Andric const locale::category locale::ctype;
1230b57cec5SDimitry Andric const locale::category locale::monetary;
1240b57cec5SDimitry Andric const locale::category locale::numeric;
1250b57cec5SDimitry Andric const locale::category locale::time;
1260b57cec5SDimitry Andric const locale::category locale::messages;
1270b57cec5SDimitry Andric const locale::category locale::all;
1280b57cec5SDimitry Andric 
129*cb14a3feSDimitry Andric class _LIBCPP_HIDDEN locale::__imp : public facet {
130e8d8bef9SDimitry Andric   enum { N = 30 };
1310b57cec5SDimitry Andric   vector<facet*, __sso_allocator<facet*, N> > facets_;
1320b57cec5SDimitry Andric   string name_;
133*cb14a3feSDimitry Andric 
1340b57cec5SDimitry Andric public:
1350b57cec5SDimitry Andric   explicit __imp(size_t refs = 0);
1360b57cec5SDimitry Andric   explicit __imp(const string& name, size_t refs = 0);
1370b57cec5SDimitry Andric   __imp(const __imp&);
1380b57cec5SDimitry Andric   __imp(const __imp&, const string&, locale::category c);
1390b57cec5SDimitry Andric   __imp(const __imp& other, const __imp& one, locale::category c);
1400b57cec5SDimitry Andric   __imp(const __imp&, facet* f, long id);
1410b57cec5SDimitry Andric   ~__imp();
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   const string& name() const { return name_; }
144*cb14a3feSDimitry Andric   bool has_facet(long id) const { return static_cast<size_t>(id) < facets_.size() && facets_[static_cast<size_t>(id)]; }
1450b57cec5SDimitry Andric   const locale::facet* use_facet(long id) const;
1460b57cec5SDimitry Andric 
1475f757f3fSDimitry Andric   void acquire();
1485f757f3fSDimitry Andric   void release();
1495f757f3fSDimitry Andric   static __no_destroy<__imp> classic_locale_imp_;
1505f757f3fSDimitry Andric 
1510b57cec5SDimitry Andric private:
1520b57cec5SDimitry Andric   void install(facet* f, long id);
153*cb14a3feSDimitry Andric   template <class F>
154*cb14a3feSDimitry Andric   void install(F* f) {
155*cb14a3feSDimitry Andric     install(f, f->id.__get());
156*cb14a3feSDimitry Andric   }
157*cb14a3feSDimitry Andric   template <class F>
158*cb14a3feSDimitry Andric   void install_from(const __imp& other);
1590b57cec5SDimitry Andric };
1600b57cec5SDimitry Andric 
161*cb14a3feSDimitry Andric locale::__imp::__imp(size_t refs) : facet(refs), facets_(N), name_("C") {
1620b57cec5SDimitry Andric   facets_.clear();
1635f757f3fSDimitry Andric   install(&make<std::collate<char> >(1u));
164349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1655f757f3fSDimitry Andric   install(&make<std::collate<wchar_t> >(1u));
166349cc55cSDimitry Andric #endif
1675f757f3fSDimitry Andric   install(&make<std::ctype<char> >(nullptr, false, 1u));
168349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1695f757f3fSDimitry Andric   install(&make<std::ctype<wchar_t> >(1u));
170349cc55cSDimitry Andric #endif
1710b57cec5SDimitry Andric   install(&make<codecvt<char, char, mbstate_t> >(1u));
172349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1730b57cec5SDimitry Andric   install(&make<codecvt<wchar_t, char, mbstate_t> >(1u));
174349cc55cSDimitry Andric #endif
175e8d8bef9SDimitry Andric   _LIBCPP_SUPPRESS_DEPRECATED_PUSH
1760b57cec5SDimitry Andric   install(&make<codecvt<char16_t, char, mbstate_t> >(1u));
1770b57cec5SDimitry Andric   install(&make<codecvt<char32_t, char, mbstate_t> >(1u));
178e8d8bef9SDimitry Andric   _LIBCPP_SUPPRESS_DEPRECATED_POP
179fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
180e8d8bef9SDimitry Andric   install(&make<codecvt<char16_t, char8_t, mbstate_t> >(1u));
181e8d8bef9SDimitry Andric   install(&make<codecvt<char32_t, char8_t, mbstate_t> >(1u));
182e8d8bef9SDimitry Andric #endif
1830b57cec5SDimitry Andric   install(&make<numpunct<char> >(1u));
184349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1850b57cec5SDimitry Andric   install(&make<numpunct<wchar_t> >(1u));
186349cc55cSDimitry Andric #endif
1870b57cec5SDimitry Andric   install(&make<num_get<char> >(1u));
188349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1890b57cec5SDimitry Andric   install(&make<num_get<wchar_t> >(1u));
190349cc55cSDimitry Andric #endif
1910b57cec5SDimitry Andric   install(&make<num_put<char> >(1u));
192349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1930b57cec5SDimitry Andric   install(&make<num_put<wchar_t> >(1u));
194349cc55cSDimitry Andric #endif
1950b57cec5SDimitry Andric   install(&make<moneypunct<char, false> >(1u));
1960b57cec5SDimitry Andric   install(&make<moneypunct<char, true> >(1u));
197349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1980b57cec5SDimitry Andric   install(&make<moneypunct<wchar_t, false> >(1u));
1990b57cec5SDimitry Andric   install(&make<moneypunct<wchar_t, true> >(1u));
200349cc55cSDimitry Andric #endif
2010b57cec5SDimitry Andric   install(&make<money_get<char> >(1u));
202349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2030b57cec5SDimitry Andric   install(&make<money_get<wchar_t> >(1u));
204349cc55cSDimitry Andric #endif
2050b57cec5SDimitry Andric   install(&make<money_put<char> >(1u));
206349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2070b57cec5SDimitry Andric   install(&make<money_put<wchar_t> >(1u));
208349cc55cSDimitry Andric #endif
2090b57cec5SDimitry Andric   install(&make<time_get<char> >(1u));
210349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2110b57cec5SDimitry Andric   install(&make<time_get<wchar_t> >(1u));
212349cc55cSDimitry Andric #endif
2130b57cec5SDimitry Andric   install(&make<time_put<char> >(1u));
214349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2150b57cec5SDimitry Andric   install(&make<time_put<wchar_t> >(1u));
216349cc55cSDimitry Andric #endif
2175f757f3fSDimitry Andric   install(&make<std::messages<char> >(1u));
218349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2195f757f3fSDimitry Andric   install(&make<std::messages<wchar_t> >(1u));
220349cc55cSDimitry Andric #endif
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric 
223*cb14a3feSDimitry Andric locale::__imp::__imp(const string& name, size_t refs) : facet(refs), facets_(N), name_(name) {
22406c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
225*cb14a3feSDimitry Andric   try {
22606c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
2270b57cec5SDimitry Andric     facets_ = locale::classic().__locale_->facets_;
2280b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
2290b57cec5SDimitry Andric       if (facets_[i])
2300b57cec5SDimitry Andric         facets_[i]->__add_shared();
2310b57cec5SDimitry Andric     install(new collate_byname<char>(name_));
232349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2330b57cec5SDimitry Andric     install(new collate_byname<wchar_t>(name_));
234349cc55cSDimitry Andric #endif
2350b57cec5SDimitry Andric     install(new ctype_byname<char>(name_));
236349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2370b57cec5SDimitry Andric     install(new ctype_byname<wchar_t>(name_));
238349cc55cSDimitry Andric #endif
2390b57cec5SDimitry Andric     install(new codecvt_byname<char, char, mbstate_t>(name_));
240349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2410b57cec5SDimitry Andric     install(new codecvt_byname<wchar_t, char, mbstate_t>(name_));
242349cc55cSDimitry Andric #endif
243e8d8bef9SDimitry Andric     _LIBCPP_SUPPRESS_DEPRECATED_PUSH
2440b57cec5SDimitry Andric     install(new codecvt_byname<char16_t, char, mbstate_t>(name_));
2450b57cec5SDimitry Andric     install(new codecvt_byname<char32_t, char, mbstate_t>(name_));
246e8d8bef9SDimitry Andric     _LIBCPP_SUPPRESS_DEPRECATED_POP
247fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
248e8d8bef9SDimitry Andric     install(new codecvt_byname<char16_t, char8_t, mbstate_t>(name_));
249e8d8bef9SDimitry Andric     install(new codecvt_byname<char32_t, char8_t, mbstate_t>(name_));
250e8d8bef9SDimitry Andric #endif
2510b57cec5SDimitry Andric     install(new numpunct_byname<char>(name_));
252349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2530b57cec5SDimitry Andric     install(new numpunct_byname<wchar_t>(name_));
254349cc55cSDimitry Andric #endif
2550b57cec5SDimitry Andric     install(new moneypunct_byname<char, false>(name_));
2560b57cec5SDimitry Andric     install(new moneypunct_byname<char, true>(name_));
257349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2580b57cec5SDimitry Andric     install(new moneypunct_byname<wchar_t, false>(name_));
2590b57cec5SDimitry Andric     install(new moneypunct_byname<wchar_t, true>(name_));
260349cc55cSDimitry Andric #endif
2610b57cec5SDimitry Andric     install(new time_get_byname<char>(name_));
262349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2630b57cec5SDimitry Andric     install(new time_get_byname<wchar_t>(name_));
264349cc55cSDimitry Andric #endif
2650b57cec5SDimitry Andric     install(new time_put_byname<char>(name_));
266349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2670b57cec5SDimitry Andric     install(new time_put_byname<wchar_t>(name_));
268349cc55cSDimitry Andric #endif
2690b57cec5SDimitry Andric     install(new messages_byname<char>(name_));
270349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2710b57cec5SDimitry Andric     install(new messages_byname<wchar_t>(name_));
272349cc55cSDimitry Andric #endif
27306c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
274*cb14a3feSDimitry Andric   } catch (...) {
2750b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
2760b57cec5SDimitry Andric       if (facets_[i])
2770b57cec5SDimitry Andric         facets_[i]->__release_shared();
2780b57cec5SDimitry Andric     throw;
2790b57cec5SDimitry Andric   }
28006c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
2810b57cec5SDimitry Andric }
2820b57cec5SDimitry Andric 
283*cb14a3feSDimitry Andric locale::__imp::__imp(const __imp& other) : facets_(max<size_t>(N, other.facets_.size())), name_(other.name_) {
2840b57cec5SDimitry Andric   facets_ = other.facets_;
2850b57cec5SDimitry Andric   for (unsigned i = 0; i < facets_.size(); ++i)
2860b57cec5SDimitry Andric     if (facets_[i])
2870b57cec5SDimitry Andric       facets_[i]->__add_shared();
2880b57cec5SDimitry Andric }
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric locale::__imp::__imp(const __imp& other, const string& name, locale::category c)
291*cb14a3feSDimitry Andric     : facets_(N), name_(build_name(other.name_, name, c)) {
2920b57cec5SDimitry Andric   facets_ = other.facets_;
2930b57cec5SDimitry Andric   for (unsigned i = 0; i < facets_.size(); ++i)
2940b57cec5SDimitry Andric     if (facets_[i])
2950b57cec5SDimitry Andric       facets_[i]->__add_shared();
29606c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
297*cb14a3feSDimitry Andric   try {
29806c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
299*cb14a3feSDimitry Andric     if (c & locale::collate) {
3000b57cec5SDimitry Andric       install(new collate_byname<char>(name));
301349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3020b57cec5SDimitry Andric       install(new collate_byname<wchar_t>(name));
303349cc55cSDimitry Andric #endif
3040b57cec5SDimitry Andric     }
305*cb14a3feSDimitry Andric     if (c & locale::ctype) {
3060b57cec5SDimitry Andric       install(new ctype_byname<char>(name));
307349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3080b57cec5SDimitry Andric       install(new ctype_byname<wchar_t>(name));
309349cc55cSDimitry Andric #endif
3100b57cec5SDimitry Andric       install(new codecvt_byname<char, char, mbstate_t>(name));
311349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3120b57cec5SDimitry Andric       install(new codecvt_byname<wchar_t, char, mbstate_t>(name));
313349cc55cSDimitry Andric #endif
314e8d8bef9SDimitry Andric       _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3150b57cec5SDimitry Andric       install(new codecvt_byname<char16_t, char, mbstate_t>(name));
3160b57cec5SDimitry Andric       install(new codecvt_byname<char32_t, char, mbstate_t>(name));
317e8d8bef9SDimitry Andric       _LIBCPP_SUPPRESS_DEPRECATED_POP
318fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
319e8d8bef9SDimitry Andric       install(new codecvt_byname<char16_t, char8_t, mbstate_t>(name));
320e8d8bef9SDimitry Andric       install(new codecvt_byname<char32_t, char8_t, mbstate_t>(name));
321e8d8bef9SDimitry Andric #endif
3220b57cec5SDimitry Andric     }
323*cb14a3feSDimitry Andric     if (c & locale::monetary) {
3240b57cec5SDimitry Andric       install(new moneypunct_byname<char, false>(name));
3250b57cec5SDimitry Andric       install(new moneypunct_byname<char, true>(name));
326349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3270b57cec5SDimitry Andric       install(new moneypunct_byname<wchar_t, false>(name));
3280b57cec5SDimitry Andric       install(new moneypunct_byname<wchar_t, true>(name));
329349cc55cSDimitry Andric #endif
3300b57cec5SDimitry Andric     }
331*cb14a3feSDimitry Andric     if (c & locale::numeric) {
3320b57cec5SDimitry Andric       install(new numpunct_byname<char>(name));
333349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3340b57cec5SDimitry Andric       install(new numpunct_byname<wchar_t>(name));
335349cc55cSDimitry Andric #endif
3360b57cec5SDimitry Andric     }
337*cb14a3feSDimitry Andric     if (c & locale::time) {
3380b57cec5SDimitry Andric       install(new time_get_byname<char>(name));
339349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3400b57cec5SDimitry Andric       install(new time_get_byname<wchar_t>(name));
341349cc55cSDimitry Andric #endif
3420b57cec5SDimitry Andric       install(new time_put_byname<char>(name));
343349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3440b57cec5SDimitry Andric       install(new time_put_byname<wchar_t>(name));
345349cc55cSDimitry Andric #endif
3460b57cec5SDimitry Andric     }
347*cb14a3feSDimitry Andric     if (c & locale::messages) {
3480b57cec5SDimitry Andric       install(new messages_byname<char>(name));
349349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3500b57cec5SDimitry Andric       install(new messages_byname<wchar_t>(name));
351349cc55cSDimitry Andric #endif
3520b57cec5SDimitry Andric     }
35306c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
354*cb14a3feSDimitry Andric   } catch (...) {
3550b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
3560b57cec5SDimitry Andric       if (facets_[i])
3570b57cec5SDimitry Andric         facets_[i]->__release_shared();
3580b57cec5SDimitry Andric     throw;
3590b57cec5SDimitry Andric   }
36006c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
3610b57cec5SDimitry Andric }
3620b57cec5SDimitry Andric 
3630b57cec5SDimitry Andric template <class F>
364*cb14a3feSDimitry Andric inline void locale::__imp::install_from(const locale::__imp& one) {
3650b57cec5SDimitry Andric   long id = F::id.__get();
3660b57cec5SDimitry Andric   install(const_cast<F*>(static_cast<const F*>(one.use_facet(id))), id);
3670b57cec5SDimitry Andric }
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric locale::__imp::__imp(const __imp& other, const __imp& one, locale::category c)
370*cb14a3feSDimitry Andric     : facets_(N), name_(build_name(other.name_, one.name_, c)) {
3710b57cec5SDimitry Andric   facets_ = other.facets_;
3720b57cec5SDimitry Andric   for (unsigned i = 0; i < facets_.size(); ++i)
3730b57cec5SDimitry Andric     if (facets_[i])
3740b57cec5SDimitry Andric       facets_[i]->__add_shared();
37506c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
376*cb14a3feSDimitry Andric   try {
37706c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
378*cb14a3feSDimitry Andric     if (c & locale::collate) {
3795f757f3fSDimitry Andric       install_from<std::collate<char> >(one);
380349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3815f757f3fSDimitry Andric       install_from<std::collate<wchar_t> >(one);
382349cc55cSDimitry Andric #endif
3830b57cec5SDimitry Andric     }
384*cb14a3feSDimitry Andric     if (c & locale::ctype) {
3855f757f3fSDimitry Andric       install_from<std::ctype<char> >(one);
386349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3875f757f3fSDimitry Andric       install_from<std::ctype<wchar_t> >(one);
388349cc55cSDimitry Andric #endif
3895f757f3fSDimitry Andric       install_from<std::codecvt<char, char, mbstate_t> >(one);
390e8d8bef9SDimitry Andric       _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3915f757f3fSDimitry Andric       install_from<std::codecvt<char16_t, char, mbstate_t> >(one);
3925f757f3fSDimitry Andric       install_from<std::codecvt<char32_t, char, mbstate_t> >(one);
393e8d8bef9SDimitry Andric       _LIBCPP_SUPPRESS_DEPRECATED_POP
394fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
3955f757f3fSDimitry Andric       install_from<std::codecvt<char16_t, char8_t, mbstate_t> >(one);
3965f757f3fSDimitry Andric       install_from<std::codecvt<char32_t, char8_t, mbstate_t> >(one);
397e8d8bef9SDimitry Andric #endif
398349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3995f757f3fSDimitry Andric       install_from<std::codecvt<wchar_t, char, mbstate_t> >(one);
400349cc55cSDimitry Andric #endif
4010b57cec5SDimitry Andric     }
402*cb14a3feSDimitry Andric     if (c & locale::monetary) {
4030b57cec5SDimitry Andric       install_from<moneypunct<char, false> >(one);
4040b57cec5SDimitry Andric       install_from<moneypunct<char, true> >(one);
405349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4060b57cec5SDimitry Andric       install_from<moneypunct<wchar_t, false> >(one);
4070b57cec5SDimitry Andric       install_from<moneypunct<wchar_t, true> >(one);
408349cc55cSDimitry Andric #endif
4090b57cec5SDimitry Andric       install_from<money_get<char> >(one);
410349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4110b57cec5SDimitry Andric       install_from<money_get<wchar_t> >(one);
412349cc55cSDimitry Andric #endif
4130b57cec5SDimitry Andric       install_from<money_put<char> >(one);
414349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4150b57cec5SDimitry Andric       install_from<money_put<wchar_t> >(one);
416349cc55cSDimitry Andric #endif
4170b57cec5SDimitry Andric     }
418*cb14a3feSDimitry Andric     if (c & locale::numeric) {
4190b57cec5SDimitry Andric       install_from<numpunct<char> >(one);
420349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4210b57cec5SDimitry Andric       install_from<numpunct<wchar_t> >(one);
422349cc55cSDimitry Andric #endif
4230b57cec5SDimitry Andric       install_from<num_get<char> >(one);
424349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4250b57cec5SDimitry Andric       install_from<num_get<wchar_t> >(one);
426349cc55cSDimitry Andric #endif
4270b57cec5SDimitry Andric       install_from<num_put<char> >(one);
428349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4290b57cec5SDimitry Andric       install_from<num_put<wchar_t> >(one);
430349cc55cSDimitry Andric #endif
4310b57cec5SDimitry Andric     }
432*cb14a3feSDimitry Andric     if (c & locale::time) {
4330b57cec5SDimitry Andric       install_from<time_get<char> >(one);
434349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4350b57cec5SDimitry Andric       install_from<time_get<wchar_t> >(one);
436349cc55cSDimitry Andric #endif
4370b57cec5SDimitry Andric       install_from<time_put<char> >(one);
438349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4390b57cec5SDimitry Andric       install_from<time_put<wchar_t> >(one);
440349cc55cSDimitry Andric #endif
4410b57cec5SDimitry Andric     }
442*cb14a3feSDimitry Andric     if (c & locale::messages) {
4435f757f3fSDimitry Andric       install_from<std::messages<char> >(one);
444349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4455f757f3fSDimitry Andric       install_from<std::messages<wchar_t> >(one);
446349cc55cSDimitry Andric #endif
4470b57cec5SDimitry Andric     }
44806c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
449*cb14a3feSDimitry Andric   } catch (...) {
4500b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
4510b57cec5SDimitry Andric       if (facets_[i])
4520b57cec5SDimitry Andric         facets_[i]->__release_shared();
4530b57cec5SDimitry Andric     throw;
4540b57cec5SDimitry Andric   }
45506c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
4560b57cec5SDimitry Andric }
4570b57cec5SDimitry Andric 
4580b57cec5SDimitry Andric locale::__imp::__imp(const __imp& other, facet* f, long id)
459*cb14a3feSDimitry Andric     : facets_(max<size_t>(N, other.facets_.size() + 1)), name_("*") {
4600b57cec5SDimitry Andric   f->__add_shared();
4615f757f3fSDimitry Andric   unique_ptr<facet, releaser> hold(f);
4620b57cec5SDimitry Andric   facets_ = other.facets_;
4630b57cec5SDimitry Andric   for (unsigned i = 0; i < other.facets_.size(); ++i)
4640b57cec5SDimitry Andric     if (facets_[i])
4650b57cec5SDimitry Andric       facets_[i]->__add_shared();
4660b57cec5SDimitry Andric   install(hold.get(), id);
4670b57cec5SDimitry Andric }
4680b57cec5SDimitry Andric 
469*cb14a3feSDimitry Andric locale::__imp::~__imp() {
4700b57cec5SDimitry Andric   for (unsigned i = 0; i < facets_.size(); ++i)
4710b57cec5SDimitry Andric     if (facets_[i])
4720b57cec5SDimitry Andric       facets_[i]->__release_shared();
4730b57cec5SDimitry Andric }
4740b57cec5SDimitry Andric 
475*cb14a3feSDimitry Andric void locale::__imp::install(facet* f, long id) {
4760b57cec5SDimitry Andric   f->__add_shared();
4775f757f3fSDimitry Andric   unique_ptr<facet, releaser> hold(f);
4780b57cec5SDimitry Andric   if (static_cast<size_t>(id) >= facets_.size())
4790b57cec5SDimitry Andric     facets_.resize(static_cast<size_t>(id + 1));
4800b57cec5SDimitry Andric   if (facets_[static_cast<size_t>(id)])
4810b57cec5SDimitry Andric     facets_[static_cast<size_t>(id)]->__release_shared();
4820b57cec5SDimitry Andric   facets_[static_cast<size_t>(id)] = hold.release();
4830b57cec5SDimitry Andric }
4840b57cec5SDimitry Andric 
485*cb14a3feSDimitry Andric const locale::facet* locale::__imp::use_facet(long id) const {
4860b57cec5SDimitry Andric   if (!has_facet(id))
4870b57cec5SDimitry Andric     __throw_bad_cast();
4880b57cec5SDimitry Andric   return facets_[static_cast<size_t>(id)];
4890b57cec5SDimitry Andric }
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric // locale
4920b57cec5SDimitry Andric 
4935f757f3fSDimitry Andric // We don't do reference counting on the classic locale.
4945f757f3fSDimitry Andric // It's never destroyed anyway, but atomic reference counting may be very
4955f757f3fSDimitry Andric // expensive in parallel applications. The classic locale is used by default
4965f757f3fSDimitry Andric // in all streams. Note: if a new global locale is installed, then we lose
4975f757f3fSDimitry Andric // the benefit of no reference counting.
4985f757f3fSDimitry Andric constinit __no_destroy<locale::__imp>
4995f757f3fSDimitry Andric     locale::__imp::classic_locale_imp_(__uninitialized_tag{}); // initialized below in classic()
5005f757f3fSDimitry Andric 
5015f757f3fSDimitry Andric const locale& locale::classic() {
5025f757f3fSDimitry Andric   static const __no_destroy<locale> classic_locale(__private_tag{}, [] {
5035f757f3fSDimitry Andric     // executed exactly once on first initialization of `classic_locale`
5045f757f3fSDimitry Andric     locale::__imp::classic_locale_imp_.__emplace(1u);
5055f757f3fSDimitry Andric     return &locale::__imp::classic_locale_imp_.__get();
5065f757f3fSDimitry Andric   }());
5075f757f3fSDimitry Andric   return classic_locale.__get();
5080b57cec5SDimitry Andric }
5090b57cec5SDimitry Andric 
5105f757f3fSDimitry Andric locale& locale::__global() {
5115f757f3fSDimitry Andric   static __no_destroy<locale> g(locale::classic());
5125f757f3fSDimitry Andric   return g.__get();
5130b57cec5SDimitry Andric }
5140b57cec5SDimitry Andric 
5155f757f3fSDimitry Andric void locale::__imp::acquire() {
5165f757f3fSDimitry Andric   if (this != &locale::__imp::classic_locale_imp_.__get())
5175f757f3fSDimitry Andric     __add_shared();
5180b57cec5SDimitry Andric }
5190b57cec5SDimitry Andric 
5205f757f3fSDimitry Andric void locale::__imp::release() {
5215f757f3fSDimitry Andric   if (this != &locale::__imp::classic_locale_imp_.__get())
5225f757f3fSDimitry Andric     __release_shared();
5230b57cec5SDimitry Andric }
5240b57cec5SDimitry Andric 
5255f757f3fSDimitry Andric locale::locale() noexcept : __locale_(__global().__locale_) { __locale_->acquire(); }
5260b57cec5SDimitry Andric 
5275f757f3fSDimitry Andric locale::locale(const locale& l) noexcept : __locale_(l.__locale_) { __locale_->acquire(); }
5280b57cec5SDimitry Andric 
5295f757f3fSDimitry Andric locale::~locale() { __locale_->release(); }
5300b57cec5SDimitry Andric 
531*cb14a3feSDimitry Andric const locale& locale::operator=(const locale& other) noexcept {
5325f757f3fSDimitry Andric   other.__locale_->acquire();
5335f757f3fSDimitry Andric   __locale_->release();
5340b57cec5SDimitry Andric   __locale_ = other.__locale_;
5350b57cec5SDimitry Andric   return *this;
5360b57cec5SDimitry Andric }
5370b57cec5SDimitry Andric 
5380b57cec5SDimitry Andric locale::locale(const char* name)
539*cb14a3feSDimitry Andric     : __locale_(name ? new __imp(name) : (__throw_runtime_error("locale constructed with null"), nullptr)) {
5405f757f3fSDimitry Andric   __locale_->acquire();
5410b57cec5SDimitry Andric }
5420b57cec5SDimitry Andric 
5435f757f3fSDimitry Andric locale::locale(const string& name) : __locale_(new __imp(name)) { __locale_->acquire(); }
5440b57cec5SDimitry Andric 
5450b57cec5SDimitry Andric locale::locale(const locale& other, const char* name, category c)
5460b57cec5SDimitry Andric     : __locale_(name ? new __imp(*other.__locale_, name, c)
547*cb14a3feSDimitry Andric                      : (__throw_runtime_error("locale constructed with null"), nullptr)) {
5485f757f3fSDimitry Andric   __locale_->acquire();
5490b57cec5SDimitry Andric }
5500b57cec5SDimitry Andric 
551*cb14a3feSDimitry Andric locale::locale(const locale& other, const string& name, category c) : __locale_(new __imp(*other.__locale_, name, c)) {
5525f757f3fSDimitry Andric   __locale_->acquire();
5530b57cec5SDimitry Andric }
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric locale::locale(const locale& other, const locale& one, category c)
556*cb14a3feSDimitry Andric     : __locale_(new __imp(*other.__locale_, *one.__locale_, c)) {
5575f757f3fSDimitry Andric   __locale_->acquire();
5580b57cec5SDimitry Andric }
5590b57cec5SDimitry Andric 
560*cb14a3feSDimitry Andric string locale::name() const { return __locale_->name(); }
5610b57cec5SDimitry Andric 
562*cb14a3feSDimitry Andric void locale::__install_ctor(const locale& other, facet* f, long id) {
5630b57cec5SDimitry Andric   if (f)
5640b57cec5SDimitry Andric     __locale_ = new __imp(*other.__locale_, f, id);
5650b57cec5SDimitry Andric   else
5660b57cec5SDimitry Andric     __locale_ = other.__locale_;
5675f757f3fSDimitry Andric   __locale_->acquire();
5680b57cec5SDimitry Andric }
5690b57cec5SDimitry Andric 
570*cb14a3feSDimitry Andric locale locale::global(const locale& loc) {
5710b57cec5SDimitry Andric   locale& g = __global();
5720b57cec5SDimitry Andric   locale r  = g;
5730b57cec5SDimitry Andric   g         = loc;
5740b57cec5SDimitry Andric   if (g.name() != "*")
5750b57cec5SDimitry Andric     setlocale(LC_ALL, g.name().c_str());
5760b57cec5SDimitry Andric   return r;
5770b57cec5SDimitry Andric }
5780b57cec5SDimitry Andric 
579*cb14a3feSDimitry Andric bool locale::has_facet(id& x) const { return __locale_->has_facet(x.__get()); }
5800b57cec5SDimitry Andric 
581*cb14a3feSDimitry Andric const locale::facet* locale::use_facet(id& x) const { return __locale_->use_facet(x.__get()); }
5820b57cec5SDimitry Andric 
583*cb14a3feSDimitry Andric bool locale::operator==(const locale& y) const {
584*cb14a3feSDimitry Andric   return (__locale_ == y.__locale_) || (__locale_->name() != "*" && __locale_->name() == y.__locale_->name());
5850b57cec5SDimitry Andric }
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric // locale::facet
5880b57cec5SDimitry Andric 
589*cb14a3feSDimitry Andric locale::facet::~facet() {}
5900b57cec5SDimitry Andric 
591*cb14a3feSDimitry Andric void locale::facet::__on_zero_shared() noexcept { delete this; }
5920b57cec5SDimitry Andric 
5930b57cec5SDimitry Andric // locale::id
5940b57cec5SDimitry Andric 
5955f757f3fSDimitry Andric constinit int32_t locale::id::__next_id = 0;
5960b57cec5SDimitry Andric 
5975f757f3fSDimitry Andric long locale::id::__get() {
5985f757f3fSDimitry Andric   call_once(__flag_, [&] { __id_ = __libcpp_atomic_add(&__next_id, 1); });
5990b57cec5SDimitry Andric   return __id_ - 1;
6000b57cec5SDimitry Andric }
6010b57cec5SDimitry Andric 
6020b57cec5SDimitry Andric // template <> class collate_byname<char>
6030b57cec5SDimitry Andric 
6040b57cec5SDimitry Andric collate_byname<char>::collate_byname(const char* n, size_t refs)
605*cb14a3feSDimitry Andric     : collate<char>(refs), __l_(newlocale(LC_ALL_MASK, n, 0)) {
606bdd1243dSDimitry Andric   if (__l_ == 0)
607*cb14a3feSDimitry Andric     __throw_runtime_error(
608*cb14a3feSDimitry Andric         ("collate_byname<char>::collate_byname"
609*cb14a3feSDimitry Andric          " failed to construct for " +
610*cb14a3feSDimitry Andric          string(n))
611*cb14a3feSDimitry Andric             .c_str());
6120b57cec5SDimitry Andric }
6130b57cec5SDimitry Andric 
6140b57cec5SDimitry Andric collate_byname<char>::collate_byname(const string& name, size_t refs)
615*cb14a3feSDimitry Andric     : collate<char>(refs), __l_(newlocale(LC_ALL_MASK, name.c_str(), 0)) {
616bdd1243dSDimitry Andric   if (__l_ == 0)
617*cb14a3feSDimitry Andric     __throw_runtime_error(
618*cb14a3feSDimitry Andric         ("collate_byname<char>::collate_byname"
619*cb14a3feSDimitry Andric          " failed to construct for " +
620*cb14a3feSDimitry Andric          name)
621*cb14a3feSDimitry Andric             .c_str());
6220b57cec5SDimitry Andric }
6230b57cec5SDimitry Andric 
624*cb14a3feSDimitry Andric collate_byname<char>::~collate_byname() { freelocale(__l_); }
6250b57cec5SDimitry Andric 
626*cb14a3feSDimitry Andric int collate_byname<char>::do_compare(
627*cb14a3feSDimitry Andric     const char_type* __lo1, const char_type* __hi1, const char_type* __lo2, const char_type* __hi2) const {
6280b57cec5SDimitry Andric   string_type lhs(__lo1, __hi1);
6290b57cec5SDimitry Andric   string_type rhs(__lo2, __hi2);
630bdd1243dSDimitry Andric   int r = strcoll_l(lhs.c_str(), rhs.c_str(), __l_);
6310b57cec5SDimitry Andric   if (r < 0)
6320b57cec5SDimitry Andric     return -1;
6330b57cec5SDimitry Andric   if (r > 0)
6340b57cec5SDimitry Andric     return 1;
6350b57cec5SDimitry Andric   return r;
6360b57cec5SDimitry Andric }
6370b57cec5SDimitry Andric 
638*cb14a3feSDimitry Andric collate_byname<char>::string_type collate_byname<char>::do_transform(const char_type* lo, const char_type* hi) const {
6390b57cec5SDimitry Andric   const string_type in(lo, hi);
640bdd1243dSDimitry Andric   string_type out(strxfrm_l(0, in.c_str(), 0, __l_), char());
641bdd1243dSDimitry Andric   strxfrm_l(const_cast<char*>(out.c_str()), in.c_str(), out.size() + 1, __l_);
6420b57cec5SDimitry Andric   return out;
6430b57cec5SDimitry Andric }
6440b57cec5SDimitry Andric 
6450b57cec5SDimitry Andric // template <> class collate_byname<wchar_t>
6460b57cec5SDimitry Andric 
647349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
6480b57cec5SDimitry Andric collate_byname<wchar_t>::collate_byname(const char* n, size_t refs)
649*cb14a3feSDimitry Andric     : collate<wchar_t>(refs), __l_(newlocale(LC_ALL_MASK, n, 0)) {
650bdd1243dSDimitry Andric   if (__l_ == 0)
651*cb14a3feSDimitry Andric     __throw_runtime_error(
652*cb14a3feSDimitry Andric         ("collate_byname<wchar_t>::collate_byname(size_t refs)"
653*cb14a3feSDimitry Andric          " failed to construct for " +
654*cb14a3feSDimitry Andric          string(n))
655*cb14a3feSDimitry Andric             .c_str());
6560b57cec5SDimitry Andric }
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric collate_byname<wchar_t>::collate_byname(const string& name, size_t refs)
659*cb14a3feSDimitry Andric     : collate<wchar_t>(refs), __l_(newlocale(LC_ALL_MASK, name.c_str(), 0)) {
660bdd1243dSDimitry Andric   if (__l_ == 0)
661*cb14a3feSDimitry Andric     __throw_runtime_error(
662*cb14a3feSDimitry Andric         ("collate_byname<wchar_t>::collate_byname(size_t refs)"
663*cb14a3feSDimitry Andric          " failed to construct for " +
664*cb14a3feSDimitry Andric          name)
665*cb14a3feSDimitry Andric             .c_str());
6660b57cec5SDimitry Andric }
6670b57cec5SDimitry Andric 
668*cb14a3feSDimitry Andric collate_byname<wchar_t>::~collate_byname() { freelocale(__l_); }
6690b57cec5SDimitry Andric 
670*cb14a3feSDimitry Andric int collate_byname<wchar_t>::do_compare(
671*cb14a3feSDimitry Andric     const char_type* __lo1, const char_type* __hi1, const char_type* __lo2, const char_type* __hi2) const {
6720b57cec5SDimitry Andric   string_type lhs(__lo1, __hi1);
6730b57cec5SDimitry Andric   string_type rhs(__lo2, __hi2);
674bdd1243dSDimitry Andric   int r = wcscoll_l(lhs.c_str(), rhs.c_str(), __l_);
6750b57cec5SDimitry Andric   if (r < 0)
6760b57cec5SDimitry Andric     return -1;
6770b57cec5SDimitry Andric   if (r > 0)
6780b57cec5SDimitry Andric     return 1;
6790b57cec5SDimitry Andric   return r;
6800b57cec5SDimitry Andric }
6810b57cec5SDimitry Andric 
6820b57cec5SDimitry Andric collate_byname<wchar_t>::string_type
683*cb14a3feSDimitry Andric collate_byname<wchar_t>::do_transform(const char_type* lo, const char_type* hi) const {
6840b57cec5SDimitry Andric   const string_type in(lo, hi);
685bdd1243dSDimitry Andric   string_type out(wcsxfrm_l(0, in.c_str(), 0, __l_), wchar_t());
686bdd1243dSDimitry Andric   wcsxfrm_l(const_cast<wchar_t*>(out.c_str()), in.c_str(), out.size() + 1, __l_);
6870b57cec5SDimitry Andric   return out;
6880b57cec5SDimitry Andric }
689349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
6900b57cec5SDimitry Andric 
6910b57cec5SDimitry Andric const ctype_base::mask ctype_base::space;
6920b57cec5SDimitry Andric const ctype_base::mask ctype_base::print;
6930b57cec5SDimitry Andric const ctype_base::mask ctype_base::cntrl;
6940b57cec5SDimitry Andric const ctype_base::mask ctype_base::upper;
6950b57cec5SDimitry Andric const ctype_base::mask ctype_base::lower;
6960b57cec5SDimitry Andric const ctype_base::mask ctype_base::alpha;
6970b57cec5SDimitry Andric const ctype_base::mask ctype_base::digit;
6980b57cec5SDimitry Andric const ctype_base::mask ctype_base::punct;
6990b57cec5SDimitry Andric const ctype_base::mask ctype_base::xdigit;
7000b57cec5SDimitry Andric const ctype_base::mask ctype_base::blank;
7010b57cec5SDimitry Andric const ctype_base::mask ctype_base::alnum;
7020b57cec5SDimitry Andric const ctype_base::mask ctype_base::graph;
7030b57cec5SDimitry Andric 
704349cc55cSDimitry Andric // template <> class ctype<wchar_t>;
705349cc55cSDimitry Andric 
706349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
7075f757f3fSDimitry Andric constinit locale::id ctype<wchar_t>::id;
7080b57cec5SDimitry Andric 
709*cb14a3feSDimitry Andric ctype<wchar_t>::~ctype() {}
7100b57cec5SDimitry Andric 
711*cb14a3feSDimitry Andric bool ctype<wchar_t>::do_is(mask m, char_type c) const {
7120b57cec5SDimitry Andric   return isascii(c) ? (ctype<char>::classic_table()[c] & m) != 0 : false;
7130b57cec5SDimitry Andric }
7140b57cec5SDimitry Andric 
715*cb14a3feSDimitry Andric const wchar_t* ctype<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const {
7160b57cec5SDimitry Andric   for (; low != high; ++low, ++vec)
717*cb14a3feSDimitry Andric     *vec = static_cast<mask>(isascii(*low) ? ctype<char>::classic_table()[*low] : 0);
7180b57cec5SDimitry Andric   return low;
7190b57cec5SDimitry Andric }
7200b57cec5SDimitry Andric 
721*cb14a3feSDimitry Andric const wchar_t* ctype<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const {
7220b57cec5SDimitry Andric   for (; low != high; ++low)
7230b57cec5SDimitry Andric     if (isascii(*low) && (ctype<char>::classic_table()[*low] & m))
7240b57cec5SDimitry Andric       break;
7250b57cec5SDimitry Andric   return low;
7260b57cec5SDimitry Andric }
7270b57cec5SDimitry Andric 
728*cb14a3feSDimitry Andric const wchar_t* ctype<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const {
7290b57cec5SDimitry Andric   for (; low != high; ++low)
7300b57cec5SDimitry Andric     if (!(isascii(*low) && (ctype<char>::classic_table()[*low] & m)))
7310b57cec5SDimitry Andric       break;
7320b57cec5SDimitry Andric   return low;
7330b57cec5SDimitry Andric }
7340b57cec5SDimitry Andric 
735*cb14a3feSDimitry Andric wchar_t ctype<wchar_t>::do_toupper(char_type c) const {
7360b57cec5SDimitry Andric #  ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
7370b57cec5SDimitry Andric   return isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c;
738*cb14a3feSDimitry Andric #  elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__NetBSD__) || defined(__MVS__)
7390b57cec5SDimitry Andric   return isascii(c) ? ctype<char>::__classic_upper_table()[c] : c;
7400b57cec5SDimitry Andric #  else
7410b57cec5SDimitry Andric   return (isascii(c) && iswlower_l(c, _LIBCPP_GET_C_LOCALE)) ? c - L'a' + L'A' : c;
7420b57cec5SDimitry Andric #  endif
7430b57cec5SDimitry Andric }
7440b57cec5SDimitry Andric 
745*cb14a3feSDimitry Andric const wchar_t* ctype<wchar_t>::do_toupper(char_type* low, const char_type* high) const {
7460b57cec5SDimitry Andric   for (; low != high; ++low)
7470b57cec5SDimitry Andric #  ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
7480b57cec5SDimitry Andric     *low = isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low;
749*cb14a3feSDimitry Andric #  elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__NetBSD__) || defined(__MVS__)
750*cb14a3feSDimitry Andric     *low = isascii(*low) ? ctype<char>::__classic_upper_table()[*low] : *low;
7510b57cec5SDimitry Andric #  else
7520b57cec5SDimitry Andric     *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? (*low - L'a' + L'A') : *low;
7530b57cec5SDimitry Andric #  endif
7540b57cec5SDimitry Andric   return low;
7550b57cec5SDimitry Andric }
7560b57cec5SDimitry Andric 
757*cb14a3feSDimitry Andric wchar_t ctype<wchar_t>::do_tolower(char_type c) const {
7580b57cec5SDimitry Andric #  ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
7590b57cec5SDimitry Andric   return isascii(c) ? _DefaultRuneLocale.__maplower[c] : c;
760*cb14a3feSDimitry Andric #  elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__NetBSD__) || defined(__MVS__)
7610b57cec5SDimitry Andric   return isascii(c) ? ctype<char>::__classic_lower_table()[c] : c;
7620b57cec5SDimitry Andric #  else
7630b57cec5SDimitry Andric   return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c - L'A' + 'a' : c;
7640b57cec5SDimitry Andric #  endif
7650b57cec5SDimitry Andric }
7660b57cec5SDimitry Andric 
767*cb14a3feSDimitry Andric const wchar_t* ctype<wchar_t>::do_tolower(char_type* low, const char_type* high) const {
7680b57cec5SDimitry Andric   for (; low != high; ++low)
7690b57cec5SDimitry Andric #  ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
7700b57cec5SDimitry Andric     *low = isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low;
771*cb14a3feSDimitry Andric #  elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__NetBSD__) || defined(__MVS__)
772*cb14a3feSDimitry Andric     *low = isascii(*low) ? ctype<char>::__classic_lower_table()[*low] : *low;
7730b57cec5SDimitry Andric #  else
7740b57cec5SDimitry Andric     *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low - L'A' + L'a' : *low;
7750b57cec5SDimitry Andric #  endif
7760b57cec5SDimitry Andric   return low;
7770b57cec5SDimitry Andric }
7780b57cec5SDimitry Andric 
779*cb14a3feSDimitry Andric wchar_t ctype<wchar_t>::do_widen(char c) const { return c; }
7800b57cec5SDimitry Andric 
781*cb14a3feSDimitry Andric const char* ctype<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const {
7820b57cec5SDimitry Andric   for (; low != high; ++low, ++dest)
7830b57cec5SDimitry Andric     *dest = *low;
7840b57cec5SDimitry Andric   return low;
7850b57cec5SDimitry Andric }
7860b57cec5SDimitry Andric 
787*cb14a3feSDimitry Andric char ctype<wchar_t>::do_narrow(char_type c, char dfault) const {
7880b57cec5SDimitry Andric   if (isascii(c))
7890b57cec5SDimitry Andric     return static_cast<char>(c);
7900b57cec5SDimitry Andric   return dfault;
7910b57cec5SDimitry Andric }
7920b57cec5SDimitry Andric 
793*cb14a3feSDimitry Andric const wchar_t* ctype<wchar_t>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const {
7940b57cec5SDimitry Andric   for (; low != high; ++low, ++dest)
7950b57cec5SDimitry Andric     if (isascii(*low))
7960b57cec5SDimitry Andric       *dest = static_cast<char>(*low);
7970b57cec5SDimitry Andric     else
7980b57cec5SDimitry Andric       *dest = dfault;
7990b57cec5SDimitry Andric   return low;
8000b57cec5SDimitry Andric }
801349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
8020b57cec5SDimitry Andric 
8030b57cec5SDimitry Andric // template <> class ctype<char>;
8040b57cec5SDimitry Andric 
8055f757f3fSDimitry Andric constinit locale::id ctype<char>::id;
8060b57cec5SDimitry Andric 
807349cc55cSDimitry Andric const size_t ctype<char>::table_size;
808349cc55cSDimitry Andric 
809*cb14a3feSDimitry Andric ctype<char>::ctype(const mask* tab, bool del, size_t refs) : locale::facet(refs), __tab_(tab), __del_(del) {
8100b57cec5SDimitry Andric   if (__tab_ == 0)
8110b57cec5SDimitry Andric     __tab_ = classic_table();
8120b57cec5SDimitry Andric }
8130b57cec5SDimitry Andric 
814*cb14a3feSDimitry Andric ctype<char>::~ctype() {
8150b57cec5SDimitry Andric   if (__tab_ && __del_)
8160b57cec5SDimitry Andric     delete[] __tab_;
8170b57cec5SDimitry Andric }
8180b57cec5SDimitry Andric 
819*cb14a3feSDimitry Andric char ctype<char>::do_toupper(char_type c) const {
8200b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
821*cb14a3feSDimitry Andric   return isascii(c) ? static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(c)]) : c;
8220b57cec5SDimitry Andric #elif defined(__NetBSD__)
8230b57cec5SDimitry Andric   return static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]);
82404eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
825*cb14a3feSDimitry Andric   return isascii(c) ? static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]) : c;
8260b57cec5SDimitry Andric #else
8270b57cec5SDimitry Andric   return (isascii(c) && islower_l(c, _LIBCPP_GET_C_LOCALE)) ? c - 'a' + 'A' : c;
8280b57cec5SDimitry Andric #endif
8290b57cec5SDimitry Andric }
8300b57cec5SDimitry Andric 
831*cb14a3feSDimitry Andric const char* ctype<char>::do_toupper(char_type* low, const char_type* high) const {
8320b57cec5SDimitry Andric   for (; low != high; ++low)
8330b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
834*cb14a3feSDimitry Andric     *low = isascii(*low) ? static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(*low)]) : *low;
8350b57cec5SDimitry Andric #elif defined(__NetBSD__)
8360b57cec5SDimitry Andric     *low = static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(*low)]);
83704eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
838*cb14a3feSDimitry Andric     *low = isascii(*low) ? static_cast<char>(__classic_upper_table()[static_cast<size_t>(*low)]) : *low;
8390b57cec5SDimitry Andric #else
8400b57cec5SDimitry Andric     *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low - 'a' + 'A' : *low;
8410b57cec5SDimitry Andric #endif
8420b57cec5SDimitry Andric   return low;
8430b57cec5SDimitry Andric }
8440b57cec5SDimitry Andric 
845*cb14a3feSDimitry Andric char ctype<char>::do_tolower(char_type c) const {
8460b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
847*cb14a3feSDimitry Andric   return isascii(c) ? static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(c)]) : c;
8480b57cec5SDimitry Andric #elif defined(__NetBSD__)
8490b57cec5SDimitry Andric   return static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(c)]);
85004eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
851*cb14a3feSDimitry Andric   return isascii(c) ? static_cast<char>(__classic_lower_table()[static_cast<size_t>(c)]) : c;
8520b57cec5SDimitry Andric #else
8530b57cec5SDimitry Andric   return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c - 'A' + 'a' : c;
8540b57cec5SDimitry Andric #endif
8550b57cec5SDimitry Andric }
8560b57cec5SDimitry Andric 
857*cb14a3feSDimitry Andric const char* ctype<char>::do_tolower(char_type* low, const char_type* high) const {
8580b57cec5SDimitry Andric   for (; low != high; ++low)
8590b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
8600b57cec5SDimitry Andric     *low = isascii(*low) ? static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(*low)]) : *low;
8610b57cec5SDimitry Andric #elif defined(__NetBSD__)
8620b57cec5SDimitry Andric     *low = static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(*low)]);
86304eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
8640b57cec5SDimitry Andric     *low = isascii(*low) ? static_cast<char>(__classic_lower_table()[static_cast<size_t>(*low)]) : *low;
8650b57cec5SDimitry Andric #else
8660b57cec5SDimitry Andric     *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low - 'A' + 'a' : *low;
8670b57cec5SDimitry Andric #endif
8680b57cec5SDimitry Andric   return low;
8690b57cec5SDimitry Andric }
8700b57cec5SDimitry Andric 
871*cb14a3feSDimitry Andric char ctype<char>::do_widen(char c) const { return c; }
8720b57cec5SDimitry Andric 
873*cb14a3feSDimitry Andric const char* ctype<char>::do_widen(const char* low, const char* high, char_type* dest) const {
8740b57cec5SDimitry Andric   for (; low != high; ++low, ++dest)
8750b57cec5SDimitry Andric     *dest = *low;
8760b57cec5SDimitry Andric   return low;
8770b57cec5SDimitry Andric }
8780b57cec5SDimitry Andric 
879*cb14a3feSDimitry Andric char ctype<char>::do_narrow(char_type c, char dfault) const {
8800b57cec5SDimitry Andric   if (isascii(c))
8810b57cec5SDimitry Andric     return static_cast<char>(c);
8820b57cec5SDimitry Andric   return dfault;
8830b57cec5SDimitry Andric }
8840b57cec5SDimitry Andric 
885*cb14a3feSDimitry Andric const char* ctype<char>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const {
8860b57cec5SDimitry Andric   for (; low != high; ++low, ++dest)
8870b57cec5SDimitry Andric     if (isascii(*low))
8880b57cec5SDimitry Andric       *dest = *low;
8890b57cec5SDimitry Andric     else
8900b57cec5SDimitry Andric       *dest = dfault;
8910b57cec5SDimitry Andric   return low;
8920b57cec5SDimitry Andric }
8930b57cec5SDimitry Andric 
8940b57cec5SDimitry Andric #if defined(__EMSCRIPTEN__)
8950b57cec5SDimitry Andric extern "C" const unsigned short** __ctype_b_loc();
8960b57cec5SDimitry Andric extern "C" const int** __ctype_tolower_loc();
8970b57cec5SDimitry Andric extern "C" const int** __ctype_toupper_loc();
8980b57cec5SDimitry Andric #endif
8990b57cec5SDimitry Andric 
9000b57cec5SDimitry Andric #ifdef _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE
901*cb14a3feSDimitry Andric const ctype<char>::mask* ctype<char>::classic_table() noexcept {
9025f757f3fSDimitry Andric   // clang-format off
9035f757f3fSDimitry Andric     static constexpr const ctype<char>::mask builtin_table[table_size] = {
9040b57cec5SDimitry Andric         cntrl,                          cntrl,
9050b57cec5SDimitry Andric         cntrl,                          cntrl,
9060b57cec5SDimitry Andric         cntrl,                          cntrl,
9070b57cec5SDimitry Andric         cntrl,                          cntrl,
9080b57cec5SDimitry Andric         cntrl,                          cntrl | space | blank,
9090b57cec5SDimitry Andric         cntrl | space,                  cntrl | space,
9100b57cec5SDimitry Andric         cntrl | space,                  cntrl | space,
9110b57cec5SDimitry Andric         cntrl,                          cntrl,
9120b57cec5SDimitry Andric         cntrl,                          cntrl,
9130b57cec5SDimitry Andric         cntrl,                          cntrl,
9140b57cec5SDimitry Andric         cntrl,                          cntrl,
9150b57cec5SDimitry Andric         cntrl,                          cntrl,
9160b57cec5SDimitry Andric         cntrl,                          cntrl,
9170b57cec5SDimitry Andric         cntrl,                          cntrl,
9180b57cec5SDimitry Andric         cntrl,                          cntrl,
9190b57cec5SDimitry Andric         cntrl,                          cntrl,
9200b57cec5SDimitry Andric         space | blank | print,          punct | print,
9210b57cec5SDimitry Andric         punct | print,                  punct | print,
9220b57cec5SDimitry Andric         punct | print,                  punct | print,
9230b57cec5SDimitry Andric         punct | print,                  punct | print,
9240b57cec5SDimitry Andric         punct | print,                  punct | print,
9250b57cec5SDimitry Andric         punct | print,                  punct | print,
9260b57cec5SDimitry Andric         punct | print,                  punct | print,
9270b57cec5SDimitry Andric         punct | print,                  punct | print,
9280b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
9290b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
9300b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
9310b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
9320b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
9330b57cec5SDimitry Andric         punct | print,                  punct | print,
9340b57cec5SDimitry Andric         punct | print,                  punct | print,
9350b57cec5SDimitry Andric         punct | print,                  punct | print,
9360b57cec5SDimitry Andric         punct | print,                  upper | xdigit | print | alpha,
9370b57cec5SDimitry Andric         upper | xdigit | print | alpha, upper | xdigit | print | alpha,
9380b57cec5SDimitry Andric         upper | xdigit | print | alpha, upper | xdigit | print | alpha,
9390b57cec5SDimitry Andric         upper | xdigit | print | alpha, upper | print | alpha,
9400b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
9410b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
9420b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
9430b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
9440b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
9450b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
9460b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
9470b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
9480b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
9490b57cec5SDimitry Andric         upper | print | alpha,          punct | print,
9500b57cec5SDimitry Andric         punct | print,                  punct | print,
9510b57cec5SDimitry Andric         punct | print,                  punct | print,
9520b57cec5SDimitry Andric         punct | print,                  lower | xdigit | print | alpha,
9530b57cec5SDimitry Andric         lower | xdigit | print | alpha, lower | xdigit | print | alpha,
9540b57cec5SDimitry Andric         lower | xdigit | print | alpha, lower | xdigit | print | alpha,
9550b57cec5SDimitry Andric         lower | xdigit | print | alpha, lower | print | alpha,
9560b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
9570b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
9580b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
9590b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
9600b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
9610b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
9620b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
9630b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
9640b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
9650b57cec5SDimitry Andric         lower | print | alpha,          punct | print,
9660b57cec5SDimitry Andric         punct | print,                  punct | print,
9670b57cec5SDimitry Andric         punct | print,                  cntrl,
9680b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9690b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9700b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9710b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9720b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9730b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9740b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9750b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
9760b57cec5SDimitry Andric     };
9775f757f3fSDimitry Andric   // clang-format on
9780b57cec5SDimitry Andric   return builtin_table;
9790b57cec5SDimitry Andric }
9800b57cec5SDimitry Andric #else
981*cb14a3feSDimitry Andric const ctype<char>::mask* ctype<char>::classic_table() noexcept {
9820b57cec5SDimitry Andric #  if defined(__APPLE__) || defined(__FreeBSD__)
9830b57cec5SDimitry Andric   return _DefaultRuneLocale.__runetype;
9840b57cec5SDimitry Andric #  elif defined(__NetBSD__)
9850b57cec5SDimitry Andric   return _C_ctype_tab_ + 1;
9860b57cec5SDimitry Andric #  elif defined(__GLIBC__)
9870b57cec5SDimitry Andric   return _LIBCPP_GET_C_LOCALE->__ctype_b;
9880b57cec5SDimitry Andric #  elif defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
9890b57cec5SDimitry Andric   return __pctype_func();
9900b57cec5SDimitry Andric #  elif defined(__EMSCRIPTEN__)
9910b57cec5SDimitry Andric   return *__ctype_b_loc();
9920b57cec5SDimitry Andric #  elif defined(_NEWLIB_VERSION)
9930b57cec5SDimitry Andric   // Newlib has a 257-entry table in ctype_.c, where (char)0 starts at [1].
9940b57cec5SDimitry Andric   return _ctype_ + 1;
9950b57cec5SDimitry Andric #  elif defined(_AIX)
9960b57cec5SDimitry Andric   return (const unsigned int*)__lc_ctype_ptr->obj->mask;
99704eeddc0SDimitry Andric #  elif defined(__MVS__)
99804eeddc0SDimitry Andric #    if defined(__NATIVE_ASCII_F)
99904eeddc0SDimitry Andric   return const_cast<const ctype<char>::mask*>(__OBJ_DATA(__lc_ctype_a)->mask);
100004eeddc0SDimitry Andric #    else
100104eeddc0SDimitry Andric   return const_cast<const ctype<char>::mask*>(__ctypec);
100204eeddc0SDimitry Andric #    endif
10030b57cec5SDimitry Andric #  else
10040b57cec5SDimitry Andric   // Platform not supported: abort so the person doing the port knows what to
10050b57cec5SDimitry Andric   // fix
10060b57cec5SDimitry Andric #    warning ctype<char>::classic_table() is not implemented
10070b57cec5SDimitry Andric   printf("ctype<char>::classic_table() is not implemented\n");
10080b57cec5SDimitry Andric   abort();
10090b57cec5SDimitry Andric   return NULL;
10100b57cec5SDimitry Andric #  endif
10110b57cec5SDimitry Andric }
10120b57cec5SDimitry Andric #endif
10130b57cec5SDimitry Andric 
10140b57cec5SDimitry Andric #if defined(__GLIBC__)
1015*cb14a3feSDimitry Andric const int* ctype<char>::__classic_lower_table() noexcept { return _LIBCPP_GET_C_LOCALE->__ctype_tolower; }
10160b57cec5SDimitry Andric 
1017*cb14a3feSDimitry Andric const int* ctype<char>::__classic_upper_table() noexcept { return _LIBCPP_GET_C_LOCALE->__ctype_toupper; }
1018e8d8bef9SDimitry Andric #elif defined(__NetBSD__)
1019*cb14a3feSDimitry Andric const short* ctype<char>::__classic_lower_table() noexcept { return _C_tolower_tab_ + 1; }
10200b57cec5SDimitry Andric 
1021*cb14a3feSDimitry Andric const short* ctype<char>::__classic_upper_table() noexcept { return _C_toupper_tab_ + 1; }
10220b57cec5SDimitry Andric 
10230b57cec5SDimitry Andric #elif defined(__EMSCRIPTEN__)
1024*cb14a3feSDimitry Andric const int* ctype<char>::__classic_lower_table() noexcept { return *__ctype_tolower_loc(); }
10250b57cec5SDimitry Andric 
1026*cb14a3feSDimitry Andric const int* ctype<char>::__classic_upper_table() noexcept { return *__ctype_toupper_loc(); }
102704eeddc0SDimitry Andric #elif defined(__MVS__)
1028*cb14a3feSDimitry Andric const unsigned short* ctype<char>::__classic_lower_table() _NOEXCEPT {
102904eeddc0SDimitry Andric #  if defined(__NATIVE_ASCII_F)
103004eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__OBJ_DATA(__lc_ctype_a)->lower);
103104eeddc0SDimitry Andric #  else
103204eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__ctype + __TOLOWER_INDEX);
103304eeddc0SDimitry Andric #  endif
103404eeddc0SDimitry Andric }
1035*cb14a3feSDimitry Andric const unsigned short* ctype<char>::__classic_upper_table() _NOEXCEPT {
103604eeddc0SDimitry Andric #  if defined(__NATIVE_ASCII_F)
103704eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__OBJ_DATA(__lc_ctype_a)->upper);
103804eeddc0SDimitry Andric #  else
103904eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__ctype + __TOUPPER_INDEX);
104004eeddc0SDimitry Andric #  endif
104104eeddc0SDimitry Andric }
104204eeddc0SDimitry Andric #endif // __GLIBC__ || __NETBSD__ || __EMSCRIPTEN__ || __MVS__
10430b57cec5SDimitry Andric 
10440b57cec5SDimitry Andric // template <> class ctype_byname<char>
10450b57cec5SDimitry Andric 
10460b57cec5SDimitry Andric ctype_byname<char>::ctype_byname(const char* name, size_t refs)
1047*cb14a3feSDimitry Andric     : ctype<char>(0, false, refs), __l_(newlocale(LC_ALL_MASK, name, 0)) {
1048bdd1243dSDimitry Andric   if (__l_ == 0)
1049*cb14a3feSDimitry Andric     __throw_runtime_error(
1050*cb14a3feSDimitry Andric         ("ctype_byname<char>::ctype_byname"
1051*cb14a3feSDimitry Andric          " failed to construct for " +
1052*cb14a3feSDimitry Andric          string(name))
1053*cb14a3feSDimitry Andric             .c_str());
10540b57cec5SDimitry Andric }
10550b57cec5SDimitry Andric 
10560b57cec5SDimitry Andric ctype_byname<char>::ctype_byname(const string& name, size_t refs)
1057*cb14a3feSDimitry Andric     : ctype<char>(0, false, refs), __l_(newlocale(LC_ALL_MASK, name.c_str(), 0)) {
1058bdd1243dSDimitry Andric   if (__l_ == 0)
1059*cb14a3feSDimitry Andric     __throw_runtime_error(
1060*cb14a3feSDimitry Andric         ("ctype_byname<char>::ctype_byname"
1061*cb14a3feSDimitry Andric          " failed to construct for " +
1062*cb14a3feSDimitry Andric          name)
1063*cb14a3feSDimitry Andric             .c_str());
10640b57cec5SDimitry Andric }
10650b57cec5SDimitry Andric 
1066*cb14a3feSDimitry Andric ctype_byname<char>::~ctype_byname() { freelocale(__l_); }
10670b57cec5SDimitry Andric 
1068*cb14a3feSDimitry Andric char ctype_byname<char>::do_toupper(char_type c) const {
1069bdd1243dSDimitry Andric   return static_cast<char>(toupper_l(static_cast<unsigned char>(c), __l_));
10700b57cec5SDimitry Andric }
10710b57cec5SDimitry Andric 
1072*cb14a3feSDimitry Andric const char* ctype_byname<char>::do_toupper(char_type* low, const char_type* high) const {
10730b57cec5SDimitry Andric   for (; low != high; ++low)
1074bdd1243dSDimitry Andric     *low = static_cast<char>(toupper_l(static_cast<unsigned char>(*low), __l_));
10750b57cec5SDimitry Andric   return low;
10760b57cec5SDimitry Andric }
10770b57cec5SDimitry Andric 
1078*cb14a3feSDimitry Andric char ctype_byname<char>::do_tolower(char_type c) const {
1079bdd1243dSDimitry Andric   return static_cast<char>(tolower_l(static_cast<unsigned char>(c), __l_));
10800b57cec5SDimitry Andric }
10810b57cec5SDimitry Andric 
1082*cb14a3feSDimitry Andric const char* ctype_byname<char>::do_tolower(char_type* low, const char_type* high) const {
10830b57cec5SDimitry Andric   for (; low != high; ++low)
1084bdd1243dSDimitry Andric     *low = static_cast<char>(tolower_l(static_cast<unsigned char>(*low), __l_));
10850b57cec5SDimitry Andric   return low;
10860b57cec5SDimitry Andric }
10870b57cec5SDimitry Andric 
10880b57cec5SDimitry Andric // template <> class ctype_byname<wchar_t>
10890b57cec5SDimitry Andric 
1090349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
10910b57cec5SDimitry Andric ctype_byname<wchar_t>::ctype_byname(const char* name, size_t refs)
1092*cb14a3feSDimitry Andric     : ctype<wchar_t>(refs), __l_(newlocale(LC_ALL_MASK, name, 0)) {
1093bdd1243dSDimitry Andric   if (__l_ == 0)
1094*cb14a3feSDimitry Andric     __throw_runtime_error(
1095*cb14a3feSDimitry Andric         ("ctype_byname<wchar_t>::ctype_byname"
1096*cb14a3feSDimitry Andric          " failed to construct for " +
1097*cb14a3feSDimitry Andric          string(name))
1098*cb14a3feSDimitry Andric             .c_str());
10990b57cec5SDimitry Andric }
11000b57cec5SDimitry Andric 
11010b57cec5SDimitry Andric ctype_byname<wchar_t>::ctype_byname(const string& name, size_t refs)
1102*cb14a3feSDimitry Andric     : ctype<wchar_t>(refs), __l_(newlocale(LC_ALL_MASK, name.c_str(), 0)) {
1103bdd1243dSDimitry Andric   if (__l_ == 0)
1104*cb14a3feSDimitry Andric     __throw_runtime_error(
1105*cb14a3feSDimitry Andric         ("ctype_byname<wchar_t>::ctype_byname"
1106*cb14a3feSDimitry Andric          " failed to construct for " +
1107*cb14a3feSDimitry Andric          name)
1108*cb14a3feSDimitry Andric             .c_str());
11090b57cec5SDimitry Andric }
11100b57cec5SDimitry Andric 
1111*cb14a3feSDimitry Andric ctype_byname<wchar_t>::~ctype_byname() { freelocale(__l_); }
11120b57cec5SDimitry Andric 
1113*cb14a3feSDimitry Andric bool ctype_byname<wchar_t>::do_is(mask m, char_type c) const {
11140b57cec5SDimitry Andric #  ifdef _LIBCPP_WCTYPE_IS_MASK
1115bdd1243dSDimitry Andric   return static_cast<bool>(iswctype_l(c, m, __l_));
11160b57cec5SDimitry Andric #  else
11170b57cec5SDimitry Andric   bool result = false;
11180b57cec5SDimitry Andric   wint_t ch   = static_cast<wint_t>(c);
1119*cb14a3feSDimitry Andric   if ((m & space) == space)
1120*cb14a3feSDimitry Andric     result |= (iswspace_l(ch, __l_) != 0);
1121*cb14a3feSDimitry Andric   if ((m & print) == print)
1122*cb14a3feSDimitry Andric     result |= (iswprint_l(ch, __l_) != 0);
1123*cb14a3feSDimitry Andric   if ((m & cntrl) == cntrl)
1124*cb14a3feSDimitry Andric     result |= (iswcntrl_l(ch, __l_) != 0);
1125*cb14a3feSDimitry Andric   if ((m & upper) == upper)
1126*cb14a3feSDimitry Andric     result |= (iswupper_l(ch, __l_) != 0);
1127*cb14a3feSDimitry Andric   if ((m & lower) == lower)
1128*cb14a3feSDimitry Andric     result |= (iswlower_l(ch, __l_) != 0);
1129*cb14a3feSDimitry Andric   if ((m & alpha) == alpha)
1130*cb14a3feSDimitry Andric     result |= (iswalpha_l(ch, __l_) != 0);
1131*cb14a3feSDimitry Andric   if ((m & digit) == digit)
1132*cb14a3feSDimitry Andric     result |= (iswdigit_l(ch, __l_) != 0);
1133*cb14a3feSDimitry Andric   if ((m & punct) == punct)
1134*cb14a3feSDimitry Andric     result |= (iswpunct_l(ch, __l_) != 0);
1135*cb14a3feSDimitry Andric   if ((m & xdigit) == xdigit)
1136*cb14a3feSDimitry Andric     result |= (iswxdigit_l(ch, __l_) != 0);
1137*cb14a3feSDimitry Andric   if ((m & blank) == blank)
1138*cb14a3feSDimitry Andric     result |= (iswblank_l(ch, __l_) != 0);
11390b57cec5SDimitry Andric   return result;
11400b57cec5SDimitry Andric #  endif
11410b57cec5SDimitry Andric }
11420b57cec5SDimitry Andric 
1143*cb14a3feSDimitry Andric const wchar_t* ctype_byname<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const {
1144*cb14a3feSDimitry Andric   for (; low != high; ++low, ++vec) {
11450b57cec5SDimitry Andric     if (isascii(*low))
11460b57cec5SDimitry Andric       *vec = static_cast<mask>(ctype<char>::classic_table()[*low]);
1147*cb14a3feSDimitry Andric     else {
11480b57cec5SDimitry Andric       *vec      = 0;
11490b57cec5SDimitry Andric       wint_t ch = static_cast<wint_t>(*low);
1150bdd1243dSDimitry Andric       if (iswspace_l(ch, __l_))
11510b57cec5SDimitry Andric         *vec |= space;
11520b57cec5SDimitry Andric #  ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT
1153bdd1243dSDimitry Andric       if (iswprint_l(ch, __l_))
11540b57cec5SDimitry Andric         *vec |= print;
11550b57cec5SDimitry Andric #  endif
1156bdd1243dSDimitry Andric       if (iswcntrl_l(ch, __l_))
11570b57cec5SDimitry Andric         *vec |= cntrl;
1158bdd1243dSDimitry Andric       if (iswupper_l(ch, __l_))
11590b57cec5SDimitry Andric         *vec |= upper;
1160bdd1243dSDimitry Andric       if (iswlower_l(ch, __l_))
11610b57cec5SDimitry Andric         *vec |= lower;
11620b57cec5SDimitry Andric #  ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA
1163bdd1243dSDimitry Andric       if (iswalpha_l(ch, __l_))
11640b57cec5SDimitry Andric         *vec |= alpha;
11650b57cec5SDimitry Andric #  endif
1166bdd1243dSDimitry Andric       if (iswdigit_l(ch, __l_))
11670b57cec5SDimitry Andric         *vec |= digit;
1168bdd1243dSDimitry Andric       if (iswpunct_l(ch, __l_))
11690b57cec5SDimitry Andric         *vec |= punct;
11700b57cec5SDimitry Andric #  ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_XDIGIT
1171bdd1243dSDimitry Andric       if (iswxdigit_l(ch, __l_))
11720b57cec5SDimitry Andric         *vec |= xdigit;
11730b57cec5SDimitry Andric #  endif
1174bdd1243dSDimitry Andric       if (iswblank_l(ch, __l_))
11750b57cec5SDimitry Andric         *vec |= blank;
11760b57cec5SDimitry Andric     }
11770b57cec5SDimitry Andric   }
11780b57cec5SDimitry Andric   return low;
11790b57cec5SDimitry Andric }
11800b57cec5SDimitry Andric 
1181*cb14a3feSDimitry Andric const wchar_t* ctype_byname<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const {
1182*cb14a3feSDimitry Andric   for (; low != high; ++low) {
11830b57cec5SDimitry Andric #  ifdef _LIBCPP_WCTYPE_IS_MASK
1184bdd1243dSDimitry Andric     if (iswctype_l(*low, m, __l_))
11850b57cec5SDimitry Andric       break;
11860b57cec5SDimitry Andric #  else
11870b57cec5SDimitry Andric     wint_t ch = static_cast<wint_t>(*low);
1188*cb14a3feSDimitry Andric     if ((m & space) == space && iswspace_l(ch, __l_))
1189*cb14a3feSDimitry Andric       break;
1190*cb14a3feSDimitry Andric     if ((m & print) == print && iswprint_l(ch, __l_))
1191*cb14a3feSDimitry Andric       break;
1192*cb14a3feSDimitry Andric     if ((m & cntrl) == cntrl && iswcntrl_l(ch, __l_))
1193*cb14a3feSDimitry Andric       break;
1194*cb14a3feSDimitry Andric     if ((m & upper) == upper && iswupper_l(ch, __l_))
1195*cb14a3feSDimitry Andric       break;
1196*cb14a3feSDimitry Andric     if ((m & lower) == lower && iswlower_l(ch, __l_))
1197*cb14a3feSDimitry Andric       break;
1198*cb14a3feSDimitry Andric     if ((m & alpha) == alpha && iswalpha_l(ch, __l_))
1199*cb14a3feSDimitry Andric       break;
1200*cb14a3feSDimitry Andric     if ((m & digit) == digit && iswdigit_l(ch, __l_))
1201*cb14a3feSDimitry Andric       break;
1202*cb14a3feSDimitry Andric     if ((m & punct) == punct && iswpunct_l(ch, __l_))
1203*cb14a3feSDimitry Andric       break;
1204*cb14a3feSDimitry Andric     if ((m & xdigit) == xdigit && iswxdigit_l(ch, __l_))
1205*cb14a3feSDimitry Andric       break;
1206*cb14a3feSDimitry Andric     if ((m & blank) == blank && iswblank_l(ch, __l_))
1207*cb14a3feSDimitry Andric       break;
12080b57cec5SDimitry Andric #  endif
12090b57cec5SDimitry Andric   }
12100b57cec5SDimitry Andric   return low;
12110b57cec5SDimitry Andric }
12120b57cec5SDimitry Andric 
1213*cb14a3feSDimitry Andric const wchar_t* ctype_byname<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const {
1214*cb14a3feSDimitry Andric   for (; low != high; ++low) {
12150b57cec5SDimitry Andric #  ifdef _LIBCPP_WCTYPE_IS_MASK
1216bdd1243dSDimitry Andric     if (!iswctype_l(*low, m, __l_))
12170b57cec5SDimitry Andric       break;
12180b57cec5SDimitry Andric #  else
12190b57cec5SDimitry Andric     wint_t ch = static_cast<wint_t>(*low);
1220*cb14a3feSDimitry Andric     if ((m & space) == space && iswspace_l(ch, __l_))
1221*cb14a3feSDimitry Andric       continue;
1222*cb14a3feSDimitry Andric     if ((m & print) == print && iswprint_l(ch, __l_))
1223*cb14a3feSDimitry Andric       continue;
1224*cb14a3feSDimitry Andric     if ((m & cntrl) == cntrl && iswcntrl_l(ch, __l_))
1225*cb14a3feSDimitry Andric       continue;
1226*cb14a3feSDimitry Andric     if ((m & upper) == upper && iswupper_l(ch, __l_))
1227*cb14a3feSDimitry Andric       continue;
1228*cb14a3feSDimitry Andric     if ((m & lower) == lower && iswlower_l(ch, __l_))
1229*cb14a3feSDimitry Andric       continue;
1230*cb14a3feSDimitry Andric     if ((m & alpha) == alpha && iswalpha_l(ch, __l_))
1231*cb14a3feSDimitry Andric       continue;
1232*cb14a3feSDimitry Andric     if ((m & digit) == digit && iswdigit_l(ch, __l_))
1233*cb14a3feSDimitry Andric       continue;
1234*cb14a3feSDimitry Andric     if ((m & punct) == punct && iswpunct_l(ch, __l_))
1235*cb14a3feSDimitry Andric       continue;
1236*cb14a3feSDimitry Andric     if ((m & xdigit) == xdigit && iswxdigit_l(ch, __l_))
1237*cb14a3feSDimitry Andric       continue;
1238*cb14a3feSDimitry Andric     if ((m & blank) == blank && iswblank_l(ch, __l_))
1239*cb14a3feSDimitry Andric       continue;
12400b57cec5SDimitry Andric     break;
12410b57cec5SDimitry Andric #  endif
12420b57cec5SDimitry Andric   }
12430b57cec5SDimitry Andric   return low;
12440b57cec5SDimitry Andric }
12450b57cec5SDimitry Andric 
1246*cb14a3feSDimitry Andric wchar_t ctype_byname<wchar_t>::do_toupper(char_type c) const { return towupper_l(c, __l_); }
12470b57cec5SDimitry Andric 
1248*cb14a3feSDimitry Andric const wchar_t* ctype_byname<wchar_t>::do_toupper(char_type* low, const char_type* high) const {
12490b57cec5SDimitry Andric   for (; low != high; ++low)
1250bdd1243dSDimitry Andric     *low = towupper_l(*low, __l_);
12510b57cec5SDimitry Andric   return low;
12520b57cec5SDimitry Andric }
12530b57cec5SDimitry Andric 
1254*cb14a3feSDimitry Andric wchar_t ctype_byname<wchar_t>::do_tolower(char_type c) const { return towlower_l(c, __l_); }
12550b57cec5SDimitry Andric 
1256*cb14a3feSDimitry Andric const wchar_t* ctype_byname<wchar_t>::do_tolower(char_type* low, const char_type* high) const {
12570b57cec5SDimitry Andric   for (; low != high; ++low)
1258bdd1243dSDimitry Andric     *low = towlower_l(*low, __l_);
12590b57cec5SDimitry Andric   return low;
12600b57cec5SDimitry Andric }
12610b57cec5SDimitry Andric 
1262*cb14a3feSDimitry Andric wchar_t ctype_byname<wchar_t>::do_widen(char c) const { return __libcpp_btowc_l(c, __l_); }
12630b57cec5SDimitry Andric 
1264*cb14a3feSDimitry Andric const char* ctype_byname<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const {
12650b57cec5SDimitry Andric   for (; low != high; ++low, ++dest)
1266bdd1243dSDimitry Andric     *dest = __libcpp_btowc_l(*low, __l_);
12670b57cec5SDimitry Andric   return low;
12680b57cec5SDimitry Andric }
12690b57cec5SDimitry Andric 
1270*cb14a3feSDimitry Andric char ctype_byname<wchar_t>::do_narrow(char_type c, char dfault) const {
1271bdd1243dSDimitry Andric   int r = __libcpp_wctob_l(c, __l_);
127281ad6265SDimitry Andric   return (r != EOF) ? static_cast<char>(r) : dfault;
12730b57cec5SDimitry Andric }
12740b57cec5SDimitry Andric 
12750b57cec5SDimitry Andric const wchar_t*
1276*cb14a3feSDimitry Andric ctype_byname<wchar_t>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const {
1277*cb14a3feSDimitry Andric   for (; low != high; ++low, ++dest) {
1278bdd1243dSDimitry Andric     int r = __libcpp_wctob_l(*low, __l_);
127981ad6265SDimitry Andric     *dest = (r != EOF) ? static_cast<char>(r) : dfault;
12800b57cec5SDimitry Andric   }
12810b57cec5SDimitry Andric   return low;
12820b57cec5SDimitry Andric }
1283349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
12840b57cec5SDimitry Andric 
12850b57cec5SDimitry Andric // template <> class codecvt<char, char, mbstate_t>
12860b57cec5SDimitry Andric 
12875f757f3fSDimitry Andric constinit locale::id codecvt<char, char, mbstate_t>::id;
12880b57cec5SDimitry Andric 
1289*cb14a3feSDimitry Andric codecvt<char, char, mbstate_t>::~codecvt() {}
1290*cb14a3feSDimitry Andric 
1291*cb14a3feSDimitry Andric codecvt<char, char, mbstate_t>::result codecvt<char, char, mbstate_t>::do_out(
1292*cb14a3feSDimitry Andric     state_type&,
1293*cb14a3feSDimitry Andric     const intern_type* frm,
1294*cb14a3feSDimitry Andric     const intern_type*,
1295*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
1296*cb14a3feSDimitry Andric     extern_type* to,
1297*cb14a3feSDimitry Andric     extern_type*,
1298*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
1299*cb14a3feSDimitry Andric   frm_nxt = frm;
1300*cb14a3feSDimitry Andric   to_nxt  = to;
1301*cb14a3feSDimitry Andric   return noconv;
13020b57cec5SDimitry Andric }
13030b57cec5SDimitry Andric 
1304*cb14a3feSDimitry Andric codecvt<char, char, mbstate_t>::result codecvt<char, char, mbstate_t>::do_in(
1305*cb14a3feSDimitry Andric     state_type&,
1306*cb14a3feSDimitry Andric     const extern_type* frm,
1307*cb14a3feSDimitry Andric     const extern_type*,
1308*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
1309*cb14a3feSDimitry Andric     intern_type* to,
1310*cb14a3feSDimitry Andric     intern_type*,
1311*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
13120b57cec5SDimitry Andric   frm_nxt = frm;
13130b57cec5SDimitry Andric   to_nxt  = to;
13140b57cec5SDimitry Andric   return noconv;
13150b57cec5SDimitry Andric }
13160b57cec5SDimitry Andric 
13170b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::result
1318*cb14a3feSDimitry Andric codecvt<char, char, mbstate_t>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
13190b57cec5SDimitry Andric   to_nxt = to;
13200b57cec5SDimitry Andric   return noconv;
13210b57cec5SDimitry Andric }
13220b57cec5SDimitry Andric 
1323*cb14a3feSDimitry Andric int codecvt<char, char, mbstate_t>::do_encoding() const noexcept { return 1; }
13240b57cec5SDimitry Andric 
1325*cb14a3feSDimitry Andric bool codecvt<char, char, mbstate_t>::do_always_noconv() const noexcept { return true; }
13260b57cec5SDimitry Andric 
1327*cb14a3feSDimitry Andric int codecvt<char, char, mbstate_t>::do_length(
1328*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* end, size_t mx) const {
13290b57cec5SDimitry Andric   return static_cast<int>(min<size_t>(mx, static_cast<size_t>(end - frm)));
13300b57cec5SDimitry Andric }
13310b57cec5SDimitry Andric 
1332*cb14a3feSDimitry Andric int codecvt<char, char, mbstate_t>::do_max_length() const noexcept { return 1; }
13330b57cec5SDimitry Andric 
13340b57cec5SDimitry Andric // template <> class codecvt<wchar_t, char, mbstate_t>
13350b57cec5SDimitry Andric 
1336349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
13375f757f3fSDimitry Andric constinit locale::id codecvt<wchar_t, char, mbstate_t>::id;
13380b57cec5SDimitry Andric 
1339*cb14a3feSDimitry Andric codecvt<wchar_t, char, mbstate_t>::codecvt(size_t refs) : locale::facet(refs), __l_(_LIBCPP_GET_C_LOCALE) {}
13400b57cec5SDimitry Andric 
13410b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::codecvt(const char* nm, size_t refs)
1342*cb14a3feSDimitry Andric     : locale::facet(refs), __l_(newlocale(LC_ALL_MASK, nm, 0)) {
1343bdd1243dSDimitry Andric   if (__l_ == 0)
1344*cb14a3feSDimitry Andric     __throw_runtime_error(
1345*cb14a3feSDimitry Andric         ("codecvt_byname<wchar_t, char, mbstate_t>::codecvt_byname"
1346*cb14a3feSDimitry Andric          " failed to construct for " +
1347*cb14a3feSDimitry Andric          string(nm))
1348*cb14a3feSDimitry Andric             .c_str());
13490b57cec5SDimitry Andric }
13500b57cec5SDimitry Andric 
1351*cb14a3feSDimitry Andric codecvt<wchar_t, char, mbstate_t>::~codecvt() {
1352bdd1243dSDimitry Andric   if (__l_ != _LIBCPP_GET_C_LOCALE)
1353bdd1243dSDimitry Andric     freelocale(__l_);
13540b57cec5SDimitry Andric }
13550b57cec5SDimitry Andric 
1356*cb14a3feSDimitry Andric codecvt<wchar_t, char, mbstate_t>::result codecvt<wchar_t, char, mbstate_t>::do_out(
1357*cb14a3feSDimitry Andric     state_type& st,
1358*cb14a3feSDimitry Andric     const intern_type* frm,
1359*cb14a3feSDimitry Andric     const intern_type* frm_end,
1360*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
1361*cb14a3feSDimitry Andric     extern_type* to,
1362*cb14a3feSDimitry Andric     extern_type* to_end,
1363*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
13640b57cec5SDimitry Andric   // look for first internal null in frm
13650b57cec5SDimitry Andric   const intern_type* fend = frm;
13660b57cec5SDimitry Andric   for (; fend != frm_end; ++fend)
13670b57cec5SDimitry Andric     if (*fend == 0)
13680b57cec5SDimitry Andric       break;
13690b57cec5SDimitry Andric   // loop over all null-terminated sequences in frm
13700b57cec5SDimitry Andric   to_nxt = to;
1371*cb14a3feSDimitry Andric   for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt) {
13720b57cec5SDimitry Andric     // save state in case it is needed to recover to_nxt on error
13730b57cec5SDimitry Andric     mbstate_t save_state = st;
1374*cb14a3feSDimitry Andric     size_t n             = __libcpp_wcsnrtombs_l(
1375*cb14a3feSDimitry Andric         to, &frm_nxt, static_cast<size_t>(fend - frm), static_cast<size_t>(to_end - to), &st, __l_);
1376*cb14a3feSDimitry Andric     if (n == size_t(-1)) {
13770b57cec5SDimitry Andric       // need to recover to_nxt
1378*cb14a3feSDimitry Andric       for (to_nxt = to; frm != frm_nxt; ++frm) {
1379bdd1243dSDimitry Andric         n = __libcpp_wcrtomb_l(to_nxt, *frm, &save_state, __l_);
13800b57cec5SDimitry Andric         if (n == size_t(-1))
13810b57cec5SDimitry Andric           break;
13820b57cec5SDimitry Andric         to_nxt += n;
13830b57cec5SDimitry Andric       }
13840b57cec5SDimitry Andric       frm_nxt = frm;
13850b57cec5SDimitry Andric       return error;
13860b57cec5SDimitry Andric     }
13870b57cec5SDimitry Andric     if (n == 0)
13880b57cec5SDimitry Andric       return partial;
13890b57cec5SDimitry Andric     to_nxt += n;
13900b57cec5SDimitry Andric     if (to_nxt == to_end)
13910b57cec5SDimitry Andric       break;
13920b57cec5SDimitry Andric     if (fend != frm_end) // set up next null terminated sequence
13930b57cec5SDimitry Andric     {
13940b57cec5SDimitry Andric       // Try to write the terminating null
13950b57cec5SDimitry Andric       extern_type tmp[MB_LEN_MAX];
1396bdd1243dSDimitry Andric       n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l_);
13970b57cec5SDimitry Andric       if (n == size_t(-1)) // on error
13980b57cec5SDimitry Andric         return error;
13990b57cec5SDimitry Andric       if (n > static_cast<size_t>(to_end - to_nxt)) // is there room?
14000b57cec5SDimitry Andric         return partial;
14010b57cec5SDimitry Andric       for (extern_type* p = tmp; n; --n) // write it
14020b57cec5SDimitry Andric         *to_nxt++ = *p++;
14030b57cec5SDimitry Andric       ++frm_nxt;
14040b57cec5SDimitry Andric       // look for next null in frm
14050b57cec5SDimitry Andric       for (fend = frm_nxt; fend != frm_end; ++fend)
14060b57cec5SDimitry Andric         if (*fend == 0)
14070b57cec5SDimitry Andric           break;
14080b57cec5SDimitry Andric     }
14090b57cec5SDimitry Andric   }
14100b57cec5SDimitry Andric   return frm_nxt == frm_end ? ok : partial;
14110b57cec5SDimitry Andric }
14120b57cec5SDimitry Andric 
1413*cb14a3feSDimitry Andric codecvt<wchar_t, char, mbstate_t>::result codecvt<wchar_t, char, mbstate_t>::do_in(
1414*cb14a3feSDimitry Andric     state_type& st,
1415*cb14a3feSDimitry Andric     const extern_type* frm,
1416*cb14a3feSDimitry Andric     const extern_type* frm_end,
1417*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
1418*cb14a3feSDimitry Andric     intern_type* to,
1419*cb14a3feSDimitry Andric     intern_type* to_end,
1420*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
14210b57cec5SDimitry Andric   // look for first internal null in frm
14220b57cec5SDimitry Andric   const extern_type* fend = frm;
14230b57cec5SDimitry Andric   for (; fend != frm_end; ++fend)
14240b57cec5SDimitry Andric     if (*fend == 0)
14250b57cec5SDimitry Andric       break;
14260b57cec5SDimitry Andric   // loop over all null-terminated sequences in frm
14270b57cec5SDimitry Andric   to_nxt = to;
1428*cb14a3feSDimitry Andric   for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt) {
14290b57cec5SDimitry Andric     // save state in case it is needed to recover to_nxt on error
14300b57cec5SDimitry Andric     mbstate_t save_state = st;
1431*cb14a3feSDimitry Andric     size_t n             = __libcpp_mbsnrtowcs_l(
1432*cb14a3feSDimitry Andric         to, &frm_nxt, static_cast<size_t>(fend - frm), static_cast<size_t>(to_end - to), &st, __l_);
1433*cb14a3feSDimitry Andric     if (n == size_t(-1)) {
14340b57cec5SDimitry Andric       // need to recover to_nxt
1435*cb14a3feSDimitry Andric       for (to_nxt = to; frm != frm_nxt; ++to_nxt) {
1436*cb14a3feSDimitry Andric         n = __libcpp_mbrtowc_l(to_nxt, frm, static_cast<size_t>(fend - frm), &save_state, __l_);
1437*cb14a3feSDimitry Andric         switch (n) {
14380b57cec5SDimitry Andric         case 0:
14390b57cec5SDimitry Andric           ++frm;
14400b57cec5SDimitry Andric           break;
14410b57cec5SDimitry Andric         case size_t(-1):
14420b57cec5SDimitry Andric           frm_nxt = frm;
14430b57cec5SDimitry Andric           return error;
14440b57cec5SDimitry Andric         case size_t(-2):
14450b57cec5SDimitry Andric           frm_nxt = frm;
14460b57cec5SDimitry Andric           return partial;
14470b57cec5SDimitry Andric         default:
14480b57cec5SDimitry Andric           frm += n;
14490b57cec5SDimitry Andric           break;
14500b57cec5SDimitry Andric         }
14510b57cec5SDimitry Andric       }
14520b57cec5SDimitry Andric       frm_nxt = frm;
14530b57cec5SDimitry Andric       return frm_nxt == frm_end ? ok : partial;
14540b57cec5SDimitry Andric     }
14550b57cec5SDimitry Andric     if (n == size_t(-1))
14560b57cec5SDimitry Andric       return error;
14570b57cec5SDimitry Andric     to_nxt += n;
14580b57cec5SDimitry Andric     if (to_nxt == to_end)
14590b57cec5SDimitry Andric       break;
14600b57cec5SDimitry Andric     if (fend != frm_end) // set up next null terminated sequence
14610b57cec5SDimitry Andric     {
14620b57cec5SDimitry Andric       // Try to write the terminating null
1463bdd1243dSDimitry Andric       n = __libcpp_mbrtowc_l(to_nxt, frm_nxt, 1, &st, __l_);
14640b57cec5SDimitry Andric       if (n != 0) // on error
14650b57cec5SDimitry Andric         return error;
14660b57cec5SDimitry Andric       ++to_nxt;
14670b57cec5SDimitry Andric       ++frm_nxt;
14680b57cec5SDimitry Andric       // look for next null in frm
14690b57cec5SDimitry Andric       for (fend = frm_nxt; fend != frm_end; ++fend)
14700b57cec5SDimitry Andric         if (*fend == 0)
14710b57cec5SDimitry Andric           break;
14720b57cec5SDimitry Andric     }
14730b57cec5SDimitry Andric   }
14740b57cec5SDimitry Andric   return frm_nxt == frm_end ? ok : partial;
14750b57cec5SDimitry Andric }
14760b57cec5SDimitry Andric 
1477*cb14a3feSDimitry Andric codecvt<wchar_t, char, mbstate_t>::result codecvt<wchar_t, char, mbstate_t>::do_unshift(
1478*cb14a3feSDimitry Andric     state_type& st, extern_type* to, extern_type* to_end, extern_type*& to_nxt) const {
14790b57cec5SDimitry Andric   to_nxt = to;
14800b57cec5SDimitry Andric   extern_type tmp[MB_LEN_MAX];
1481bdd1243dSDimitry Andric   size_t n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l_);
14820b57cec5SDimitry Andric   if (n == size_t(-1) || n == 0) // on error
14830b57cec5SDimitry Andric     return error;
14840b57cec5SDimitry Andric   --n;
14850b57cec5SDimitry Andric   if (n > static_cast<size_t>(to_end - to_nxt)) // is there room?
14860b57cec5SDimitry Andric     return partial;
14870b57cec5SDimitry Andric   for (extern_type* p = tmp; n; --n) // write it
14880b57cec5SDimitry Andric     *to_nxt++ = *p++;
14890b57cec5SDimitry Andric   return ok;
14900b57cec5SDimitry Andric }
14910b57cec5SDimitry Andric 
1492*cb14a3feSDimitry Andric int codecvt<wchar_t, char, mbstate_t>::do_encoding() const noexcept {
1493bdd1243dSDimitry Andric   if (__libcpp_mbtowc_l(nullptr, nullptr, MB_LEN_MAX, __l_) != 0)
14940b57cec5SDimitry Andric     return -1;
14950b57cec5SDimitry Andric 
14960b57cec5SDimitry Andric   // stateless encoding
1497bdd1243dSDimitry Andric   if (__l_ == 0 || __libcpp_mb_cur_max_l(__l_) == 1) // there are no known constant length encodings
14980b57cec5SDimitry Andric     return 1;                                        // which take more than 1 char to form a wchar_t
14990b57cec5SDimitry Andric   return 0;
15000b57cec5SDimitry Andric }
15010b57cec5SDimitry Andric 
1502*cb14a3feSDimitry Andric bool codecvt<wchar_t, char, mbstate_t>::do_always_noconv() const noexcept { return false; }
15030b57cec5SDimitry Andric 
1504*cb14a3feSDimitry Andric int codecvt<wchar_t, char, mbstate_t>::do_length(
1505*cb14a3feSDimitry Andric     state_type& st, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
15060b57cec5SDimitry Andric   int nbytes = 0;
1507*cb14a3feSDimitry Andric   for (size_t nwchar_t = 0; nwchar_t < mx && frm != frm_end; ++nwchar_t) {
1508bdd1243dSDimitry Andric     size_t n = __libcpp_mbrlen_l(frm, static_cast<size_t>(frm_end - frm), &st, __l_);
1509*cb14a3feSDimitry Andric     switch (n) {
15100b57cec5SDimitry Andric     case 0:
15110b57cec5SDimitry Andric       ++nbytes;
15120b57cec5SDimitry Andric       ++frm;
15130b57cec5SDimitry Andric       break;
15140b57cec5SDimitry Andric     case size_t(-1):
15150b57cec5SDimitry Andric     case size_t(-2):
15160b57cec5SDimitry Andric       return nbytes;
15170b57cec5SDimitry Andric     default:
15180b57cec5SDimitry Andric       nbytes += n;
15190b57cec5SDimitry Andric       frm += n;
15200b57cec5SDimitry Andric       break;
15210b57cec5SDimitry Andric     }
15220b57cec5SDimitry Andric   }
15230b57cec5SDimitry Andric   return nbytes;
15240b57cec5SDimitry Andric }
15250b57cec5SDimitry Andric 
1526*cb14a3feSDimitry Andric int codecvt<wchar_t, char, mbstate_t>::do_max_length() const noexcept {
1527bdd1243dSDimitry Andric   return __l_ == 0 ? 1 : static_cast<int>(__libcpp_mb_cur_max_l(__l_));
15280b57cec5SDimitry Andric }
1529349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
15300b57cec5SDimitry Andric 
15310b57cec5SDimitry Andric //                                     Valid UTF ranges
15320b57cec5SDimitry Andric //     UTF-32               UTF-16                          UTF-8               # of code points
15330b57cec5SDimitry Andric //                     first      second       first   second    third   fourth
15340b57cec5SDimitry Andric // 000000 - 00007F  0000 - 007F               00 - 7F                                 127
15350b57cec5SDimitry Andric // 000080 - 0007FF  0080 - 07FF               C2 - DF, 80 - BF                       1920
15360b57cec5SDimitry Andric // 000800 - 000FFF  0800 - 0FFF               E0 - E0, A0 - BF, 80 - BF              2048
15370b57cec5SDimitry Andric // 001000 - 00CFFF  1000 - CFFF               E1 - EC, 80 - BF, 80 - BF             49152
15380b57cec5SDimitry Andric // 00D000 - 00D7FF  D000 - D7FF               ED - ED, 80 - 9F, 80 - BF              2048
15390b57cec5SDimitry Andric // 00D800 - 00DFFF                invalid
15400b57cec5SDimitry Andric // 00E000 - 00FFFF  E000 - FFFF               EE - EF, 80 - BF, 80 - BF              8192
15410b57cec5SDimitry Andric // 010000 - 03FFFF  D800 - D8BF, DC00 - DFFF  F0 - F0, 90 - BF, 80 - BF, 80 - BF   196608
15420b57cec5SDimitry Andric // 040000 - 0FFFFF  D8C0 - DBBF, DC00 - DFFF  F1 - F3, 80 - BF, 80 - BF, 80 - BF   786432
15430b57cec5SDimitry Andric // 100000 - 10FFFF  DBC0 - DBFF, DC00 - DFFF  F4 - F4, 80 - 8F, 80 - BF, 80 - BF    65536
15440b57cec5SDimitry Andric 
154581ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
1546*cb14a3feSDimitry Andric static codecvt_base::result utf16_to_utf8(
1547*cb14a3feSDimitry Andric     const uint16_t* frm,
1548*cb14a3feSDimitry Andric     const uint16_t* frm_end,
1549*cb14a3feSDimitry Andric     const uint16_t*& frm_nxt,
1550*cb14a3feSDimitry Andric     uint8_t* to,
1551*cb14a3feSDimitry Andric     uint8_t* to_end,
1552*cb14a3feSDimitry Andric     uint8_t*& to_nxt,
1553*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
1554*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
15550b57cec5SDimitry Andric   frm_nxt = frm;
15560b57cec5SDimitry Andric   to_nxt  = to;
1557*cb14a3feSDimitry Andric   if (mode & generate_header) {
15580b57cec5SDimitry Andric     if (to_end - to_nxt < 3)
15590b57cec5SDimitry Andric       return codecvt_base::partial;
15600b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xEF);
15610b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xBB);
15620b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xBF);
15630b57cec5SDimitry Andric   }
1564*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end; ++frm_nxt) {
15650b57cec5SDimitry Andric     uint16_t wc1 = *frm_nxt;
15660b57cec5SDimitry Andric     if (wc1 > Maxcode)
15670b57cec5SDimitry Andric       return codecvt_base::error;
1568*cb14a3feSDimitry Andric     if (wc1 < 0x0080) {
15690b57cec5SDimitry Andric       if (to_end - to_nxt < 1)
15700b57cec5SDimitry Andric         return codecvt_base::partial;
15710b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(wc1);
1572*cb14a3feSDimitry Andric     } else if (wc1 < 0x0800) {
15730b57cec5SDimitry Andric       if (to_end - to_nxt < 2)
15740b57cec5SDimitry Andric         return codecvt_base::partial;
15750b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc1 >> 6));
15760b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x03F));
1577*cb14a3feSDimitry Andric     } else if (wc1 < 0xD800) {
15780b57cec5SDimitry Andric       if (to_end - to_nxt < 3)
15790b57cec5SDimitry Andric         return codecvt_base::partial;
15800b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0xE0 | (wc1 >> 12));
15810b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
15820b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x003F));
1583*cb14a3feSDimitry Andric     } else if (wc1 < 0xDC00) {
15840b57cec5SDimitry Andric       if (frm_end - frm_nxt < 2)
15850b57cec5SDimitry Andric         return codecvt_base::partial;
15860b57cec5SDimitry Andric       uint16_t wc2 = frm_nxt[1];
15870b57cec5SDimitry Andric       if ((wc2 & 0xFC00) != 0xDC00)
15880b57cec5SDimitry Andric         return codecvt_base::error;
15890b57cec5SDimitry Andric       if (to_end - to_nxt < 4)
15900b57cec5SDimitry Andric         return codecvt_base::partial;
1591*cb14a3feSDimitry Andric       if (((((wc1 & 0x03C0UL) >> 6) + 1) << 16) + ((wc1 & 0x003FUL) << 10) + (wc2 & 0x03FF) > Maxcode)
15920b57cec5SDimitry Andric         return codecvt_base::error;
15930b57cec5SDimitry Andric       ++frm_nxt;
15940b57cec5SDimitry Andric       uint8_t z = ((wc1 & 0x03C0) >> 6) + 1;
15950b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0xF0 | (z >> 2));
15960b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | ((z & 0x03) << 4) | ((wc1 & 0x003C) >> 2));
15970b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6));
15980b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | (wc2 & 0x003F));
1599*cb14a3feSDimitry Andric     } else if (wc1 < 0xE000) {
16000b57cec5SDimitry Andric       return codecvt_base::error;
1601*cb14a3feSDimitry Andric     } else {
16020b57cec5SDimitry Andric       if (to_end - to_nxt < 3)
16030b57cec5SDimitry Andric         return codecvt_base::partial;
16040b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0xE0 | (wc1 >> 12));
16050b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
16060b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x003F));
16070b57cec5SDimitry Andric     }
16080b57cec5SDimitry Andric   }
16090b57cec5SDimitry Andric   return codecvt_base::ok;
16100b57cec5SDimitry Andric }
16110b57cec5SDimitry Andric 
1612*cb14a3feSDimitry Andric static codecvt_base::result utf16_to_utf8(
1613*cb14a3feSDimitry Andric     const uint32_t* frm,
1614*cb14a3feSDimitry Andric     const uint32_t* frm_end,
1615*cb14a3feSDimitry Andric     const uint32_t*& frm_nxt,
1616*cb14a3feSDimitry Andric     uint8_t* to,
1617*cb14a3feSDimitry Andric     uint8_t* to_end,
1618*cb14a3feSDimitry Andric     uint8_t*& to_nxt,
1619*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
1620*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
16210b57cec5SDimitry Andric   frm_nxt = frm;
16220b57cec5SDimitry Andric   to_nxt  = to;
1623*cb14a3feSDimitry Andric   if (mode & generate_header) {
16240b57cec5SDimitry Andric     if (to_end - to_nxt < 3)
16250b57cec5SDimitry Andric       return codecvt_base::partial;
16260b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xEF);
16270b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xBB);
16280b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xBF);
16290b57cec5SDimitry Andric   }
1630*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end; ++frm_nxt) {
16310b57cec5SDimitry Andric     uint16_t wc1 = static_cast<uint16_t>(*frm_nxt);
16320b57cec5SDimitry Andric     if (wc1 > Maxcode)
16330b57cec5SDimitry Andric       return codecvt_base::error;
1634*cb14a3feSDimitry Andric     if (wc1 < 0x0080) {
16350b57cec5SDimitry Andric       if (to_end - to_nxt < 1)
16360b57cec5SDimitry Andric         return codecvt_base::partial;
16370b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(wc1);
1638*cb14a3feSDimitry Andric     } else if (wc1 < 0x0800) {
16390b57cec5SDimitry Andric       if (to_end - to_nxt < 2)
16400b57cec5SDimitry Andric         return codecvt_base::partial;
16410b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc1 >> 6));
16420b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x03F));
1643*cb14a3feSDimitry Andric     } else if (wc1 < 0xD800) {
16440b57cec5SDimitry Andric       if (to_end - to_nxt < 3)
16450b57cec5SDimitry Andric         return codecvt_base::partial;
16460b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0xE0 | (wc1 >> 12));
16470b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
16480b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x003F));
1649*cb14a3feSDimitry Andric     } else if (wc1 < 0xDC00) {
16500b57cec5SDimitry Andric       if (frm_end - frm_nxt < 2)
16510b57cec5SDimitry Andric         return codecvt_base::partial;
16520b57cec5SDimitry Andric       uint16_t wc2 = static_cast<uint16_t>(frm_nxt[1]);
16530b57cec5SDimitry Andric       if ((wc2 & 0xFC00) != 0xDC00)
16540b57cec5SDimitry Andric         return codecvt_base::error;
16550b57cec5SDimitry Andric       if (to_end - to_nxt < 4)
16560b57cec5SDimitry Andric         return codecvt_base::partial;
1657*cb14a3feSDimitry Andric       if (((((wc1 & 0x03C0UL) >> 6) + 1) << 16) + ((wc1 & 0x003FUL) << 10) + (wc2 & 0x03FF) > Maxcode)
16580b57cec5SDimitry Andric         return codecvt_base::error;
16590b57cec5SDimitry Andric       ++frm_nxt;
16600b57cec5SDimitry Andric       uint8_t z = ((wc1 & 0x03C0) >> 6) + 1;
16610b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0xF0 | (z >> 2));
16620b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | ((z & 0x03) << 4) | ((wc1 & 0x003C) >> 2));
16630b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6));
16640b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | (wc2 & 0x003F));
1665*cb14a3feSDimitry Andric     } else if (wc1 < 0xE000) {
16660b57cec5SDimitry Andric       return codecvt_base::error;
1667*cb14a3feSDimitry Andric     } else {
16680b57cec5SDimitry Andric       if (to_end - to_nxt < 3)
16690b57cec5SDimitry Andric         return codecvt_base::partial;
16700b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0xE0 | (wc1 >> 12));
16710b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
16720b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x003F));
16730b57cec5SDimitry Andric     }
16740b57cec5SDimitry Andric   }
16750b57cec5SDimitry Andric   return codecvt_base::ok;
16760b57cec5SDimitry Andric }
16770b57cec5SDimitry Andric 
1678*cb14a3feSDimitry Andric static codecvt_base::result utf8_to_utf16(
1679*cb14a3feSDimitry Andric     const uint8_t* frm,
1680*cb14a3feSDimitry Andric     const uint8_t* frm_end,
1681*cb14a3feSDimitry Andric     const uint8_t*& frm_nxt,
1682*cb14a3feSDimitry Andric     uint16_t* to,
1683*cb14a3feSDimitry Andric     uint16_t* to_end,
1684*cb14a3feSDimitry Andric     uint16_t*& to_nxt,
1685*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
1686*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
16870b57cec5SDimitry Andric   frm_nxt = frm;
16880b57cec5SDimitry Andric   to_nxt  = to;
1689*cb14a3feSDimitry Andric   if (mode & consume_header) {
1690*cb14a3feSDimitry Andric     if (frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF)
16910b57cec5SDimitry Andric       frm_nxt += 3;
16920b57cec5SDimitry Andric   }
1693*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt) {
16940b57cec5SDimitry Andric     uint8_t c1 = *frm_nxt;
16950b57cec5SDimitry Andric     if (c1 > Maxcode)
16960b57cec5SDimitry Andric       return codecvt_base::error;
1697*cb14a3feSDimitry Andric     if (c1 < 0x80) {
16980b57cec5SDimitry Andric       *to_nxt = static_cast<uint16_t>(c1);
16990b57cec5SDimitry Andric       ++frm_nxt;
1700*cb14a3feSDimitry Andric     } else if (c1 < 0xC2) {
17010b57cec5SDimitry Andric       return codecvt_base::error;
1702*cb14a3feSDimitry Andric     } else if (c1 < 0xE0) {
17030b57cec5SDimitry Andric       if (frm_end - frm_nxt < 2)
17040b57cec5SDimitry Andric         return codecvt_base::partial;
17050b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
17060b57cec5SDimitry Andric       if ((c2 & 0xC0) != 0x80)
17070b57cec5SDimitry Andric         return codecvt_base::error;
17080b57cec5SDimitry Andric       uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
17090b57cec5SDimitry Andric       if (t > Maxcode)
17100b57cec5SDimitry Andric         return codecvt_base::error;
17110b57cec5SDimitry Andric       *to_nxt = t;
17120b57cec5SDimitry Andric       frm_nxt += 2;
1713*cb14a3feSDimitry Andric     } else if (c1 < 0xF0) {
17145f757f3fSDimitry Andric       if (frm_end - frm_nxt < 2)
17150b57cec5SDimitry Andric         return codecvt_base::partial;
17160b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
1717*cb14a3feSDimitry Andric       switch (c1) {
17180b57cec5SDimitry Andric       case 0xE0:
17190b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0xA0)
17200b57cec5SDimitry Andric           return codecvt_base::error;
17210b57cec5SDimitry Andric         break;
17220b57cec5SDimitry Andric       case 0xED:
17230b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0x80)
17240b57cec5SDimitry Andric           return codecvt_base::error;
17250b57cec5SDimitry Andric         break;
17260b57cec5SDimitry Andric       default:
17270b57cec5SDimitry Andric         if ((c2 & 0xC0) != 0x80)
17280b57cec5SDimitry Andric           return codecvt_base::error;
17290b57cec5SDimitry Andric         break;
17300b57cec5SDimitry Andric       }
17315f757f3fSDimitry Andric       if (frm_end - frm_nxt < 3)
17325f757f3fSDimitry Andric         return codecvt_base::partial;
17335f757f3fSDimitry Andric       uint8_t c3 = frm_nxt[2];
17340b57cec5SDimitry Andric       if ((c3 & 0xC0) != 0x80)
17350b57cec5SDimitry Andric         return codecvt_base::error;
1736*cb14a3feSDimitry Andric       uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F));
17370b57cec5SDimitry Andric       if (t > Maxcode)
17380b57cec5SDimitry Andric         return codecvt_base::error;
17390b57cec5SDimitry Andric       *to_nxt = t;
17400b57cec5SDimitry Andric       frm_nxt += 3;
1741*cb14a3feSDimitry Andric     } else if (c1 < 0xF5) {
17425f757f3fSDimitry Andric       if (frm_end - frm_nxt < 2)
17430b57cec5SDimitry Andric         return codecvt_base::partial;
17440b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
1745*cb14a3feSDimitry Andric       switch (c1) {
17460b57cec5SDimitry Andric       case 0xF0:
17470b57cec5SDimitry Andric         if (!(0x90 <= c2 && c2 <= 0xBF))
17480b57cec5SDimitry Andric           return codecvt_base::error;
17490b57cec5SDimitry Andric         break;
17500b57cec5SDimitry Andric       case 0xF4:
17510b57cec5SDimitry Andric         if ((c2 & 0xF0) != 0x80)
17520b57cec5SDimitry Andric           return codecvt_base::error;
17530b57cec5SDimitry Andric         break;
17540b57cec5SDimitry Andric       default:
17550b57cec5SDimitry Andric         if ((c2 & 0xC0) != 0x80)
17560b57cec5SDimitry Andric           return codecvt_base::error;
17570b57cec5SDimitry Andric         break;
17580b57cec5SDimitry Andric       }
17595f757f3fSDimitry Andric       if (frm_end - frm_nxt < 3)
17605f757f3fSDimitry Andric         return codecvt_base::partial;
17615f757f3fSDimitry Andric       uint8_t c3 = frm_nxt[2];
17625f757f3fSDimitry Andric       if ((c3 & 0xC0) != 0x80)
17635f757f3fSDimitry Andric         return codecvt_base::error;
17645f757f3fSDimitry Andric       if (frm_end - frm_nxt < 4)
17655f757f3fSDimitry Andric         return codecvt_base::partial;
17665f757f3fSDimitry Andric       uint8_t c4 = frm_nxt[3];
17675f757f3fSDimitry Andric       if ((c4 & 0xC0) != 0x80)
17680b57cec5SDimitry Andric         return codecvt_base::error;
17690b57cec5SDimitry Andric       if (to_end - to_nxt < 2)
17700b57cec5SDimitry Andric         return codecvt_base::partial;
1771*cb14a3feSDimitry Andric       if ((((c1 & 7UL) << 18) + ((c2 & 0x3FUL) << 12) + ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
17720b57cec5SDimitry Andric         return codecvt_base::error;
17730b57cec5SDimitry Andric       *to_nxt = static_cast<uint16_t>(
1774*cb14a3feSDimitry Andric           0xD800 | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6) | ((c2 & 0x0F) << 2) | ((c3 & 0x30) >> 4));
1775*cb14a3feSDimitry Andric       *++to_nxt = static_cast<uint16_t>(0xDC00 | ((c3 & 0x0F) << 6) | (c4 & 0x3F));
17760b57cec5SDimitry Andric       frm_nxt += 4;
1777*cb14a3feSDimitry Andric     } else {
17780b57cec5SDimitry Andric       return codecvt_base::error;
17790b57cec5SDimitry Andric     }
17800b57cec5SDimitry Andric   }
17810b57cec5SDimitry Andric   return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
17820b57cec5SDimitry Andric }
17830b57cec5SDimitry Andric 
1784*cb14a3feSDimitry Andric static codecvt_base::result utf8_to_utf16(
1785*cb14a3feSDimitry Andric     const uint8_t* frm,
1786*cb14a3feSDimitry Andric     const uint8_t* frm_end,
1787*cb14a3feSDimitry Andric     const uint8_t*& frm_nxt,
1788*cb14a3feSDimitry Andric     uint32_t* to,
1789*cb14a3feSDimitry Andric     uint32_t* to_end,
1790*cb14a3feSDimitry Andric     uint32_t*& to_nxt,
1791*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
1792*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
17930b57cec5SDimitry Andric   frm_nxt = frm;
17940b57cec5SDimitry Andric   to_nxt  = to;
1795*cb14a3feSDimitry Andric   if (mode & consume_header) {
1796*cb14a3feSDimitry Andric     if (frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF)
17970b57cec5SDimitry Andric       frm_nxt += 3;
17980b57cec5SDimitry Andric   }
1799*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt) {
18000b57cec5SDimitry Andric     uint8_t c1 = *frm_nxt;
18010b57cec5SDimitry Andric     if (c1 > Maxcode)
18020b57cec5SDimitry Andric       return codecvt_base::error;
1803*cb14a3feSDimitry Andric     if (c1 < 0x80) {
18040b57cec5SDimitry Andric       *to_nxt = static_cast<uint32_t>(c1);
18050b57cec5SDimitry Andric       ++frm_nxt;
1806*cb14a3feSDimitry Andric     } else if (c1 < 0xC2) {
18070b57cec5SDimitry Andric       return codecvt_base::error;
1808*cb14a3feSDimitry Andric     } else if (c1 < 0xE0) {
18090b57cec5SDimitry Andric       if (frm_end - frm_nxt < 2)
18100b57cec5SDimitry Andric         return codecvt_base::partial;
18110b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
18120b57cec5SDimitry Andric       if ((c2 & 0xC0) != 0x80)
18130b57cec5SDimitry Andric         return codecvt_base::error;
18140b57cec5SDimitry Andric       uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
18150b57cec5SDimitry Andric       if (t > Maxcode)
18160b57cec5SDimitry Andric         return codecvt_base::error;
18170b57cec5SDimitry Andric       *to_nxt = static_cast<uint32_t>(t);
18180b57cec5SDimitry Andric       frm_nxt += 2;
1819*cb14a3feSDimitry Andric     } else if (c1 < 0xF0) {
18205f757f3fSDimitry Andric       if (frm_end - frm_nxt < 2)
18210b57cec5SDimitry Andric         return codecvt_base::partial;
18220b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
1823*cb14a3feSDimitry Andric       switch (c1) {
18240b57cec5SDimitry Andric       case 0xE0:
18250b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0xA0)
18260b57cec5SDimitry Andric           return codecvt_base::error;
18270b57cec5SDimitry Andric         break;
18280b57cec5SDimitry Andric       case 0xED:
18290b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0x80)
18300b57cec5SDimitry Andric           return codecvt_base::error;
18310b57cec5SDimitry Andric         break;
18320b57cec5SDimitry Andric       default:
18330b57cec5SDimitry Andric         if ((c2 & 0xC0) != 0x80)
18340b57cec5SDimitry Andric           return codecvt_base::error;
18350b57cec5SDimitry Andric         break;
18360b57cec5SDimitry Andric       }
18375f757f3fSDimitry Andric       if (frm_end - frm_nxt < 3)
18385f757f3fSDimitry Andric         return codecvt_base::partial;
18395f757f3fSDimitry Andric       uint8_t c3 = frm_nxt[2];
18400b57cec5SDimitry Andric       if ((c3 & 0xC0) != 0x80)
18410b57cec5SDimitry Andric         return codecvt_base::error;
1842*cb14a3feSDimitry Andric       uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F));
18430b57cec5SDimitry Andric       if (t > Maxcode)
18440b57cec5SDimitry Andric         return codecvt_base::error;
18450b57cec5SDimitry Andric       *to_nxt = static_cast<uint32_t>(t);
18460b57cec5SDimitry Andric       frm_nxt += 3;
1847*cb14a3feSDimitry Andric     } else if (c1 < 0xF5) {
18485f757f3fSDimitry Andric       if (frm_end - frm_nxt < 2)
18490b57cec5SDimitry Andric         return codecvt_base::partial;
18500b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
1851*cb14a3feSDimitry Andric       switch (c1) {
18520b57cec5SDimitry Andric       case 0xF0:
18530b57cec5SDimitry Andric         if (!(0x90 <= c2 && c2 <= 0xBF))
18540b57cec5SDimitry Andric           return codecvt_base::error;
18550b57cec5SDimitry Andric         break;
18560b57cec5SDimitry Andric       case 0xF4:
18570b57cec5SDimitry Andric         if ((c2 & 0xF0) != 0x80)
18580b57cec5SDimitry Andric           return codecvt_base::error;
18590b57cec5SDimitry Andric         break;
18600b57cec5SDimitry Andric       default:
18610b57cec5SDimitry Andric         if ((c2 & 0xC0) != 0x80)
18620b57cec5SDimitry Andric           return codecvt_base::error;
18630b57cec5SDimitry Andric         break;
18640b57cec5SDimitry Andric       }
18655f757f3fSDimitry Andric       if (frm_end - frm_nxt < 3)
18665f757f3fSDimitry Andric         return codecvt_base::partial;
18675f757f3fSDimitry Andric       uint8_t c3 = frm_nxt[2];
18685f757f3fSDimitry Andric       if ((c3 & 0xC0) != 0x80)
18695f757f3fSDimitry Andric         return codecvt_base::error;
18705f757f3fSDimitry Andric       if (frm_end - frm_nxt < 4)
18715f757f3fSDimitry Andric         return codecvt_base::partial;
18725f757f3fSDimitry Andric       uint8_t c4 = frm_nxt[3];
18735f757f3fSDimitry Andric       if ((c4 & 0xC0) != 0x80)
18740b57cec5SDimitry Andric         return codecvt_base::error;
18750b57cec5SDimitry Andric       if (to_end - to_nxt < 2)
18760b57cec5SDimitry Andric         return codecvt_base::partial;
1877*cb14a3feSDimitry Andric       if ((((c1 & 7UL) << 18) + ((c2 & 0x3FUL) << 12) + ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
18780b57cec5SDimitry Andric         return codecvt_base::error;
18790b57cec5SDimitry Andric       *to_nxt = static_cast<uint32_t>(
1880*cb14a3feSDimitry Andric           0xD800 | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6) | ((c2 & 0x0F) << 2) | ((c3 & 0x30) >> 4));
1881*cb14a3feSDimitry Andric       *++to_nxt = static_cast<uint32_t>(0xDC00 | ((c3 & 0x0F) << 6) | (c4 & 0x3F));
18820b57cec5SDimitry Andric       frm_nxt += 4;
1883*cb14a3feSDimitry Andric     } else {
18840b57cec5SDimitry Andric       return codecvt_base::error;
18850b57cec5SDimitry Andric     }
18860b57cec5SDimitry Andric   }
18870b57cec5SDimitry Andric   return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
18880b57cec5SDimitry Andric }
18890b57cec5SDimitry Andric 
1890*cb14a3feSDimitry Andric static int utf8_to_utf16_length(
1891*cb14a3feSDimitry Andric     const uint8_t* frm,
1892*cb14a3feSDimitry Andric     const uint8_t* frm_end,
1893*cb14a3feSDimitry Andric     size_t mx,
1894*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
1895*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
18960b57cec5SDimitry Andric   const uint8_t* frm_nxt = frm;
1897*cb14a3feSDimitry Andric   if (mode & consume_header) {
1898*cb14a3feSDimitry Andric     if (frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF)
18990b57cec5SDimitry Andric       frm_nxt += 3;
19000b57cec5SDimitry Andric   }
1901*cb14a3feSDimitry Andric   for (size_t nchar16_t = 0; frm_nxt < frm_end && nchar16_t < mx; ++nchar16_t) {
19020b57cec5SDimitry Andric     uint8_t c1 = *frm_nxt;
19030b57cec5SDimitry Andric     if (c1 > Maxcode)
19040b57cec5SDimitry Andric       break;
1905*cb14a3feSDimitry Andric     if (c1 < 0x80) {
19060b57cec5SDimitry Andric       ++frm_nxt;
1907*cb14a3feSDimitry Andric     } else if (c1 < 0xC2) {
19080b57cec5SDimitry Andric       break;
1909*cb14a3feSDimitry Andric     } else if (c1 < 0xE0) {
19100b57cec5SDimitry Andric       if ((frm_end - frm_nxt < 2) || (frm_nxt[1] & 0xC0) != 0x80)
19110b57cec5SDimitry Andric         break;
19120b57cec5SDimitry Andric       uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (frm_nxt[1] & 0x3F));
19130b57cec5SDimitry Andric       if (t > Maxcode)
19140b57cec5SDimitry Andric         break;
19150b57cec5SDimitry Andric       frm_nxt += 2;
1916*cb14a3feSDimitry Andric     } else if (c1 < 0xF0) {
19170b57cec5SDimitry Andric       if (frm_end - frm_nxt < 3)
19180b57cec5SDimitry Andric         break;
19190b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
19200b57cec5SDimitry Andric       uint8_t c3 = frm_nxt[2];
1921*cb14a3feSDimitry Andric       switch (c1) {
19220b57cec5SDimitry Andric       case 0xE0:
19230b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0xA0)
19240b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
19250b57cec5SDimitry Andric         break;
19260b57cec5SDimitry Andric       case 0xED:
19270b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0x80)
19280b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
19290b57cec5SDimitry Andric         break;
19300b57cec5SDimitry Andric       default:
19310b57cec5SDimitry Andric         if ((c2 & 0xC0) != 0x80)
19320b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
19330b57cec5SDimitry Andric         break;
19340b57cec5SDimitry Andric       }
19350b57cec5SDimitry Andric       if ((c3 & 0xC0) != 0x80)
19360b57cec5SDimitry Andric         break;
19370b57cec5SDimitry Andric       if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
19380b57cec5SDimitry Andric         break;
19390b57cec5SDimitry Andric       frm_nxt += 3;
1940*cb14a3feSDimitry Andric     } else if (c1 < 0xF5) {
19410b57cec5SDimitry Andric       if (frm_end - frm_nxt < 4 || mx - nchar16_t < 2)
19420b57cec5SDimitry Andric         break;
19430b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
19440b57cec5SDimitry Andric       uint8_t c3 = frm_nxt[2];
19450b57cec5SDimitry Andric       uint8_t c4 = frm_nxt[3];
1946*cb14a3feSDimitry Andric       switch (c1) {
19470b57cec5SDimitry Andric       case 0xF0:
19480b57cec5SDimitry Andric         if (!(0x90 <= c2 && c2 <= 0xBF))
19490b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
19500b57cec5SDimitry Andric         break;
19510b57cec5SDimitry Andric       case 0xF4:
19520b57cec5SDimitry Andric         if ((c2 & 0xF0) != 0x80)
19530b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
19540b57cec5SDimitry Andric         break;
19550b57cec5SDimitry Andric       default:
19560b57cec5SDimitry Andric         if ((c2 & 0xC0) != 0x80)
19570b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
19580b57cec5SDimitry Andric         break;
19590b57cec5SDimitry Andric       }
19600b57cec5SDimitry Andric       if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
19610b57cec5SDimitry Andric         break;
1962*cb14a3feSDimitry Andric       if ((((c1 & 7UL) << 18) + ((c2 & 0x3FUL) << 12) + ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
19630b57cec5SDimitry Andric         break;
19640b57cec5SDimitry Andric       ++nchar16_t;
19650b57cec5SDimitry Andric       frm_nxt += 4;
1966*cb14a3feSDimitry Andric     } else {
19670b57cec5SDimitry Andric       break;
19680b57cec5SDimitry Andric     }
19690b57cec5SDimitry Andric   }
19700b57cec5SDimitry Andric   return static_cast<int>(frm_nxt - frm);
19710b57cec5SDimitry Andric }
19720b57cec5SDimitry Andric 
1973*cb14a3feSDimitry Andric static codecvt_base::result ucs4_to_utf8(
1974*cb14a3feSDimitry Andric     const uint32_t* frm,
1975*cb14a3feSDimitry Andric     const uint32_t* frm_end,
1976*cb14a3feSDimitry Andric     const uint32_t*& frm_nxt,
1977*cb14a3feSDimitry Andric     uint8_t* to,
1978*cb14a3feSDimitry Andric     uint8_t* to_end,
1979*cb14a3feSDimitry Andric     uint8_t*& to_nxt,
1980*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
1981*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
19820b57cec5SDimitry Andric   frm_nxt = frm;
19830b57cec5SDimitry Andric   to_nxt  = to;
1984*cb14a3feSDimitry Andric   if (mode & generate_header) {
19850b57cec5SDimitry Andric     if (to_end - to_nxt < 3)
19860b57cec5SDimitry Andric       return codecvt_base::partial;
19870b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xEF);
19880b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xBB);
19890b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xBF);
19900b57cec5SDimitry Andric   }
1991*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end; ++frm_nxt) {
19920b57cec5SDimitry Andric     uint32_t wc = *frm_nxt;
19930b57cec5SDimitry Andric     if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
19940b57cec5SDimitry Andric       return codecvt_base::error;
1995*cb14a3feSDimitry Andric     if (wc < 0x000080) {
19960b57cec5SDimitry Andric       if (to_end - to_nxt < 1)
19970b57cec5SDimitry Andric         return codecvt_base::partial;
19980b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(wc);
1999*cb14a3feSDimitry Andric     } else if (wc < 0x000800) {
20000b57cec5SDimitry Andric       if (to_end - to_nxt < 2)
20010b57cec5SDimitry Andric         return codecvt_base::partial;
20020b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc >> 6));
20030b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x03F));
2004*cb14a3feSDimitry Andric     } else if (wc < 0x010000) {
20050b57cec5SDimitry Andric       if (to_end - to_nxt < 3)
20060b57cec5SDimitry Andric         return codecvt_base::partial;
20070b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0xE0 | (wc >> 12));
20080b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6));
20090b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x003F));
2010*cb14a3feSDimitry Andric     } else // if (wc < 0x110000)
20110b57cec5SDimitry Andric     {
20120b57cec5SDimitry Andric       if (to_end - to_nxt < 4)
20130b57cec5SDimitry Andric         return codecvt_base::partial;
20140b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0xF0 | (wc >> 18));
20150b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x03F000) >> 12));
20160b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x000FC0) >> 6));
20170b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x00003F));
20180b57cec5SDimitry Andric     }
20190b57cec5SDimitry Andric   }
20200b57cec5SDimitry Andric   return codecvt_base::ok;
20210b57cec5SDimitry Andric }
20220b57cec5SDimitry Andric 
2023*cb14a3feSDimitry Andric static codecvt_base::result utf8_to_ucs4(
2024*cb14a3feSDimitry Andric     const uint8_t* frm,
2025*cb14a3feSDimitry Andric     const uint8_t* frm_end,
2026*cb14a3feSDimitry Andric     const uint8_t*& frm_nxt,
2027*cb14a3feSDimitry Andric     uint32_t* to,
2028*cb14a3feSDimitry Andric     uint32_t* to_end,
2029*cb14a3feSDimitry Andric     uint32_t*& to_nxt,
2030*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2031*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
20320b57cec5SDimitry Andric   frm_nxt = frm;
20330b57cec5SDimitry Andric   to_nxt  = to;
2034*cb14a3feSDimitry Andric   if (mode & consume_header) {
2035*cb14a3feSDimitry Andric     if (frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF)
20360b57cec5SDimitry Andric       frm_nxt += 3;
20370b57cec5SDimitry Andric   }
2038*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt) {
20390b57cec5SDimitry Andric     uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
2040*cb14a3feSDimitry Andric     if (c1 < 0x80) {
20410b57cec5SDimitry Andric       if (c1 > Maxcode)
20420b57cec5SDimitry Andric         return codecvt_base::error;
20430b57cec5SDimitry Andric       *to_nxt = static_cast<uint32_t>(c1);
20440b57cec5SDimitry Andric       ++frm_nxt;
2045*cb14a3feSDimitry Andric     } else if (c1 < 0xC2) {
20460b57cec5SDimitry Andric       return codecvt_base::error;
2047*cb14a3feSDimitry Andric     } else if (c1 < 0xE0) {
20480b57cec5SDimitry Andric       if (frm_end - frm_nxt < 2)
20490b57cec5SDimitry Andric         return codecvt_base::partial;
20500b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
20510b57cec5SDimitry Andric       if ((c2 & 0xC0) != 0x80)
20520b57cec5SDimitry Andric         return codecvt_base::error;
2053*cb14a3feSDimitry Andric       uint32_t t = static_cast<uint32_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
20540b57cec5SDimitry Andric       if (t > Maxcode)
20550b57cec5SDimitry Andric         return codecvt_base::error;
20560b57cec5SDimitry Andric       *to_nxt = t;
20570b57cec5SDimitry Andric       frm_nxt += 2;
2058*cb14a3feSDimitry Andric     } else if (c1 < 0xF0) {
20595f757f3fSDimitry Andric       if (frm_end - frm_nxt < 2)
20600b57cec5SDimitry Andric         return codecvt_base::partial;
20610b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
2062*cb14a3feSDimitry Andric       switch (c1) {
20630b57cec5SDimitry Andric       case 0xE0:
20640b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0xA0)
20650b57cec5SDimitry Andric           return codecvt_base::error;
20660b57cec5SDimitry Andric         break;
20670b57cec5SDimitry Andric       case 0xED:
20680b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0x80)
20690b57cec5SDimitry Andric           return codecvt_base::error;
20700b57cec5SDimitry Andric         break;
20710b57cec5SDimitry Andric       default:
20720b57cec5SDimitry Andric         if ((c2 & 0xC0) != 0x80)
20730b57cec5SDimitry Andric           return codecvt_base::error;
20740b57cec5SDimitry Andric         break;
20750b57cec5SDimitry Andric       }
20765f757f3fSDimitry Andric       if (frm_end - frm_nxt < 3)
20775f757f3fSDimitry Andric         return codecvt_base::partial;
20785f757f3fSDimitry Andric       uint8_t c3 = frm_nxt[2];
20790b57cec5SDimitry Andric       if ((c3 & 0xC0) != 0x80)
20800b57cec5SDimitry Andric         return codecvt_base::error;
2081*cb14a3feSDimitry Andric       uint32_t t = static_cast<uint32_t>(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F));
20820b57cec5SDimitry Andric       if (t > Maxcode)
20830b57cec5SDimitry Andric         return codecvt_base::error;
20840b57cec5SDimitry Andric       *to_nxt = t;
20850b57cec5SDimitry Andric       frm_nxt += 3;
2086*cb14a3feSDimitry Andric     } else if (c1 < 0xF5) {
20875f757f3fSDimitry Andric       if (frm_end - frm_nxt < 2)
20880b57cec5SDimitry Andric         return codecvt_base::partial;
20890b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
2090*cb14a3feSDimitry Andric       switch (c1) {
20910b57cec5SDimitry Andric       case 0xF0:
20920b57cec5SDimitry Andric         if (!(0x90 <= c2 && c2 <= 0xBF))
20930b57cec5SDimitry Andric           return codecvt_base::error;
20940b57cec5SDimitry Andric         break;
20950b57cec5SDimitry Andric       case 0xF4:
20960b57cec5SDimitry Andric         if ((c2 & 0xF0) != 0x80)
20970b57cec5SDimitry Andric           return codecvt_base::error;
20980b57cec5SDimitry Andric         break;
20990b57cec5SDimitry Andric       default:
21000b57cec5SDimitry Andric         if ((c2 & 0xC0) != 0x80)
21010b57cec5SDimitry Andric           return codecvt_base::error;
21020b57cec5SDimitry Andric         break;
21030b57cec5SDimitry Andric       }
21045f757f3fSDimitry Andric       if (frm_end - frm_nxt < 3)
21055f757f3fSDimitry Andric         return codecvt_base::partial;
21065f757f3fSDimitry Andric       uint8_t c3 = frm_nxt[2];
21075f757f3fSDimitry Andric       if ((c3 & 0xC0) != 0x80)
21085f757f3fSDimitry Andric         return codecvt_base::error;
21095f757f3fSDimitry Andric       if (frm_end - frm_nxt < 4)
21105f757f3fSDimitry Andric         return codecvt_base::partial;
21115f757f3fSDimitry Andric       uint8_t c4 = frm_nxt[3];
21125f757f3fSDimitry Andric       if ((c4 & 0xC0) != 0x80)
21130b57cec5SDimitry Andric         return codecvt_base::error;
2114*cb14a3feSDimitry Andric       uint32_t t = static_cast<uint32_t>(((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) | ((c3 & 0x3F) << 6) | (c4 & 0x3F));
21150b57cec5SDimitry Andric       if (t > Maxcode)
21160b57cec5SDimitry Andric         return codecvt_base::error;
21170b57cec5SDimitry Andric       *to_nxt = t;
21180b57cec5SDimitry Andric       frm_nxt += 4;
2119*cb14a3feSDimitry Andric     } else {
21200b57cec5SDimitry Andric       return codecvt_base::error;
21210b57cec5SDimitry Andric     }
21220b57cec5SDimitry Andric   }
21230b57cec5SDimitry Andric   return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
21240b57cec5SDimitry Andric }
21250b57cec5SDimitry Andric 
2126*cb14a3feSDimitry Andric static int utf8_to_ucs4_length(
2127*cb14a3feSDimitry Andric     const uint8_t* frm,
2128*cb14a3feSDimitry Andric     const uint8_t* frm_end,
2129*cb14a3feSDimitry Andric     size_t mx,
2130*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2131*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
21320b57cec5SDimitry Andric   const uint8_t* frm_nxt = frm;
2133*cb14a3feSDimitry Andric   if (mode & consume_header) {
2134*cb14a3feSDimitry Andric     if (frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF)
21350b57cec5SDimitry Andric       frm_nxt += 3;
21360b57cec5SDimitry Andric   }
2137*cb14a3feSDimitry Andric   for (size_t nchar32_t = 0; frm_nxt < frm_end && nchar32_t < mx; ++nchar32_t) {
21380b57cec5SDimitry Andric     uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
2139*cb14a3feSDimitry Andric     if (c1 < 0x80) {
21400b57cec5SDimitry Andric       if (c1 > Maxcode)
21410b57cec5SDimitry Andric         break;
21420b57cec5SDimitry Andric       ++frm_nxt;
2143*cb14a3feSDimitry Andric     } else if (c1 < 0xC2) {
21440b57cec5SDimitry Andric       break;
2145*cb14a3feSDimitry Andric     } else if (c1 < 0xE0) {
21460b57cec5SDimitry Andric       if ((frm_end - frm_nxt < 2) || ((frm_nxt[1] & 0xC0) != 0x80))
21470b57cec5SDimitry Andric         break;
21480b57cec5SDimitry Andric       if ((((c1 & 0x1Fu) << 6) | (frm_nxt[1] & 0x3Fu)) > Maxcode)
21490b57cec5SDimitry Andric         break;
21500b57cec5SDimitry Andric       frm_nxt += 2;
2151*cb14a3feSDimitry Andric     } else if (c1 < 0xF0) {
21520b57cec5SDimitry Andric       if (frm_end - frm_nxt < 3)
21530b57cec5SDimitry Andric         break;
21540b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
21550b57cec5SDimitry Andric       uint8_t c3 = frm_nxt[2];
2156*cb14a3feSDimitry Andric       switch (c1) {
21570b57cec5SDimitry Andric       case 0xE0:
21580b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0xA0)
21590b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
21600b57cec5SDimitry Andric         break;
21610b57cec5SDimitry Andric       case 0xED:
21620b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0x80)
21630b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
21640b57cec5SDimitry Andric         break;
21650b57cec5SDimitry Andric       default:
21660b57cec5SDimitry Andric         if ((c2 & 0xC0) != 0x80)
21670b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
21680b57cec5SDimitry Andric         break;
21690b57cec5SDimitry Andric       }
21700b57cec5SDimitry Andric       if ((c3 & 0xC0) != 0x80)
21710b57cec5SDimitry Andric         break;
21720b57cec5SDimitry Andric       if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
21730b57cec5SDimitry Andric         break;
21740b57cec5SDimitry Andric       frm_nxt += 3;
2175*cb14a3feSDimitry Andric     } else if (c1 < 0xF5) {
21760b57cec5SDimitry Andric       if (frm_end - frm_nxt < 4)
21770b57cec5SDimitry Andric         break;
21780b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
21790b57cec5SDimitry Andric       uint8_t c3 = frm_nxt[2];
21800b57cec5SDimitry Andric       uint8_t c4 = frm_nxt[3];
2181*cb14a3feSDimitry Andric       switch (c1) {
21820b57cec5SDimitry Andric       case 0xF0:
21830b57cec5SDimitry Andric         if (!(0x90 <= c2 && c2 <= 0xBF))
21840b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
21850b57cec5SDimitry Andric         break;
21860b57cec5SDimitry Andric       case 0xF4:
21870b57cec5SDimitry Andric         if ((c2 & 0xF0) != 0x80)
21880b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
21890b57cec5SDimitry Andric         break;
21900b57cec5SDimitry Andric       default:
21910b57cec5SDimitry Andric         if ((c2 & 0xC0) != 0x80)
21920b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
21930b57cec5SDimitry Andric         break;
21940b57cec5SDimitry Andric       }
21950b57cec5SDimitry Andric       if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
21960b57cec5SDimitry Andric         break;
2197*cb14a3feSDimitry Andric       if ((((c1 & 0x07u) << 18) | ((c2 & 0x3Fu) << 12) | ((c3 & 0x3Fu) << 6) | (c4 & 0x3Fu)) > Maxcode)
21980b57cec5SDimitry Andric         break;
21990b57cec5SDimitry Andric       frm_nxt += 4;
2200*cb14a3feSDimitry Andric     } else {
22010b57cec5SDimitry Andric       break;
22020b57cec5SDimitry Andric     }
22030b57cec5SDimitry Andric   }
22040b57cec5SDimitry Andric   return static_cast<int>(frm_nxt - frm);
22050b57cec5SDimitry Andric }
22060b57cec5SDimitry Andric 
2207*cb14a3feSDimitry Andric static codecvt_base::result ucs2_to_utf8(
2208*cb14a3feSDimitry Andric     const uint16_t* frm,
2209*cb14a3feSDimitry Andric     const uint16_t* frm_end,
2210*cb14a3feSDimitry Andric     const uint16_t*& frm_nxt,
2211*cb14a3feSDimitry Andric     uint8_t* to,
2212*cb14a3feSDimitry Andric     uint8_t* to_end,
2213*cb14a3feSDimitry Andric     uint8_t*& to_nxt,
2214*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2215*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
22160b57cec5SDimitry Andric   frm_nxt = frm;
22170b57cec5SDimitry Andric   to_nxt  = to;
2218*cb14a3feSDimitry Andric   if (mode & generate_header) {
22190b57cec5SDimitry Andric     if (to_end - to_nxt < 3)
22200b57cec5SDimitry Andric       return codecvt_base::partial;
22210b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xEF);
22220b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xBB);
22230b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xBF);
22240b57cec5SDimitry Andric   }
2225*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end; ++frm_nxt) {
22260b57cec5SDimitry Andric     uint16_t wc = *frm_nxt;
22270b57cec5SDimitry Andric     if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
22280b57cec5SDimitry Andric       return codecvt_base::error;
2229*cb14a3feSDimitry Andric     if (wc < 0x0080) {
22300b57cec5SDimitry Andric       if (to_end - to_nxt < 1)
22310b57cec5SDimitry Andric         return codecvt_base::partial;
22320b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(wc);
2233*cb14a3feSDimitry Andric     } else if (wc < 0x0800) {
22340b57cec5SDimitry Andric       if (to_end - to_nxt < 2)
22350b57cec5SDimitry Andric         return codecvt_base::partial;
22360b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc >> 6));
22370b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x03F));
2238*cb14a3feSDimitry Andric     } else // if (wc <= 0xFFFF)
22390b57cec5SDimitry Andric     {
22400b57cec5SDimitry Andric       if (to_end - to_nxt < 3)
22410b57cec5SDimitry Andric         return codecvt_base::partial;
22420b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0xE0 | (wc >> 12));
22430b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6));
22440b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x003F));
22450b57cec5SDimitry Andric     }
22460b57cec5SDimitry Andric   }
22470b57cec5SDimitry Andric   return codecvt_base::ok;
22480b57cec5SDimitry Andric }
22490b57cec5SDimitry Andric 
2250*cb14a3feSDimitry Andric static codecvt_base::result utf8_to_ucs2(
2251*cb14a3feSDimitry Andric     const uint8_t* frm,
2252*cb14a3feSDimitry Andric     const uint8_t* frm_end,
2253*cb14a3feSDimitry Andric     const uint8_t*& frm_nxt,
2254*cb14a3feSDimitry Andric     uint16_t* to,
2255*cb14a3feSDimitry Andric     uint16_t* to_end,
2256*cb14a3feSDimitry Andric     uint16_t*& to_nxt,
2257*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2258*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
22590b57cec5SDimitry Andric   frm_nxt = frm;
22600b57cec5SDimitry Andric   to_nxt  = to;
2261*cb14a3feSDimitry Andric   if (mode & consume_header) {
2262*cb14a3feSDimitry Andric     if (frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF)
22630b57cec5SDimitry Andric       frm_nxt += 3;
22640b57cec5SDimitry Andric   }
2265*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt) {
22660b57cec5SDimitry Andric     uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
2267*cb14a3feSDimitry Andric     if (c1 < 0x80) {
22680b57cec5SDimitry Andric       if (c1 > Maxcode)
22690b57cec5SDimitry Andric         return codecvt_base::error;
22700b57cec5SDimitry Andric       *to_nxt = static_cast<uint16_t>(c1);
22710b57cec5SDimitry Andric       ++frm_nxt;
2272*cb14a3feSDimitry Andric     } else if (c1 < 0xC2) {
22730b57cec5SDimitry Andric       return codecvt_base::error;
2274*cb14a3feSDimitry Andric     } else if (c1 < 0xE0) {
22750b57cec5SDimitry Andric       if (frm_end - frm_nxt < 2)
22760b57cec5SDimitry Andric         return codecvt_base::partial;
22770b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
22780b57cec5SDimitry Andric       if ((c2 & 0xC0) != 0x80)
22790b57cec5SDimitry Andric         return codecvt_base::error;
2280*cb14a3feSDimitry Andric       uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
22810b57cec5SDimitry Andric       if (t > Maxcode)
22820b57cec5SDimitry Andric         return codecvt_base::error;
22830b57cec5SDimitry Andric       *to_nxt = t;
22840b57cec5SDimitry Andric       frm_nxt += 2;
2285*cb14a3feSDimitry Andric     } else if (c1 < 0xF0) {
22865f757f3fSDimitry Andric       if (frm_end - frm_nxt < 2)
22870b57cec5SDimitry Andric         return codecvt_base::partial;
22880b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
2289*cb14a3feSDimitry Andric       switch (c1) {
22900b57cec5SDimitry Andric       case 0xE0:
22910b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0xA0)
22920b57cec5SDimitry Andric           return codecvt_base::error;
22930b57cec5SDimitry Andric         break;
22940b57cec5SDimitry Andric       case 0xED:
22950b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0x80)
22960b57cec5SDimitry Andric           return codecvt_base::error;
22970b57cec5SDimitry Andric         break;
22980b57cec5SDimitry Andric       default:
22990b57cec5SDimitry Andric         if ((c2 & 0xC0) != 0x80)
23000b57cec5SDimitry Andric           return codecvt_base::error;
23010b57cec5SDimitry Andric         break;
23020b57cec5SDimitry Andric       }
23035f757f3fSDimitry Andric       if (frm_end - frm_nxt < 3)
23045f757f3fSDimitry Andric         return codecvt_base::partial;
23055f757f3fSDimitry Andric       uint8_t c3 = frm_nxt[2];
23060b57cec5SDimitry Andric       if ((c3 & 0xC0) != 0x80)
23070b57cec5SDimitry Andric         return codecvt_base::error;
2308*cb14a3feSDimitry Andric       uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F));
23090b57cec5SDimitry Andric       if (t > Maxcode)
23100b57cec5SDimitry Andric         return codecvt_base::error;
23110b57cec5SDimitry Andric       *to_nxt = t;
23120b57cec5SDimitry Andric       frm_nxt += 3;
2313*cb14a3feSDimitry Andric     } else {
23140b57cec5SDimitry Andric       return codecvt_base::error;
23150b57cec5SDimitry Andric     }
23160b57cec5SDimitry Andric   }
23170b57cec5SDimitry Andric   return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
23180b57cec5SDimitry Andric }
23190b57cec5SDimitry Andric 
2320*cb14a3feSDimitry Andric static int utf8_to_ucs2_length(
2321*cb14a3feSDimitry Andric     const uint8_t* frm,
2322*cb14a3feSDimitry Andric     const uint8_t* frm_end,
2323*cb14a3feSDimitry Andric     size_t mx,
2324*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2325*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
23260b57cec5SDimitry Andric   const uint8_t* frm_nxt = frm;
2327*cb14a3feSDimitry Andric   if (mode & consume_header) {
2328*cb14a3feSDimitry Andric     if (frm_end - frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB && frm_nxt[2] == 0xBF)
23290b57cec5SDimitry Andric       frm_nxt += 3;
23300b57cec5SDimitry Andric   }
2331*cb14a3feSDimitry Andric   for (size_t nchar32_t = 0; frm_nxt < frm_end && nchar32_t < mx; ++nchar32_t) {
23320b57cec5SDimitry Andric     uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
2333*cb14a3feSDimitry Andric     if (c1 < 0x80) {
23340b57cec5SDimitry Andric       if (c1 > Maxcode)
23350b57cec5SDimitry Andric         break;
23360b57cec5SDimitry Andric       ++frm_nxt;
2337*cb14a3feSDimitry Andric     } else if (c1 < 0xC2) {
23380b57cec5SDimitry Andric       break;
2339*cb14a3feSDimitry Andric     } else if (c1 < 0xE0) {
23400b57cec5SDimitry Andric       if ((frm_end - frm_nxt < 2) || ((frm_nxt[1] & 0xC0) != 0x80))
23410b57cec5SDimitry Andric         break;
23420b57cec5SDimitry Andric       if ((((c1 & 0x1Fu) << 6) | (frm_nxt[1] & 0x3Fu)) > Maxcode)
23430b57cec5SDimitry Andric         break;
23440b57cec5SDimitry Andric       frm_nxt += 2;
2345*cb14a3feSDimitry Andric     } else if (c1 < 0xF0) {
23460b57cec5SDimitry Andric       if (frm_end - frm_nxt < 3)
23470b57cec5SDimitry Andric         break;
23480b57cec5SDimitry Andric       uint8_t c2 = frm_nxt[1];
23490b57cec5SDimitry Andric       uint8_t c3 = frm_nxt[2];
2350*cb14a3feSDimitry Andric       switch (c1) {
23510b57cec5SDimitry Andric       case 0xE0:
23520b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0xA0)
23530b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
23540b57cec5SDimitry Andric         break;
23550b57cec5SDimitry Andric       case 0xED:
23560b57cec5SDimitry Andric         if ((c2 & 0xE0) != 0x80)
23570b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
23580b57cec5SDimitry Andric         break;
23590b57cec5SDimitry Andric       default:
23600b57cec5SDimitry Andric         if ((c2 & 0xC0) != 0x80)
23610b57cec5SDimitry Andric           return static_cast<int>(frm_nxt - frm);
23620b57cec5SDimitry Andric         break;
23630b57cec5SDimitry Andric       }
23640b57cec5SDimitry Andric       if ((c3 & 0xC0) != 0x80)
23650b57cec5SDimitry Andric         break;
23660b57cec5SDimitry Andric       if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
23670b57cec5SDimitry Andric         break;
23680b57cec5SDimitry Andric       frm_nxt += 3;
2369*cb14a3feSDimitry Andric     } else {
23700b57cec5SDimitry Andric       break;
23710b57cec5SDimitry Andric     }
23720b57cec5SDimitry Andric   }
23730b57cec5SDimitry Andric   return static_cast<int>(frm_nxt - frm);
23740b57cec5SDimitry Andric }
23750b57cec5SDimitry Andric 
2376*cb14a3feSDimitry Andric static codecvt_base::result ucs4_to_utf16be(
2377*cb14a3feSDimitry Andric     const uint32_t* frm,
2378*cb14a3feSDimitry Andric     const uint32_t* frm_end,
2379*cb14a3feSDimitry Andric     const uint32_t*& frm_nxt,
2380*cb14a3feSDimitry Andric     uint8_t* to,
2381*cb14a3feSDimitry Andric     uint8_t* to_end,
2382*cb14a3feSDimitry Andric     uint8_t*& to_nxt,
2383*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2384*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
23850b57cec5SDimitry Andric   frm_nxt = frm;
23860b57cec5SDimitry Andric   to_nxt  = to;
2387*cb14a3feSDimitry Andric   if (mode & generate_header) {
23880b57cec5SDimitry Andric     if (to_end - to_nxt < 2)
23890b57cec5SDimitry Andric       return codecvt_base::partial;
23900b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xFE);
23910b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xFF);
23920b57cec5SDimitry Andric   }
2393*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end; ++frm_nxt) {
23940b57cec5SDimitry Andric     uint32_t wc = *frm_nxt;
23950b57cec5SDimitry Andric     if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
23960b57cec5SDimitry Andric       return codecvt_base::error;
2397*cb14a3feSDimitry Andric     if (wc < 0x010000) {
23980b57cec5SDimitry Andric       if (to_end - to_nxt < 2)
23990b57cec5SDimitry Andric         return codecvt_base::partial;
24000b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(wc >> 8);
24010b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(wc);
2402*cb14a3feSDimitry Andric     } else {
24030b57cec5SDimitry Andric       if (to_end - to_nxt < 4)
24040b57cec5SDimitry Andric         return codecvt_base::partial;
2405*cb14a3feSDimitry Andric       uint16_t t = static_cast<uint16_t>(0xD800 | ((((wc & 0x1F0000) >> 16) - 1) << 6) | ((wc & 0x00FC00) >> 10));
24060b57cec5SDimitry Andric       *to_nxt++  = static_cast<uint8_t>(t >> 8);
24070b57cec5SDimitry Andric       *to_nxt++  = static_cast<uint8_t>(t);
24080b57cec5SDimitry Andric       t          = static_cast<uint16_t>(0xDC00 | (wc & 0x03FF));
24090b57cec5SDimitry Andric       *to_nxt++  = static_cast<uint8_t>(t >> 8);
24100b57cec5SDimitry Andric       *to_nxt++  = static_cast<uint8_t>(t);
24110b57cec5SDimitry Andric     }
24120b57cec5SDimitry Andric   }
24130b57cec5SDimitry Andric   return codecvt_base::ok;
24140b57cec5SDimitry Andric }
24150b57cec5SDimitry Andric 
2416*cb14a3feSDimitry Andric static codecvt_base::result utf16be_to_ucs4(
2417*cb14a3feSDimitry Andric     const uint8_t* frm,
2418*cb14a3feSDimitry Andric     const uint8_t* frm_end,
2419*cb14a3feSDimitry Andric     const uint8_t*& frm_nxt,
2420*cb14a3feSDimitry Andric     uint32_t* to,
2421*cb14a3feSDimitry Andric     uint32_t* to_end,
2422*cb14a3feSDimitry Andric     uint32_t*& to_nxt,
2423*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2424*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
24250b57cec5SDimitry Andric   frm_nxt = frm;
24260b57cec5SDimitry Andric   to_nxt  = to;
2427*cb14a3feSDimitry Andric   if (mode & consume_header) {
24280b57cec5SDimitry Andric     if (frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
24290b57cec5SDimitry Andric       frm_nxt += 2;
24300b57cec5SDimitry Andric   }
2431*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt) {
24320b57cec5SDimitry Andric     uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
24330b57cec5SDimitry Andric     if ((c1 & 0xFC00) == 0xDC00)
24340b57cec5SDimitry Andric       return codecvt_base::error;
2435*cb14a3feSDimitry Andric     if ((c1 & 0xFC00) != 0xD800) {
24360b57cec5SDimitry Andric       if (c1 > Maxcode)
24370b57cec5SDimitry Andric         return codecvt_base::error;
24380b57cec5SDimitry Andric       *to_nxt = static_cast<uint32_t>(c1);
24390b57cec5SDimitry Andric       frm_nxt += 2;
2440*cb14a3feSDimitry Andric     } else {
24410b57cec5SDimitry Andric       if (frm_end - frm_nxt < 4)
24420b57cec5SDimitry Andric         return codecvt_base::partial;
24430b57cec5SDimitry Andric       uint16_t c2 = static_cast<uint16_t>(frm_nxt[2] << 8 | frm_nxt[3]);
24440b57cec5SDimitry Andric       if ((c2 & 0xFC00) != 0xDC00)
24450b57cec5SDimitry Andric         return codecvt_base::error;
2446*cb14a3feSDimitry Andric       uint32_t t = static_cast<uint32_t>(((((c1 & 0x03C0) >> 6) + 1) << 16) | ((c1 & 0x003F) << 10) | (c2 & 0x03FF));
24470b57cec5SDimitry Andric       if (t > Maxcode)
24480b57cec5SDimitry Andric         return codecvt_base::error;
24490b57cec5SDimitry Andric       *to_nxt = t;
24500b57cec5SDimitry Andric       frm_nxt += 4;
24510b57cec5SDimitry Andric     }
24520b57cec5SDimitry Andric   }
24530b57cec5SDimitry Andric   return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
24540b57cec5SDimitry Andric }
24550b57cec5SDimitry Andric 
2456*cb14a3feSDimitry Andric static int utf16be_to_ucs4_length(
2457*cb14a3feSDimitry Andric     const uint8_t* frm,
2458*cb14a3feSDimitry Andric     const uint8_t* frm_end,
2459*cb14a3feSDimitry Andric     size_t mx,
2460*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2461*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
24620b57cec5SDimitry Andric   const uint8_t* frm_nxt = frm;
2463*cb14a3feSDimitry Andric   if (mode & consume_header) {
24640b57cec5SDimitry Andric     if (frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
24650b57cec5SDimitry Andric       frm_nxt += 2;
24660b57cec5SDimitry Andric   }
2467*cb14a3feSDimitry Andric   for (size_t nchar32_t = 0; frm_nxt < frm_end - 1 && nchar32_t < mx; ++nchar32_t) {
24680b57cec5SDimitry Andric     uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
24690b57cec5SDimitry Andric     if ((c1 & 0xFC00) == 0xDC00)
24700b57cec5SDimitry Andric       break;
2471*cb14a3feSDimitry Andric     if ((c1 & 0xFC00) != 0xD800) {
24720b57cec5SDimitry Andric       if (c1 > Maxcode)
24730b57cec5SDimitry Andric         break;
24740b57cec5SDimitry Andric       frm_nxt += 2;
2475*cb14a3feSDimitry Andric     } else {
24760b57cec5SDimitry Andric       if (frm_end - frm_nxt < 4)
24770b57cec5SDimitry Andric         break;
24780b57cec5SDimitry Andric       uint16_t c2 = static_cast<uint16_t>(frm_nxt[2] << 8 | frm_nxt[3]);
24790b57cec5SDimitry Andric       if ((c2 & 0xFC00) != 0xDC00)
24800b57cec5SDimitry Andric         break;
2481*cb14a3feSDimitry Andric       uint32_t t = static_cast<uint32_t>(((((c1 & 0x03C0) >> 6) + 1) << 16) | ((c1 & 0x003F) << 10) | (c2 & 0x03FF));
24820b57cec5SDimitry Andric       if (t > Maxcode)
24830b57cec5SDimitry Andric         break;
24840b57cec5SDimitry Andric       frm_nxt += 4;
24850b57cec5SDimitry Andric     }
24860b57cec5SDimitry Andric   }
24870b57cec5SDimitry Andric   return static_cast<int>(frm_nxt - frm);
24880b57cec5SDimitry Andric }
24890b57cec5SDimitry Andric 
2490*cb14a3feSDimitry Andric static codecvt_base::result ucs4_to_utf16le(
2491*cb14a3feSDimitry Andric     const uint32_t* frm,
2492*cb14a3feSDimitry Andric     const uint32_t* frm_end,
2493*cb14a3feSDimitry Andric     const uint32_t*& frm_nxt,
2494*cb14a3feSDimitry Andric     uint8_t* to,
2495*cb14a3feSDimitry Andric     uint8_t* to_end,
2496*cb14a3feSDimitry Andric     uint8_t*& to_nxt,
2497*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2498*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
24990b57cec5SDimitry Andric   frm_nxt = frm;
25000b57cec5SDimitry Andric   to_nxt  = to;
2501*cb14a3feSDimitry Andric   if (mode & generate_header) {
25020b57cec5SDimitry Andric     if (to_end - to_nxt < 2)
25030b57cec5SDimitry Andric       return codecvt_base::partial;
25040b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xFF);
25050b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xFE);
25060b57cec5SDimitry Andric   }
2507*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end; ++frm_nxt) {
25080b57cec5SDimitry Andric     uint32_t wc = *frm_nxt;
25090b57cec5SDimitry Andric     if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
25100b57cec5SDimitry Andric       return codecvt_base::error;
2511*cb14a3feSDimitry Andric     if (wc < 0x010000) {
25120b57cec5SDimitry Andric       if (to_end - to_nxt < 2)
25130b57cec5SDimitry Andric         return codecvt_base::partial;
25140b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(wc);
25150b57cec5SDimitry Andric       *to_nxt++ = static_cast<uint8_t>(wc >> 8);
2516*cb14a3feSDimitry Andric     } else {
25170b57cec5SDimitry Andric       if (to_end - to_nxt < 4)
25180b57cec5SDimitry Andric         return codecvt_base::partial;
2519*cb14a3feSDimitry Andric       uint16_t t = static_cast<uint16_t>(0xD800 | ((((wc & 0x1F0000) >> 16) - 1) << 6) | ((wc & 0x00FC00) >> 10));
25200b57cec5SDimitry Andric       *to_nxt++  = static_cast<uint8_t>(t);
25210b57cec5SDimitry Andric       *to_nxt++  = static_cast<uint8_t>(t >> 8);
25220b57cec5SDimitry Andric       t          = static_cast<uint16_t>(0xDC00 | (wc & 0x03FF));
25230b57cec5SDimitry Andric       *to_nxt++  = static_cast<uint8_t>(t);
25240b57cec5SDimitry Andric       *to_nxt++  = static_cast<uint8_t>(t >> 8);
25250b57cec5SDimitry Andric     }
25260b57cec5SDimitry Andric   }
25270b57cec5SDimitry Andric   return codecvt_base::ok;
25280b57cec5SDimitry Andric }
25290b57cec5SDimitry Andric 
2530*cb14a3feSDimitry Andric static codecvt_base::result utf16le_to_ucs4(
2531*cb14a3feSDimitry Andric     const uint8_t* frm,
2532*cb14a3feSDimitry Andric     const uint8_t* frm_end,
2533*cb14a3feSDimitry Andric     const uint8_t*& frm_nxt,
2534*cb14a3feSDimitry Andric     uint32_t* to,
2535*cb14a3feSDimitry Andric     uint32_t* to_end,
2536*cb14a3feSDimitry Andric     uint32_t*& to_nxt,
2537*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2538*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
25390b57cec5SDimitry Andric   frm_nxt = frm;
25400b57cec5SDimitry Andric   to_nxt  = to;
2541*cb14a3feSDimitry Andric   if (mode & consume_header) {
25420b57cec5SDimitry Andric     if (frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
25430b57cec5SDimitry Andric       frm_nxt += 2;
25440b57cec5SDimitry Andric   }
2545*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt) {
25460b57cec5SDimitry Andric     uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
25470b57cec5SDimitry Andric     if ((c1 & 0xFC00) == 0xDC00)
25480b57cec5SDimitry Andric       return codecvt_base::error;
2549*cb14a3feSDimitry Andric     if ((c1 & 0xFC00) != 0xD800) {
25500b57cec5SDimitry Andric       if (c1 > Maxcode)
25510b57cec5SDimitry Andric         return codecvt_base::error;
25520b57cec5SDimitry Andric       *to_nxt = static_cast<uint32_t>(c1);
25530b57cec5SDimitry Andric       frm_nxt += 2;
2554*cb14a3feSDimitry Andric     } else {
25550b57cec5SDimitry Andric       if (frm_end - frm_nxt < 4)
25560b57cec5SDimitry Andric         return codecvt_base::partial;
25570b57cec5SDimitry Andric       uint16_t c2 = static_cast<uint16_t>(frm_nxt[3] << 8 | frm_nxt[2]);
25580b57cec5SDimitry Andric       if ((c2 & 0xFC00) != 0xDC00)
25590b57cec5SDimitry Andric         return codecvt_base::error;
2560*cb14a3feSDimitry Andric       uint32_t t = static_cast<uint32_t>(((((c1 & 0x03C0) >> 6) + 1) << 16) | ((c1 & 0x003F) << 10) | (c2 & 0x03FF));
25610b57cec5SDimitry Andric       if (t > Maxcode)
25620b57cec5SDimitry Andric         return codecvt_base::error;
25630b57cec5SDimitry Andric       *to_nxt = t;
25640b57cec5SDimitry Andric       frm_nxt += 4;
25650b57cec5SDimitry Andric     }
25660b57cec5SDimitry Andric   }
25670b57cec5SDimitry Andric   return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
25680b57cec5SDimitry Andric }
25690b57cec5SDimitry Andric 
2570*cb14a3feSDimitry Andric static int utf16le_to_ucs4_length(
2571*cb14a3feSDimitry Andric     const uint8_t* frm,
2572*cb14a3feSDimitry Andric     const uint8_t* frm_end,
2573*cb14a3feSDimitry Andric     size_t mx,
2574*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2575*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
25760b57cec5SDimitry Andric   const uint8_t* frm_nxt = frm;
2577*cb14a3feSDimitry Andric   if (mode & consume_header) {
25780b57cec5SDimitry Andric     if (frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
25790b57cec5SDimitry Andric       frm_nxt += 2;
25800b57cec5SDimitry Andric   }
2581*cb14a3feSDimitry Andric   for (size_t nchar32_t = 0; frm_nxt < frm_end - 1 && nchar32_t < mx; ++nchar32_t) {
25820b57cec5SDimitry Andric     uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
25830b57cec5SDimitry Andric     if ((c1 & 0xFC00) == 0xDC00)
25840b57cec5SDimitry Andric       break;
2585*cb14a3feSDimitry Andric     if ((c1 & 0xFC00) != 0xD800) {
25860b57cec5SDimitry Andric       if (c1 > Maxcode)
25870b57cec5SDimitry Andric         break;
25880b57cec5SDimitry Andric       frm_nxt += 2;
2589*cb14a3feSDimitry Andric     } else {
25900b57cec5SDimitry Andric       if (frm_end - frm_nxt < 4)
25910b57cec5SDimitry Andric         break;
25920b57cec5SDimitry Andric       uint16_t c2 = static_cast<uint16_t>(frm_nxt[3] << 8 | frm_nxt[2]);
25930b57cec5SDimitry Andric       if ((c2 & 0xFC00) != 0xDC00)
25940b57cec5SDimitry Andric         break;
2595*cb14a3feSDimitry Andric       uint32_t t = static_cast<uint32_t>(((((c1 & 0x03C0) >> 6) + 1) << 16) | ((c1 & 0x003F) << 10) | (c2 & 0x03FF));
25960b57cec5SDimitry Andric       if (t > Maxcode)
25970b57cec5SDimitry Andric         break;
25980b57cec5SDimitry Andric       frm_nxt += 4;
25990b57cec5SDimitry Andric     }
26000b57cec5SDimitry Andric   }
26010b57cec5SDimitry Andric   return static_cast<int>(frm_nxt - frm);
26020b57cec5SDimitry Andric }
26030b57cec5SDimitry Andric 
2604*cb14a3feSDimitry Andric static codecvt_base::result ucs2_to_utf16be(
2605*cb14a3feSDimitry Andric     const uint16_t* frm,
2606*cb14a3feSDimitry Andric     const uint16_t* frm_end,
2607*cb14a3feSDimitry Andric     const uint16_t*& frm_nxt,
2608*cb14a3feSDimitry Andric     uint8_t* to,
2609*cb14a3feSDimitry Andric     uint8_t* to_end,
2610*cb14a3feSDimitry Andric     uint8_t*& to_nxt,
2611*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2612*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
26130b57cec5SDimitry Andric   frm_nxt = frm;
26140b57cec5SDimitry Andric   to_nxt  = to;
2615*cb14a3feSDimitry Andric   if (mode & generate_header) {
26160b57cec5SDimitry Andric     if (to_end - to_nxt < 2)
26170b57cec5SDimitry Andric       return codecvt_base::partial;
26180b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xFE);
26190b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xFF);
26200b57cec5SDimitry Andric   }
2621*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end; ++frm_nxt) {
26220b57cec5SDimitry Andric     uint16_t wc = *frm_nxt;
26230b57cec5SDimitry Andric     if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
26240b57cec5SDimitry Andric       return codecvt_base::error;
26250b57cec5SDimitry Andric     if (to_end - to_nxt < 2)
26260b57cec5SDimitry Andric       return codecvt_base::partial;
26270b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(wc >> 8);
26280b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(wc);
26290b57cec5SDimitry Andric   }
26300b57cec5SDimitry Andric   return codecvt_base::ok;
26310b57cec5SDimitry Andric }
26320b57cec5SDimitry Andric 
2633*cb14a3feSDimitry Andric static codecvt_base::result utf16be_to_ucs2(
2634*cb14a3feSDimitry Andric     const uint8_t* frm,
2635*cb14a3feSDimitry Andric     const uint8_t* frm_end,
2636*cb14a3feSDimitry Andric     const uint8_t*& frm_nxt,
2637*cb14a3feSDimitry Andric     uint16_t* to,
2638*cb14a3feSDimitry Andric     uint16_t* to_end,
2639*cb14a3feSDimitry Andric     uint16_t*& to_nxt,
2640*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2641*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
26420b57cec5SDimitry Andric   frm_nxt = frm;
26430b57cec5SDimitry Andric   to_nxt  = to;
2644*cb14a3feSDimitry Andric   if (mode & consume_header) {
26450b57cec5SDimitry Andric     if (frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
26460b57cec5SDimitry Andric       frm_nxt += 2;
26470b57cec5SDimitry Andric   }
2648*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt) {
26490b57cec5SDimitry Andric     uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
26500b57cec5SDimitry Andric     if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
26510b57cec5SDimitry Andric       return codecvt_base::error;
26520b57cec5SDimitry Andric     *to_nxt = c1;
26530b57cec5SDimitry Andric     frm_nxt += 2;
26540b57cec5SDimitry Andric   }
26550b57cec5SDimitry Andric   return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
26560b57cec5SDimitry Andric }
26570b57cec5SDimitry Andric 
2658*cb14a3feSDimitry Andric static int utf16be_to_ucs2_length(
2659*cb14a3feSDimitry Andric     const uint8_t* frm,
2660*cb14a3feSDimitry Andric     const uint8_t* frm_end,
2661*cb14a3feSDimitry Andric     size_t mx,
2662*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2663*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
26640b57cec5SDimitry Andric   const uint8_t* frm_nxt = frm;
2665*cb14a3feSDimitry Andric   if (mode & consume_header) {
26660b57cec5SDimitry Andric     if (frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
26670b57cec5SDimitry Andric       frm_nxt += 2;
26680b57cec5SDimitry Andric   }
2669*cb14a3feSDimitry Andric   for (size_t nchar16_t = 0; frm_nxt < frm_end - 1 && nchar16_t < mx; ++nchar16_t) {
26700b57cec5SDimitry Andric     uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
26710b57cec5SDimitry Andric     if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
26720b57cec5SDimitry Andric       break;
26730b57cec5SDimitry Andric     frm_nxt += 2;
26740b57cec5SDimitry Andric   }
26750b57cec5SDimitry Andric   return static_cast<int>(frm_nxt - frm);
26760b57cec5SDimitry Andric }
26770b57cec5SDimitry Andric 
2678*cb14a3feSDimitry Andric static codecvt_base::result ucs2_to_utf16le(
2679*cb14a3feSDimitry Andric     const uint16_t* frm,
2680*cb14a3feSDimitry Andric     const uint16_t* frm_end,
2681*cb14a3feSDimitry Andric     const uint16_t*& frm_nxt,
2682*cb14a3feSDimitry Andric     uint8_t* to,
2683*cb14a3feSDimitry Andric     uint8_t* to_end,
2684*cb14a3feSDimitry Andric     uint8_t*& to_nxt,
2685*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2686*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
26870b57cec5SDimitry Andric   frm_nxt = frm;
26880b57cec5SDimitry Andric   to_nxt  = to;
2689*cb14a3feSDimitry Andric   if (mode & generate_header) {
26900b57cec5SDimitry Andric     if (to_end - to_nxt < 2)
26910b57cec5SDimitry Andric       return codecvt_base::partial;
26920b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xFF);
26930b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(0xFE);
26940b57cec5SDimitry Andric   }
2695*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end; ++frm_nxt) {
26960b57cec5SDimitry Andric     uint16_t wc = *frm_nxt;
26970b57cec5SDimitry Andric     if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
26980b57cec5SDimitry Andric       return codecvt_base::error;
26990b57cec5SDimitry Andric     if (to_end - to_nxt < 2)
27000b57cec5SDimitry Andric       return codecvt_base::partial;
27010b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(wc);
27020b57cec5SDimitry Andric     *to_nxt++ = static_cast<uint8_t>(wc >> 8);
27030b57cec5SDimitry Andric   }
27040b57cec5SDimitry Andric   return codecvt_base::ok;
27050b57cec5SDimitry Andric }
27060b57cec5SDimitry Andric 
2707*cb14a3feSDimitry Andric static codecvt_base::result utf16le_to_ucs2(
2708*cb14a3feSDimitry Andric     const uint8_t* frm,
2709*cb14a3feSDimitry Andric     const uint8_t* frm_end,
2710*cb14a3feSDimitry Andric     const uint8_t*& frm_nxt,
2711*cb14a3feSDimitry Andric     uint16_t* to,
2712*cb14a3feSDimitry Andric     uint16_t* to_end,
2713*cb14a3feSDimitry Andric     uint16_t*& to_nxt,
2714*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2715*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
27160b57cec5SDimitry Andric   frm_nxt = frm;
27170b57cec5SDimitry Andric   to_nxt  = to;
2718*cb14a3feSDimitry Andric   if (mode & consume_header) {
27190b57cec5SDimitry Andric     if (frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
27200b57cec5SDimitry Andric       frm_nxt += 2;
27210b57cec5SDimitry Andric   }
2722*cb14a3feSDimitry Andric   for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt) {
27230b57cec5SDimitry Andric     uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
27240b57cec5SDimitry Andric     if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
27250b57cec5SDimitry Andric       return codecvt_base::error;
27260b57cec5SDimitry Andric     *to_nxt = c1;
27270b57cec5SDimitry Andric     frm_nxt += 2;
27280b57cec5SDimitry Andric   }
27290b57cec5SDimitry Andric   return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
27300b57cec5SDimitry Andric }
27310b57cec5SDimitry Andric 
2732*cb14a3feSDimitry Andric static int utf16le_to_ucs2_length(
2733*cb14a3feSDimitry Andric     const uint8_t* frm,
2734*cb14a3feSDimitry Andric     const uint8_t* frm_end,
2735*cb14a3feSDimitry Andric     size_t mx,
2736*cb14a3feSDimitry Andric     unsigned long Maxcode = 0x10FFFF,
2737*cb14a3feSDimitry Andric     codecvt_mode mode     = codecvt_mode(0)) {
27380b57cec5SDimitry Andric   const uint8_t* frm_nxt = frm;
27390b57cec5SDimitry Andric   frm_nxt                = frm;
2740*cb14a3feSDimitry Andric   if (mode & consume_header) {
27410b57cec5SDimitry Andric     if (frm_end - frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
27420b57cec5SDimitry Andric       frm_nxt += 2;
27430b57cec5SDimitry Andric   }
2744*cb14a3feSDimitry Andric   for (size_t nchar16_t = 0; frm_nxt < frm_end - 1 && nchar16_t < mx; ++nchar16_t) {
27450b57cec5SDimitry Andric     uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
27460b57cec5SDimitry Andric     if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
27470b57cec5SDimitry Andric       break;
27480b57cec5SDimitry Andric     frm_nxt += 2;
27490b57cec5SDimitry Andric   }
27500b57cec5SDimitry Andric   return static_cast<int>(frm_nxt - frm);
27510b57cec5SDimitry Andric }
27520b57cec5SDimitry Andric 
275381ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
275481ad6265SDimitry Andric 
27550b57cec5SDimitry Andric // template <> class codecvt<char16_t, char, mbstate_t>
27560b57cec5SDimitry Andric 
27575f757f3fSDimitry Andric constinit locale::id codecvt<char16_t, char, mbstate_t>::id;
27580b57cec5SDimitry Andric 
2759*cb14a3feSDimitry Andric codecvt<char16_t, char, mbstate_t>::~codecvt() {}
27600b57cec5SDimitry Andric 
2761*cb14a3feSDimitry Andric codecvt<char16_t, char, mbstate_t>::result codecvt<char16_t, char, mbstate_t>::do_out(
2762*cb14a3feSDimitry Andric     state_type&,
2763*cb14a3feSDimitry Andric     const intern_type* frm,
2764*cb14a3feSDimitry Andric     const intern_type* frm_end,
2765*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
2766*cb14a3feSDimitry Andric     extern_type* to,
2767*cb14a3feSDimitry Andric     extern_type* to_end,
2768*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
27690b57cec5SDimitry Andric   const uint16_t* _frm     = reinterpret_cast<const uint16_t*>(frm);
27700b57cec5SDimitry Andric   const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
27710b57cec5SDimitry Andric   const uint16_t* _frm_nxt = _frm;
27720b57cec5SDimitry Andric   uint8_t* _to             = reinterpret_cast<uint8_t*>(to);
27730b57cec5SDimitry Andric   uint8_t* _to_end         = reinterpret_cast<uint8_t*>(to_end);
27740b57cec5SDimitry Andric   uint8_t* _to_nxt         = _to;
27750b57cec5SDimitry Andric   result r                 = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
27760b57cec5SDimitry Andric   frm_nxt                  = frm + (_frm_nxt - _frm);
27770b57cec5SDimitry Andric   to_nxt                   = to + (_to_nxt - _to);
27780b57cec5SDimitry Andric   return r;
27790b57cec5SDimitry Andric }
27800b57cec5SDimitry Andric 
2781*cb14a3feSDimitry Andric codecvt<char16_t, char, mbstate_t>::result codecvt<char16_t, char, mbstate_t>::do_in(
2782*cb14a3feSDimitry Andric     state_type&,
2783*cb14a3feSDimitry Andric     const extern_type* frm,
2784*cb14a3feSDimitry Andric     const extern_type* frm_end,
2785*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
2786*cb14a3feSDimitry Andric     intern_type* to,
2787*cb14a3feSDimitry Andric     intern_type* to_end,
2788*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
27890b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
27900b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
27910b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
27920b57cec5SDimitry Andric   uint16_t* _to           = reinterpret_cast<uint16_t*>(to);
27930b57cec5SDimitry Andric   uint16_t* _to_end       = reinterpret_cast<uint16_t*>(to_end);
27940b57cec5SDimitry Andric   uint16_t* _to_nxt       = _to;
27950b57cec5SDimitry Andric   result r                = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
27960b57cec5SDimitry Andric   frm_nxt                 = frm + (_frm_nxt - _frm);
27970b57cec5SDimitry Andric   to_nxt                  = to + (_to_nxt - _to);
27980b57cec5SDimitry Andric   return r;
27990b57cec5SDimitry Andric }
28000b57cec5SDimitry Andric 
28010b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::result
2802*cb14a3feSDimitry Andric codecvt<char16_t, char, mbstate_t>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
28030b57cec5SDimitry Andric   to_nxt = to;
28040b57cec5SDimitry Andric   return noconv;
28050b57cec5SDimitry Andric }
28060b57cec5SDimitry Andric 
2807*cb14a3feSDimitry Andric int codecvt<char16_t, char, mbstate_t>::do_encoding() const noexcept { return 0; }
28080b57cec5SDimitry Andric 
2809*cb14a3feSDimitry Andric bool codecvt<char16_t, char, mbstate_t>::do_always_noconv() const noexcept { return false; }
28100b57cec5SDimitry Andric 
2811*cb14a3feSDimitry Andric int codecvt<char16_t, char, mbstate_t>::do_length(
2812*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
28130b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
28140b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
28150b57cec5SDimitry Andric   return utf8_to_utf16_length(_frm, _frm_end, mx);
28160b57cec5SDimitry Andric }
28170b57cec5SDimitry Andric 
2818*cb14a3feSDimitry Andric int codecvt<char16_t, char, mbstate_t>::do_max_length() const noexcept { return 4; }
28190b57cec5SDimitry Andric 
2820fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
2821e8d8bef9SDimitry Andric 
2822e8d8bef9SDimitry Andric // template <> class codecvt<char16_t, char8_t, mbstate_t>
2823e8d8bef9SDimitry Andric 
28245f757f3fSDimitry Andric constinit locale::id codecvt<char16_t, char8_t, mbstate_t>::id;
2825e8d8bef9SDimitry Andric 
2826*cb14a3feSDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::~codecvt() {}
2827e8d8bef9SDimitry Andric 
2828*cb14a3feSDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::result codecvt<char16_t, char8_t, mbstate_t>::do_out(
2829*cb14a3feSDimitry Andric     state_type&,
2830*cb14a3feSDimitry Andric     const intern_type* frm,
2831*cb14a3feSDimitry Andric     const intern_type* frm_end,
2832*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
2833*cb14a3feSDimitry Andric     extern_type* to,
2834*cb14a3feSDimitry Andric     extern_type* to_end,
2835*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
2836e8d8bef9SDimitry Andric   const uint16_t* _frm     = reinterpret_cast<const uint16_t*>(frm);
2837e8d8bef9SDimitry Andric   const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
2838e8d8bef9SDimitry Andric   const uint16_t* _frm_nxt = _frm;
2839e8d8bef9SDimitry Andric   uint8_t* _to             = reinterpret_cast<uint8_t*>(to);
2840e8d8bef9SDimitry Andric   uint8_t* _to_end         = reinterpret_cast<uint8_t*>(to_end);
2841e8d8bef9SDimitry Andric   uint8_t* _to_nxt         = _to;
2842e8d8bef9SDimitry Andric   result r                 = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
2843e8d8bef9SDimitry Andric   frm_nxt                  = frm + (_frm_nxt - _frm);
2844e8d8bef9SDimitry Andric   to_nxt                   = to + (_to_nxt - _to);
2845e8d8bef9SDimitry Andric   return r;
2846e8d8bef9SDimitry Andric }
2847e8d8bef9SDimitry Andric 
2848*cb14a3feSDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::result codecvt<char16_t, char8_t, mbstate_t>::do_in(
2849*cb14a3feSDimitry Andric     state_type&,
2850*cb14a3feSDimitry Andric     const extern_type* frm,
2851*cb14a3feSDimitry Andric     const extern_type* frm_end,
2852*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
2853*cb14a3feSDimitry Andric     intern_type* to,
2854*cb14a3feSDimitry Andric     intern_type* to_end,
2855*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
2856e8d8bef9SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
2857e8d8bef9SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
2858e8d8bef9SDimitry Andric   const uint8_t* _frm_nxt = _frm;
2859e8d8bef9SDimitry Andric   uint16_t* _to           = reinterpret_cast<uint16_t*>(to);
2860e8d8bef9SDimitry Andric   uint16_t* _to_end       = reinterpret_cast<uint16_t*>(to_end);
2861e8d8bef9SDimitry Andric   uint16_t* _to_nxt       = _to;
2862e8d8bef9SDimitry Andric   result r                = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
2863e8d8bef9SDimitry Andric   frm_nxt                 = frm + (_frm_nxt - _frm);
2864e8d8bef9SDimitry Andric   to_nxt                  = to + (_to_nxt - _to);
2865e8d8bef9SDimitry Andric   return r;
2866e8d8bef9SDimitry Andric }
2867e8d8bef9SDimitry Andric 
2868*cb14a3feSDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::result codecvt<char16_t, char8_t, mbstate_t>::do_unshift(
2869*cb14a3feSDimitry Andric     state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
2870e8d8bef9SDimitry Andric   to_nxt = to;
2871e8d8bef9SDimitry Andric   return noconv;
2872e8d8bef9SDimitry Andric }
2873e8d8bef9SDimitry Andric 
2874*cb14a3feSDimitry Andric int codecvt<char16_t, char8_t, mbstate_t>::do_encoding() const noexcept { return 0; }
2875e8d8bef9SDimitry Andric 
2876*cb14a3feSDimitry Andric bool codecvt<char16_t, char8_t, mbstate_t>::do_always_noconv() const noexcept { return false; }
2877e8d8bef9SDimitry Andric 
2878*cb14a3feSDimitry Andric int codecvt<char16_t, char8_t, mbstate_t>::do_length(
2879*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
2880e8d8bef9SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
2881e8d8bef9SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
2882e8d8bef9SDimitry Andric   return utf8_to_utf16_length(_frm, _frm_end, mx);
2883e8d8bef9SDimitry Andric }
2884e8d8bef9SDimitry Andric 
2885*cb14a3feSDimitry Andric int codecvt<char16_t, char8_t, mbstate_t>::do_max_length() const noexcept { return 4; }
2886e8d8bef9SDimitry Andric 
2887e8d8bef9SDimitry Andric #endif
2888e8d8bef9SDimitry Andric 
28890b57cec5SDimitry Andric // template <> class codecvt<char32_t, char, mbstate_t>
28900b57cec5SDimitry Andric 
28915f757f3fSDimitry Andric constinit locale::id codecvt<char32_t, char, mbstate_t>::id;
28920b57cec5SDimitry Andric 
2893*cb14a3feSDimitry Andric codecvt<char32_t, char, mbstate_t>::~codecvt() {}
28940b57cec5SDimitry Andric 
2895*cb14a3feSDimitry Andric codecvt<char32_t, char, mbstate_t>::result codecvt<char32_t, char, mbstate_t>::do_out(
2896*cb14a3feSDimitry Andric     state_type&,
2897*cb14a3feSDimitry Andric     const intern_type* frm,
2898*cb14a3feSDimitry Andric     const intern_type* frm_end,
2899*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
2900*cb14a3feSDimitry Andric     extern_type* to,
2901*cb14a3feSDimitry Andric     extern_type* to_end,
2902*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
29030b57cec5SDimitry Andric   const uint32_t* _frm     = reinterpret_cast<const uint32_t*>(frm);
29040b57cec5SDimitry Andric   const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
29050b57cec5SDimitry Andric   const uint32_t* _frm_nxt = _frm;
29060b57cec5SDimitry Andric   uint8_t* _to             = reinterpret_cast<uint8_t*>(to);
29070b57cec5SDimitry Andric   uint8_t* _to_end         = reinterpret_cast<uint8_t*>(to_end);
29080b57cec5SDimitry Andric   uint8_t* _to_nxt         = _to;
29090b57cec5SDimitry Andric   result r                 = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
29100b57cec5SDimitry Andric   frm_nxt                  = frm + (_frm_nxt - _frm);
29110b57cec5SDimitry Andric   to_nxt                   = to + (_to_nxt - _to);
29120b57cec5SDimitry Andric   return r;
29130b57cec5SDimitry Andric }
29140b57cec5SDimitry Andric 
2915*cb14a3feSDimitry Andric codecvt<char32_t, char, mbstate_t>::result codecvt<char32_t, char, mbstate_t>::do_in(
2916*cb14a3feSDimitry Andric     state_type&,
2917*cb14a3feSDimitry Andric     const extern_type* frm,
2918*cb14a3feSDimitry Andric     const extern_type* frm_end,
2919*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
2920*cb14a3feSDimitry Andric     intern_type* to,
2921*cb14a3feSDimitry Andric     intern_type* to_end,
2922*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
29230b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
29240b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
29250b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
29260b57cec5SDimitry Andric   uint32_t* _to           = reinterpret_cast<uint32_t*>(to);
29270b57cec5SDimitry Andric   uint32_t* _to_end       = reinterpret_cast<uint32_t*>(to_end);
29280b57cec5SDimitry Andric   uint32_t* _to_nxt       = _to;
29290b57cec5SDimitry Andric   result r                = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
29300b57cec5SDimitry Andric   frm_nxt                 = frm + (_frm_nxt - _frm);
29310b57cec5SDimitry Andric   to_nxt                  = to + (_to_nxt - _to);
29320b57cec5SDimitry Andric   return r;
29330b57cec5SDimitry Andric }
29340b57cec5SDimitry Andric 
29350b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::result
2936*cb14a3feSDimitry Andric codecvt<char32_t, char, mbstate_t>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
29370b57cec5SDimitry Andric   to_nxt = to;
29380b57cec5SDimitry Andric   return noconv;
29390b57cec5SDimitry Andric }
29400b57cec5SDimitry Andric 
2941*cb14a3feSDimitry Andric int codecvt<char32_t, char, mbstate_t>::do_encoding() const noexcept { return 0; }
29420b57cec5SDimitry Andric 
2943*cb14a3feSDimitry Andric bool codecvt<char32_t, char, mbstate_t>::do_always_noconv() const noexcept { return false; }
29440b57cec5SDimitry Andric 
2945*cb14a3feSDimitry Andric int codecvt<char32_t, char, mbstate_t>::do_length(
2946*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
29470b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
29480b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
29490b57cec5SDimitry Andric   return utf8_to_ucs4_length(_frm, _frm_end, mx);
29500b57cec5SDimitry Andric }
29510b57cec5SDimitry Andric 
2952*cb14a3feSDimitry Andric int codecvt<char32_t, char, mbstate_t>::do_max_length() const noexcept { return 4; }
29530b57cec5SDimitry Andric 
2954fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
2955e8d8bef9SDimitry Andric 
2956e8d8bef9SDimitry Andric // template <> class codecvt<char32_t, char8_t, mbstate_t>
2957e8d8bef9SDimitry Andric 
29585f757f3fSDimitry Andric constinit locale::id codecvt<char32_t, char8_t, mbstate_t>::id;
2959e8d8bef9SDimitry Andric 
2960*cb14a3feSDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::~codecvt() {}
2961e8d8bef9SDimitry Andric 
2962*cb14a3feSDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::result codecvt<char32_t, char8_t, mbstate_t>::do_out(
2963*cb14a3feSDimitry Andric     state_type&,
2964*cb14a3feSDimitry Andric     const intern_type* frm,
2965*cb14a3feSDimitry Andric     const intern_type* frm_end,
2966*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
2967*cb14a3feSDimitry Andric     extern_type* to,
2968*cb14a3feSDimitry Andric     extern_type* to_end,
2969*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
2970e8d8bef9SDimitry Andric   const uint32_t* _frm     = reinterpret_cast<const uint32_t*>(frm);
2971e8d8bef9SDimitry Andric   const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
2972e8d8bef9SDimitry Andric   const uint32_t* _frm_nxt = _frm;
2973e8d8bef9SDimitry Andric   uint8_t* _to             = reinterpret_cast<uint8_t*>(to);
2974e8d8bef9SDimitry Andric   uint8_t* _to_end         = reinterpret_cast<uint8_t*>(to_end);
2975e8d8bef9SDimitry Andric   uint8_t* _to_nxt         = _to;
2976e8d8bef9SDimitry Andric   result r                 = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
2977e8d8bef9SDimitry Andric   frm_nxt                  = frm + (_frm_nxt - _frm);
2978e8d8bef9SDimitry Andric   to_nxt                   = to + (_to_nxt - _to);
2979e8d8bef9SDimitry Andric   return r;
2980e8d8bef9SDimitry Andric }
2981e8d8bef9SDimitry Andric 
2982*cb14a3feSDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::result codecvt<char32_t, char8_t, mbstate_t>::do_in(
2983*cb14a3feSDimitry Andric     state_type&,
2984*cb14a3feSDimitry Andric     const extern_type* frm,
2985*cb14a3feSDimitry Andric     const extern_type* frm_end,
2986*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
2987*cb14a3feSDimitry Andric     intern_type* to,
2988*cb14a3feSDimitry Andric     intern_type* to_end,
2989*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
2990e8d8bef9SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
2991e8d8bef9SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
2992e8d8bef9SDimitry Andric   const uint8_t* _frm_nxt = _frm;
2993e8d8bef9SDimitry Andric   uint32_t* _to           = reinterpret_cast<uint32_t*>(to);
2994e8d8bef9SDimitry Andric   uint32_t* _to_end       = reinterpret_cast<uint32_t*>(to_end);
2995e8d8bef9SDimitry Andric   uint32_t* _to_nxt       = _to;
2996e8d8bef9SDimitry Andric   result r                = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
2997e8d8bef9SDimitry Andric   frm_nxt                 = frm + (_frm_nxt - _frm);
2998e8d8bef9SDimitry Andric   to_nxt                  = to + (_to_nxt - _to);
2999e8d8bef9SDimitry Andric   return r;
3000e8d8bef9SDimitry Andric }
3001e8d8bef9SDimitry Andric 
3002*cb14a3feSDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::result codecvt<char32_t, char8_t, mbstate_t>::do_unshift(
3003*cb14a3feSDimitry Andric     state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
3004e8d8bef9SDimitry Andric   to_nxt = to;
3005e8d8bef9SDimitry Andric   return noconv;
3006e8d8bef9SDimitry Andric }
3007e8d8bef9SDimitry Andric 
3008*cb14a3feSDimitry Andric int codecvt<char32_t, char8_t, mbstate_t>::do_encoding() const noexcept { return 0; }
3009e8d8bef9SDimitry Andric 
3010*cb14a3feSDimitry Andric bool codecvt<char32_t, char8_t, mbstate_t>::do_always_noconv() const noexcept { return false; }
3011e8d8bef9SDimitry Andric 
3012*cb14a3feSDimitry Andric int codecvt<char32_t, char8_t, mbstate_t>::do_length(
3013*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
3014e8d8bef9SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
3015e8d8bef9SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3016e8d8bef9SDimitry Andric   return utf8_to_ucs4_length(_frm, _frm_end, mx);
3017e8d8bef9SDimitry Andric }
3018e8d8bef9SDimitry Andric 
3019*cb14a3feSDimitry Andric int codecvt<char32_t, char8_t, mbstate_t>::do_max_length() const noexcept { return 4; }
3020e8d8bef9SDimitry Andric 
3021e8d8bef9SDimitry Andric #endif
3022e8d8bef9SDimitry Andric 
30230b57cec5SDimitry Andric // __codecvt_utf8<wchar_t>
30240b57cec5SDimitry Andric 
3025349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3026*cb14a3feSDimitry Andric __codecvt_utf8<wchar_t>::result __codecvt_utf8<wchar_t>::do_out(
3027*cb14a3feSDimitry Andric     state_type&,
3028*cb14a3feSDimitry Andric     const intern_type* frm,
3029*cb14a3feSDimitry Andric     const intern_type* frm_end,
3030*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
3031*cb14a3feSDimitry Andric     extern_type* to,
3032*cb14a3feSDimitry Andric     extern_type* to_end,
3033*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
30340b57cec5SDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
30350b57cec5SDimitry Andric   const uint16_t* _frm     = reinterpret_cast<const uint16_t*>(frm);
30360b57cec5SDimitry Andric   const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
30370b57cec5SDimitry Andric   const uint16_t* _frm_nxt = _frm;
30380b57cec5SDimitry Andric #  else
30390b57cec5SDimitry Andric   const uint32_t* _frm     = reinterpret_cast<const uint32_t*>(frm);
30400b57cec5SDimitry Andric   const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
30410b57cec5SDimitry Andric   const uint32_t* _frm_nxt = _frm;
30420b57cec5SDimitry Andric #  endif
30430b57cec5SDimitry Andric   uint8_t* _to     = reinterpret_cast<uint8_t*>(to);
30440b57cec5SDimitry Andric   uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
30450b57cec5SDimitry Andric   uint8_t* _to_nxt = _to;
30460b57cec5SDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3047*cb14a3feSDimitry Andric   result r = ucs2_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
30480b57cec5SDimitry Andric #  else
3049*cb14a3feSDimitry Andric   result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
30500b57cec5SDimitry Andric #  endif
30510b57cec5SDimitry Andric   frm_nxt = frm + (_frm_nxt - _frm);
30520b57cec5SDimitry Andric   to_nxt  = to + (_to_nxt - _to);
30530b57cec5SDimitry Andric   return r;
30540b57cec5SDimitry Andric }
30550b57cec5SDimitry Andric 
3056*cb14a3feSDimitry Andric __codecvt_utf8<wchar_t>::result __codecvt_utf8<wchar_t>::do_in(
3057*cb14a3feSDimitry Andric     state_type&,
3058*cb14a3feSDimitry Andric     const extern_type* frm,
3059*cb14a3feSDimitry Andric     const extern_type* frm_end,
3060*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
3061*cb14a3feSDimitry Andric     intern_type* to,
3062*cb14a3feSDimitry Andric     intern_type* to_end,
3063*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
30640b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
30650b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
30660b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
30670b57cec5SDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
30680b57cec5SDimitry Andric   uint16_t* _to     = reinterpret_cast<uint16_t*>(to);
30690b57cec5SDimitry Andric   uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
30700b57cec5SDimitry Andric   uint16_t* _to_nxt = _to;
3071*cb14a3feSDimitry Andric   result r          = utf8_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
30720b57cec5SDimitry Andric #  else
30730b57cec5SDimitry Andric   uint32_t* _to     = reinterpret_cast<uint32_t*>(to);
30740b57cec5SDimitry Andric   uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
30750b57cec5SDimitry Andric   uint32_t* _to_nxt = _to;
3076*cb14a3feSDimitry Andric   result r          = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
30770b57cec5SDimitry Andric #  endif
30780b57cec5SDimitry Andric   frm_nxt = frm + (_frm_nxt - _frm);
30790b57cec5SDimitry Andric   to_nxt  = to + (_to_nxt - _to);
30800b57cec5SDimitry Andric   return r;
30810b57cec5SDimitry Andric }
30820b57cec5SDimitry Andric 
30830b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::result
3084*cb14a3feSDimitry Andric __codecvt_utf8<wchar_t>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
30850b57cec5SDimitry Andric   to_nxt = to;
30860b57cec5SDimitry Andric   return noconv;
30870b57cec5SDimitry Andric }
30880b57cec5SDimitry Andric 
3089*cb14a3feSDimitry Andric int __codecvt_utf8<wchar_t>::do_encoding() const noexcept { return 0; }
30900b57cec5SDimitry Andric 
3091*cb14a3feSDimitry Andric bool __codecvt_utf8<wchar_t>::do_always_noconv() const noexcept { return false; }
30920b57cec5SDimitry Andric 
3093*cb14a3feSDimitry Andric int __codecvt_utf8<wchar_t>::do_length(
3094*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
30950b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
30960b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3097349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3098bdd1243dSDimitry Andric   return utf8_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3099349cc55cSDimitry Andric #  else
3100bdd1243dSDimitry Andric   return utf8_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3101349cc55cSDimitry Andric #  endif
31020b57cec5SDimitry Andric }
31030b57cec5SDimitry Andric 
310481ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3105*cb14a3feSDimitry Andric int __codecvt_utf8<wchar_t>::do_max_length() const noexcept {
3106349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3107bdd1243dSDimitry Andric   if (__mode_ & consume_header)
3108349cc55cSDimitry Andric     return 6;
3109349cc55cSDimitry Andric   return 3;
3110349cc55cSDimitry Andric #  else
3111bdd1243dSDimitry Andric   if (__mode_ & consume_header)
31120b57cec5SDimitry Andric     return 7;
31130b57cec5SDimitry Andric   return 4;
3114349cc55cSDimitry Andric #  endif
31150b57cec5SDimitry Andric }
3116349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
31170b57cec5SDimitry Andric 
31180b57cec5SDimitry Andric // __codecvt_utf8<char16_t>
31190b57cec5SDimitry Andric 
3120*cb14a3feSDimitry Andric __codecvt_utf8<char16_t>::result __codecvt_utf8<char16_t>::do_out(
3121*cb14a3feSDimitry Andric     state_type&,
3122*cb14a3feSDimitry Andric     const intern_type* frm,
3123*cb14a3feSDimitry Andric     const intern_type* frm_end,
3124*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
3125*cb14a3feSDimitry Andric     extern_type* to,
3126*cb14a3feSDimitry Andric     extern_type* to_end,
3127*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
31280b57cec5SDimitry Andric   const uint16_t* _frm     = reinterpret_cast<const uint16_t*>(frm);
31290b57cec5SDimitry Andric   const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
31300b57cec5SDimitry Andric   const uint16_t* _frm_nxt = _frm;
31310b57cec5SDimitry Andric   uint8_t* _to             = reinterpret_cast<uint8_t*>(to);
31320b57cec5SDimitry Andric   uint8_t* _to_end         = reinterpret_cast<uint8_t*>(to_end);
31330b57cec5SDimitry Andric   uint8_t* _to_nxt         = _to;
3134*cb14a3feSDimitry Andric   result r                 = ucs2_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
31350b57cec5SDimitry Andric   frm_nxt                  = frm + (_frm_nxt - _frm);
31360b57cec5SDimitry Andric   to_nxt                   = to + (_to_nxt - _to);
31370b57cec5SDimitry Andric   return r;
31380b57cec5SDimitry Andric }
31390b57cec5SDimitry Andric 
3140*cb14a3feSDimitry Andric __codecvt_utf8<char16_t>::result __codecvt_utf8<char16_t>::do_in(
3141*cb14a3feSDimitry Andric     state_type&,
3142*cb14a3feSDimitry Andric     const extern_type* frm,
3143*cb14a3feSDimitry Andric     const extern_type* frm_end,
3144*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
3145*cb14a3feSDimitry Andric     intern_type* to,
3146*cb14a3feSDimitry Andric     intern_type* to_end,
3147*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
31480b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
31490b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
31500b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
31510b57cec5SDimitry Andric   uint16_t* _to           = reinterpret_cast<uint16_t*>(to);
31520b57cec5SDimitry Andric   uint16_t* _to_end       = reinterpret_cast<uint16_t*>(to_end);
31530b57cec5SDimitry Andric   uint16_t* _to_nxt       = _to;
3154*cb14a3feSDimitry Andric   result r                = utf8_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
31550b57cec5SDimitry Andric   frm_nxt                 = frm + (_frm_nxt - _frm);
31560b57cec5SDimitry Andric   to_nxt                  = to + (_to_nxt - _to);
31570b57cec5SDimitry Andric   return r;
31580b57cec5SDimitry Andric }
31590b57cec5SDimitry Andric 
31600b57cec5SDimitry Andric __codecvt_utf8<char16_t>::result
3161*cb14a3feSDimitry Andric __codecvt_utf8<char16_t>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
31620b57cec5SDimitry Andric   to_nxt = to;
31630b57cec5SDimitry Andric   return noconv;
31640b57cec5SDimitry Andric }
31650b57cec5SDimitry Andric 
3166*cb14a3feSDimitry Andric int __codecvt_utf8<char16_t>::do_encoding() const noexcept { return 0; }
31670b57cec5SDimitry Andric 
3168*cb14a3feSDimitry Andric bool __codecvt_utf8<char16_t>::do_always_noconv() const noexcept { return false; }
31690b57cec5SDimitry Andric 
3170*cb14a3feSDimitry Andric int __codecvt_utf8<char16_t>::do_length(
3171*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
31720b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
31730b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3174bdd1243dSDimitry Andric   return utf8_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
31750b57cec5SDimitry Andric }
31760b57cec5SDimitry Andric 
317781ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3178*cb14a3feSDimitry Andric int __codecvt_utf8<char16_t>::do_max_length() const noexcept {
3179bdd1243dSDimitry Andric   if (__mode_ & consume_header)
31800b57cec5SDimitry Andric     return 6;
31810b57cec5SDimitry Andric   return 3;
31820b57cec5SDimitry Andric }
318381ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
31840b57cec5SDimitry Andric 
31850b57cec5SDimitry Andric // __codecvt_utf8<char32_t>
31860b57cec5SDimitry Andric 
3187*cb14a3feSDimitry Andric __codecvt_utf8<char32_t>::result __codecvt_utf8<char32_t>::do_out(
3188*cb14a3feSDimitry Andric     state_type&,
3189*cb14a3feSDimitry Andric     const intern_type* frm,
3190*cb14a3feSDimitry Andric     const intern_type* frm_end,
3191*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
3192*cb14a3feSDimitry Andric     extern_type* to,
3193*cb14a3feSDimitry Andric     extern_type* to_end,
3194*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
31950b57cec5SDimitry Andric   const uint32_t* _frm     = reinterpret_cast<const uint32_t*>(frm);
31960b57cec5SDimitry Andric   const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
31970b57cec5SDimitry Andric   const uint32_t* _frm_nxt = _frm;
31980b57cec5SDimitry Andric   uint8_t* _to             = reinterpret_cast<uint8_t*>(to);
31990b57cec5SDimitry Andric   uint8_t* _to_end         = reinterpret_cast<uint8_t*>(to_end);
32000b57cec5SDimitry Andric   uint8_t* _to_nxt         = _to;
3201*cb14a3feSDimitry Andric   result r                 = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
32020b57cec5SDimitry Andric   frm_nxt                  = frm + (_frm_nxt - _frm);
32030b57cec5SDimitry Andric   to_nxt                   = to + (_to_nxt - _to);
32040b57cec5SDimitry Andric   return r;
32050b57cec5SDimitry Andric }
32060b57cec5SDimitry Andric 
3207*cb14a3feSDimitry Andric __codecvt_utf8<char32_t>::result __codecvt_utf8<char32_t>::do_in(
3208*cb14a3feSDimitry Andric     state_type&,
3209*cb14a3feSDimitry Andric     const extern_type* frm,
3210*cb14a3feSDimitry Andric     const extern_type* frm_end,
3211*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
3212*cb14a3feSDimitry Andric     intern_type* to,
3213*cb14a3feSDimitry Andric     intern_type* to_end,
3214*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
32150b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
32160b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
32170b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
32180b57cec5SDimitry Andric   uint32_t* _to           = reinterpret_cast<uint32_t*>(to);
32190b57cec5SDimitry Andric   uint32_t* _to_end       = reinterpret_cast<uint32_t*>(to_end);
32200b57cec5SDimitry Andric   uint32_t* _to_nxt       = _to;
3221*cb14a3feSDimitry Andric   result r                = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
32220b57cec5SDimitry Andric   frm_nxt                 = frm + (_frm_nxt - _frm);
32230b57cec5SDimitry Andric   to_nxt                  = to + (_to_nxt - _to);
32240b57cec5SDimitry Andric   return r;
32250b57cec5SDimitry Andric }
32260b57cec5SDimitry Andric 
32270b57cec5SDimitry Andric __codecvt_utf8<char32_t>::result
3228*cb14a3feSDimitry Andric __codecvt_utf8<char32_t>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
32290b57cec5SDimitry Andric   to_nxt = to;
32300b57cec5SDimitry Andric   return noconv;
32310b57cec5SDimitry Andric }
32320b57cec5SDimitry Andric 
3233*cb14a3feSDimitry Andric int __codecvt_utf8<char32_t>::do_encoding() const noexcept { return 0; }
32340b57cec5SDimitry Andric 
3235*cb14a3feSDimitry Andric bool __codecvt_utf8<char32_t>::do_always_noconv() const noexcept { return false; }
32360b57cec5SDimitry Andric 
3237*cb14a3feSDimitry Andric int __codecvt_utf8<char32_t>::do_length(
3238*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
32390b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
32400b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3241bdd1243dSDimitry Andric   return utf8_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
32420b57cec5SDimitry Andric }
32430b57cec5SDimitry Andric 
324481ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3245*cb14a3feSDimitry Andric int __codecvt_utf8<char32_t>::do_max_length() const noexcept {
3246bdd1243dSDimitry Andric   if (__mode_ & consume_header)
32470b57cec5SDimitry Andric     return 7;
32480b57cec5SDimitry Andric   return 4;
32490b57cec5SDimitry Andric }
325081ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
32510b57cec5SDimitry Andric 
32520b57cec5SDimitry Andric // __codecvt_utf16<wchar_t, false>
32530b57cec5SDimitry Andric 
3254349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3255*cb14a3feSDimitry Andric __codecvt_utf16<wchar_t, false>::result __codecvt_utf16<wchar_t, false>::do_out(
3256*cb14a3feSDimitry Andric     state_type&,
3257*cb14a3feSDimitry Andric     const intern_type* frm,
3258*cb14a3feSDimitry Andric     const intern_type* frm_end,
3259*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
3260*cb14a3feSDimitry Andric     extern_type* to,
3261*cb14a3feSDimitry Andric     extern_type* to_end,
3262*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
3263349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3264349cc55cSDimitry Andric   const uint16_t* _frm     = reinterpret_cast<const uint16_t*>(frm);
3265349cc55cSDimitry Andric   const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3266349cc55cSDimitry Andric   const uint16_t* _frm_nxt = _frm;
3267349cc55cSDimitry Andric #  else
32680b57cec5SDimitry Andric   const uint32_t* _frm     = reinterpret_cast<const uint32_t*>(frm);
32690b57cec5SDimitry Andric   const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
32700b57cec5SDimitry Andric   const uint32_t* _frm_nxt = _frm;
3271349cc55cSDimitry Andric #  endif
32720b57cec5SDimitry Andric   uint8_t* _to     = reinterpret_cast<uint8_t*>(to);
32730b57cec5SDimitry Andric   uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
32740b57cec5SDimitry Andric   uint8_t* _to_nxt = _to;
3275349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3276*cb14a3feSDimitry Andric   result r = ucs2_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
3277349cc55cSDimitry Andric #  else
3278*cb14a3feSDimitry Andric   result r = ucs4_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
3279349cc55cSDimitry Andric #  endif
32800b57cec5SDimitry Andric   frm_nxt = frm + (_frm_nxt - _frm);
32810b57cec5SDimitry Andric   to_nxt  = to + (_to_nxt - _to);
32820b57cec5SDimitry Andric   return r;
32830b57cec5SDimitry Andric }
32840b57cec5SDimitry Andric 
3285*cb14a3feSDimitry Andric __codecvt_utf16<wchar_t, false>::result __codecvt_utf16<wchar_t, false>::do_in(
3286*cb14a3feSDimitry Andric     state_type&,
3287*cb14a3feSDimitry Andric     const extern_type* frm,
3288*cb14a3feSDimitry Andric     const extern_type* frm_end,
3289*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
3290*cb14a3feSDimitry Andric     intern_type* to,
3291*cb14a3feSDimitry Andric     intern_type* to_end,
3292*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
32930b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
32940b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
32950b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
3296349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3297349cc55cSDimitry Andric   uint16_t* _to     = reinterpret_cast<uint16_t*>(to);
3298349cc55cSDimitry Andric   uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3299349cc55cSDimitry Andric   uint16_t* _to_nxt = _to;
3300*cb14a3feSDimitry Andric   result r          = utf16be_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
3301349cc55cSDimitry Andric #  else
33020b57cec5SDimitry Andric   uint32_t* _to     = reinterpret_cast<uint32_t*>(to);
33030b57cec5SDimitry Andric   uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
33040b57cec5SDimitry Andric   uint32_t* _to_nxt = _to;
3305*cb14a3feSDimitry Andric   result r          = utf16be_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
3306349cc55cSDimitry Andric #  endif
33070b57cec5SDimitry Andric   frm_nxt = frm + (_frm_nxt - _frm);
33080b57cec5SDimitry Andric   to_nxt  = to + (_to_nxt - _to);
33090b57cec5SDimitry Andric   return r;
33100b57cec5SDimitry Andric }
33110b57cec5SDimitry Andric 
33120b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::result
3313*cb14a3feSDimitry Andric __codecvt_utf16<wchar_t, false>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
33140b57cec5SDimitry Andric   to_nxt = to;
33150b57cec5SDimitry Andric   return noconv;
33160b57cec5SDimitry Andric }
33170b57cec5SDimitry Andric 
3318*cb14a3feSDimitry Andric int __codecvt_utf16<wchar_t, false>::do_encoding() const noexcept { return 0; }
33190b57cec5SDimitry Andric 
3320*cb14a3feSDimitry Andric bool __codecvt_utf16<wchar_t, false>::do_always_noconv() const noexcept { return false; }
33210b57cec5SDimitry Andric 
3322*cb14a3feSDimitry Andric int __codecvt_utf16<wchar_t, false>::do_length(
3323*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
33240b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
33250b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3326349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3327bdd1243dSDimitry Andric   return utf16be_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3328349cc55cSDimitry Andric #  else
3329bdd1243dSDimitry Andric   return utf16be_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3330349cc55cSDimitry Andric #  endif
33310b57cec5SDimitry Andric }
33320b57cec5SDimitry Andric 
3333*cb14a3feSDimitry Andric int __codecvt_utf16<wchar_t, false>::do_max_length() const noexcept {
3334349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3335bdd1243dSDimitry Andric   if (__mode_ & consume_header)
3336349cc55cSDimitry Andric     return 4;
3337349cc55cSDimitry Andric   return 2;
3338349cc55cSDimitry Andric #  else
3339bdd1243dSDimitry Andric   if (__mode_ & consume_header)
33400b57cec5SDimitry Andric     return 6;
33410b57cec5SDimitry Andric   return 4;
3342349cc55cSDimitry Andric #  endif
33430b57cec5SDimitry Andric }
33440b57cec5SDimitry Andric 
33450b57cec5SDimitry Andric // __codecvt_utf16<wchar_t, true>
33460b57cec5SDimitry Andric 
3347*cb14a3feSDimitry Andric __codecvt_utf16<wchar_t, true>::result __codecvt_utf16<wchar_t, true>::do_out(
3348*cb14a3feSDimitry Andric     state_type&,
3349*cb14a3feSDimitry Andric     const intern_type* frm,
3350*cb14a3feSDimitry Andric     const intern_type* frm_end,
3351*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
3352*cb14a3feSDimitry Andric     extern_type* to,
3353*cb14a3feSDimitry Andric     extern_type* to_end,
3354*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
3355349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3356349cc55cSDimitry Andric   const uint16_t* _frm     = reinterpret_cast<const uint16_t*>(frm);
3357349cc55cSDimitry Andric   const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3358349cc55cSDimitry Andric   const uint16_t* _frm_nxt = _frm;
3359349cc55cSDimitry Andric #  else
33600b57cec5SDimitry Andric   const uint32_t* _frm     = reinterpret_cast<const uint32_t*>(frm);
33610b57cec5SDimitry Andric   const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
33620b57cec5SDimitry Andric   const uint32_t* _frm_nxt = _frm;
3363349cc55cSDimitry Andric #  endif
33640b57cec5SDimitry Andric   uint8_t* _to     = reinterpret_cast<uint8_t*>(to);
33650b57cec5SDimitry Andric   uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
33660b57cec5SDimitry Andric   uint8_t* _to_nxt = _to;
3367349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3368*cb14a3feSDimitry Andric   result r = ucs2_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
3369349cc55cSDimitry Andric #  else
3370*cb14a3feSDimitry Andric   result r = ucs4_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
3371349cc55cSDimitry Andric #  endif
33720b57cec5SDimitry Andric   frm_nxt = frm + (_frm_nxt - _frm);
33730b57cec5SDimitry Andric   to_nxt  = to + (_to_nxt - _to);
33740b57cec5SDimitry Andric   return r;
33750b57cec5SDimitry Andric }
33760b57cec5SDimitry Andric 
3377*cb14a3feSDimitry Andric __codecvt_utf16<wchar_t, true>::result __codecvt_utf16<wchar_t, true>::do_in(
3378*cb14a3feSDimitry Andric     state_type&,
3379*cb14a3feSDimitry Andric     const extern_type* frm,
3380*cb14a3feSDimitry Andric     const extern_type* frm_end,
3381*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
3382*cb14a3feSDimitry Andric     intern_type* to,
3383*cb14a3feSDimitry Andric     intern_type* to_end,
3384*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
33850b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
33860b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
33870b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
3388349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3389349cc55cSDimitry Andric   uint16_t* _to     = reinterpret_cast<uint16_t*>(to);
3390349cc55cSDimitry Andric   uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3391349cc55cSDimitry Andric   uint16_t* _to_nxt = _to;
3392*cb14a3feSDimitry Andric   result r          = utf16le_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
3393349cc55cSDimitry Andric #  else
33940b57cec5SDimitry Andric   uint32_t* _to     = reinterpret_cast<uint32_t*>(to);
33950b57cec5SDimitry Andric   uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
33960b57cec5SDimitry Andric   uint32_t* _to_nxt = _to;
3397*cb14a3feSDimitry Andric   result r          = utf16le_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
3398349cc55cSDimitry Andric #  endif
33990b57cec5SDimitry Andric   frm_nxt = frm + (_frm_nxt - _frm);
34000b57cec5SDimitry Andric   to_nxt  = to + (_to_nxt - _to);
34010b57cec5SDimitry Andric   return r;
34020b57cec5SDimitry Andric }
34030b57cec5SDimitry Andric 
34040b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::result
3405*cb14a3feSDimitry Andric __codecvt_utf16<wchar_t, true>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
34060b57cec5SDimitry Andric   to_nxt = to;
34070b57cec5SDimitry Andric   return noconv;
34080b57cec5SDimitry Andric }
34090b57cec5SDimitry Andric 
3410*cb14a3feSDimitry Andric int __codecvt_utf16<wchar_t, true>::do_encoding() const noexcept { return 0; }
34110b57cec5SDimitry Andric 
3412*cb14a3feSDimitry Andric bool __codecvt_utf16<wchar_t, true>::do_always_noconv() const noexcept { return false; }
34130b57cec5SDimitry Andric 
3414*cb14a3feSDimitry Andric int __codecvt_utf16<wchar_t, true>::do_length(
3415*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
34160b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
34170b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3418349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3419bdd1243dSDimitry Andric   return utf16le_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3420349cc55cSDimitry Andric #  else
3421bdd1243dSDimitry Andric   return utf16le_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3422349cc55cSDimitry Andric #  endif
34230b57cec5SDimitry Andric }
34240b57cec5SDimitry Andric 
3425*cb14a3feSDimitry Andric int __codecvt_utf16<wchar_t, true>::do_max_length() const noexcept {
3426349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3427bdd1243dSDimitry Andric   if (__mode_ & consume_header)
3428349cc55cSDimitry Andric     return 4;
3429349cc55cSDimitry Andric   return 2;
3430349cc55cSDimitry Andric #  else
3431bdd1243dSDimitry Andric   if (__mode_ & consume_header)
34320b57cec5SDimitry Andric     return 6;
34330b57cec5SDimitry Andric   return 4;
3434349cc55cSDimitry Andric #  endif
34350b57cec5SDimitry Andric }
3436349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
34370b57cec5SDimitry Andric 
34380b57cec5SDimitry Andric // __codecvt_utf16<char16_t, false>
34390b57cec5SDimitry Andric 
3440*cb14a3feSDimitry Andric __codecvt_utf16<char16_t, false>::result __codecvt_utf16<char16_t, false>::do_out(
3441*cb14a3feSDimitry Andric     state_type&,
3442*cb14a3feSDimitry Andric     const intern_type* frm,
3443*cb14a3feSDimitry Andric     const intern_type* frm_end,
3444*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
3445*cb14a3feSDimitry Andric     extern_type* to,
3446*cb14a3feSDimitry Andric     extern_type* to_end,
3447*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
34480b57cec5SDimitry Andric   const uint16_t* _frm     = reinterpret_cast<const uint16_t*>(frm);
34490b57cec5SDimitry Andric   const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
34500b57cec5SDimitry Andric   const uint16_t* _frm_nxt = _frm;
34510b57cec5SDimitry Andric   uint8_t* _to             = reinterpret_cast<uint8_t*>(to);
34520b57cec5SDimitry Andric   uint8_t* _to_end         = reinterpret_cast<uint8_t*>(to_end);
34530b57cec5SDimitry Andric   uint8_t* _to_nxt         = _to;
3454*cb14a3feSDimitry Andric   result r                 = ucs2_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
34550b57cec5SDimitry Andric   frm_nxt                  = frm + (_frm_nxt - _frm);
34560b57cec5SDimitry Andric   to_nxt                   = to + (_to_nxt - _to);
34570b57cec5SDimitry Andric   return r;
34580b57cec5SDimitry Andric }
34590b57cec5SDimitry Andric 
3460*cb14a3feSDimitry Andric __codecvt_utf16<char16_t, false>::result __codecvt_utf16<char16_t, false>::do_in(
3461*cb14a3feSDimitry Andric     state_type&,
3462*cb14a3feSDimitry Andric     const extern_type* frm,
3463*cb14a3feSDimitry Andric     const extern_type* frm_end,
3464*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
3465*cb14a3feSDimitry Andric     intern_type* to,
3466*cb14a3feSDimitry Andric     intern_type* to_end,
3467*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
34680b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
34690b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
34700b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
34710b57cec5SDimitry Andric   uint16_t* _to           = reinterpret_cast<uint16_t*>(to);
34720b57cec5SDimitry Andric   uint16_t* _to_end       = reinterpret_cast<uint16_t*>(to_end);
34730b57cec5SDimitry Andric   uint16_t* _to_nxt       = _to;
3474*cb14a3feSDimitry Andric   result r                = utf16be_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
34750b57cec5SDimitry Andric   frm_nxt                 = frm + (_frm_nxt - _frm);
34760b57cec5SDimitry Andric   to_nxt                  = to + (_to_nxt - _to);
34770b57cec5SDimitry Andric   return r;
34780b57cec5SDimitry Andric }
34790b57cec5SDimitry Andric 
34800b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::result
3481*cb14a3feSDimitry Andric __codecvt_utf16<char16_t, false>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
34820b57cec5SDimitry Andric   to_nxt = to;
34830b57cec5SDimitry Andric   return noconv;
34840b57cec5SDimitry Andric }
34850b57cec5SDimitry Andric 
3486*cb14a3feSDimitry Andric int __codecvt_utf16<char16_t, false>::do_encoding() const noexcept { return 0; }
34870b57cec5SDimitry Andric 
3488*cb14a3feSDimitry Andric bool __codecvt_utf16<char16_t, false>::do_always_noconv() const noexcept { return false; }
34890b57cec5SDimitry Andric 
3490*cb14a3feSDimitry Andric int __codecvt_utf16<char16_t, false>::do_length(
3491*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
34920b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
34930b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3494bdd1243dSDimitry Andric   return utf16be_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
34950b57cec5SDimitry Andric }
34960b57cec5SDimitry Andric 
349781ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3498*cb14a3feSDimitry Andric int __codecvt_utf16<char16_t, false>::do_max_length() const noexcept {
3499bdd1243dSDimitry Andric   if (__mode_ & consume_header)
35000b57cec5SDimitry Andric     return 4;
35010b57cec5SDimitry Andric   return 2;
35020b57cec5SDimitry Andric }
350381ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
35040b57cec5SDimitry Andric 
35050b57cec5SDimitry Andric // __codecvt_utf16<char16_t, true>
35060b57cec5SDimitry Andric 
3507*cb14a3feSDimitry Andric __codecvt_utf16<char16_t, true>::result __codecvt_utf16<char16_t, true>::do_out(
3508*cb14a3feSDimitry Andric     state_type&,
3509*cb14a3feSDimitry Andric     const intern_type* frm,
3510*cb14a3feSDimitry Andric     const intern_type* frm_end,
3511*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
3512*cb14a3feSDimitry Andric     extern_type* to,
3513*cb14a3feSDimitry Andric     extern_type* to_end,
3514*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
35150b57cec5SDimitry Andric   const uint16_t* _frm     = reinterpret_cast<const uint16_t*>(frm);
35160b57cec5SDimitry Andric   const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
35170b57cec5SDimitry Andric   const uint16_t* _frm_nxt = _frm;
35180b57cec5SDimitry Andric   uint8_t* _to             = reinterpret_cast<uint8_t*>(to);
35190b57cec5SDimitry Andric   uint8_t* _to_end         = reinterpret_cast<uint8_t*>(to_end);
35200b57cec5SDimitry Andric   uint8_t* _to_nxt         = _to;
3521*cb14a3feSDimitry Andric   result r                 = ucs2_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
35220b57cec5SDimitry Andric   frm_nxt                  = frm + (_frm_nxt - _frm);
35230b57cec5SDimitry Andric   to_nxt                   = to + (_to_nxt - _to);
35240b57cec5SDimitry Andric   return r;
35250b57cec5SDimitry Andric }
35260b57cec5SDimitry Andric 
3527*cb14a3feSDimitry Andric __codecvt_utf16<char16_t, true>::result __codecvt_utf16<char16_t, true>::do_in(
3528*cb14a3feSDimitry Andric     state_type&,
3529*cb14a3feSDimitry Andric     const extern_type* frm,
3530*cb14a3feSDimitry Andric     const extern_type* frm_end,
3531*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
3532*cb14a3feSDimitry Andric     intern_type* to,
3533*cb14a3feSDimitry Andric     intern_type* to_end,
3534*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
35350b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
35360b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
35370b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
35380b57cec5SDimitry Andric   uint16_t* _to           = reinterpret_cast<uint16_t*>(to);
35390b57cec5SDimitry Andric   uint16_t* _to_end       = reinterpret_cast<uint16_t*>(to_end);
35400b57cec5SDimitry Andric   uint16_t* _to_nxt       = _to;
3541*cb14a3feSDimitry Andric   result r                = utf16le_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
35420b57cec5SDimitry Andric   frm_nxt                 = frm + (_frm_nxt - _frm);
35430b57cec5SDimitry Andric   to_nxt                  = to + (_to_nxt - _to);
35440b57cec5SDimitry Andric   return r;
35450b57cec5SDimitry Andric }
35460b57cec5SDimitry Andric 
35470b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::result
3548*cb14a3feSDimitry Andric __codecvt_utf16<char16_t, true>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
35490b57cec5SDimitry Andric   to_nxt = to;
35500b57cec5SDimitry Andric   return noconv;
35510b57cec5SDimitry Andric }
35520b57cec5SDimitry Andric 
3553*cb14a3feSDimitry Andric int __codecvt_utf16<char16_t, true>::do_encoding() const noexcept { return 0; }
35540b57cec5SDimitry Andric 
3555*cb14a3feSDimitry Andric bool __codecvt_utf16<char16_t, true>::do_always_noconv() const noexcept { return false; }
35560b57cec5SDimitry Andric 
3557*cb14a3feSDimitry Andric int __codecvt_utf16<char16_t, true>::do_length(
3558*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
35590b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
35600b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3561bdd1243dSDimitry Andric   return utf16le_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
35620b57cec5SDimitry Andric }
35630b57cec5SDimitry Andric 
356481ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3565*cb14a3feSDimitry Andric int __codecvt_utf16<char16_t, true>::do_max_length() const noexcept {
3566bdd1243dSDimitry Andric   if (__mode_ & consume_header)
35670b57cec5SDimitry Andric     return 4;
35680b57cec5SDimitry Andric   return 2;
35690b57cec5SDimitry Andric }
357081ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
35710b57cec5SDimitry Andric 
35720b57cec5SDimitry Andric // __codecvt_utf16<char32_t, false>
35730b57cec5SDimitry Andric 
3574*cb14a3feSDimitry Andric __codecvt_utf16<char32_t, false>::result __codecvt_utf16<char32_t, false>::do_out(
3575*cb14a3feSDimitry Andric     state_type&,
3576*cb14a3feSDimitry Andric     const intern_type* frm,
3577*cb14a3feSDimitry Andric     const intern_type* frm_end,
3578*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
3579*cb14a3feSDimitry Andric     extern_type* to,
3580*cb14a3feSDimitry Andric     extern_type* to_end,
3581*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
35820b57cec5SDimitry Andric   const uint32_t* _frm     = reinterpret_cast<const uint32_t*>(frm);
35830b57cec5SDimitry Andric   const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
35840b57cec5SDimitry Andric   const uint32_t* _frm_nxt = _frm;
35850b57cec5SDimitry Andric   uint8_t* _to             = reinterpret_cast<uint8_t*>(to);
35860b57cec5SDimitry Andric   uint8_t* _to_end         = reinterpret_cast<uint8_t*>(to_end);
35870b57cec5SDimitry Andric   uint8_t* _to_nxt         = _to;
3588*cb14a3feSDimitry Andric   result r                 = ucs4_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
35890b57cec5SDimitry Andric   frm_nxt                  = frm + (_frm_nxt - _frm);
35900b57cec5SDimitry Andric   to_nxt                   = to + (_to_nxt - _to);
35910b57cec5SDimitry Andric   return r;
35920b57cec5SDimitry Andric }
35930b57cec5SDimitry Andric 
3594*cb14a3feSDimitry Andric __codecvt_utf16<char32_t, false>::result __codecvt_utf16<char32_t, false>::do_in(
3595*cb14a3feSDimitry Andric     state_type&,
3596*cb14a3feSDimitry Andric     const extern_type* frm,
3597*cb14a3feSDimitry Andric     const extern_type* frm_end,
3598*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
3599*cb14a3feSDimitry Andric     intern_type* to,
3600*cb14a3feSDimitry Andric     intern_type* to_end,
3601*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
36020b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
36030b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
36040b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
36050b57cec5SDimitry Andric   uint32_t* _to           = reinterpret_cast<uint32_t*>(to);
36060b57cec5SDimitry Andric   uint32_t* _to_end       = reinterpret_cast<uint32_t*>(to_end);
36070b57cec5SDimitry Andric   uint32_t* _to_nxt       = _to;
3608*cb14a3feSDimitry Andric   result r                = utf16be_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
36090b57cec5SDimitry Andric   frm_nxt                 = frm + (_frm_nxt - _frm);
36100b57cec5SDimitry Andric   to_nxt                  = to + (_to_nxt - _to);
36110b57cec5SDimitry Andric   return r;
36120b57cec5SDimitry Andric }
36130b57cec5SDimitry Andric 
36140b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::result
3615*cb14a3feSDimitry Andric __codecvt_utf16<char32_t, false>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
36160b57cec5SDimitry Andric   to_nxt = to;
36170b57cec5SDimitry Andric   return noconv;
36180b57cec5SDimitry Andric }
36190b57cec5SDimitry Andric 
3620*cb14a3feSDimitry Andric int __codecvt_utf16<char32_t, false>::do_encoding() const noexcept { return 0; }
36210b57cec5SDimitry Andric 
3622*cb14a3feSDimitry Andric bool __codecvt_utf16<char32_t, false>::do_always_noconv() const noexcept { return false; }
36230b57cec5SDimitry Andric 
3624*cb14a3feSDimitry Andric int __codecvt_utf16<char32_t, false>::do_length(
3625*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
36260b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
36270b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3628bdd1243dSDimitry Andric   return utf16be_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
36290b57cec5SDimitry Andric }
36300b57cec5SDimitry Andric 
363181ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3632*cb14a3feSDimitry Andric int __codecvt_utf16<char32_t, false>::do_max_length() const noexcept {
3633bdd1243dSDimitry Andric   if (__mode_ & consume_header)
36340b57cec5SDimitry Andric     return 6;
36350b57cec5SDimitry Andric   return 4;
36360b57cec5SDimitry Andric }
363781ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
36380b57cec5SDimitry Andric 
36390b57cec5SDimitry Andric // __codecvt_utf16<char32_t, true>
36400b57cec5SDimitry Andric 
3641*cb14a3feSDimitry Andric __codecvt_utf16<char32_t, true>::result __codecvt_utf16<char32_t, true>::do_out(
3642*cb14a3feSDimitry Andric     state_type&,
3643*cb14a3feSDimitry Andric     const intern_type* frm,
3644*cb14a3feSDimitry Andric     const intern_type* frm_end,
3645*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
3646*cb14a3feSDimitry Andric     extern_type* to,
3647*cb14a3feSDimitry Andric     extern_type* to_end,
3648*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
36490b57cec5SDimitry Andric   const uint32_t* _frm     = reinterpret_cast<const uint32_t*>(frm);
36500b57cec5SDimitry Andric   const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
36510b57cec5SDimitry Andric   const uint32_t* _frm_nxt = _frm;
36520b57cec5SDimitry Andric   uint8_t* _to             = reinterpret_cast<uint8_t*>(to);
36530b57cec5SDimitry Andric   uint8_t* _to_end         = reinterpret_cast<uint8_t*>(to_end);
36540b57cec5SDimitry Andric   uint8_t* _to_nxt         = _to;
3655*cb14a3feSDimitry Andric   result r                 = ucs4_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
36560b57cec5SDimitry Andric   frm_nxt                  = frm + (_frm_nxt - _frm);
36570b57cec5SDimitry Andric   to_nxt                   = to + (_to_nxt - _to);
36580b57cec5SDimitry Andric   return r;
36590b57cec5SDimitry Andric }
36600b57cec5SDimitry Andric 
3661*cb14a3feSDimitry Andric __codecvt_utf16<char32_t, true>::result __codecvt_utf16<char32_t, true>::do_in(
3662*cb14a3feSDimitry Andric     state_type&,
3663*cb14a3feSDimitry Andric     const extern_type* frm,
3664*cb14a3feSDimitry Andric     const extern_type* frm_end,
3665*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
3666*cb14a3feSDimitry Andric     intern_type* to,
3667*cb14a3feSDimitry Andric     intern_type* to_end,
3668*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
36690b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
36700b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
36710b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
36720b57cec5SDimitry Andric   uint32_t* _to           = reinterpret_cast<uint32_t*>(to);
36730b57cec5SDimitry Andric   uint32_t* _to_end       = reinterpret_cast<uint32_t*>(to_end);
36740b57cec5SDimitry Andric   uint32_t* _to_nxt       = _to;
3675*cb14a3feSDimitry Andric   result r                = utf16le_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
36760b57cec5SDimitry Andric   frm_nxt                 = frm + (_frm_nxt - _frm);
36770b57cec5SDimitry Andric   to_nxt                  = to + (_to_nxt - _to);
36780b57cec5SDimitry Andric   return r;
36790b57cec5SDimitry Andric }
36800b57cec5SDimitry Andric 
36810b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::result
3682*cb14a3feSDimitry Andric __codecvt_utf16<char32_t, true>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
36830b57cec5SDimitry Andric   to_nxt = to;
36840b57cec5SDimitry Andric   return noconv;
36850b57cec5SDimitry Andric }
36860b57cec5SDimitry Andric 
3687*cb14a3feSDimitry Andric int __codecvt_utf16<char32_t, true>::do_encoding() const noexcept { return 0; }
36880b57cec5SDimitry Andric 
3689*cb14a3feSDimitry Andric bool __codecvt_utf16<char32_t, true>::do_always_noconv() const noexcept { return false; }
36900b57cec5SDimitry Andric 
3691*cb14a3feSDimitry Andric int __codecvt_utf16<char32_t, true>::do_length(
3692*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
36930b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
36940b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3695bdd1243dSDimitry Andric   return utf16le_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
36960b57cec5SDimitry Andric }
36970b57cec5SDimitry Andric 
369881ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3699*cb14a3feSDimitry Andric int __codecvt_utf16<char32_t, true>::do_max_length() const noexcept {
3700bdd1243dSDimitry Andric   if (__mode_ & consume_header)
37010b57cec5SDimitry Andric     return 6;
37020b57cec5SDimitry Andric   return 4;
37030b57cec5SDimitry Andric }
370481ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
37050b57cec5SDimitry Andric 
37060b57cec5SDimitry Andric // __codecvt_utf8_utf16<wchar_t>
37070b57cec5SDimitry Andric 
3708349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3709*cb14a3feSDimitry Andric __codecvt_utf8_utf16<wchar_t>::result __codecvt_utf8_utf16<wchar_t>::do_out(
3710*cb14a3feSDimitry Andric     state_type&,
3711*cb14a3feSDimitry Andric     const intern_type* frm,
3712*cb14a3feSDimitry Andric     const intern_type* frm_end,
3713*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
3714*cb14a3feSDimitry Andric     extern_type* to,
3715*cb14a3feSDimitry Andric     extern_type* to_end,
3716*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
3717349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3718349cc55cSDimitry Andric   const uint16_t* _frm     = reinterpret_cast<const uint16_t*>(frm);
3719349cc55cSDimitry Andric   const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3720349cc55cSDimitry Andric   const uint16_t* _frm_nxt = _frm;
3721349cc55cSDimitry Andric #  else
37220b57cec5SDimitry Andric   const uint32_t* _frm     = reinterpret_cast<const uint32_t*>(frm);
37230b57cec5SDimitry Andric   const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
37240b57cec5SDimitry Andric   const uint32_t* _frm_nxt = _frm;
3725349cc55cSDimitry Andric #  endif
37260b57cec5SDimitry Andric   uint8_t* _to     = reinterpret_cast<uint8_t*>(to);
37270b57cec5SDimitry Andric   uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
37280b57cec5SDimitry Andric   uint8_t* _to_nxt = _to;
3729*cb14a3feSDimitry Andric   result r         = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
37300b57cec5SDimitry Andric   frm_nxt          = frm + (_frm_nxt - _frm);
37310b57cec5SDimitry Andric   to_nxt           = to + (_to_nxt - _to);
37320b57cec5SDimitry Andric   return r;
37330b57cec5SDimitry Andric }
37340b57cec5SDimitry Andric 
3735*cb14a3feSDimitry Andric __codecvt_utf8_utf16<wchar_t>::result __codecvt_utf8_utf16<wchar_t>::do_in(
3736*cb14a3feSDimitry Andric     state_type&,
3737*cb14a3feSDimitry Andric     const extern_type* frm,
3738*cb14a3feSDimitry Andric     const extern_type* frm_end,
3739*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
3740*cb14a3feSDimitry Andric     intern_type* to,
3741*cb14a3feSDimitry Andric     intern_type* to_end,
3742*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
37430b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
37440b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
37450b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
3746349cc55cSDimitry Andric #  if defined(_LIBCPP_SHORT_WCHAR)
3747349cc55cSDimitry Andric   uint16_t* _to     = reinterpret_cast<uint16_t*>(to);
3748349cc55cSDimitry Andric   uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3749349cc55cSDimitry Andric   uint16_t* _to_nxt = _to;
3750349cc55cSDimitry Andric #  else
37510b57cec5SDimitry Andric   uint32_t* _to     = reinterpret_cast<uint32_t*>(to);
37520b57cec5SDimitry Andric   uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
37530b57cec5SDimitry Andric   uint32_t* _to_nxt = _to;
3754349cc55cSDimitry Andric #  endif
3755*cb14a3feSDimitry Andric   result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
37560b57cec5SDimitry Andric   frm_nxt  = frm + (_frm_nxt - _frm);
37570b57cec5SDimitry Andric   to_nxt   = to + (_to_nxt - _to);
37580b57cec5SDimitry Andric   return r;
37590b57cec5SDimitry Andric }
37600b57cec5SDimitry Andric 
37610b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::result
3762*cb14a3feSDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
37630b57cec5SDimitry Andric   to_nxt = to;
37640b57cec5SDimitry Andric   return noconv;
37650b57cec5SDimitry Andric }
37660b57cec5SDimitry Andric 
3767*cb14a3feSDimitry Andric int __codecvt_utf8_utf16<wchar_t>::do_encoding() const noexcept { return 0; }
37680b57cec5SDimitry Andric 
3769*cb14a3feSDimitry Andric bool __codecvt_utf8_utf16<wchar_t>::do_always_noconv() const noexcept { return false; }
37700b57cec5SDimitry Andric 
3771*cb14a3feSDimitry Andric int __codecvt_utf8_utf16<wchar_t>::do_length(
3772*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
37730b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
37740b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3775bdd1243dSDimitry Andric   return utf8_to_utf16_length(_frm, _frm_end, mx, __maxcode_, __mode_);
37760b57cec5SDimitry Andric }
37770b57cec5SDimitry Andric 
3778*cb14a3feSDimitry Andric int __codecvt_utf8_utf16<wchar_t>::do_max_length() const noexcept {
3779bdd1243dSDimitry Andric   if (__mode_ & consume_header)
37800b57cec5SDimitry Andric     return 7;
37810b57cec5SDimitry Andric   return 4;
37820b57cec5SDimitry Andric }
3783349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
37840b57cec5SDimitry Andric 
37850b57cec5SDimitry Andric // __codecvt_utf8_utf16<char16_t>
37860b57cec5SDimitry Andric 
3787*cb14a3feSDimitry Andric __codecvt_utf8_utf16<char16_t>::result __codecvt_utf8_utf16<char16_t>::do_out(
3788*cb14a3feSDimitry Andric     state_type&,
3789*cb14a3feSDimitry Andric     const intern_type* frm,
3790*cb14a3feSDimitry Andric     const intern_type* frm_end,
3791*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
3792*cb14a3feSDimitry Andric     extern_type* to,
3793*cb14a3feSDimitry Andric     extern_type* to_end,
3794*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
37950b57cec5SDimitry Andric   const uint16_t* _frm     = reinterpret_cast<const uint16_t*>(frm);
37960b57cec5SDimitry Andric   const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
37970b57cec5SDimitry Andric   const uint16_t* _frm_nxt = _frm;
37980b57cec5SDimitry Andric   uint8_t* _to             = reinterpret_cast<uint8_t*>(to);
37990b57cec5SDimitry Andric   uint8_t* _to_end         = reinterpret_cast<uint8_t*>(to_end);
38000b57cec5SDimitry Andric   uint8_t* _to_nxt         = _to;
3801*cb14a3feSDimitry Andric   result r                 = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
38020b57cec5SDimitry Andric   frm_nxt                  = frm + (_frm_nxt - _frm);
38030b57cec5SDimitry Andric   to_nxt                   = to + (_to_nxt - _to);
38040b57cec5SDimitry Andric   return r;
38050b57cec5SDimitry Andric }
38060b57cec5SDimitry Andric 
3807*cb14a3feSDimitry Andric __codecvt_utf8_utf16<char16_t>::result __codecvt_utf8_utf16<char16_t>::do_in(
3808*cb14a3feSDimitry Andric     state_type&,
3809*cb14a3feSDimitry Andric     const extern_type* frm,
3810*cb14a3feSDimitry Andric     const extern_type* frm_end,
3811*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
3812*cb14a3feSDimitry Andric     intern_type* to,
3813*cb14a3feSDimitry Andric     intern_type* to_end,
3814*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
38150b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
38160b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
38170b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
38180b57cec5SDimitry Andric   uint16_t* _to           = reinterpret_cast<uint16_t*>(to);
38190b57cec5SDimitry Andric   uint16_t* _to_end       = reinterpret_cast<uint16_t*>(to_end);
38200b57cec5SDimitry Andric   uint16_t* _to_nxt       = _to;
3821*cb14a3feSDimitry Andric   result r                = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
38220b57cec5SDimitry Andric   frm_nxt                 = frm + (_frm_nxt - _frm);
38230b57cec5SDimitry Andric   to_nxt                  = to + (_to_nxt - _to);
38240b57cec5SDimitry Andric   return r;
38250b57cec5SDimitry Andric }
38260b57cec5SDimitry Andric 
38270b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::result
3828*cb14a3feSDimitry Andric __codecvt_utf8_utf16<char16_t>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
38290b57cec5SDimitry Andric   to_nxt = to;
38300b57cec5SDimitry Andric   return noconv;
38310b57cec5SDimitry Andric }
38320b57cec5SDimitry Andric 
3833*cb14a3feSDimitry Andric int __codecvt_utf8_utf16<char16_t>::do_encoding() const noexcept { return 0; }
38340b57cec5SDimitry Andric 
3835*cb14a3feSDimitry Andric bool __codecvt_utf8_utf16<char16_t>::do_always_noconv() const noexcept { return false; }
38360b57cec5SDimitry Andric 
3837*cb14a3feSDimitry Andric int __codecvt_utf8_utf16<char16_t>::do_length(
3838*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
38390b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
38400b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3841bdd1243dSDimitry Andric   return utf8_to_utf16_length(_frm, _frm_end, mx, __maxcode_, __mode_);
38420b57cec5SDimitry Andric }
38430b57cec5SDimitry Andric 
384481ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3845*cb14a3feSDimitry Andric int __codecvt_utf8_utf16<char16_t>::do_max_length() const noexcept {
3846bdd1243dSDimitry Andric   if (__mode_ & consume_header)
38470b57cec5SDimitry Andric     return 7;
38480b57cec5SDimitry Andric   return 4;
38490b57cec5SDimitry Andric }
385081ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
38510b57cec5SDimitry Andric 
38520b57cec5SDimitry Andric // __codecvt_utf8_utf16<char32_t>
38530b57cec5SDimitry Andric 
3854*cb14a3feSDimitry Andric __codecvt_utf8_utf16<char32_t>::result __codecvt_utf8_utf16<char32_t>::do_out(
3855*cb14a3feSDimitry Andric     state_type&,
3856*cb14a3feSDimitry Andric     const intern_type* frm,
3857*cb14a3feSDimitry Andric     const intern_type* frm_end,
3858*cb14a3feSDimitry Andric     const intern_type*& frm_nxt,
3859*cb14a3feSDimitry Andric     extern_type* to,
3860*cb14a3feSDimitry Andric     extern_type* to_end,
3861*cb14a3feSDimitry Andric     extern_type*& to_nxt) const {
38620b57cec5SDimitry Andric   const uint32_t* _frm     = reinterpret_cast<const uint32_t*>(frm);
38630b57cec5SDimitry Andric   const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
38640b57cec5SDimitry Andric   const uint32_t* _frm_nxt = _frm;
38650b57cec5SDimitry Andric   uint8_t* _to             = reinterpret_cast<uint8_t*>(to);
38660b57cec5SDimitry Andric   uint8_t* _to_end         = reinterpret_cast<uint8_t*>(to_end);
38670b57cec5SDimitry Andric   uint8_t* _to_nxt         = _to;
3868*cb14a3feSDimitry Andric   result r                 = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
38690b57cec5SDimitry Andric   frm_nxt                  = frm + (_frm_nxt - _frm);
38700b57cec5SDimitry Andric   to_nxt                   = to + (_to_nxt - _to);
38710b57cec5SDimitry Andric   return r;
38720b57cec5SDimitry Andric }
38730b57cec5SDimitry Andric 
3874*cb14a3feSDimitry Andric __codecvt_utf8_utf16<char32_t>::result __codecvt_utf8_utf16<char32_t>::do_in(
3875*cb14a3feSDimitry Andric     state_type&,
3876*cb14a3feSDimitry Andric     const extern_type* frm,
3877*cb14a3feSDimitry Andric     const extern_type* frm_end,
3878*cb14a3feSDimitry Andric     const extern_type*& frm_nxt,
3879*cb14a3feSDimitry Andric     intern_type* to,
3880*cb14a3feSDimitry Andric     intern_type* to_end,
3881*cb14a3feSDimitry Andric     intern_type*& to_nxt) const {
38820b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
38830b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
38840b57cec5SDimitry Andric   const uint8_t* _frm_nxt = _frm;
38850b57cec5SDimitry Andric   uint32_t* _to           = reinterpret_cast<uint32_t*>(to);
38860b57cec5SDimitry Andric   uint32_t* _to_end       = reinterpret_cast<uint32_t*>(to_end);
38870b57cec5SDimitry Andric   uint32_t* _to_nxt       = _to;
3888*cb14a3feSDimitry Andric   result r                = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt, __maxcode_, __mode_);
38890b57cec5SDimitry Andric   frm_nxt                 = frm + (_frm_nxt - _frm);
38900b57cec5SDimitry Andric   to_nxt                  = to + (_to_nxt - _to);
38910b57cec5SDimitry Andric   return r;
38920b57cec5SDimitry Andric }
38930b57cec5SDimitry Andric 
38940b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::result
3895*cb14a3feSDimitry Andric __codecvt_utf8_utf16<char32_t>::do_unshift(state_type&, extern_type* to, extern_type*, extern_type*& to_nxt) const {
38960b57cec5SDimitry Andric   to_nxt = to;
38970b57cec5SDimitry Andric   return noconv;
38980b57cec5SDimitry Andric }
38990b57cec5SDimitry Andric 
3900*cb14a3feSDimitry Andric int __codecvt_utf8_utf16<char32_t>::do_encoding() const noexcept { return 0; }
39010b57cec5SDimitry Andric 
3902*cb14a3feSDimitry Andric bool __codecvt_utf8_utf16<char32_t>::do_always_noconv() const noexcept { return false; }
39030b57cec5SDimitry Andric 
3904*cb14a3feSDimitry Andric int __codecvt_utf8_utf16<char32_t>::do_length(
3905*cb14a3feSDimitry Andric     state_type&, const extern_type* frm, const extern_type* frm_end, size_t mx) const {
39060b57cec5SDimitry Andric   const uint8_t* _frm     = reinterpret_cast<const uint8_t*>(frm);
39070b57cec5SDimitry Andric   const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3908bdd1243dSDimitry Andric   return utf8_to_utf16_length(_frm, _frm_end, mx, __maxcode_, __mode_);
39090b57cec5SDimitry Andric }
39100b57cec5SDimitry Andric 
391181ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3912*cb14a3feSDimitry Andric int __codecvt_utf8_utf16<char32_t>::do_max_length() const noexcept {
3913bdd1243dSDimitry Andric   if (__mode_ & consume_header)
39140b57cec5SDimitry Andric     return 7;
39150b57cec5SDimitry Andric   return 4;
39160b57cec5SDimitry Andric }
391781ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
39180b57cec5SDimitry Andric 
39190b57cec5SDimitry Andric // __narrow_to_utf8<16>
39200b57cec5SDimitry Andric 
3921*cb14a3feSDimitry Andric __narrow_to_utf8<16>::~__narrow_to_utf8() {}
39220b57cec5SDimitry Andric 
39230b57cec5SDimitry Andric // __narrow_to_utf8<32>
39240b57cec5SDimitry Andric 
3925*cb14a3feSDimitry Andric __narrow_to_utf8<32>::~__narrow_to_utf8() {}
39260b57cec5SDimitry Andric 
39270b57cec5SDimitry Andric // __widen_from_utf8<16>
39280b57cec5SDimitry Andric 
3929*cb14a3feSDimitry Andric __widen_from_utf8<16>::~__widen_from_utf8() {}
39300b57cec5SDimitry Andric 
39310b57cec5SDimitry Andric // __widen_from_utf8<32>
39320b57cec5SDimitry Andric 
3933*cb14a3feSDimitry Andric __widen_from_utf8<32>::~__widen_from_utf8() {}
39340b57cec5SDimitry Andric 
3935349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3936*cb14a3feSDimitry Andric static bool checked_string_to_wchar_convert(wchar_t& dest, const char* ptr, locale_t loc) {
39370b57cec5SDimitry Andric   if (*ptr == '\0')
39380b57cec5SDimitry Andric     return false;
39390b57cec5SDimitry Andric   mbstate_t mb = {};
39400b57cec5SDimitry Andric   wchar_t out;
39410b57cec5SDimitry Andric   size_t ret = __libcpp_mbrtowc_l(&out, ptr, strlen(ptr), &mb, loc);
39420b57cec5SDimitry Andric   if (ret == static_cast<size_t>(-1) || ret == static_cast<size_t>(-2)) {
39430b57cec5SDimitry Andric     return false;
39440b57cec5SDimitry Andric   }
39450b57cec5SDimitry Andric   dest = out;
39460b57cec5SDimitry Andric   return true;
39470b57cec5SDimitry Andric }
3948349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
3949349cc55cSDimitry Andric 
3950349cc55cSDimitry Andric #ifdef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3951349cc55cSDimitry Andric static bool is_narrow_non_breaking_space(const char* ptr) {
3952349cc55cSDimitry Andric   // https://www.fileformat.info/info/unicode/char/202f/index.htm
3953349cc55cSDimitry Andric   return ptr[0] == '\xe2' && ptr[1] == '\x80' && ptr[2] == '\xaf';
3954349cc55cSDimitry Andric }
3955349cc55cSDimitry Andric 
3956349cc55cSDimitry Andric static bool is_non_breaking_space(const char* ptr) {
3957349cc55cSDimitry Andric   // https://www.fileformat.info/info/unicode/char/0a/index.htm
3958349cc55cSDimitry Andric   return ptr[0] == '\xc2' && ptr[1] == '\xa0';
3959349cc55cSDimitry Andric }
3960349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
39610b57cec5SDimitry Andric 
3962*cb14a3feSDimitry Andric static bool checked_string_to_char_convert(char& dest, const char* ptr, locale_t __loc) {
39630b57cec5SDimitry Andric   if (*ptr == '\0')
39640b57cec5SDimitry Andric     return false;
39650b57cec5SDimitry Andric   if (!ptr[1]) {
39660b57cec5SDimitry Andric     dest = *ptr;
39670b57cec5SDimitry Andric     return true;
39680b57cec5SDimitry Andric   }
3969349cc55cSDimitry Andric 
3970349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
39710b57cec5SDimitry Andric   // First convert the MBS into a wide char then attempt to narrow it using
39720b57cec5SDimitry Andric   // wctob_l.
39730b57cec5SDimitry Andric   wchar_t wout;
39740b57cec5SDimitry Andric   if (!checked_string_to_wchar_convert(wout, ptr, __loc))
39750b57cec5SDimitry Andric     return false;
39760b57cec5SDimitry Andric   int res;
39770b57cec5SDimitry Andric   if ((res = __libcpp_wctob_l(wout, __loc)) != char_traits<char>::eof()) {
39780b57cec5SDimitry Andric     dest = res;
39790b57cec5SDimitry Andric     return true;
39800b57cec5SDimitry Andric   }
3981349cc55cSDimitry Andric   // FIXME: Work around specific multibyte sequences that we can reasonably
39820b57cec5SDimitry Andric   // translate into a different single byte.
39830b57cec5SDimitry Andric   switch (wout) {
39840b57cec5SDimitry Andric   case L'\u202F': // narrow non-breaking space
39850b57cec5SDimitry Andric   case L'\u00A0': // non-breaking space
39860b57cec5SDimitry Andric     dest = ' ';
39870b57cec5SDimitry Andric     return true;
39880b57cec5SDimitry Andric   default:
39890b57cec5SDimitry Andric     return false;
39900b57cec5SDimitry Andric   }
3991349cc55cSDimitry Andric #else  // _LIBCPP_HAS_NO_WIDE_CHARACTERS
3992349cc55cSDimitry Andric   // FIXME: Work around specific multibyte sequences that we can reasonably
3993349cc55cSDimitry Andric   // translate into a different single byte.
3994349cc55cSDimitry Andric   if (is_narrow_non_breaking_space(ptr) || is_non_breaking_space(ptr)) {
3995349cc55cSDimitry Andric     dest = ' ';
3996349cc55cSDimitry Andric     return true;
3997349cc55cSDimitry Andric   }
3998349cc55cSDimitry Andric 
3999349cc55cSDimitry Andric   return false;
4000349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
400181ad6265SDimitry Andric   __libcpp_unreachable();
40020b57cec5SDimitry Andric }
40030b57cec5SDimitry Andric 
40040b57cec5SDimitry Andric // numpunct<char> && numpunct<wchar_t>
40050b57cec5SDimitry Andric 
40065f757f3fSDimitry Andric constinit locale::id numpunct<char>::id;
4007349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
40085f757f3fSDimitry Andric constinit locale::id numpunct<wchar_t>::id;
4009349cc55cSDimitry Andric #endif
40100b57cec5SDimitry Andric 
4011*cb14a3feSDimitry Andric numpunct<char>::numpunct(size_t refs) : locale::facet(refs), __decimal_point_('.'), __thousands_sep_(',') {}
40120b57cec5SDimitry Andric 
4013349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4014*cb14a3feSDimitry Andric numpunct<wchar_t>::numpunct(size_t refs) : locale::facet(refs), __decimal_point_(L'.'), __thousands_sep_(L',') {}
4015349cc55cSDimitry Andric #endif
40160b57cec5SDimitry Andric 
4017*cb14a3feSDimitry Andric numpunct<char>::~numpunct() {}
40180b57cec5SDimitry Andric 
4019349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4020*cb14a3feSDimitry Andric numpunct<wchar_t>::~numpunct() {}
4021349cc55cSDimitry Andric #endif
40220b57cec5SDimitry Andric 
40230b57cec5SDimitry Andric char numpunct< char >::do_decimal_point() const { return __decimal_point_; }
4024349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
40250b57cec5SDimitry Andric wchar_t numpunct<wchar_t>::do_decimal_point() const { return __decimal_point_; }
4026349cc55cSDimitry Andric #endif
40270b57cec5SDimitry Andric 
40280b57cec5SDimitry Andric char numpunct< char >::do_thousands_sep() const { return __thousands_sep_; }
4029349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
40300b57cec5SDimitry Andric wchar_t numpunct<wchar_t>::do_thousands_sep() const { return __thousands_sep_; }
4031349cc55cSDimitry Andric #endif
40320b57cec5SDimitry Andric 
40330b57cec5SDimitry Andric string numpunct< char >::do_grouping() const { return __grouping_; }
4034349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
40350b57cec5SDimitry Andric string numpunct<wchar_t>::do_grouping() const { return __grouping_; }
4036349cc55cSDimitry Andric #endif
40370b57cec5SDimitry Andric 
40380b57cec5SDimitry Andric string numpunct< char >::do_truename() const { return "true"; }
4039349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
40400b57cec5SDimitry Andric wstring numpunct<wchar_t>::do_truename() const { return L"true"; }
4041349cc55cSDimitry Andric #endif
40420b57cec5SDimitry Andric 
40430b57cec5SDimitry Andric string numpunct< char >::do_falsename() const { return "false"; }
4044349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
40450b57cec5SDimitry Andric wstring numpunct<wchar_t>::do_falsename() const { return L"false"; }
4046349cc55cSDimitry Andric #endif
40470b57cec5SDimitry Andric 
40480b57cec5SDimitry Andric // numpunct_byname<char>
40490b57cec5SDimitry Andric 
4050*cb14a3feSDimitry Andric numpunct_byname<char>::numpunct_byname(const char* nm, size_t refs) : numpunct<char>(refs) { __init(nm); }
40510b57cec5SDimitry Andric 
4052*cb14a3feSDimitry Andric numpunct_byname<char>::numpunct_byname(const string& nm, size_t refs) : numpunct<char>(refs) { __init(nm.c_str()); }
40530b57cec5SDimitry Andric 
4054*cb14a3feSDimitry Andric numpunct_byname<char>::~numpunct_byname() {}
40550b57cec5SDimitry Andric 
4056*cb14a3feSDimitry Andric void numpunct_byname<char>::__init(const char* nm) {
4057349cc55cSDimitry Andric   typedef numpunct<char> base;
4058*cb14a3feSDimitry Andric   if (strcmp(nm, "C") != 0) {
40590b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
40600b57cec5SDimitry Andric     if (!loc)
4061*cb14a3feSDimitry Andric       __throw_runtime_error(
4062*cb14a3feSDimitry Andric           ("numpunct_byname<char>::numpunct_byname"
4063*cb14a3feSDimitry Andric            " failed to construct for " +
4064*cb14a3feSDimitry Andric            string(nm))
4065*cb14a3feSDimitry Andric               .c_str());
40660b57cec5SDimitry Andric 
40670b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
4068*cb14a3feSDimitry Andric     if (!checked_string_to_char_convert(__decimal_point_, lc->decimal_point, loc.get()))
4069349cc55cSDimitry Andric       __decimal_point_ = base::do_decimal_point();
4070*cb14a3feSDimitry Andric     if (!checked_string_to_char_convert(__thousands_sep_, lc->thousands_sep, loc.get()))
4071349cc55cSDimitry Andric       __thousands_sep_ = base::do_thousands_sep();
40720b57cec5SDimitry Andric     __grouping_ = lc->grouping;
40730b57cec5SDimitry Andric     // localization for truename and falsename is not available
40740b57cec5SDimitry Andric   }
40750b57cec5SDimitry Andric }
40760b57cec5SDimitry Andric 
40770b57cec5SDimitry Andric // numpunct_byname<wchar_t>
40780b57cec5SDimitry Andric 
4079349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4080*cb14a3feSDimitry Andric numpunct_byname<wchar_t>::numpunct_byname(const char* nm, size_t refs) : numpunct<wchar_t>(refs) { __init(nm); }
40810b57cec5SDimitry Andric 
4082*cb14a3feSDimitry Andric numpunct_byname<wchar_t>::numpunct_byname(const string& nm, size_t refs) : numpunct<wchar_t>(refs) {
40830b57cec5SDimitry Andric   __init(nm.c_str());
40840b57cec5SDimitry Andric }
40850b57cec5SDimitry Andric 
4086*cb14a3feSDimitry Andric numpunct_byname<wchar_t>::~numpunct_byname() {}
40870b57cec5SDimitry Andric 
4088*cb14a3feSDimitry Andric void numpunct_byname<wchar_t>::__init(const char* nm) {
4089*cb14a3feSDimitry Andric   if (strcmp(nm, "C") != 0) {
40900b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
40910b57cec5SDimitry Andric     if (!loc)
4092*cb14a3feSDimitry Andric       __throw_runtime_error(
4093*cb14a3feSDimitry Andric           ("numpunct_byname<wchar_t>::numpunct_byname"
4094*cb14a3feSDimitry Andric            " failed to construct for " +
4095*cb14a3feSDimitry Andric            string(nm))
4096*cb14a3feSDimitry Andric               .c_str());
40970b57cec5SDimitry Andric 
40980b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
4099*cb14a3feSDimitry Andric     checked_string_to_wchar_convert(__decimal_point_, lc->decimal_point, loc.get());
4100*cb14a3feSDimitry Andric     checked_string_to_wchar_convert(__thousands_sep_, lc->thousands_sep, loc.get());
41010b57cec5SDimitry Andric     __grouping_ = lc->grouping;
41020b57cec5SDimitry Andric     // localization for truename and falsename is not available
41030b57cec5SDimitry Andric   }
41040b57cec5SDimitry Andric }
4105349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
41060b57cec5SDimitry Andric 
41070b57cec5SDimitry Andric // num_get helpers
41080b57cec5SDimitry Andric 
4109*cb14a3feSDimitry Andric int __num_get_base::__get_base(ios_base& iob) {
41100b57cec5SDimitry Andric   ios_base::fmtflags __basefield = iob.flags() & ios_base::basefield;
41110b57cec5SDimitry Andric   if (__basefield == ios_base::oct)
41120b57cec5SDimitry Andric     return 8;
41130b57cec5SDimitry Andric   else if (__basefield == ios_base::hex)
41140b57cec5SDimitry Andric     return 16;
41150b57cec5SDimitry Andric   else if (__basefield == 0)
41160b57cec5SDimitry Andric     return 0;
41170b57cec5SDimitry Andric   return 10;
41180b57cec5SDimitry Andric }
41190b57cec5SDimitry Andric 
41200b57cec5SDimitry Andric const char __num_get_base::__src[33] = "0123456789abcdefABCDEFxX+-pPiInN";
41210b57cec5SDimitry Andric 
4122*cb14a3feSDimitry Andric void __check_grouping(const string& __grouping, unsigned* __g, unsigned* __g_end, ios_base::iostate& __err) {
41230b57cec5SDimitry Andric   //  if the grouping pattern is empty _or_ there are no grouping bits, then do nothing
41240b57cec5SDimitry Andric   //  we always have at least a single entry in [__g, __g_end); the end of the input sequence
4125*cb14a3feSDimitry Andric   if (__grouping.size() != 0 && __g_end - __g > 1) {
41260b57cec5SDimitry Andric     reverse(__g, __g_end);
41270b57cec5SDimitry Andric     const char* __ig = __grouping.data();
41280b57cec5SDimitry Andric     const char* __eg = __ig + __grouping.size();
4129*cb14a3feSDimitry Andric     for (unsigned* __r = __g; __r < __g_end - 1; ++__r) {
4130*cb14a3feSDimitry Andric       if (0 < *__ig && *__ig < numeric_limits<char>::max()) {
4131*cb14a3feSDimitry Andric         if (static_cast<unsigned>(*__ig) != *__r) {
41320b57cec5SDimitry Andric           __err = ios_base::failbit;
41330b57cec5SDimitry Andric           return;
41340b57cec5SDimitry Andric         }
41350b57cec5SDimitry Andric       }
41360b57cec5SDimitry Andric       if (__eg - __ig > 1)
41370b57cec5SDimitry Andric         ++__ig;
41380b57cec5SDimitry Andric     }
4139*cb14a3feSDimitry Andric     if (0 < *__ig && *__ig < numeric_limits<char>::max()) {
41400b57cec5SDimitry Andric       if (static_cast<unsigned>(*__ig) < __g_end[-1] || __g_end[-1] == 0)
41410b57cec5SDimitry Andric         __err = ios_base::failbit;
41420b57cec5SDimitry Andric     }
41430b57cec5SDimitry Andric   }
41440b57cec5SDimitry Andric }
41450b57cec5SDimitry Andric 
4146*cb14a3feSDimitry Andric void __num_put_base::__format_int(char* __fmtp, const char* __len, bool __signd, ios_base::fmtflags __flags) {
4147*cb14a3feSDimitry Andric   if ((__flags & ios_base::showpos) && (__flags & ios_base::basefield) != ios_base::oct &&
4148*cb14a3feSDimitry Andric       (__flags & ios_base::basefield) != ios_base::hex && __signd)
41490b57cec5SDimitry Andric     *__fmtp++ = '+';
41500b57cec5SDimitry Andric   if (__flags & ios_base::showbase)
41510b57cec5SDimitry Andric     *__fmtp++ = '#';
41520b57cec5SDimitry Andric   while (*__len)
41530b57cec5SDimitry Andric     *__fmtp++ = *__len++;
41540b57cec5SDimitry Andric   if ((__flags & ios_base::basefield) == ios_base::oct)
41550b57cec5SDimitry Andric     *__fmtp = 'o';
4156*cb14a3feSDimitry Andric   else if ((__flags & ios_base::basefield) == ios_base::hex) {
41570b57cec5SDimitry Andric     if (__flags & ios_base::uppercase)
41580b57cec5SDimitry Andric       *__fmtp = 'X';
41590b57cec5SDimitry Andric     else
41600b57cec5SDimitry Andric       *__fmtp = 'x';
4161*cb14a3feSDimitry Andric   } else if (__signd)
41620b57cec5SDimitry Andric     *__fmtp = 'd';
41630b57cec5SDimitry Andric   else
41640b57cec5SDimitry Andric     *__fmtp = 'u';
41650b57cec5SDimitry Andric }
41660b57cec5SDimitry Andric 
4167*cb14a3feSDimitry Andric bool __num_put_base::__format_float(char* __fmtp, const char* __len, ios_base::fmtflags __flags) {
41680b57cec5SDimitry Andric   bool specify_precision = true;
41690b57cec5SDimitry Andric   if (__flags & ios_base::showpos)
41700b57cec5SDimitry Andric     *__fmtp++ = '+';
41710b57cec5SDimitry Andric   if (__flags & ios_base::showpoint)
41720b57cec5SDimitry Andric     *__fmtp++ = '#';
41730b57cec5SDimitry Andric   ios_base::fmtflags floatfield = __flags & ios_base::floatfield;
41740b57cec5SDimitry Andric   bool uppercase                = (__flags & ios_base::uppercase) != 0;
41750b57cec5SDimitry Andric   if (floatfield == (ios_base::fixed | ios_base::scientific))
41760b57cec5SDimitry Andric     specify_precision = false;
4177*cb14a3feSDimitry Andric   else {
41780b57cec5SDimitry Andric     *__fmtp++ = '.';
41790b57cec5SDimitry Andric     *__fmtp++ = '*';
41800b57cec5SDimitry Andric   }
41810b57cec5SDimitry Andric   while (*__len)
41820b57cec5SDimitry Andric     *__fmtp++ = *__len++;
4183*cb14a3feSDimitry Andric   if (floatfield == ios_base::fixed) {
41840b57cec5SDimitry Andric     if (uppercase)
41850b57cec5SDimitry Andric       *__fmtp = 'F';
41860b57cec5SDimitry Andric     else
41870b57cec5SDimitry Andric       *__fmtp = 'f';
4188*cb14a3feSDimitry Andric   } else if (floatfield == ios_base::scientific) {
41890b57cec5SDimitry Andric     if (uppercase)
41900b57cec5SDimitry Andric       *__fmtp = 'E';
41910b57cec5SDimitry Andric     else
41920b57cec5SDimitry Andric       *__fmtp = 'e';
4193*cb14a3feSDimitry Andric   } else if (floatfield == (ios_base::fixed | ios_base::scientific)) {
41940b57cec5SDimitry Andric     if (uppercase)
41950b57cec5SDimitry Andric       *__fmtp = 'A';
41960b57cec5SDimitry Andric     else
41970b57cec5SDimitry Andric       *__fmtp = 'a';
4198*cb14a3feSDimitry Andric   } else {
41990b57cec5SDimitry Andric     if (uppercase)
42000b57cec5SDimitry Andric       *__fmtp = 'G';
42010b57cec5SDimitry Andric     else
42020b57cec5SDimitry Andric       *__fmtp = 'g';
42030b57cec5SDimitry Andric   }
42040b57cec5SDimitry Andric   return specify_precision;
42050b57cec5SDimitry Andric }
42060b57cec5SDimitry Andric 
4207*cb14a3feSDimitry Andric char* __num_put_base::__identify_padding(char* __nb, char* __ne, const ios_base& __iob) {
4208*cb14a3feSDimitry Andric   switch (__iob.flags() & ios_base::adjustfield) {
42090b57cec5SDimitry Andric   case ios_base::internal:
42100b57cec5SDimitry Andric     if (__nb[0] == '-' || __nb[0] == '+')
42110b57cec5SDimitry Andric       return __nb + 1;
4212*cb14a3feSDimitry Andric     if (__ne - __nb >= 2 && __nb[0] == '0' && (__nb[1] == 'x' || __nb[1] == 'X'))
42130b57cec5SDimitry Andric       return __nb + 2;
42140b57cec5SDimitry Andric     break;
42150b57cec5SDimitry Andric   case ios_base::left:
42160b57cec5SDimitry Andric     return __ne;
42170b57cec5SDimitry Andric   case ios_base::right:
42180b57cec5SDimitry Andric   default:
42190b57cec5SDimitry Andric     break;
42200b57cec5SDimitry Andric   }
42210b57cec5SDimitry Andric   return __nb;
42220b57cec5SDimitry Andric }
42230b57cec5SDimitry Andric 
42240b57cec5SDimitry Andric // time_get
42250b57cec5SDimitry Andric 
4226*cb14a3feSDimitry Andric static string* init_weeks() {
42270b57cec5SDimitry Andric   static string weeks[14];
42280b57cec5SDimitry Andric   weeks[0]  = "Sunday";
42290b57cec5SDimitry Andric   weeks[1]  = "Monday";
42300b57cec5SDimitry Andric   weeks[2]  = "Tuesday";
42310b57cec5SDimitry Andric   weeks[3]  = "Wednesday";
42320b57cec5SDimitry Andric   weeks[4]  = "Thursday";
42330b57cec5SDimitry Andric   weeks[5]  = "Friday";
42340b57cec5SDimitry Andric   weeks[6]  = "Saturday";
42350b57cec5SDimitry Andric   weeks[7]  = "Sun";
42360b57cec5SDimitry Andric   weeks[8]  = "Mon";
42370b57cec5SDimitry Andric   weeks[9]  = "Tue";
42380b57cec5SDimitry Andric   weeks[10] = "Wed";
42390b57cec5SDimitry Andric   weeks[11] = "Thu";
42400b57cec5SDimitry Andric   weeks[12] = "Fri";
42410b57cec5SDimitry Andric   weeks[13] = "Sat";
42420b57cec5SDimitry Andric   return weeks;
42430b57cec5SDimitry Andric }
42440b57cec5SDimitry Andric 
4245349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4246*cb14a3feSDimitry Andric static wstring* init_wweeks() {
42470b57cec5SDimitry Andric   static wstring weeks[14];
42480b57cec5SDimitry Andric   weeks[0]  = L"Sunday";
42490b57cec5SDimitry Andric   weeks[1]  = L"Monday";
42500b57cec5SDimitry Andric   weeks[2]  = L"Tuesday";
42510b57cec5SDimitry Andric   weeks[3]  = L"Wednesday";
42520b57cec5SDimitry Andric   weeks[4]  = L"Thursday";
42530b57cec5SDimitry Andric   weeks[5]  = L"Friday";
42540b57cec5SDimitry Andric   weeks[6]  = L"Saturday";
42550b57cec5SDimitry Andric   weeks[7]  = L"Sun";
42560b57cec5SDimitry Andric   weeks[8]  = L"Mon";
42570b57cec5SDimitry Andric   weeks[9]  = L"Tue";
42580b57cec5SDimitry Andric   weeks[10] = L"Wed";
42590b57cec5SDimitry Andric   weeks[11] = L"Thu";
42600b57cec5SDimitry Andric   weeks[12] = L"Fri";
42610b57cec5SDimitry Andric   weeks[13] = L"Sat";
42620b57cec5SDimitry Andric   return weeks;
42630b57cec5SDimitry Andric }
4264349cc55cSDimitry Andric #endif
42650b57cec5SDimitry Andric 
42660b57cec5SDimitry Andric template <>
4267*cb14a3feSDimitry Andric const string* __time_get_c_storage<char>::__weeks() const {
42680b57cec5SDimitry Andric   static const string* weeks = init_weeks();
42690b57cec5SDimitry Andric   return weeks;
42700b57cec5SDimitry Andric }
42710b57cec5SDimitry Andric 
4272349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
42730b57cec5SDimitry Andric template <>
4274*cb14a3feSDimitry Andric const wstring* __time_get_c_storage<wchar_t>::__weeks() const {
42750b57cec5SDimitry Andric   static const wstring* weeks = init_wweeks();
42760b57cec5SDimitry Andric   return weeks;
42770b57cec5SDimitry Andric }
4278349cc55cSDimitry Andric #endif
42790b57cec5SDimitry Andric 
4280*cb14a3feSDimitry Andric static string* init_months() {
42810b57cec5SDimitry Andric   static string months[24];
42820b57cec5SDimitry Andric   months[0]  = "January";
42830b57cec5SDimitry Andric   months[1]  = "February";
42840b57cec5SDimitry Andric   months[2]  = "March";
42850b57cec5SDimitry Andric   months[3]  = "April";
42860b57cec5SDimitry Andric   months[4]  = "May";
42870b57cec5SDimitry Andric   months[5]  = "June";
42880b57cec5SDimitry Andric   months[6]  = "July";
42890b57cec5SDimitry Andric   months[7]  = "August";
42900b57cec5SDimitry Andric   months[8]  = "September";
42910b57cec5SDimitry Andric   months[9]  = "October";
42920b57cec5SDimitry Andric   months[10] = "November";
42930b57cec5SDimitry Andric   months[11] = "December";
42940b57cec5SDimitry Andric   months[12] = "Jan";
42950b57cec5SDimitry Andric   months[13] = "Feb";
42960b57cec5SDimitry Andric   months[14] = "Mar";
42970b57cec5SDimitry Andric   months[15] = "Apr";
42980b57cec5SDimitry Andric   months[16] = "May";
42990b57cec5SDimitry Andric   months[17] = "Jun";
43000b57cec5SDimitry Andric   months[18] = "Jul";
43010b57cec5SDimitry Andric   months[19] = "Aug";
43020b57cec5SDimitry Andric   months[20] = "Sep";
43030b57cec5SDimitry Andric   months[21] = "Oct";
43040b57cec5SDimitry Andric   months[22] = "Nov";
43050b57cec5SDimitry Andric   months[23] = "Dec";
43060b57cec5SDimitry Andric   return months;
43070b57cec5SDimitry Andric }
43080b57cec5SDimitry Andric 
4309349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4310*cb14a3feSDimitry Andric static wstring* init_wmonths() {
43110b57cec5SDimitry Andric   static wstring months[24];
43120b57cec5SDimitry Andric   months[0]  = L"January";
43130b57cec5SDimitry Andric   months[1]  = L"February";
43140b57cec5SDimitry Andric   months[2]  = L"March";
43150b57cec5SDimitry Andric   months[3]  = L"April";
43160b57cec5SDimitry Andric   months[4]  = L"May";
43170b57cec5SDimitry Andric   months[5]  = L"June";
43180b57cec5SDimitry Andric   months[6]  = L"July";
43190b57cec5SDimitry Andric   months[7]  = L"August";
43200b57cec5SDimitry Andric   months[8]  = L"September";
43210b57cec5SDimitry Andric   months[9]  = L"October";
43220b57cec5SDimitry Andric   months[10] = L"November";
43230b57cec5SDimitry Andric   months[11] = L"December";
43240b57cec5SDimitry Andric   months[12] = L"Jan";
43250b57cec5SDimitry Andric   months[13] = L"Feb";
43260b57cec5SDimitry Andric   months[14] = L"Mar";
43270b57cec5SDimitry Andric   months[15] = L"Apr";
43280b57cec5SDimitry Andric   months[16] = L"May";
43290b57cec5SDimitry Andric   months[17] = L"Jun";
43300b57cec5SDimitry Andric   months[18] = L"Jul";
43310b57cec5SDimitry Andric   months[19] = L"Aug";
43320b57cec5SDimitry Andric   months[20] = L"Sep";
43330b57cec5SDimitry Andric   months[21] = L"Oct";
43340b57cec5SDimitry Andric   months[22] = L"Nov";
43350b57cec5SDimitry Andric   months[23] = L"Dec";
43360b57cec5SDimitry Andric   return months;
43370b57cec5SDimitry Andric }
4338349cc55cSDimitry Andric #endif
43390b57cec5SDimitry Andric 
43400b57cec5SDimitry Andric template <>
4341*cb14a3feSDimitry Andric const string* __time_get_c_storage<char>::__months() const {
43420b57cec5SDimitry Andric   static const string* months = init_months();
43430b57cec5SDimitry Andric   return months;
43440b57cec5SDimitry Andric }
43450b57cec5SDimitry Andric 
4346349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
43470b57cec5SDimitry Andric template <>
4348*cb14a3feSDimitry Andric const wstring* __time_get_c_storage<wchar_t>::__months() const {
43490b57cec5SDimitry Andric   static const wstring* months = init_wmonths();
43500b57cec5SDimitry Andric   return months;
43510b57cec5SDimitry Andric }
4352349cc55cSDimitry Andric #endif
43530b57cec5SDimitry Andric 
4354*cb14a3feSDimitry Andric static string* init_am_pm() {
43550b57cec5SDimitry Andric   static string am_pm[2];
43560b57cec5SDimitry Andric   am_pm[0] = "AM";
43570b57cec5SDimitry Andric   am_pm[1] = "PM";
43580b57cec5SDimitry Andric   return am_pm;
43590b57cec5SDimitry Andric }
43600b57cec5SDimitry Andric 
4361349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4362*cb14a3feSDimitry Andric static wstring* init_wam_pm() {
43630b57cec5SDimitry Andric   static wstring am_pm[2];
43640b57cec5SDimitry Andric   am_pm[0] = L"AM";
43650b57cec5SDimitry Andric   am_pm[1] = L"PM";
43660b57cec5SDimitry Andric   return am_pm;
43670b57cec5SDimitry Andric }
4368349cc55cSDimitry Andric #endif
43690b57cec5SDimitry Andric 
43700b57cec5SDimitry Andric template <>
4371*cb14a3feSDimitry Andric const string* __time_get_c_storage<char>::__am_pm() const {
43720b57cec5SDimitry Andric   static const string* am_pm = init_am_pm();
43730b57cec5SDimitry Andric   return am_pm;
43740b57cec5SDimitry Andric }
43750b57cec5SDimitry Andric 
4376349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
43770b57cec5SDimitry Andric template <>
4378*cb14a3feSDimitry Andric const wstring* __time_get_c_storage<wchar_t>::__am_pm() const {
43790b57cec5SDimitry Andric   static const wstring* am_pm = init_wam_pm();
43800b57cec5SDimitry Andric   return am_pm;
43810b57cec5SDimitry Andric }
4382349cc55cSDimitry Andric #endif
43830b57cec5SDimitry Andric 
43840b57cec5SDimitry Andric template <>
4385*cb14a3feSDimitry Andric const string& __time_get_c_storage<char>::__x() const {
43860b57cec5SDimitry Andric   static string s("%m/%d/%y");
43870b57cec5SDimitry Andric   return s;
43880b57cec5SDimitry Andric }
43890b57cec5SDimitry Andric 
4390349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
43910b57cec5SDimitry Andric template <>
4392*cb14a3feSDimitry Andric const wstring& __time_get_c_storage<wchar_t>::__x() const {
43930b57cec5SDimitry Andric   static wstring s(L"%m/%d/%y");
43940b57cec5SDimitry Andric   return s;
43950b57cec5SDimitry Andric }
4396349cc55cSDimitry Andric #endif
43970b57cec5SDimitry Andric 
43980b57cec5SDimitry Andric template <>
4399*cb14a3feSDimitry Andric const string& __time_get_c_storage<char>::__X() const {
44000b57cec5SDimitry Andric   static string s("%H:%M:%S");
44010b57cec5SDimitry Andric   return s;
44020b57cec5SDimitry Andric }
44030b57cec5SDimitry Andric 
4404349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
44050b57cec5SDimitry Andric template <>
4406*cb14a3feSDimitry Andric const wstring& __time_get_c_storage<wchar_t>::__X() const {
44070b57cec5SDimitry Andric   static wstring s(L"%H:%M:%S");
44080b57cec5SDimitry Andric   return s;
44090b57cec5SDimitry Andric }
4410349cc55cSDimitry Andric #endif
44110b57cec5SDimitry Andric 
44120b57cec5SDimitry Andric template <>
4413*cb14a3feSDimitry Andric const string& __time_get_c_storage<char>::__c() const {
44140b57cec5SDimitry Andric   static string s("%a %b %d %H:%M:%S %Y");
44150b57cec5SDimitry Andric   return s;
44160b57cec5SDimitry Andric }
44170b57cec5SDimitry Andric 
4418349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
44190b57cec5SDimitry Andric template <>
4420*cb14a3feSDimitry Andric const wstring& __time_get_c_storage<wchar_t>::__c() const {
44210b57cec5SDimitry Andric   static wstring s(L"%a %b %d %H:%M:%S %Y");
44220b57cec5SDimitry Andric   return s;
44230b57cec5SDimitry Andric }
4424349cc55cSDimitry Andric #endif
44250b57cec5SDimitry Andric 
44260b57cec5SDimitry Andric template <>
4427*cb14a3feSDimitry Andric const string& __time_get_c_storage<char>::__r() const {
44280b57cec5SDimitry Andric   static string s("%I:%M:%S %p");
44290b57cec5SDimitry Andric   return s;
44300b57cec5SDimitry Andric }
44310b57cec5SDimitry Andric 
4432349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
44330b57cec5SDimitry Andric template <>
4434*cb14a3feSDimitry Andric const wstring& __time_get_c_storage<wchar_t>::__r() const {
44350b57cec5SDimitry Andric   static wstring s(L"%I:%M:%S %p");
44360b57cec5SDimitry Andric   return s;
44370b57cec5SDimitry Andric }
4438349cc55cSDimitry Andric #endif
44390b57cec5SDimitry Andric 
44400b57cec5SDimitry Andric // time_get_byname
44410b57cec5SDimitry Andric 
4442*cb14a3feSDimitry Andric __time_get::__time_get(const char* nm) : __loc_(newlocale(LC_ALL_MASK, nm, 0)) {
44430b57cec5SDimitry Andric   if (__loc_ == 0)
44445f757f3fSDimitry Andric     __throw_runtime_error(("time_get_byname failed to construct for " + string(nm)).c_str());
44450b57cec5SDimitry Andric }
44460b57cec5SDimitry Andric 
4447*cb14a3feSDimitry Andric __time_get::__time_get(const string& nm) : __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0)) {
44480b57cec5SDimitry Andric   if (__loc_ == 0)
44495f757f3fSDimitry Andric     __throw_runtime_error(("time_get_byname failed to construct for " + nm).c_str());
44500b57cec5SDimitry Andric }
44510b57cec5SDimitry Andric 
4452*cb14a3feSDimitry Andric __time_get::~__time_get() { freelocale(__loc_); }
445381ad6265SDimitry Andric 
445481ad6265SDimitry Andric _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-field-initializers")
44550b57cec5SDimitry Andric 
44560b57cec5SDimitry Andric template <>
4457*cb14a3feSDimitry Andric string __time_get_storage<char>::__analyze(char fmt, const ctype<char>& ct) {
44580b57cec5SDimitry Andric   tm t       = {0};
44590b57cec5SDimitry Andric   t.tm_sec   = 59;
44600b57cec5SDimitry Andric   t.tm_min   = 55;
44610b57cec5SDimitry Andric   t.tm_hour  = 23;
44620b57cec5SDimitry Andric   t.tm_mday  = 31;
44630b57cec5SDimitry Andric   t.tm_mon   = 11;
44640b57cec5SDimitry Andric   t.tm_year  = 161;
44650b57cec5SDimitry Andric   t.tm_wday  = 6;
44660b57cec5SDimitry Andric   t.tm_yday  = 364;
44670b57cec5SDimitry Andric   t.tm_isdst = -1;
44680b57cec5SDimitry Andric   char buf[100];
44690b57cec5SDimitry Andric   char f[3] = {0};
44700b57cec5SDimitry Andric   f[0]      = '%';
44710b57cec5SDimitry Andric   f[1]      = fmt;
44720b57cec5SDimitry Andric   size_t n  = strftime_l(buf, countof(buf), f, &t, __loc_);
44730b57cec5SDimitry Andric   char* bb  = buf;
44740b57cec5SDimitry Andric   char* be  = buf + n;
44750b57cec5SDimitry Andric   string result;
4476*cb14a3feSDimitry Andric   while (bb != be) {
4477*cb14a3feSDimitry Andric     if (ct.is(ctype_base::space, *bb)) {
44780b57cec5SDimitry Andric       result.push_back(' ');
44790b57cec5SDimitry Andric       for (++bb; bb != be && ct.is(ctype_base::space, *bb); ++bb)
44800b57cec5SDimitry Andric         ;
44810b57cec5SDimitry Andric       continue;
44820b57cec5SDimitry Andric     }
44830b57cec5SDimitry Andric     char* w               = bb;
44840b57cec5SDimitry Andric     ios_base::iostate err = ios_base::goodbit;
4485*cb14a3feSDimitry Andric     ptrdiff_t i           = __scan_keyword(w, be, this->__weeks_, this->__weeks_ + 14, ct, err, false) - this->__weeks_;
4486*cb14a3feSDimitry Andric     if (i < 14) {
44870b57cec5SDimitry Andric       result.push_back('%');
44880b57cec5SDimitry Andric       if (i < 7)
44890b57cec5SDimitry Andric         result.push_back('A');
44900b57cec5SDimitry Andric       else
44910b57cec5SDimitry Andric         result.push_back('a');
44920b57cec5SDimitry Andric       bb = w;
44930b57cec5SDimitry Andric       continue;
44940b57cec5SDimitry Andric     }
44950b57cec5SDimitry Andric     w = bb;
4496*cb14a3feSDimitry Andric     i = __scan_keyword(w, be, this->__months_, this->__months_ + 24, ct, err, false) - this->__months_;
4497*cb14a3feSDimitry Andric     if (i < 24) {
44980b57cec5SDimitry Andric       result.push_back('%');
44990b57cec5SDimitry Andric       if (i < 12)
45000b57cec5SDimitry Andric         result.push_back('B');
45010b57cec5SDimitry Andric       else
45020b57cec5SDimitry Andric         result.push_back('b');
45030b57cec5SDimitry Andric       if (fmt == 'x' && ct.is(ctype_base::digit, this->__months_[i][0]))
45040b57cec5SDimitry Andric         result.back() = 'm';
45050b57cec5SDimitry Andric       bb = w;
45060b57cec5SDimitry Andric       continue;
45070b57cec5SDimitry Andric     }
4508*cb14a3feSDimitry Andric     if (this->__am_pm_[0].size() + this->__am_pm_[1].size() > 0) {
45090b57cec5SDimitry Andric       w = bb;
4510*cb14a3feSDimitry Andric       i = __scan_keyword(w, be, this->__am_pm_, this->__am_pm_ + 2, ct, err, false) - this->__am_pm_;
4511*cb14a3feSDimitry Andric       if (i < 2) {
45120b57cec5SDimitry Andric         result.push_back('%');
45130b57cec5SDimitry Andric         result.push_back('p');
45140b57cec5SDimitry Andric         bb = w;
45150b57cec5SDimitry Andric         continue;
45160b57cec5SDimitry Andric       }
45170b57cec5SDimitry Andric     }
45180b57cec5SDimitry Andric     w = bb;
4519*cb14a3feSDimitry Andric     if (ct.is(ctype_base::digit, *bb)) {
4520*cb14a3feSDimitry Andric       switch (__get_up_to_n_digits(bb, be, err, ct, 4)) {
45210b57cec5SDimitry Andric       case 6:
45220b57cec5SDimitry Andric         result.push_back('%');
45230b57cec5SDimitry Andric         result.push_back('w');
45240b57cec5SDimitry Andric         break;
45250b57cec5SDimitry Andric       case 7:
45260b57cec5SDimitry Andric         result.push_back('%');
45270b57cec5SDimitry Andric         result.push_back('u');
45280b57cec5SDimitry Andric         break;
45290b57cec5SDimitry Andric       case 11:
45300b57cec5SDimitry Andric         result.push_back('%');
45310b57cec5SDimitry Andric         result.push_back('I');
45320b57cec5SDimitry Andric         break;
45330b57cec5SDimitry Andric       case 12:
45340b57cec5SDimitry Andric         result.push_back('%');
45350b57cec5SDimitry Andric         result.push_back('m');
45360b57cec5SDimitry Andric         break;
45370b57cec5SDimitry Andric       case 23:
45380b57cec5SDimitry Andric         result.push_back('%');
45390b57cec5SDimitry Andric         result.push_back('H');
45400b57cec5SDimitry Andric         break;
45410b57cec5SDimitry Andric       case 31:
45420b57cec5SDimitry Andric         result.push_back('%');
45430b57cec5SDimitry Andric         result.push_back('d');
45440b57cec5SDimitry Andric         break;
45450b57cec5SDimitry Andric       case 55:
45460b57cec5SDimitry Andric         result.push_back('%');
45470b57cec5SDimitry Andric         result.push_back('M');
45480b57cec5SDimitry Andric         break;
45490b57cec5SDimitry Andric       case 59:
45500b57cec5SDimitry Andric         result.push_back('%');
45510b57cec5SDimitry Andric         result.push_back('S');
45520b57cec5SDimitry Andric         break;
45530b57cec5SDimitry Andric       case 61:
45540b57cec5SDimitry Andric         result.push_back('%');
45550b57cec5SDimitry Andric         result.push_back('y');
45560b57cec5SDimitry Andric         break;
45570b57cec5SDimitry Andric       case 364:
45580b57cec5SDimitry Andric         result.push_back('%');
45590b57cec5SDimitry Andric         result.push_back('j');
45600b57cec5SDimitry Andric         break;
45610b57cec5SDimitry Andric       case 2061:
45620b57cec5SDimitry Andric         result.push_back('%');
45630b57cec5SDimitry Andric         result.push_back('Y');
45640b57cec5SDimitry Andric         break;
45650b57cec5SDimitry Andric       default:
45660b57cec5SDimitry Andric         for (; w != bb; ++w)
45670b57cec5SDimitry Andric           result.push_back(*w);
45680b57cec5SDimitry Andric         break;
45690b57cec5SDimitry Andric       }
45700b57cec5SDimitry Andric       continue;
45710b57cec5SDimitry Andric     }
4572*cb14a3feSDimitry Andric     if (*bb == '%') {
45730b57cec5SDimitry Andric       result.push_back('%');
45740b57cec5SDimitry Andric       result.push_back('%');
45750b57cec5SDimitry Andric       ++bb;
45760b57cec5SDimitry Andric       continue;
45770b57cec5SDimitry Andric     }
45780b57cec5SDimitry Andric     result.push_back(*bb);
45790b57cec5SDimitry Andric     ++bb;
45800b57cec5SDimitry Andric   }
45810b57cec5SDimitry Andric   return result;
45820b57cec5SDimitry Andric }
45830b57cec5SDimitry Andric 
458481ad6265SDimitry Andric _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-braces")
45850b57cec5SDimitry Andric 
4586349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
45870b57cec5SDimitry Andric template <>
4588*cb14a3feSDimitry Andric wstring __time_get_storage<wchar_t>::__analyze(char fmt, const ctype<wchar_t>& ct) {
45890b57cec5SDimitry Andric   tm t       = {0};
45900b57cec5SDimitry Andric   t.tm_sec   = 59;
45910b57cec5SDimitry Andric   t.tm_min   = 55;
45920b57cec5SDimitry Andric   t.tm_hour  = 23;
45930b57cec5SDimitry Andric   t.tm_mday  = 31;
45940b57cec5SDimitry Andric   t.tm_mon   = 11;
45950b57cec5SDimitry Andric   t.tm_year  = 161;
45960b57cec5SDimitry Andric   t.tm_wday  = 6;
45970b57cec5SDimitry Andric   t.tm_yday  = 364;
45980b57cec5SDimitry Andric   t.tm_isdst = -1;
45990b57cec5SDimitry Andric   char buf[100];
46000b57cec5SDimitry Andric   char f[3] = {0};
46010b57cec5SDimitry Andric   f[0]      = '%';
46020b57cec5SDimitry Andric   f[1]      = fmt;
46030b57cec5SDimitry Andric   strftime_l(buf, countof(buf), f, &t, __loc_);
46040b57cec5SDimitry Andric   wchar_t wbuf[100];
46050b57cec5SDimitry Andric   wchar_t* wbb   = wbuf;
46060b57cec5SDimitry Andric   mbstate_t mb   = {0};
46070b57cec5SDimitry Andric   const char* bb = buf;
46080b57cec5SDimitry Andric   size_t j       = __libcpp_mbsrtowcs_l(wbb, &bb, countof(wbuf), &mb, __loc_);
46090b57cec5SDimitry Andric   if (j == size_t(-1))
46100b57cec5SDimitry Andric     __throw_runtime_error("locale not supported");
46110b57cec5SDimitry Andric   wchar_t* wbe = wbb + j;
46120b57cec5SDimitry Andric   wstring result;
4613*cb14a3feSDimitry Andric   while (wbb != wbe) {
4614*cb14a3feSDimitry Andric     if (ct.is(ctype_base::space, *wbb)) {
46150b57cec5SDimitry Andric       result.push_back(L' ');
46160b57cec5SDimitry Andric       for (++wbb; wbb != wbe && ct.is(ctype_base::space, *wbb); ++wbb)
46170b57cec5SDimitry Andric         ;
46180b57cec5SDimitry Andric       continue;
46190b57cec5SDimitry Andric     }
46200b57cec5SDimitry Andric     wchar_t* w            = wbb;
46210b57cec5SDimitry Andric     ios_base::iostate err = ios_base::goodbit;
4622*cb14a3feSDimitry Andric     ptrdiff_t i = __scan_keyword(w, wbe, this->__weeks_, this->__weeks_ + 14, ct, err, false) - this->__weeks_;
4623*cb14a3feSDimitry Andric     if (i < 14) {
46240b57cec5SDimitry Andric       result.push_back(L'%');
46250b57cec5SDimitry Andric       if (i < 7)
46260b57cec5SDimitry Andric         result.push_back(L'A');
46270b57cec5SDimitry Andric       else
46280b57cec5SDimitry Andric         result.push_back(L'a');
46290b57cec5SDimitry Andric       wbb = w;
46300b57cec5SDimitry Andric       continue;
46310b57cec5SDimitry Andric     }
46320b57cec5SDimitry Andric     w = wbb;
4633*cb14a3feSDimitry Andric     i = __scan_keyword(w, wbe, this->__months_, this->__months_ + 24, ct, err, false) - this->__months_;
4634*cb14a3feSDimitry Andric     if (i < 24) {
46350b57cec5SDimitry Andric       result.push_back(L'%');
46360b57cec5SDimitry Andric       if (i < 12)
46370b57cec5SDimitry Andric         result.push_back(L'B');
46380b57cec5SDimitry Andric       else
46390b57cec5SDimitry Andric         result.push_back(L'b');
46400b57cec5SDimitry Andric       if (fmt == 'x' && ct.is(ctype_base::digit, this->__months_[i][0]))
46410b57cec5SDimitry Andric         result.back() = L'm';
46420b57cec5SDimitry Andric       wbb = w;
46430b57cec5SDimitry Andric       continue;
46440b57cec5SDimitry Andric     }
4645*cb14a3feSDimitry Andric     if (this->__am_pm_[0].size() + this->__am_pm_[1].size() > 0) {
46460b57cec5SDimitry Andric       w = wbb;
4647*cb14a3feSDimitry Andric       i = __scan_keyword(w, wbe, this->__am_pm_, this->__am_pm_ + 2, ct, err, false) - this->__am_pm_;
4648*cb14a3feSDimitry Andric       if (i < 2) {
46490b57cec5SDimitry Andric         result.push_back(L'%');
46500b57cec5SDimitry Andric         result.push_back(L'p');
46510b57cec5SDimitry Andric         wbb = w;
46520b57cec5SDimitry Andric         continue;
46530b57cec5SDimitry Andric       }
46540b57cec5SDimitry Andric     }
46550b57cec5SDimitry Andric     w = wbb;
4656*cb14a3feSDimitry Andric     if (ct.is(ctype_base::digit, *wbb)) {
4657*cb14a3feSDimitry Andric       switch (__get_up_to_n_digits(wbb, wbe, err, ct, 4)) {
46580b57cec5SDimitry Andric       case 6:
46590b57cec5SDimitry Andric         result.push_back(L'%');
46600b57cec5SDimitry Andric         result.push_back(L'w');
46610b57cec5SDimitry Andric         break;
46620b57cec5SDimitry Andric       case 7:
46630b57cec5SDimitry Andric         result.push_back(L'%');
46640b57cec5SDimitry Andric         result.push_back(L'u');
46650b57cec5SDimitry Andric         break;
46660b57cec5SDimitry Andric       case 11:
46670b57cec5SDimitry Andric         result.push_back(L'%');
46680b57cec5SDimitry Andric         result.push_back(L'I');
46690b57cec5SDimitry Andric         break;
46700b57cec5SDimitry Andric       case 12:
46710b57cec5SDimitry Andric         result.push_back(L'%');
46720b57cec5SDimitry Andric         result.push_back(L'm');
46730b57cec5SDimitry Andric         break;
46740b57cec5SDimitry Andric       case 23:
46750b57cec5SDimitry Andric         result.push_back(L'%');
46760b57cec5SDimitry Andric         result.push_back(L'H');
46770b57cec5SDimitry Andric         break;
46780b57cec5SDimitry Andric       case 31:
46790b57cec5SDimitry Andric         result.push_back(L'%');
46800b57cec5SDimitry Andric         result.push_back(L'd');
46810b57cec5SDimitry Andric         break;
46820b57cec5SDimitry Andric       case 55:
46830b57cec5SDimitry Andric         result.push_back(L'%');
46840b57cec5SDimitry Andric         result.push_back(L'M');
46850b57cec5SDimitry Andric         break;
46860b57cec5SDimitry Andric       case 59:
46870b57cec5SDimitry Andric         result.push_back(L'%');
46880b57cec5SDimitry Andric         result.push_back(L'S');
46890b57cec5SDimitry Andric         break;
46900b57cec5SDimitry Andric       case 61:
46910b57cec5SDimitry Andric         result.push_back(L'%');
46920b57cec5SDimitry Andric         result.push_back(L'y');
46930b57cec5SDimitry Andric         break;
46940b57cec5SDimitry Andric       case 364:
46950b57cec5SDimitry Andric         result.push_back(L'%');
46960b57cec5SDimitry Andric         result.push_back(L'j');
46970b57cec5SDimitry Andric         break;
46980b57cec5SDimitry Andric       case 2061:
46990b57cec5SDimitry Andric         result.push_back(L'%');
47000b57cec5SDimitry Andric         result.push_back(L'Y');
47010b57cec5SDimitry Andric         break;
47020b57cec5SDimitry Andric       default:
47030b57cec5SDimitry Andric         for (; w != wbb; ++w)
47040b57cec5SDimitry Andric           result.push_back(*w);
47050b57cec5SDimitry Andric         break;
47060b57cec5SDimitry Andric       }
47070b57cec5SDimitry Andric       continue;
47080b57cec5SDimitry Andric     }
4709*cb14a3feSDimitry Andric     if (ct.narrow(*wbb, 0) == '%') {
47100b57cec5SDimitry Andric       result.push_back(L'%');
47110b57cec5SDimitry Andric       result.push_back(L'%');
47120b57cec5SDimitry Andric       ++wbb;
47130b57cec5SDimitry Andric       continue;
47140b57cec5SDimitry Andric     }
47150b57cec5SDimitry Andric     result.push_back(*wbb);
47160b57cec5SDimitry Andric     ++wbb;
47170b57cec5SDimitry Andric   }
47180b57cec5SDimitry Andric   return result;
47190b57cec5SDimitry Andric }
4720349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
47210b57cec5SDimitry Andric 
47220b57cec5SDimitry Andric template <>
4723*cb14a3feSDimitry Andric void __time_get_storage<char>::init(const ctype<char>& ct) {
47240b57cec5SDimitry Andric   tm t = {0};
47250b57cec5SDimitry Andric   char buf[100];
47260b57cec5SDimitry Andric   // __weeks_
4727*cb14a3feSDimitry Andric   for (int i = 0; i < 7; ++i) {
47280b57cec5SDimitry Andric     t.tm_wday = i;
47290b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%A", &t, __loc_);
47300b57cec5SDimitry Andric     __weeks_[i] = buf;
47310b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%a", &t, __loc_);
47320b57cec5SDimitry Andric     __weeks_[i + 7] = buf;
47330b57cec5SDimitry Andric   }
47340b57cec5SDimitry Andric   // __months_
4735*cb14a3feSDimitry Andric   for (int i = 0; i < 12; ++i) {
47360b57cec5SDimitry Andric     t.tm_mon = i;
47370b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%B", &t, __loc_);
47380b57cec5SDimitry Andric     __months_[i] = buf;
47390b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%b", &t, __loc_);
47400b57cec5SDimitry Andric     __months_[i + 12] = buf;
47410b57cec5SDimitry Andric   }
47420b57cec5SDimitry Andric   // __am_pm_
47430b57cec5SDimitry Andric   t.tm_hour = 1;
47440b57cec5SDimitry Andric   strftime_l(buf, countof(buf), "%p", &t, __loc_);
47450b57cec5SDimitry Andric   __am_pm_[0] = buf;
47460b57cec5SDimitry Andric   t.tm_hour   = 13;
47470b57cec5SDimitry Andric   strftime_l(buf, countof(buf), "%p", &t, __loc_);
47480b57cec5SDimitry Andric   __am_pm_[1] = buf;
47490b57cec5SDimitry Andric   __c_        = __analyze('c', ct);
47500b57cec5SDimitry Andric   __r_        = __analyze('r', ct);
47510b57cec5SDimitry Andric   __x_        = __analyze('x', ct);
47520b57cec5SDimitry Andric   __X_        = __analyze('X', ct);
47530b57cec5SDimitry Andric }
47540b57cec5SDimitry Andric 
4755349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
47560b57cec5SDimitry Andric template <>
4757*cb14a3feSDimitry Andric void __time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct) {
47580b57cec5SDimitry Andric   tm t = {0};
47590b57cec5SDimitry Andric   char buf[100];
47600b57cec5SDimitry Andric   wchar_t wbuf[100];
47610b57cec5SDimitry Andric   wchar_t* wbe;
47620b57cec5SDimitry Andric   mbstate_t mb = {0};
47630b57cec5SDimitry Andric   // __weeks_
4764*cb14a3feSDimitry Andric   for (int i = 0; i < 7; ++i) {
47650b57cec5SDimitry Andric     t.tm_wday = i;
47660b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%A", &t, __loc_);
47670b57cec5SDimitry Andric     mb             = mbstate_t();
47680b57cec5SDimitry Andric     const char* bb = buf;
47690b57cec5SDimitry Andric     size_t j       = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
4770e8d8bef9SDimitry Andric     if (j == size_t(-1) || j == 0)
47710b57cec5SDimitry Andric       __throw_runtime_error("locale not supported");
47720b57cec5SDimitry Andric     wbe = wbuf + j;
47730b57cec5SDimitry Andric     __weeks_[i].assign(wbuf, wbe);
47740b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%a", &t, __loc_);
47750b57cec5SDimitry Andric     mb = mbstate_t();
47760b57cec5SDimitry Andric     bb = buf;
47770b57cec5SDimitry Andric     j  = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
4778e8d8bef9SDimitry Andric     if (j == size_t(-1) || j == 0)
47790b57cec5SDimitry Andric       __throw_runtime_error("locale not supported");
47800b57cec5SDimitry Andric     wbe = wbuf + j;
47810b57cec5SDimitry Andric     __weeks_[i + 7].assign(wbuf, wbe);
47820b57cec5SDimitry Andric   }
47830b57cec5SDimitry Andric   // __months_
4784*cb14a3feSDimitry Andric   for (int i = 0; i < 12; ++i) {
47850b57cec5SDimitry Andric     t.tm_mon = i;
47860b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%B", &t, __loc_);
47870b57cec5SDimitry Andric     mb             = mbstate_t();
47880b57cec5SDimitry Andric     const char* bb = buf;
47890b57cec5SDimitry Andric     size_t j       = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
4790e8d8bef9SDimitry Andric     if (j == size_t(-1) || j == 0)
47910b57cec5SDimitry Andric       __throw_runtime_error("locale not supported");
47920b57cec5SDimitry Andric     wbe = wbuf + j;
47930b57cec5SDimitry Andric     __months_[i].assign(wbuf, wbe);
47940b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%b", &t, __loc_);
47950b57cec5SDimitry Andric     mb = mbstate_t();
47960b57cec5SDimitry Andric     bb = buf;
47970b57cec5SDimitry Andric     j  = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
4798e8d8bef9SDimitry Andric     if (j == size_t(-1) || j == 0)
47990b57cec5SDimitry Andric       __throw_runtime_error("locale not supported");
48000b57cec5SDimitry Andric     wbe = wbuf + j;
48010b57cec5SDimitry Andric     __months_[i + 12].assign(wbuf, wbe);
48020b57cec5SDimitry Andric   }
48030b57cec5SDimitry Andric   // __am_pm_
48040b57cec5SDimitry Andric   t.tm_hour = 1;
48050b57cec5SDimitry Andric   strftime_l(buf, countof(buf), "%p", &t, __loc_);
48060b57cec5SDimitry Andric   mb             = mbstate_t();
48070b57cec5SDimitry Andric   const char* bb = buf;
48080b57cec5SDimitry Andric   size_t j       = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
48090b57cec5SDimitry Andric   if (j == size_t(-1))
48100b57cec5SDimitry Andric     __throw_runtime_error("locale not supported");
48110b57cec5SDimitry Andric   wbe = wbuf + j;
48120b57cec5SDimitry Andric   __am_pm_[0].assign(wbuf, wbe);
48130b57cec5SDimitry Andric   t.tm_hour = 13;
48140b57cec5SDimitry Andric   strftime_l(buf, countof(buf), "%p", &t, __loc_);
48150b57cec5SDimitry Andric   mb = mbstate_t();
48160b57cec5SDimitry Andric   bb = buf;
48170b57cec5SDimitry Andric   j  = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
48180b57cec5SDimitry Andric   if (j == size_t(-1))
48190b57cec5SDimitry Andric     __throw_runtime_error("locale not supported");
48200b57cec5SDimitry Andric   wbe = wbuf + j;
48210b57cec5SDimitry Andric   __am_pm_[1].assign(wbuf, wbe);
48220b57cec5SDimitry Andric   __c_ = __analyze('c', ct);
48230b57cec5SDimitry Andric   __r_ = __analyze('r', ct);
48240b57cec5SDimitry Andric   __x_ = __analyze('x', ct);
48250b57cec5SDimitry Andric   __X_ = __analyze('X', ct);
48260b57cec5SDimitry Andric }
4827349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
48280b57cec5SDimitry Andric 
48290b57cec5SDimitry Andric template <class CharT>
4830*cb14a3feSDimitry Andric struct _LIBCPP_HIDDEN __time_get_temp : public ctype_byname<CharT> {
4831*cb14a3feSDimitry Andric   explicit __time_get_temp(const char* nm) : ctype_byname<CharT>(nm, 1) {}
4832*cb14a3feSDimitry Andric   explicit __time_get_temp(const string& nm) : ctype_byname<CharT>(nm, 1) {}
48330b57cec5SDimitry Andric };
48340b57cec5SDimitry Andric 
48350b57cec5SDimitry Andric template <>
4836*cb14a3feSDimitry Andric __time_get_storage<char>::__time_get_storage(const char* __nm) : __time_get(__nm) {
48370b57cec5SDimitry Andric   const __time_get_temp<char> ct(__nm);
48380b57cec5SDimitry Andric   init(ct);
48390b57cec5SDimitry Andric }
48400b57cec5SDimitry Andric 
48410b57cec5SDimitry Andric template <>
4842*cb14a3feSDimitry Andric __time_get_storage<char>::__time_get_storage(const string& __nm) : __time_get(__nm) {
48430b57cec5SDimitry Andric   const __time_get_temp<char> ct(__nm);
48440b57cec5SDimitry Andric   init(ct);
48450b57cec5SDimitry Andric }
48460b57cec5SDimitry Andric 
4847349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
48480b57cec5SDimitry Andric template <>
4849*cb14a3feSDimitry Andric __time_get_storage<wchar_t>::__time_get_storage(const char* __nm) : __time_get(__nm) {
48500b57cec5SDimitry Andric   const __time_get_temp<wchar_t> ct(__nm);
48510b57cec5SDimitry Andric   init(ct);
48520b57cec5SDimitry Andric }
48530b57cec5SDimitry Andric 
48540b57cec5SDimitry Andric template <>
4855*cb14a3feSDimitry Andric __time_get_storage<wchar_t>::__time_get_storage(const string& __nm) : __time_get(__nm) {
48560b57cec5SDimitry Andric   const __time_get_temp<wchar_t> ct(__nm);
48570b57cec5SDimitry Andric   init(ct);
48580b57cec5SDimitry Andric }
4859349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
48600b57cec5SDimitry Andric 
48610b57cec5SDimitry Andric template <>
4862*cb14a3feSDimitry Andric time_base::dateorder __time_get_storage<char>::__do_date_order() const {
48630b57cec5SDimitry Andric   unsigned i;
48640b57cec5SDimitry Andric   for (i = 0; i < __x_.size(); ++i)
48650b57cec5SDimitry Andric     if (__x_[i] == '%')
48660b57cec5SDimitry Andric       break;
48670b57cec5SDimitry Andric   ++i;
4868*cb14a3feSDimitry Andric   switch (__x_[i]) {
48690b57cec5SDimitry Andric   case 'y':
48700b57cec5SDimitry Andric   case 'Y':
48710b57cec5SDimitry Andric     for (++i; i < __x_.size(); ++i)
48720b57cec5SDimitry Andric       if (__x_[i] == '%')
48730b57cec5SDimitry Andric         break;
48740b57cec5SDimitry Andric     if (i == __x_.size())
48750b57cec5SDimitry Andric       break;
48760b57cec5SDimitry Andric     ++i;
4877*cb14a3feSDimitry Andric     switch (__x_[i]) {
48780b57cec5SDimitry Andric     case 'm':
48790b57cec5SDimitry Andric       for (++i; i < __x_.size(); ++i)
48800b57cec5SDimitry Andric         if (__x_[i] == '%')
48810b57cec5SDimitry Andric           break;
48820b57cec5SDimitry Andric       if (i == __x_.size())
48830b57cec5SDimitry Andric         break;
48840b57cec5SDimitry Andric       ++i;
48850b57cec5SDimitry Andric       if (__x_[i] == 'd')
48860b57cec5SDimitry Andric         return time_base::ymd;
48870b57cec5SDimitry Andric       break;
48880b57cec5SDimitry Andric     case 'd':
48890b57cec5SDimitry Andric       for (++i; i < __x_.size(); ++i)
48900b57cec5SDimitry Andric         if (__x_[i] == '%')
48910b57cec5SDimitry Andric           break;
48920b57cec5SDimitry Andric       if (i == __x_.size())
48930b57cec5SDimitry Andric         break;
48940b57cec5SDimitry Andric       ++i;
48950b57cec5SDimitry Andric       if (__x_[i] == 'm')
48960b57cec5SDimitry Andric         return time_base::ydm;
48970b57cec5SDimitry Andric       break;
48980b57cec5SDimitry Andric     }
48990b57cec5SDimitry Andric     break;
49000b57cec5SDimitry Andric   case 'm':
49010b57cec5SDimitry Andric     for (++i; i < __x_.size(); ++i)
49020b57cec5SDimitry Andric       if (__x_[i] == '%')
49030b57cec5SDimitry Andric         break;
49040b57cec5SDimitry Andric     if (i == __x_.size())
49050b57cec5SDimitry Andric       break;
49060b57cec5SDimitry Andric     ++i;
4907*cb14a3feSDimitry Andric     if (__x_[i] == 'd') {
49080b57cec5SDimitry Andric       for (++i; i < __x_.size(); ++i)
49090b57cec5SDimitry Andric         if (__x_[i] == '%')
49100b57cec5SDimitry Andric           break;
49110b57cec5SDimitry Andric       if (i == __x_.size())
49120b57cec5SDimitry Andric         break;
49130b57cec5SDimitry Andric       ++i;
49140b57cec5SDimitry Andric       if (__x_[i] == 'y' || __x_[i] == 'Y')
49150b57cec5SDimitry Andric         return time_base::mdy;
49160b57cec5SDimitry Andric       break;
49170b57cec5SDimitry Andric     }
49180b57cec5SDimitry Andric     break;
49190b57cec5SDimitry Andric   case 'd':
49200b57cec5SDimitry Andric     for (++i; i < __x_.size(); ++i)
49210b57cec5SDimitry Andric       if (__x_[i] == '%')
49220b57cec5SDimitry Andric         break;
49230b57cec5SDimitry Andric     if (i == __x_.size())
49240b57cec5SDimitry Andric       break;
49250b57cec5SDimitry Andric     ++i;
4926*cb14a3feSDimitry Andric     if (__x_[i] == 'm') {
49270b57cec5SDimitry Andric       for (++i; i < __x_.size(); ++i)
49280b57cec5SDimitry Andric         if (__x_[i] == '%')
49290b57cec5SDimitry Andric           break;
49300b57cec5SDimitry Andric       if (i == __x_.size())
49310b57cec5SDimitry Andric         break;
49320b57cec5SDimitry Andric       ++i;
49330b57cec5SDimitry Andric       if (__x_[i] == 'y' || __x_[i] == 'Y')
49340b57cec5SDimitry Andric         return time_base::dmy;
49350b57cec5SDimitry Andric       break;
49360b57cec5SDimitry Andric     }
49370b57cec5SDimitry Andric     break;
49380b57cec5SDimitry Andric   }
49390b57cec5SDimitry Andric   return time_base::no_order;
49400b57cec5SDimitry Andric }
49410b57cec5SDimitry Andric 
4942349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
49430b57cec5SDimitry Andric template <>
4944*cb14a3feSDimitry Andric time_base::dateorder __time_get_storage<wchar_t>::__do_date_order() const {
49450b57cec5SDimitry Andric   unsigned i;
49460b57cec5SDimitry Andric   for (i = 0; i < __x_.size(); ++i)
49470b57cec5SDimitry Andric     if (__x_[i] == L'%')
49480b57cec5SDimitry Andric       break;
49490b57cec5SDimitry Andric   ++i;
4950*cb14a3feSDimitry Andric   switch (__x_[i]) {
49510b57cec5SDimitry Andric   case L'y':
49520b57cec5SDimitry Andric   case L'Y':
49530b57cec5SDimitry Andric     for (++i; i < __x_.size(); ++i)
49540b57cec5SDimitry Andric       if (__x_[i] == L'%')
49550b57cec5SDimitry Andric         break;
49560b57cec5SDimitry Andric     if (i == __x_.size())
49570b57cec5SDimitry Andric       break;
49580b57cec5SDimitry Andric     ++i;
4959*cb14a3feSDimitry Andric     switch (__x_[i]) {
49600b57cec5SDimitry Andric     case L'm':
49610b57cec5SDimitry Andric       for (++i; i < __x_.size(); ++i)
49620b57cec5SDimitry Andric         if (__x_[i] == L'%')
49630b57cec5SDimitry Andric           break;
49640b57cec5SDimitry Andric       if (i == __x_.size())
49650b57cec5SDimitry Andric         break;
49660b57cec5SDimitry Andric       ++i;
49670b57cec5SDimitry Andric       if (__x_[i] == L'd')
49680b57cec5SDimitry Andric         return time_base::ymd;
49690b57cec5SDimitry Andric       break;
49700b57cec5SDimitry Andric     case L'd':
49710b57cec5SDimitry Andric       for (++i; i < __x_.size(); ++i)
49720b57cec5SDimitry Andric         if (__x_[i] == L'%')
49730b57cec5SDimitry Andric           break;
49740b57cec5SDimitry Andric       if (i == __x_.size())
49750b57cec5SDimitry Andric         break;
49760b57cec5SDimitry Andric       ++i;
49770b57cec5SDimitry Andric       if (__x_[i] == L'm')
49780b57cec5SDimitry Andric         return time_base::ydm;
49790b57cec5SDimitry Andric       break;
49800b57cec5SDimitry Andric     }
49810b57cec5SDimitry Andric     break;
49820b57cec5SDimitry Andric   case L'm':
49830b57cec5SDimitry Andric     for (++i; i < __x_.size(); ++i)
49840b57cec5SDimitry Andric       if (__x_[i] == L'%')
49850b57cec5SDimitry Andric         break;
49860b57cec5SDimitry Andric     if (i == __x_.size())
49870b57cec5SDimitry Andric       break;
49880b57cec5SDimitry Andric     ++i;
4989*cb14a3feSDimitry Andric     if (__x_[i] == L'd') {
49900b57cec5SDimitry Andric       for (++i; i < __x_.size(); ++i)
49910b57cec5SDimitry Andric         if (__x_[i] == L'%')
49920b57cec5SDimitry Andric           break;
49930b57cec5SDimitry Andric       if (i == __x_.size())
49940b57cec5SDimitry Andric         break;
49950b57cec5SDimitry Andric       ++i;
49960b57cec5SDimitry Andric       if (__x_[i] == L'y' || __x_[i] == L'Y')
49970b57cec5SDimitry Andric         return time_base::mdy;
49980b57cec5SDimitry Andric       break;
49990b57cec5SDimitry Andric     }
50000b57cec5SDimitry Andric     break;
50010b57cec5SDimitry Andric   case L'd':
50020b57cec5SDimitry Andric     for (++i; i < __x_.size(); ++i)
50030b57cec5SDimitry Andric       if (__x_[i] == L'%')
50040b57cec5SDimitry Andric         break;
50050b57cec5SDimitry Andric     if (i == __x_.size())
50060b57cec5SDimitry Andric       break;
50070b57cec5SDimitry Andric     ++i;
5008*cb14a3feSDimitry Andric     if (__x_[i] == L'm') {
50090b57cec5SDimitry Andric       for (++i; i < __x_.size(); ++i)
50100b57cec5SDimitry Andric         if (__x_[i] == L'%')
50110b57cec5SDimitry Andric           break;
50120b57cec5SDimitry Andric       if (i == __x_.size())
50130b57cec5SDimitry Andric         break;
50140b57cec5SDimitry Andric       ++i;
50150b57cec5SDimitry Andric       if (__x_[i] == L'y' || __x_[i] == L'Y')
50160b57cec5SDimitry Andric         return time_base::dmy;
50170b57cec5SDimitry Andric       break;
50180b57cec5SDimitry Andric     }
50190b57cec5SDimitry Andric     break;
50200b57cec5SDimitry Andric   }
50210b57cec5SDimitry Andric   return time_base::no_order;
50220b57cec5SDimitry Andric }
5023349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
50240b57cec5SDimitry Andric 
50250b57cec5SDimitry Andric // time_put
50260b57cec5SDimitry Andric 
5027*cb14a3feSDimitry Andric __time_put::__time_put(const char* nm) : __loc_(newlocale(LC_ALL_MASK, nm, 0)) {
50280b57cec5SDimitry Andric   if (__loc_ == 0)
50295f757f3fSDimitry Andric     __throw_runtime_error(("time_put_byname failed to construct for " + string(nm)).c_str());
50300b57cec5SDimitry Andric }
50310b57cec5SDimitry Andric 
5032*cb14a3feSDimitry Andric __time_put::__time_put(const string& nm) : __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0)) {
50330b57cec5SDimitry Andric   if (__loc_ == 0)
50345f757f3fSDimitry Andric     __throw_runtime_error(("time_put_byname failed to construct for " + nm).c_str());
50350b57cec5SDimitry Andric }
50360b57cec5SDimitry Andric 
5037*cb14a3feSDimitry Andric __time_put::~__time_put() {
50380b57cec5SDimitry Andric   if (__loc_ != _LIBCPP_GET_C_LOCALE)
50390b57cec5SDimitry Andric     freelocale(__loc_);
50400b57cec5SDimitry Andric }
50410b57cec5SDimitry Andric 
5042*cb14a3feSDimitry Andric void __time_put::__do_put(char* __nb, char*& __ne, const tm* __tm, char __fmt, char __mod) const {
50430b57cec5SDimitry Andric   char fmt[] = {'%', __fmt, __mod, 0};
50440b57cec5SDimitry Andric   if (__mod != 0)
50450b57cec5SDimitry Andric     swap(fmt[1], fmt[2]);
50460b57cec5SDimitry Andric   size_t n = strftime_l(__nb, countof(__nb, __ne), fmt, __tm, __loc_);
50470b57cec5SDimitry Andric   __ne     = __nb + n;
50480b57cec5SDimitry Andric }
50490b57cec5SDimitry Andric 
5050349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
5051*cb14a3feSDimitry Andric void __time_put::__do_put(wchar_t* __wb, wchar_t*& __we, const tm* __tm, char __fmt, char __mod) const {
50520b57cec5SDimitry Andric   char __nar[100];
50530b57cec5SDimitry Andric   char* __ne = __nar + 100;
50540b57cec5SDimitry Andric   __do_put(__nar, __ne, __tm, __fmt, __mod);
50550b57cec5SDimitry Andric   mbstate_t mb     = {0};
50560b57cec5SDimitry Andric   const char* __nb = __nar;
50570b57cec5SDimitry Andric   size_t j         = __libcpp_mbsrtowcs_l(__wb, &__nb, countof(__wb, __we), &mb, __loc_);
50580b57cec5SDimitry Andric   if (j == size_t(-1))
50590b57cec5SDimitry Andric     __throw_runtime_error("locale not supported");
50600b57cec5SDimitry Andric   __we = __wb + j;
50610b57cec5SDimitry Andric }
5062349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
50630b57cec5SDimitry Andric 
50640b57cec5SDimitry Andric // moneypunct_byname
50650b57cec5SDimitry Andric 
50660b57cec5SDimitry Andric template <class charT>
5067*cb14a3feSDimitry Andric static void __init_pat(
5068*cb14a3feSDimitry Andric     money_base::pattern& pat,
5069*cb14a3feSDimitry Andric     basic_string<charT>& __curr_symbol_,
5070*cb14a3feSDimitry Andric     bool intl,
5071*cb14a3feSDimitry Andric     char cs_precedes,
5072*cb14a3feSDimitry Andric     char sep_by_space,
5073*cb14a3feSDimitry Andric     char sign_posn,
5074*cb14a3feSDimitry Andric     charT space_char) {
50750b57cec5SDimitry Andric   const char sign                = static_cast<char>(money_base::sign);
50760b57cec5SDimitry Andric   const char space               = static_cast<char>(money_base::space);
50770b57cec5SDimitry Andric   const char none                = static_cast<char>(money_base::none);
50780b57cec5SDimitry Andric   const char symbol              = static_cast<char>(money_base::symbol);
50790b57cec5SDimitry Andric   const char value               = static_cast<char>(money_base::value);
50800b57cec5SDimitry Andric   const bool symbol_contains_sep = intl && __curr_symbol_.size() == 4;
50810b57cec5SDimitry Andric 
50820b57cec5SDimitry Andric   // Comments on case branches reflect 'C11 7.11.2.1 The localeconv
50830b57cec5SDimitry Andric   // function'. "Space between sign and symbol or value" means that
50840b57cec5SDimitry Andric   // if the sign is adjacent to the symbol, there's a space between
50850b57cec5SDimitry Andric   // them, and otherwise there's a space between the sign and value.
50860b57cec5SDimitry Andric   //
50870b57cec5SDimitry Andric   // C11's localeconv specifies that the fourth character of an
50880b57cec5SDimitry Andric   // international curr_symbol is used to separate the sign and
50890b57cec5SDimitry Andric   // value when sep_by_space says to do so. C++ can't represent
50900b57cec5SDimitry Andric   // that, so we just use a space.  When sep_by_space says to
50910b57cec5SDimitry Andric   // separate the symbol and value-or-sign with a space, we rearrange the
50920b57cec5SDimitry Andric   // curr_symbol to put its spacing character on the correct side of
50930b57cec5SDimitry Andric   // the symbol.
50940b57cec5SDimitry Andric   //
50950b57cec5SDimitry Andric   // We also need to avoid adding an extra space between the sign
50960b57cec5SDimitry Andric   // and value when the currency symbol is suppressed (by not
50970b57cec5SDimitry Andric   // setting showbase).  We match glibc's strfmon by interpreting
50980b57cec5SDimitry Andric   // sep_by_space==1 as "omit the space when the currency symbol is
50990b57cec5SDimitry Andric   // absent".
51000b57cec5SDimitry Andric   //
51010b57cec5SDimitry Andric   // Users who want to get this right should use ICU instead.
51020b57cec5SDimitry Andric 
5103*cb14a3feSDimitry Andric   switch (cs_precedes) {
51040b57cec5SDimitry Andric   case 0: // value before curr_symbol
51050b57cec5SDimitry Andric     if (symbol_contains_sep) {
51060b57cec5SDimitry Andric       // Move the separator to before the symbol, to place it
51070b57cec5SDimitry Andric       // between the value and symbol.
5108*cb14a3feSDimitry Andric       rotate(__curr_symbol_.begin(), __curr_symbol_.begin() + 3, __curr_symbol_.end());
51090b57cec5SDimitry Andric     }
5110*cb14a3feSDimitry Andric     switch (sign_posn) {
51110b57cec5SDimitry Andric     case 0: // Parentheses surround the quantity and currency symbol.
51120b57cec5SDimitry Andric       pat.field[0] = sign;
51130b57cec5SDimitry Andric       pat.field[1] = value;
51140b57cec5SDimitry Andric       pat.field[2] = none; // Any space appears in the symbol.
51150b57cec5SDimitry Andric       pat.field[3] = symbol;
5116*cb14a3feSDimitry Andric       switch (sep_by_space) {
51170b57cec5SDimitry Andric       case 0: // No space separates the currency symbol and value.
51180b57cec5SDimitry Andric               // This case may have changed between C99 and C11;
51190b57cec5SDimitry Andric               // assume the currency symbol matches the intention.
51200b57cec5SDimitry Andric       case 2: // Space between sign and currency or value.
51210b57cec5SDimitry Andric         // The "sign" is two parentheses, so no space here either.
51220b57cec5SDimitry Andric         return;
51230b57cec5SDimitry Andric       case 1: // Space between currency-and-sign or currency and value.
51240b57cec5SDimitry Andric         if (!symbol_contains_sep) {
51250b57cec5SDimitry Andric           // We insert the space into the symbol instead of
51260b57cec5SDimitry Andric           // setting pat.field[2]=space so that when
51270b57cec5SDimitry Andric           // showbase is not set, the space goes away too.
51280b57cec5SDimitry Andric           __curr_symbol_.insert(0, 1, space_char);
51290b57cec5SDimitry Andric         }
51300b57cec5SDimitry Andric         return;
51310b57cec5SDimitry Andric       default:
51320b57cec5SDimitry Andric         break;
51330b57cec5SDimitry Andric       }
51340b57cec5SDimitry Andric       break;
51350b57cec5SDimitry Andric     case 1: // The sign string precedes the quantity and currency symbol.
51360b57cec5SDimitry Andric       pat.field[0] = sign;
51370b57cec5SDimitry Andric       pat.field[3] = symbol;
5138*cb14a3feSDimitry Andric       switch (sep_by_space) {
51390b57cec5SDimitry Andric       case 0: // No space separates the currency symbol and value.
51400b57cec5SDimitry Andric         pat.field[1] = value;
51410b57cec5SDimitry Andric         pat.field[2] = none;
51420b57cec5SDimitry Andric         return;
51430b57cec5SDimitry Andric       case 1: // Space between currency-and-sign or currency and value.
51440b57cec5SDimitry Andric         pat.field[1] = value;
51450b57cec5SDimitry Andric         pat.field[2] = none;
51460b57cec5SDimitry Andric         if (!symbol_contains_sep) {
51470b57cec5SDimitry Andric           // We insert the space into the symbol instead of
51480b57cec5SDimitry Andric           // setting pat.field[2]=space so that when
51490b57cec5SDimitry Andric           // showbase is not set, the space goes away too.
51500b57cec5SDimitry Andric           __curr_symbol_.insert(0, 1, space_char);
51510b57cec5SDimitry Andric         }
51520b57cec5SDimitry Andric         return;
51530b57cec5SDimitry Andric       case 2: // Space between sign and currency or value.
51540b57cec5SDimitry Andric         pat.field[1] = space;
51550b57cec5SDimitry Andric         pat.field[2] = value;
51560b57cec5SDimitry Andric         if (symbol_contains_sep) {
51570b57cec5SDimitry Andric           // Remove the separator from the symbol, since it
51580b57cec5SDimitry Andric           // has already appeared after the sign.
51590b57cec5SDimitry Andric           __curr_symbol_.erase(__curr_symbol_.begin());
51600b57cec5SDimitry Andric         }
51610b57cec5SDimitry Andric         return;
51620b57cec5SDimitry Andric       default:
51630b57cec5SDimitry Andric         break;
51640b57cec5SDimitry Andric       }
51650b57cec5SDimitry Andric       break;
51660b57cec5SDimitry Andric     case 2: // The sign string succeeds the quantity and currency symbol.
51670b57cec5SDimitry Andric       pat.field[0] = value;
51680b57cec5SDimitry Andric       pat.field[3] = sign;
5169*cb14a3feSDimitry Andric       switch (sep_by_space) {
51700b57cec5SDimitry Andric       case 0: // No space separates the currency symbol and value.
51710b57cec5SDimitry Andric         pat.field[1] = none;
51720b57cec5SDimitry Andric         pat.field[2] = symbol;
51730b57cec5SDimitry Andric         return;
51740b57cec5SDimitry Andric       case 1: // Space between currency-and-sign or currency and value.
51750b57cec5SDimitry Andric         if (!symbol_contains_sep) {
51760b57cec5SDimitry Andric           // We insert the space into the symbol instead of
51770b57cec5SDimitry Andric           // setting pat.field[1]=space so that when
51780b57cec5SDimitry Andric           // showbase is not set, the space goes away too.
51790b57cec5SDimitry Andric           __curr_symbol_.insert(0, 1, space_char);
51800b57cec5SDimitry Andric         }
51810b57cec5SDimitry Andric         pat.field[1] = none;
51820b57cec5SDimitry Andric         pat.field[2] = symbol;
51830b57cec5SDimitry Andric         return;
51840b57cec5SDimitry Andric       case 2: // Space between sign and currency or value.
51850b57cec5SDimitry Andric         pat.field[1] = symbol;
51860b57cec5SDimitry Andric         pat.field[2] = space;
51870b57cec5SDimitry Andric         if (symbol_contains_sep) {
51880b57cec5SDimitry Andric           // Remove the separator from the symbol, since it
51890b57cec5SDimitry Andric           // should not be removed if showbase is absent.
51900b57cec5SDimitry Andric           __curr_symbol_.erase(__curr_symbol_.begin());
51910b57cec5SDimitry Andric         }
51920b57cec5SDimitry Andric         return;
51930b57cec5SDimitry Andric       default:
51940b57cec5SDimitry Andric         break;
51950b57cec5SDimitry Andric       }
51960b57cec5SDimitry Andric       break;
51970b57cec5SDimitry Andric     case 3: // The sign string immediately precedes the currency symbol.
51980b57cec5SDimitry Andric       pat.field[0] = value;
51990b57cec5SDimitry Andric       pat.field[3] = symbol;
5200*cb14a3feSDimitry Andric       switch (sep_by_space) {
52010b57cec5SDimitry Andric       case 0: // No space separates the currency symbol and value.
52020b57cec5SDimitry Andric         pat.field[1] = none;
52030b57cec5SDimitry Andric         pat.field[2] = sign;
52040b57cec5SDimitry Andric         return;
52050b57cec5SDimitry Andric       case 1: // Space between currency-and-sign or currency and value.
52060b57cec5SDimitry Andric         pat.field[1] = space;
52070b57cec5SDimitry Andric         pat.field[2] = sign;
52080b57cec5SDimitry Andric         if (symbol_contains_sep) {
52090b57cec5SDimitry Andric           // Remove the separator from the symbol, since it
52100b57cec5SDimitry Andric           // has already appeared before the sign.
52110b57cec5SDimitry Andric           __curr_symbol_.erase(__curr_symbol_.begin());
52120b57cec5SDimitry Andric         }
52130b57cec5SDimitry Andric         return;
52140b57cec5SDimitry Andric       case 2: // Space between sign and currency or value.
52150b57cec5SDimitry Andric         pat.field[1] = sign;
52160b57cec5SDimitry Andric         pat.field[2] = none;
52170b57cec5SDimitry Andric         if (!symbol_contains_sep) {
52180b57cec5SDimitry Andric           // We insert the space into the symbol instead of
52190b57cec5SDimitry Andric           // setting pat.field[2]=space so that when
52200b57cec5SDimitry Andric           // showbase is not set, the space goes away too.
52210b57cec5SDimitry Andric           __curr_symbol_.insert(0, 1, space_char);
52220b57cec5SDimitry Andric         }
52230b57cec5SDimitry Andric         return;
52240b57cec5SDimitry Andric       default:
52250b57cec5SDimitry Andric         break;
52260b57cec5SDimitry Andric       }
52270b57cec5SDimitry Andric       break;
52280b57cec5SDimitry Andric     case 4: // The sign string immediately succeeds the currency symbol.
52290b57cec5SDimitry Andric       pat.field[0] = value;
52300b57cec5SDimitry Andric       pat.field[3] = sign;
5231*cb14a3feSDimitry Andric       switch (sep_by_space) {
52320b57cec5SDimitry Andric       case 0: // No space separates the currency symbol and value.
52330b57cec5SDimitry Andric         pat.field[1] = none;
52340b57cec5SDimitry Andric         pat.field[2] = symbol;
52350b57cec5SDimitry Andric         return;
52360b57cec5SDimitry Andric       case 1: // Space between currency-and-sign or currency and value.
52370b57cec5SDimitry Andric         pat.field[1] = none;
52380b57cec5SDimitry Andric         pat.field[2] = symbol;
52390b57cec5SDimitry Andric         if (!symbol_contains_sep) {
52400b57cec5SDimitry Andric           // We insert the space into the symbol instead of
52410b57cec5SDimitry Andric           // setting pat.field[1]=space so that when
52420b57cec5SDimitry Andric           // showbase is not set, the space goes away too.
52430b57cec5SDimitry Andric           __curr_symbol_.insert(0, 1, space_char);
52440b57cec5SDimitry Andric         }
52450b57cec5SDimitry Andric         return;
52460b57cec5SDimitry Andric       case 2: // Space between sign and currency or value.
52470b57cec5SDimitry Andric         pat.field[1] = symbol;
52480b57cec5SDimitry Andric         pat.field[2] = space;
52490b57cec5SDimitry Andric         if (symbol_contains_sep) {
52500b57cec5SDimitry Andric           // Remove the separator from the symbol, since it
52510b57cec5SDimitry Andric           // should not disappear when showbase is absent.
52520b57cec5SDimitry Andric           __curr_symbol_.erase(__curr_symbol_.begin());
52530b57cec5SDimitry Andric         }
52540b57cec5SDimitry Andric         return;
52550b57cec5SDimitry Andric       default:
52560b57cec5SDimitry Andric         break;
52570b57cec5SDimitry Andric       }
52580b57cec5SDimitry Andric       break;
52590b57cec5SDimitry Andric     default:
52600b57cec5SDimitry Andric       break;
52610b57cec5SDimitry Andric     }
52620b57cec5SDimitry Andric     break;
52630b57cec5SDimitry Andric   case 1: // curr_symbol before value
5264*cb14a3feSDimitry Andric     switch (sign_posn) {
52650b57cec5SDimitry Andric     case 0: // Parentheses surround the quantity and currency symbol.
52660b57cec5SDimitry Andric       pat.field[0] = sign;
52670b57cec5SDimitry Andric       pat.field[1] = symbol;
52680b57cec5SDimitry Andric       pat.field[2] = none; // Any space appears in the symbol.
52690b57cec5SDimitry Andric       pat.field[3] = value;
5270*cb14a3feSDimitry Andric       switch (sep_by_space) {
52710b57cec5SDimitry Andric       case 0: // No space separates the currency symbol and value.
52720b57cec5SDimitry Andric               // This case may have changed between C99 and C11;
52730b57cec5SDimitry Andric               // assume the currency symbol matches the intention.
52740b57cec5SDimitry Andric       case 2: // Space between sign and currency or value.
52750b57cec5SDimitry Andric         // The "sign" is two parentheses, so no space here either.
52760b57cec5SDimitry Andric         return;
52770b57cec5SDimitry Andric       case 1: // Space between currency-and-sign or currency and value.
52780b57cec5SDimitry Andric         if (!symbol_contains_sep) {
52790b57cec5SDimitry Andric           // We insert the space into the symbol instead of
52800b57cec5SDimitry Andric           // setting pat.field[2]=space so that when
52810b57cec5SDimitry Andric           // showbase is not set, the space goes away too.
52820b57cec5SDimitry Andric           __curr_symbol_.insert(0, 1, space_char);
52830b57cec5SDimitry Andric         }
52840b57cec5SDimitry Andric         return;
52850b57cec5SDimitry Andric       default:
52860b57cec5SDimitry Andric         break;
52870b57cec5SDimitry Andric       }
52880b57cec5SDimitry Andric       break;
52890b57cec5SDimitry Andric     case 1: // The sign string precedes the quantity and currency symbol.
52900b57cec5SDimitry Andric       pat.field[0] = sign;
52910b57cec5SDimitry Andric       pat.field[3] = value;
5292*cb14a3feSDimitry Andric       switch (sep_by_space) {
52930b57cec5SDimitry Andric       case 0: // No space separates the currency symbol and value.
52940b57cec5SDimitry Andric         pat.field[1] = symbol;
52950b57cec5SDimitry Andric         pat.field[2] = none;
52960b57cec5SDimitry Andric         return;
52970b57cec5SDimitry Andric       case 1: // Space between currency-and-sign or currency and value.
52980b57cec5SDimitry Andric         pat.field[1] = symbol;
52990b57cec5SDimitry Andric         pat.field[2] = none;
53000b57cec5SDimitry Andric         if (!symbol_contains_sep) {
53010b57cec5SDimitry Andric           // We insert the space into the symbol instead of
53020b57cec5SDimitry Andric           // setting pat.field[2]=space so that when
53030b57cec5SDimitry Andric           // showbase is not set, the space goes away too.
53040b57cec5SDimitry Andric           __curr_symbol_.push_back(space_char);
53050b57cec5SDimitry Andric         }
53060b57cec5SDimitry Andric         return;
53070b57cec5SDimitry Andric       case 2: // Space between sign and currency or value.
53080b57cec5SDimitry Andric         pat.field[1] = space;
53090b57cec5SDimitry Andric         pat.field[2] = symbol;
53100b57cec5SDimitry Andric         if (symbol_contains_sep) {
53110b57cec5SDimitry Andric           // Remove the separator from the symbol, since it
53120b57cec5SDimitry Andric           // has already appeared after the sign.
53130b57cec5SDimitry Andric           __curr_symbol_.pop_back();
53140b57cec5SDimitry Andric         }
53150b57cec5SDimitry Andric         return;
53160b57cec5SDimitry Andric       default:
53170b57cec5SDimitry Andric         break;
53180b57cec5SDimitry Andric       }
53190b57cec5SDimitry Andric       break;
53200b57cec5SDimitry Andric     case 2: // The sign string succeeds the quantity and currency symbol.
53210b57cec5SDimitry Andric       pat.field[0] = symbol;
53220b57cec5SDimitry Andric       pat.field[3] = sign;
5323*cb14a3feSDimitry Andric       switch (sep_by_space) {
53240b57cec5SDimitry Andric       case 0: // No space separates the currency symbol and value.
53250b57cec5SDimitry Andric         pat.field[1] = none;
53260b57cec5SDimitry Andric         pat.field[2] = value;
53270b57cec5SDimitry Andric         return;
53280b57cec5SDimitry Andric       case 1: // Space between currency-and-sign or currency and value.
53290b57cec5SDimitry Andric         pat.field[1] = none;
53300b57cec5SDimitry Andric         pat.field[2] = value;
53310b57cec5SDimitry Andric         if (!symbol_contains_sep) {
53320b57cec5SDimitry Andric           // We insert the space into the symbol instead of
53330b57cec5SDimitry Andric           // setting pat.field[1]=space so that when
53340b57cec5SDimitry Andric           // showbase is not set, the space goes away too.
53350b57cec5SDimitry Andric           __curr_symbol_.push_back(space_char);
53360b57cec5SDimitry Andric         }
53370b57cec5SDimitry Andric         return;
53380b57cec5SDimitry Andric       case 2: // Space between sign and currency or value.
53390b57cec5SDimitry Andric         pat.field[1] = value;
53400b57cec5SDimitry Andric         pat.field[2] = space;
53410b57cec5SDimitry Andric         if (symbol_contains_sep) {
53420b57cec5SDimitry Andric           // Remove the separator from the symbol, since it
53430b57cec5SDimitry Andric           // will appear before the sign.
53440b57cec5SDimitry Andric           __curr_symbol_.pop_back();
53450b57cec5SDimitry Andric         }
53460b57cec5SDimitry Andric         return;
53470b57cec5SDimitry Andric       default:
53480b57cec5SDimitry Andric         break;
53490b57cec5SDimitry Andric       }
53500b57cec5SDimitry Andric       break;
53510b57cec5SDimitry Andric     case 3: // The sign string immediately precedes the currency symbol.
53520b57cec5SDimitry Andric       pat.field[0] = sign;
53530b57cec5SDimitry Andric       pat.field[3] = value;
5354*cb14a3feSDimitry Andric       switch (sep_by_space) {
53550b57cec5SDimitry Andric       case 0: // No space separates the currency symbol and value.
53560b57cec5SDimitry Andric         pat.field[1] = symbol;
53570b57cec5SDimitry Andric         pat.field[2] = none;
53580b57cec5SDimitry Andric         return;
53590b57cec5SDimitry Andric       case 1: // Space between currency-and-sign or currency and value.
53600b57cec5SDimitry Andric         pat.field[1] = symbol;
53610b57cec5SDimitry Andric         pat.field[2] = none;
53620b57cec5SDimitry Andric         if (!symbol_contains_sep) {
53630b57cec5SDimitry Andric           // We insert the space into the symbol instead of
53640b57cec5SDimitry Andric           // setting pat.field[2]=space so that when
53650b57cec5SDimitry Andric           // showbase is not set, the space goes away too.
53660b57cec5SDimitry Andric           __curr_symbol_.push_back(space_char);
53670b57cec5SDimitry Andric         }
53680b57cec5SDimitry Andric         return;
53690b57cec5SDimitry Andric       case 2: // Space between sign and currency or value.
53700b57cec5SDimitry Andric         pat.field[1] = space;
53710b57cec5SDimitry Andric         pat.field[2] = symbol;
53720b57cec5SDimitry Andric         if (symbol_contains_sep) {
53730b57cec5SDimitry Andric           // Remove the separator from the symbol, since it
53740b57cec5SDimitry Andric           // has already appeared after the sign.
53750b57cec5SDimitry Andric           __curr_symbol_.pop_back();
53760b57cec5SDimitry Andric         }
53770b57cec5SDimitry Andric         return;
53780b57cec5SDimitry Andric       default:
53790b57cec5SDimitry Andric         break;
53800b57cec5SDimitry Andric       }
53810b57cec5SDimitry Andric       break;
53820b57cec5SDimitry Andric     case 4: // The sign string immediately succeeds the currency symbol.
53830b57cec5SDimitry Andric       pat.field[0] = symbol;
53840b57cec5SDimitry Andric       pat.field[3] = value;
5385*cb14a3feSDimitry Andric       switch (sep_by_space) {
53860b57cec5SDimitry Andric       case 0: // No space separates the currency symbol and value.
53870b57cec5SDimitry Andric         pat.field[1] = sign;
53880b57cec5SDimitry Andric         pat.field[2] = none;
53890b57cec5SDimitry Andric         return;
53900b57cec5SDimitry Andric       case 1: // Space between currency-and-sign or currency and value.
53910b57cec5SDimitry Andric         pat.field[1] = sign;
53920b57cec5SDimitry Andric         pat.field[2] = space;
53930b57cec5SDimitry Andric         if (symbol_contains_sep) {
53940b57cec5SDimitry Andric           // Remove the separator from the symbol, since it
53950b57cec5SDimitry Andric           // should not disappear when showbase is absent.
53960b57cec5SDimitry Andric           __curr_symbol_.pop_back();
53970b57cec5SDimitry Andric         }
53980b57cec5SDimitry Andric         return;
53990b57cec5SDimitry Andric       case 2: // Space between sign and currency or value.
54000b57cec5SDimitry Andric         pat.field[1] = none;
54010b57cec5SDimitry Andric         pat.field[2] = sign;
54020b57cec5SDimitry Andric         if (!symbol_contains_sep) {
54030b57cec5SDimitry Andric           // We insert the space into the symbol instead of
54040b57cec5SDimitry Andric           // setting pat.field[1]=space so that when
54050b57cec5SDimitry Andric           // showbase is not set, the space goes away too.
54060b57cec5SDimitry Andric           __curr_symbol_.push_back(space_char);
54070b57cec5SDimitry Andric         }
54080b57cec5SDimitry Andric         return;
54090b57cec5SDimitry Andric       default:
54100b57cec5SDimitry Andric         break;
54110b57cec5SDimitry Andric       }
54120b57cec5SDimitry Andric       break;
54130b57cec5SDimitry Andric     default:
54140b57cec5SDimitry Andric       break;
54150b57cec5SDimitry Andric     }
54160b57cec5SDimitry Andric     break;
54170b57cec5SDimitry Andric   default:
54180b57cec5SDimitry Andric     break;
54190b57cec5SDimitry Andric   }
54200b57cec5SDimitry Andric   pat.field[0] = symbol;
54210b57cec5SDimitry Andric   pat.field[1] = sign;
54220b57cec5SDimitry Andric   pat.field[2] = none;
54230b57cec5SDimitry Andric   pat.field[3] = value;
54240b57cec5SDimitry Andric }
54250b57cec5SDimitry Andric 
54260b57cec5SDimitry Andric template <>
5427*cb14a3feSDimitry Andric void moneypunct_byname<char, false>::init(const char* nm) {
54280b57cec5SDimitry Andric   typedef moneypunct<char, false> base;
54290b57cec5SDimitry Andric   __libcpp_unique_locale loc(nm);
54300b57cec5SDimitry Andric   if (!loc)
54315f757f3fSDimitry Andric     __throw_runtime_error(("moneypunct_byname failed to construct for " + string(nm)).c_str());
54320b57cec5SDimitry Andric 
54330b57cec5SDimitry Andric   lconv* lc = __libcpp_localeconv_l(loc.get());
5434*cb14a3feSDimitry Andric   if (!checked_string_to_char_convert(__decimal_point_, lc->mon_decimal_point, loc.get()))
54350b57cec5SDimitry Andric     __decimal_point_ = base::do_decimal_point();
5436*cb14a3feSDimitry Andric   if (!checked_string_to_char_convert(__thousands_sep_, lc->mon_thousands_sep, loc.get()))
54370b57cec5SDimitry Andric     __thousands_sep_ = base::do_thousands_sep();
54380b57cec5SDimitry Andric 
54390b57cec5SDimitry Andric   __grouping_    = lc->mon_grouping;
54400b57cec5SDimitry Andric   __curr_symbol_ = lc->currency_symbol;
54410b57cec5SDimitry Andric   if (lc->frac_digits != CHAR_MAX)
54420b57cec5SDimitry Andric     __frac_digits_ = lc->frac_digits;
54430b57cec5SDimitry Andric   else
54440b57cec5SDimitry Andric     __frac_digits_ = base::do_frac_digits();
54450b57cec5SDimitry Andric   if (lc->p_sign_posn == 0)
54460b57cec5SDimitry Andric     __positive_sign_ = "()";
54470b57cec5SDimitry Andric   else
54480b57cec5SDimitry Andric     __positive_sign_ = lc->positive_sign;
54490b57cec5SDimitry Andric   if (lc->n_sign_posn == 0)
54500b57cec5SDimitry Andric     __negative_sign_ = "()";
54510b57cec5SDimitry Andric   else
54520b57cec5SDimitry Andric     __negative_sign_ = lc->negative_sign;
54530b57cec5SDimitry Andric   // Assume the positive and negative formats will want spaces in
54540b57cec5SDimitry Andric   // the same places in curr_symbol since there's no way to
54550b57cec5SDimitry Andric   // represent anything else.
54560b57cec5SDimitry Andric   string_type __dummy_curr_symbol = __curr_symbol_;
5457*cb14a3feSDimitry Andric   __init_pat(__pos_format_, __dummy_curr_symbol, false, lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, ' ');
5458*cb14a3feSDimitry Andric   __init_pat(__neg_format_, __curr_symbol_, false, lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, ' ');
54590b57cec5SDimitry Andric }
54600b57cec5SDimitry Andric 
54610b57cec5SDimitry Andric template <>
5462*cb14a3feSDimitry Andric void moneypunct_byname<char, true>::init(const char* nm) {
54630b57cec5SDimitry Andric   typedef moneypunct<char, true> base;
54640b57cec5SDimitry Andric   __libcpp_unique_locale loc(nm);
54650b57cec5SDimitry Andric   if (!loc)
54665f757f3fSDimitry Andric     __throw_runtime_error(("moneypunct_byname failed to construct for " + string(nm)).c_str());
54670b57cec5SDimitry Andric 
54680b57cec5SDimitry Andric   lconv* lc = __libcpp_localeconv_l(loc.get());
5469*cb14a3feSDimitry Andric   if (!checked_string_to_char_convert(__decimal_point_, lc->mon_decimal_point, loc.get()))
54700b57cec5SDimitry Andric     __decimal_point_ = base::do_decimal_point();
5471*cb14a3feSDimitry Andric   if (!checked_string_to_char_convert(__thousands_sep_, lc->mon_thousands_sep, loc.get()))
54720b57cec5SDimitry Andric     __thousands_sep_ = base::do_thousands_sep();
54730b57cec5SDimitry Andric   __grouping_    = lc->mon_grouping;
54740b57cec5SDimitry Andric   __curr_symbol_ = lc->int_curr_symbol;
54750b57cec5SDimitry Andric   if (lc->int_frac_digits != CHAR_MAX)
54760b57cec5SDimitry Andric     __frac_digits_ = lc->int_frac_digits;
54770b57cec5SDimitry Andric   else
54780b57cec5SDimitry Andric     __frac_digits_ = base::do_frac_digits();
54790b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
54800b57cec5SDimitry Andric   if (lc->p_sign_posn == 0)
54810b57cec5SDimitry Andric #else  // _LIBCPP_MSVCRT
54820b57cec5SDimitry Andric   if (lc->int_p_sign_posn == 0)
54830b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
54840b57cec5SDimitry Andric     __positive_sign_ = "()";
54850b57cec5SDimitry Andric   else
54860b57cec5SDimitry Andric     __positive_sign_ = lc->positive_sign;
54870b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
54880b57cec5SDimitry Andric   if (lc->n_sign_posn == 0)
54890b57cec5SDimitry Andric #else  // _LIBCPP_MSVCRT
54900b57cec5SDimitry Andric   if (lc->int_n_sign_posn == 0)
54910b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
54920b57cec5SDimitry Andric     __negative_sign_ = "()";
54930b57cec5SDimitry Andric   else
54940b57cec5SDimitry Andric     __negative_sign_ = lc->negative_sign;
54950b57cec5SDimitry Andric   // Assume the positive and negative formats will want spaces in
54960b57cec5SDimitry Andric   // the same places in curr_symbol since there's no way to
54970b57cec5SDimitry Andric   // represent anything else.
54980b57cec5SDimitry Andric   string_type __dummy_curr_symbol = __curr_symbol_;
54990b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
5500*cb14a3feSDimitry Andric   __init_pat(__pos_format_, __dummy_curr_symbol, true, lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, ' ');
5501*cb14a3feSDimitry Andric   __init_pat(__neg_format_, __curr_symbol_, true, lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, ' ');
55020b57cec5SDimitry Andric #else  // _LIBCPP_MSVCRT
5503*cb14a3feSDimitry Andric   __init_pat(
5504*cb14a3feSDimitry Andric       __pos_format_,
5505*cb14a3feSDimitry Andric       __dummy_curr_symbol,
5506*cb14a3feSDimitry Andric       true,
5507*cb14a3feSDimitry Andric       lc->int_p_cs_precedes,
5508*cb14a3feSDimitry Andric       lc->int_p_sep_by_space,
5509*cb14a3feSDimitry Andric       lc->int_p_sign_posn,
5510*cb14a3feSDimitry Andric       ' ');
5511*cb14a3feSDimitry Andric   __init_pat(
5512*cb14a3feSDimitry Andric       __neg_format_, __curr_symbol_, true, lc->int_n_cs_precedes, lc->int_n_sep_by_space, lc->int_n_sign_posn, ' ');
55130b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
55140b57cec5SDimitry Andric }
55150b57cec5SDimitry Andric 
5516349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
55170b57cec5SDimitry Andric template <>
5518*cb14a3feSDimitry Andric void moneypunct_byname<wchar_t, false>::init(const char* nm) {
55190b57cec5SDimitry Andric   typedef moneypunct<wchar_t, false> base;
55200b57cec5SDimitry Andric   __libcpp_unique_locale loc(nm);
55210b57cec5SDimitry Andric   if (!loc)
55225f757f3fSDimitry Andric     __throw_runtime_error(("moneypunct_byname failed to construct for " + string(nm)).c_str());
55230b57cec5SDimitry Andric   lconv* lc = __libcpp_localeconv_l(loc.get());
5524*cb14a3feSDimitry Andric   if (!checked_string_to_wchar_convert(__decimal_point_, lc->mon_decimal_point, loc.get()))
55250b57cec5SDimitry Andric     __decimal_point_ = base::do_decimal_point();
5526*cb14a3feSDimitry Andric   if (!checked_string_to_wchar_convert(__thousands_sep_, lc->mon_thousands_sep, loc.get()))
55270b57cec5SDimitry Andric     __thousands_sep_ = base::do_thousands_sep();
55280b57cec5SDimitry Andric   __grouping_ = lc->mon_grouping;
55290b57cec5SDimitry Andric   wchar_t wbuf[100];
55300b57cec5SDimitry Andric   mbstate_t mb   = {0};
55310b57cec5SDimitry Andric   const char* bb = lc->currency_symbol;
55320b57cec5SDimitry Andric   size_t j       = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
55330b57cec5SDimitry Andric   if (j == size_t(-1))
55340b57cec5SDimitry Andric     __throw_runtime_error("locale not supported");
55350b57cec5SDimitry Andric   wchar_t* wbe = wbuf + j;
55360b57cec5SDimitry Andric   __curr_symbol_.assign(wbuf, wbe);
55370b57cec5SDimitry Andric   if (lc->frac_digits != CHAR_MAX)
55380b57cec5SDimitry Andric     __frac_digits_ = lc->frac_digits;
55390b57cec5SDimitry Andric   else
55400b57cec5SDimitry Andric     __frac_digits_ = base::do_frac_digits();
55410b57cec5SDimitry Andric   if (lc->p_sign_posn == 0)
55420b57cec5SDimitry Andric     __positive_sign_ = L"()";
5543*cb14a3feSDimitry Andric   else {
55440b57cec5SDimitry Andric     mb = mbstate_t();
55450b57cec5SDimitry Andric     bb = lc->positive_sign;
55460b57cec5SDimitry Andric     j  = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
55470b57cec5SDimitry Andric     if (j == size_t(-1))
55480b57cec5SDimitry Andric       __throw_runtime_error("locale not supported");
55490b57cec5SDimitry Andric     wbe = wbuf + j;
55500b57cec5SDimitry Andric     __positive_sign_.assign(wbuf, wbe);
55510b57cec5SDimitry Andric   }
55520b57cec5SDimitry Andric   if (lc->n_sign_posn == 0)
55530b57cec5SDimitry Andric     __negative_sign_ = L"()";
5554*cb14a3feSDimitry Andric   else {
55550b57cec5SDimitry Andric     mb = mbstate_t();
55560b57cec5SDimitry Andric     bb = lc->negative_sign;
55570b57cec5SDimitry Andric     j  = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
55580b57cec5SDimitry Andric     if (j == size_t(-1))
55590b57cec5SDimitry Andric       __throw_runtime_error("locale not supported");
55600b57cec5SDimitry Andric     wbe = wbuf + j;
55610b57cec5SDimitry Andric     __negative_sign_.assign(wbuf, wbe);
55620b57cec5SDimitry Andric   }
55630b57cec5SDimitry Andric   // Assume the positive and negative formats will want spaces in
55640b57cec5SDimitry Andric   // the same places in curr_symbol since there's no way to
55650b57cec5SDimitry Andric   // represent anything else.
55660b57cec5SDimitry Andric   string_type __dummy_curr_symbol = __curr_symbol_;
5567*cb14a3feSDimitry Andric   __init_pat(__pos_format_, __dummy_curr_symbol, false, lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, L' ');
5568*cb14a3feSDimitry Andric   __init_pat(__neg_format_, __curr_symbol_, false, lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, L' ');
55690b57cec5SDimitry Andric }
55700b57cec5SDimitry Andric 
55710b57cec5SDimitry Andric template <>
5572*cb14a3feSDimitry Andric void moneypunct_byname<wchar_t, true>::init(const char* nm) {
55730b57cec5SDimitry Andric   typedef moneypunct<wchar_t, true> base;
55740b57cec5SDimitry Andric   __libcpp_unique_locale loc(nm);
55750b57cec5SDimitry Andric   if (!loc)
55765f757f3fSDimitry Andric     __throw_runtime_error(("moneypunct_byname failed to construct for " + string(nm)).c_str());
55770b57cec5SDimitry Andric 
55780b57cec5SDimitry Andric   lconv* lc = __libcpp_localeconv_l(loc.get());
5579*cb14a3feSDimitry Andric   if (!checked_string_to_wchar_convert(__decimal_point_, lc->mon_decimal_point, loc.get()))
55800b57cec5SDimitry Andric     __decimal_point_ = base::do_decimal_point();
5581*cb14a3feSDimitry Andric   if (!checked_string_to_wchar_convert(__thousands_sep_, lc->mon_thousands_sep, loc.get()))
55820b57cec5SDimitry Andric     __thousands_sep_ = base::do_thousands_sep();
55830b57cec5SDimitry Andric   __grouping_ = lc->mon_grouping;
55840b57cec5SDimitry Andric   wchar_t wbuf[100];
55850b57cec5SDimitry Andric   mbstate_t mb   = {0};
55860b57cec5SDimitry Andric   const char* bb = lc->int_curr_symbol;
55870b57cec5SDimitry Andric   size_t j       = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
55880b57cec5SDimitry Andric   if (j == size_t(-1))
55890b57cec5SDimitry Andric     __throw_runtime_error("locale not supported");
55900b57cec5SDimitry Andric   wchar_t* wbe = wbuf + j;
55910b57cec5SDimitry Andric   __curr_symbol_.assign(wbuf, wbe);
55920b57cec5SDimitry Andric   if (lc->int_frac_digits != CHAR_MAX)
55930b57cec5SDimitry Andric     __frac_digits_ = lc->int_frac_digits;
55940b57cec5SDimitry Andric   else
55950b57cec5SDimitry Andric     __frac_digits_ = base::do_frac_digits();
55960b57cec5SDimitry Andric #  if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
55970b57cec5SDimitry Andric   if (lc->p_sign_posn == 0)
55980b57cec5SDimitry Andric #  else  // _LIBCPP_MSVCRT
55990b57cec5SDimitry Andric   if (lc->int_p_sign_posn == 0)
56000b57cec5SDimitry Andric #  endif // !_LIBCPP_MSVCRT
56010b57cec5SDimitry Andric     __positive_sign_ = L"()";
5602*cb14a3feSDimitry Andric   else {
56030b57cec5SDimitry Andric     mb = mbstate_t();
56040b57cec5SDimitry Andric     bb = lc->positive_sign;
56050b57cec5SDimitry Andric     j  = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
56060b57cec5SDimitry Andric     if (j == size_t(-1))
56070b57cec5SDimitry Andric       __throw_runtime_error("locale not supported");
56080b57cec5SDimitry Andric     wbe = wbuf + j;
56090b57cec5SDimitry Andric     __positive_sign_.assign(wbuf, wbe);
56100b57cec5SDimitry Andric   }
56110b57cec5SDimitry Andric #  if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
56120b57cec5SDimitry Andric   if (lc->n_sign_posn == 0)
56130b57cec5SDimitry Andric #  else  // _LIBCPP_MSVCRT
56140b57cec5SDimitry Andric   if (lc->int_n_sign_posn == 0)
56150b57cec5SDimitry Andric #  endif // !_LIBCPP_MSVCRT
56160b57cec5SDimitry Andric     __negative_sign_ = L"()";
5617*cb14a3feSDimitry Andric   else {
56180b57cec5SDimitry Andric     mb = mbstate_t();
56190b57cec5SDimitry Andric     bb = lc->negative_sign;
56200b57cec5SDimitry Andric     j  = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
56210b57cec5SDimitry Andric     if (j == size_t(-1))
56220b57cec5SDimitry Andric       __throw_runtime_error("locale not supported");
56230b57cec5SDimitry Andric     wbe = wbuf + j;
56240b57cec5SDimitry Andric     __negative_sign_.assign(wbuf, wbe);
56250b57cec5SDimitry Andric   }
56260b57cec5SDimitry Andric   // Assume the positive and negative formats will want spaces in
56270b57cec5SDimitry Andric   // the same places in curr_symbol since there's no way to
56280b57cec5SDimitry Andric   // represent anything else.
56290b57cec5SDimitry Andric   string_type __dummy_curr_symbol = __curr_symbol_;
56300b57cec5SDimitry Andric #  if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
5631*cb14a3feSDimitry Andric   __init_pat(__pos_format_, __dummy_curr_symbol, true, lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, L' ');
5632*cb14a3feSDimitry Andric   __init_pat(__neg_format_, __curr_symbol_, true, lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, L' ');
56330b57cec5SDimitry Andric #  else  // _LIBCPP_MSVCRT
5634*cb14a3feSDimitry Andric   __init_pat(
5635*cb14a3feSDimitry Andric       __pos_format_,
5636*cb14a3feSDimitry Andric       __dummy_curr_symbol,
5637*cb14a3feSDimitry Andric       true,
5638*cb14a3feSDimitry Andric       lc->int_p_cs_precedes,
5639*cb14a3feSDimitry Andric       lc->int_p_sep_by_space,
5640*cb14a3feSDimitry Andric       lc->int_p_sign_posn,
5641*cb14a3feSDimitry Andric       L' ');
5642*cb14a3feSDimitry Andric   __init_pat(
5643*cb14a3feSDimitry Andric       __neg_format_, __curr_symbol_, true, lc->int_n_cs_precedes, lc->int_n_sep_by_space, lc->int_n_sign_posn, L' ');
56440b57cec5SDimitry Andric #  endif // !_LIBCPP_MSVCRT
56450b57cec5SDimitry Andric }
5646349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
56470b57cec5SDimitry Andric 
56480b57cec5SDimitry Andric void __do_nothing(void*) {}
56490b57cec5SDimitry Andric 
56500b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<char>;
5651349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<wchar_t>;)
56520b57cec5SDimitry Andric 
56530b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<char>;
5654349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<wchar_t>;)
56550b57cec5SDimitry Andric 
56560b57cec5SDimitry Andric template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<char>;
5657349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<wchar_t>;)
56580b57cec5SDimitry Andric 
56590b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<char>;
5660349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<wchar_t>;)
56610b57cec5SDimitry Andric 
56620b57cec5SDimitry Andric template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<char>;
5663349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<wchar_t>;)
56640b57cec5SDimitry Andric 
56650b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<char>;
5666349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<wchar_t>;)
56670b57cec5SDimitry Andric 
56680b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<char>;
5669349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<wchar_t>;)
56700b57cec5SDimitry Andric 
56710b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<char>;
5672349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<wchar_t>;)
56730b57cec5SDimitry Andric 
56740b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<char>;
5675349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<wchar_t>;)
56760b57cec5SDimitry Andric 
56770b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, false>;
56780b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, true>;
5679349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, false>;)
5680349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, true>;)
56810b57cec5SDimitry Andric 
56820b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, false>;
56830b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, true>;
5684349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, false>;)
5685349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, true>;)
56860b57cec5SDimitry Andric 
56870b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<char>;
5688349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<wchar_t>;)
56890b57cec5SDimitry Andric 
56900b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<char>;
5691349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<wchar_t>;)
56920b57cec5SDimitry Andric 
56930b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<char>;
5694349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<wchar_t>;)
56950b57cec5SDimitry Andric 
56960b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<char>;
5697349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<wchar_t>;)
56980b57cec5SDimitry Andric 
56990b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<char>;
5700349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<wchar_t>;)
57010b57cec5SDimitry Andric 
57020b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<char>;
5703349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<wchar_t>;)
57040b57cec5SDimitry Andric 
57050b57cec5SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char, char, mbstate_t>;
5706*cb14a3feSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(
5707*cb14a3feSDimitry Andric     template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<wchar_t, char, mbstate_t>;)
5708*cb14a3feSDimitry Andric template class _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
5709*cb14a3feSDimitry Andric     codecvt_byname<char16_t, char, mbstate_t>;
5710*cb14a3feSDimitry Andric template class _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
5711*cb14a3feSDimitry Andric     codecvt_byname<char32_t, char, mbstate_t>;
5712fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
5713e8d8bef9SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char16_t, char8_t, mbstate_t>;
5714e8d8bef9SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char32_t, char8_t, mbstate_t>;
5715e8d8bef9SDimitry Andric #endif
57160b57cec5SDimitry Andric 
57170b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
571881ad6265SDimitry Andric 
571981ad6265SDimitry Andric _LIBCPP_POP_MACROS
5720