xref: /freebsd/contrib/llvm-project/libcxx/src/locale.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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 
9*5f757f3fSDimitry Andric #include <__utility/no_destroy.h>
1081ad6265SDimitry Andric #include <algorithm>
1181ad6265SDimitry Andric #include <clocale>
1281ad6265SDimitry Andric #include <codecvt>
13*5f757f3fSDimitry Andric #include <cstddef>
1481ad6265SDimitry Andric #include <cstdio>
1581ad6265SDimitry Andric #include <cstdlib>
1681ad6265SDimitry Andric #include <cstring>
1781ad6265SDimitry Andric #include <locale>
18*5f757f3fSDimitry Andric #include <new>
1981ad6265SDimitry Andric #include <string>
2081ad6265SDimitry Andric #include <type_traits>
2181ad6265SDimitry Andric #include <typeinfo>
22*5f757f3fSDimitry 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_;
680b57cec5SDimitry Andric private:
690b57cec5SDimitry Andric   __libcpp_unique_locale(__libcpp_unique_locale const&);
700b57cec5SDimitry Andric   __libcpp_unique_locale& operator=(__libcpp_unique_locale const&);
710b57cec5SDimitry Andric };
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric #ifdef __cloc_defined
740b57cec5SDimitry Andric locale_t __cloc() {
750b57cec5SDimitry Andric   // In theory this could create a race condition. In practice
760b57cec5SDimitry Andric   // the race condition is non-fatal since it will just create
770b57cec5SDimitry Andric   // a little resource leak. Better approach would be appreciated.
780b57cec5SDimitry Andric   static locale_t result = newlocale(LC_ALL_MASK, "C", 0);
790b57cec5SDimitry Andric   return result;
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric #endif // __cloc_defined
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric namespace {
840b57cec5SDimitry Andric 
85*5f757f3fSDimitry Andric struct releaser {
860b57cec5SDimitry Andric   void operator()(locale::facet* p) { p->__release_shared(); }
870b57cec5SDimitry Andric };
880b57cec5SDimitry Andric 
89349cc55cSDimitry Andric template <class T, class ...Args>
90349cc55cSDimitry Andric T& make(Args ...args)
910b57cec5SDimitry Andric {
92*5f757f3fSDimitry 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>
980b57cec5SDimitry Andric inline
99*5f757f3fSDimitry Andric constexpr
1000b57cec5SDimitry Andric size_t
1010b57cec5SDimitry Andric countof(const T (&)[N])
1020b57cec5SDimitry Andric {
1030b57cec5SDimitry Andric     return N;
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric template <typename T>
1070b57cec5SDimitry Andric inline
108*5f757f3fSDimitry Andric constexpr
1090b57cec5SDimitry Andric size_t
1100b57cec5SDimitry Andric countof(const T * const begin, const T * const end)
1110b57cec5SDimitry Andric {
1120b57cec5SDimitry Andric     return static_cast<size_t>(end - begin);
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric 
11706c3fb27SDimitry Andric string
11806c3fb27SDimitry Andric build_name(const string& other, const string& one, locale::category c) {
11906c3fb27SDimitry Andric     if (other == "*" || one == "*")
12006c3fb27SDimitry Andric         return "*";
12106c3fb27SDimitry Andric     if (c == locale::none || other == one)
12206c3fb27SDimitry Andric         return other;
12306c3fb27SDimitry Andric 
12406c3fb27SDimitry Andric     // FIXME: Handle the more complicated cases, such as when the locale has
12506c3fb27SDimitry Andric     // different names for different categories.
12606c3fb27SDimitry Andric     return "*";
12706c3fb27SDimitry Andric }
12806c3fb27SDimitry Andric 
1290b57cec5SDimitry Andric const locale::category locale::none;
1300b57cec5SDimitry Andric const locale::category locale::collate;
1310b57cec5SDimitry Andric const locale::category locale::ctype;
1320b57cec5SDimitry Andric const locale::category locale::monetary;
1330b57cec5SDimitry Andric const locale::category locale::numeric;
1340b57cec5SDimitry Andric const locale::category locale::time;
1350b57cec5SDimitry Andric const locale::category locale::messages;
1360b57cec5SDimitry Andric const locale::category locale::all;
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric class _LIBCPP_HIDDEN locale::__imp
1390b57cec5SDimitry Andric     : public facet
1400b57cec5SDimitry Andric {
141e8d8bef9SDimitry Andric     enum {N = 30};
1420b57cec5SDimitry Andric     vector<facet*, __sso_allocator<facet*, N> > facets_;
1430b57cec5SDimitry Andric     string         name_;
1440b57cec5SDimitry Andric public:
1450b57cec5SDimitry Andric     explicit __imp(size_t refs = 0);
1460b57cec5SDimitry Andric     explicit __imp(const string& name, size_t refs = 0);
1470b57cec5SDimitry Andric     __imp(const __imp&);
1480b57cec5SDimitry Andric     __imp(const __imp&, const string&, locale::category c);
1490b57cec5SDimitry Andric     __imp(const __imp& other, const __imp& one, locale::category c);
1500b57cec5SDimitry Andric     __imp(const __imp&, facet* f, long id);
1510b57cec5SDimitry Andric     ~__imp();
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric     const string& name() const {return name_;}
1540b57cec5SDimitry Andric     bool has_facet(long id) const
1550b57cec5SDimitry Andric         {return static_cast<size_t>(id) < facets_.size() && facets_[static_cast<size_t>(id)];}
1560b57cec5SDimitry Andric     const locale::facet* use_facet(long id) const;
1570b57cec5SDimitry Andric 
158*5f757f3fSDimitry Andric     void acquire();
159*5f757f3fSDimitry Andric     void release();
160*5f757f3fSDimitry Andric     static __no_destroy<__imp> classic_locale_imp_;
161*5f757f3fSDimitry Andric 
1620b57cec5SDimitry Andric   private:
1630b57cec5SDimitry Andric     void install(facet* f, long id);
1640b57cec5SDimitry Andric     template <class F> void install(F* f) {install(f, f->id.__get());}
1650b57cec5SDimitry Andric     template <class F> void install_from(const __imp& other);
1660b57cec5SDimitry Andric };
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric locale::__imp::__imp(size_t refs)
1690b57cec5SDimitry Andric     : facet(refs),
1700b57cec5SDimitry Andric       facets_(N),
1710b57cec5SDimitry Andric       name_("C")
1720b57cec5SDimitry Andric {
1730b57cec5SDimitry Andric     facets_.clear();
174*5f757f3fSDimitry Andric     install(&make<std::collate<char> >(1u));
175349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
176*5f757f3fSDimitry Andric     install(&make<std::collate<wchar_t> >(1u));
177349cc55cSDimitry Andric #endif
178*5f757f3fSDimitry Andric     install(&make<std::ctype<char> >(nullptr, false, 1u));
179349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
180*5f757f3fSDimitry Andric     install(&make<std::ctype<wchar_t> >(1u));
181349cc55cSDimitry Andric #endif
1820b57cec5SDimitry Andric     install(&make<codecvt<char, char, mbstate_t> >(1u));
183349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1840b57cec5SDimitry Andric     install(&make<codecvt<wchar_t, char, mbstate_t> >(1u));
185349cc55cSDimitry Andric #endif
186e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
1870b57cec5SDimitry Andric     install(&make<codecvt<char16_t, char, mbstate_t> >(1u));
1880b57cec5SDimitry Andric     install(&make<codecvt<char32_t, char, mbstate_t> >(1u));
189e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
190fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
191e8d8bef9SDimitry Andric     install(&make<codecvt<char16_t, char8_t, mbstate_t> >(1u));
192e8d8bef9SDimitry Andric     install(&make<codecvt<char32_t, char8_t, mbstate_t> >(1u));
193e8d8bef9SDimitry Andric #endif
1940b57cec5SDimitry Andric     install(&make<numpunct<char> >(1u));
195349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1960b57cec5SDimitry Andric     install(&make<numpunct<wchar_t> >(1u));
197349cc55cSDimitry Andric #endif
1980b57cec5SDimitry Andric     install(&make<num_get<char> >(1u));
199349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2000b57cec5SDimitry Andric     install(&make<num_get<wchar_t> >(1u));
201349cc55cSDimitry Andric #endif
2020b57cec5SDimitry Andric     install(&make<num_put<char> >(1u));
203349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2040b57cec5SDimitry Andric     install(&make<num_put<wchar_t> >(1u));
205349cc55cSDimitry Andric #endif
2060b57cec5SDimitry Andric     install(&make<moneypunct<char, false> >(1u));
2070b57cec5SDimitry Andric     install(&make<moneypunct<char, true> >(1u));
208349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2090b57cec5SDimitry Andric     install(&make<moneypunct<wchar_t, false> >(1u));
2100b57cec5SDimitry Andric     install(&make<moneypunct<wchar_t, true> >(1u));
211349cc55cSDimitry Andric #endif
2120b57cec5SDimitry Andric     install(&make<money_get<char> >(1u));
213349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2140b57cec5SDimitry Andric     install(&make<money_get<wchar_t> >(1u));
215349cc55cSDimitry Andric #endif
2160b57cec5SDimitry Andric     install(&make<money_put<char> >(1u));
217349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2180b57cec5SDimitry Andric     install(&make<money_put<wchar_t> >(1u));
219349cc55cSDimitry Andric #endif
2200b57cec5SDimitry Andric     install(&make<time_get<char> >(1u));
221349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2220b57cec5SDimitry Andric     install(&make<time_get<wchar_t> >(1u));
223349cc55cSDimitry Andric #endif
2240b57cec5SDimitry Andric     install(&make<time_put<char> >(1u));
225349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2260b57cec5SDimitry Andric     install(&make<time_put<wchar_t> >(1u));
227349cc55cSDimitry Andric #endif
228*5f757f3fSDimitry Andric     install(&make<std::messages<char> >(1u));
229349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
230*5f757f3fSDimitry Andric     install(&make<std::messages<wchar_t> >(1u));
231349cc55cSDimitry Andric #endif
2320b57cec5SDimitry Andric }
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric locale::__imp::__imp(const string& name, size_t refs)
2350b57cec5SDimitry Andric     : facet(refs),
2360b57cec5SDimitry Andric       facets_(N),
2370b57cec5SDimitry Andric       name_(name)
2380b57cec5SDimitry Andric {
23906c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
2400b57cec5SDimitry Andric     try
2410b57cec5SDimitry Andric     {
24206c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
2430b57cec5SDimitry Andric         facets_ = locale::classic().__locale_->facets_;
2440b57cec5SDimitry Andric         for (unsigned i = 0; i < facets_.size(); ++i)
2450b57cec5SDimitry Andric             if (facets_[i])
2460b57cec5SDimitry Andric                 facets_[i]->__add_shared();
2470b57cec5SDimitry Andric         install(new collate_byname<char>(name_));
248349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2490b57cec5SDimitry Andric         install(new collate_byname<wchar_t>(name_));
250349cc55cSDimitry Andric #endif
2510b57cec5SDimitry Andric         install(new ctype_byname<char>(name_));
252349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2530b57cec5SDimitry Andric         install(new ctype_byname<wchar_t>(name_));
254349cc55cSDimitry Andric #endif
2550b57cec5SDimitry Andric         install(new codecvt_byname<char, char, mbstate_t>(name_));
256349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2570b57cec5SDimitry Andric         install(new codecvt_byname<wchar_t, char, mbstate_t>(name_));
258349cc55cSDimitry Andric #endif
259e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
2600b57cec5SDimitry Andric         install(new codecvt_byname<char16_t, char, mbstate_t>(name_));
2610b57cec5SDimitry Andric         install(new codecvt_byname<char32_t, char, mbstate_t>(name_));
262e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
263fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
264e8d8bef9SDimitry Andric         install(new codecvt_byname<char16_t, char8_t, mbstate_t>(name_));
265e8d8bef9SDimitry Andric         install(new codecvt_byname<char32_t, char8_t, mbstate_t>(name_));
266e8d8bef9SDimitry Andric #endif
2670b57cec5SDimitry Andric         install(new numpunct_byname<char>(name_));
268349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2690b57cec5SDimitry Andric         install(new numpunct_byname<wchar_t>(name_));
270349cc55cSDimitry Andric #endif
2710b57cec5SDimitry Andric         install(new moneypunct_byname<char, false>(name_));
2720b57cec5SDimitry Andric         install(new moneypunct_byname<char, true>(name_));
273349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2740b57cec5SDimitry Andric         install(new moneypunct_byname<wchar_t, false>(name_));
2750b57cec5SDimitry Andric         install(new moneypunct_byname<wchar_t, true>(name_));
276349cc55cSDimitry Andric #endif
2770b57cec5SDimitry Andric         install(new time_get_byname<char>(name_));
278349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2790b57cec5SDimitry Andric         install(new time_get_byname<wchar_t>(name_));
280349cc55cSDimitry Andric #endif
2810b57cec5SDimitry Andric         install(new time_put_byname<char>(name_));
282349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2830b57cec5SDimitry Andric         install(new time_put_byname<wchar_t>(name_));
284349cc55cSDimitry Andric #endif
2850b57cec5SDimitry Andric         install(new messages_byname<char>(name_));
286349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2870b57cec5SDimitry Andric         install(new messages_byname<wchar_t>(name_));
288349cc55cSDimitry Andric #endif
28906c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
2900b57cec5SDimitry Andric     }
2910b57cec5SDimitry Andric     catch (...)
2920b57cec5SDimitry Andric     {
2930b57cec5SDimitry Andric         for (unsigned i = 0; i < facets_.size(); ++i)
2940b57cec5SDimitry Andric             if (facets_[i])
2950b57cec5SDimitry Andric                 facets_[i]->__release_shared();
2960b57cec5SDimitry Andric         throw;
2970b57cec5SDimitry Andric     }
29806c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
2990b57cec5SDimitry Andric }
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric locale::__imp::__imp(const __imp& other)
3020b57cec5SDimitry Andric     : facets_(max<size_t>(N, other.facets_.size())),
3030b57cec5SDimitry Andric       name_(other.name_)
3040b57cec5SDimitry Andric {
3050b57cec5SDimitry Andric     facets_ = other.facets_;
3060b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
3070b57cec5SDimitry Andric         if (facets_[i])
3080b57cec5SDimitry Andric             facets_[i]->__add_shared();
3090b57cec5SDimitry Andric }
3100b57cec5SDimitry Andric 
3110b57cec5SDimitry Andric locale::__imp::__imp(const __imp& other, const string& name, locale::category c)
31206c3fb27SDimitry Andric     : facets_(N), name_(build_name(other.name_, name, c))
3130b57cec5SDimitry Andric {
3140b57cec5SDimitry Andric     facets_ = other.facets_;
3150b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
3160b57cec5SDimitry Andric         if (facets_[i])
3170b57cec5SDimitry Andric             facets_[i]->__add_shared();
31806c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
3190b57cec5SDimitry Andric     try
3200b57cec5SDimitry Andric     {
32106c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
3220b57cec5SDimitry Andric         if (c & locale::collate)
3230b57cec5SDimitry Andric         {
3240b57cec5SDimitry Andric             install(new collate_byname<char>(name));
325349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3260b57cec5SDimitry Andric             install(new collate_byname<wchar_t>(name));
327349cc55cSDimitry Andric #endif
3280b57cec5SDimitry Andric         }
3290b57cec5SDimitry Andric         if (c & locale::ctype)
3300b57cec5SDimitry Andric         {
3310b57cec5SDimitry Andric             install(new ctype_byname<char>(name));
332349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3330b57cec5SDimitry Andric             install(new ctype_byname<wchar_t>(name));
334349cc55cSDimitry Andric #endif
3350b57cec5SDimitry Andric             install(new codecvt_byname<char, char, mbstate_t>(name));
336349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3370b57cec5SDimitry Andric             install(new codecvt_byname<wchar_t, char, mbstate_t>(name));
338349cc55cSDimitry Andric #endif
339e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3400b57cec5SDimitry Andric             install(new codecvt_byname<char16_t, char, mbstate_t>(name));
3410b57cec5SDimitry Andric             install(new codecvt_byname<char32_t, char, mbstate_t>(name));
342e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
343fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
344e8d8bef9SDimitry Andric             install(new codecvt_byname<char16_t, char8_t, mbstate_t>(name));
345e8d8bef9SDimitry Andric             install(new codecvt_byname<char32_t, char8_t, mbstate_t>(name));
346e8d8bef9SDimitry Andric #endif
3470b57cec5SDimitry Andric         }
3480b57cec5SDimitry Andric         if (c & locale::monetary)
3490b57cec5SDimitry Andric         {
3500b57cec5SDimitry Andric             install(new moneypunct_byname<char, false>(name));
3510b57cec5SDimitry Andric             install(new moneypunct_byname<char, true>(name));
352349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3530b57cec5SDimitry Andric             install(new moneypunct_byname<wchar_t, false>(name));
3540b57cec5SDimitry Andric             install(new moneypunct_byname<wchar_t, true>(name));
355349cc55cSDimitry Andric #endif
3560b57cec5SDimitry Andric         }
3570b57cec5SDimitry Andric         if (c & locale::numeric)
3580b57cec5SDimitry Andric         {
3590b57cec5SDimitry Andric             install(new numpunct_byname<char>(name));
360349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3610b57cec5SDimitry Andric             install(new numpunct_byname<wchar_t>(name));
362349cc55cSDimitry Andric #endif
3630b57cec5SDimitry Andric         }
3640b57cec5SDimitry Andric         if (c & locale::time)
3650b57cec5SDimitry Andric         {
3660b57cec5SDimitry Andric             install(new time_get_byname<char>(name));
367349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3680b57cec5SDimitry Andric             install(new time_get_byname<wchar_t>(name));
369349cc55cSDimitry Andric #endif
3700b57cec5SDimitry Andric             install(new time_put_byname<char>(name));
371349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3720b57cec5SDimitry Andric             install(new time_put_byname<wchar_t>(name));
373349cc55cSDimitry Andric #endif
3740b57cec5SDimitry Andric         }
3750b57cec5SDimitry Andric         if (c & locale::messages)
3760b57cec5SDimitry Andric         {
3770b57cec5SDimitry Andric             install(new messages_byname<char>(name));
378349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3790b57cec5SDimitry Andric             install(new messages_byname<wchar_t>(name));
380349cc55cSDimitry Andric #endif
3810b57cec5SDimitry Andric         }
38206c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
3830b57cec5SDimitry Andric     }
3840b57cec5SDimitry Andric     catch (...)
3850b57cec5SDimitry Andric     {
3860b57cec5SDimitry Andric         for (unsigned i = 0; i < facets_.size(); ++i)
3870b57cec5SDimitry Andric             if (facets_[i])
3880b57cec5SDimitry Andric                 facets_[i]->__release_shared();
3890b57cec5SDimitry Andric         throw;
3900b57cec5SDimitry Andric     }
39106c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
3920b57cec5SDimitry Andric }
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric template<class F>
3950b57cec5SDimitry Andric inline
3960b57cec5SDimitry Andric void
3970b57cec5SDimitry Andric locale::__imp::install_from(const locale::__imp& one)
3980b57cec5SDimitry Andric {
3990b57cec5SDimitry Andric     long id = F::id.__get();
4000b57cec5SDimitry Andric     install(const_cast<F*>(static_cast<const F*>(one.use_facet(id))), id);
4010b57cec5SDimitry Andric }
4020b57cec5SDimitry Andric 
4030b57cec5SDimitry Andric locale::__imp::__imp(const __imp& other, const __imp& one, locale::category c)
40406c3fb27SDimitry Andric     : facets_(N), name_(build_name(other.name_, one.name_, c))
4050b57cec5SDimitry Andric {
4060b57cec5SDimitry Andric     facets_ = other.facets_;
4070b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
4080b57cec5SDimitry Andric         if (facets_[i])
4090b57cec5SDimitry Andric             facets_[i]->__add_shared();
41006c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
4110b57cec5SDimitry Andric     try
4120b57cec5SDimitry Andric     {
41306c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
4140b57cec5SDimitry Andric         if (c & locale::collate)
4150b57cec5SDimitry Andric         {
416*5f757f3fSDimitry Andric             install_from<std::collate<char> >(one);
417349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
418*5f757f3fSDimitry Andric             install_from<std::collate<wchar_t> >(one);
419349cc55cSDimitry Andric #endif
4200b57cec5SDimitry Andric         }
4210b57cec5SDimitry Andric         if (c & locale::ctype)
4220b57cec5SDimitry Andric         {
423*5f757f3fSDimitry Andric             install_from<std::ctype<char> >(one);
424349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
425*5f757f3fSDimitry Andric             install_from<std::ctype<wchar_t> >(one);
426349cc55cSDimitry Andric #endif
427*5f757f3fSDimitry Andric             install_from<std::codecvt<char, char, mbstate_t> >(one);
428e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
429*5f757f3fSDimitry Andric             install_from<std::codecvt<char16_t, char, mbstate_t> >(one);
430*5f757f3fSDimitry Andric             install_from<std::codecvt<char32_t, char, mbstate_t> >(one);
431e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
432fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
433*5f757f3fSDimitry Andric             install_from<std::codecvt<char16_t, char8_t, mbstate_t> >(one);
434*5f757f3fSDimitry Andric             install_from<std::codecvt<char32_t, char8_t, mbstate_t> >(one);
435e8d8bef9SDimitry Andric #endif
436349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
437*5f757f3fSDimitry Andric             install_from<std::codecvt<wchar_t, char, mbstate_t> >(one);
438349cc55cSDimitry Andric #endif
4390b57cec5SDimitry Andric         }
4400b57cec5SDimitry Andric         if (c & locale::monetary)
4410b57cec5SDimitry Andric         {
4420b57cec5SDimitry Andric             install_from<moneypunct<char, false> >(one);
4430b57cec5SDimitry Andric             install_from<moneypunct<char, true> >(one);
444349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4450b57cec5SDimitry Andric             install_from<moneypunct<wchar_t, false> >(one);
4460b57cec5SDimitry Andric             install_from<moneypunct<wchar_t, true> >(one);
447349cc55cSDimitry Andric #endif
4480b57cec5SDimitry Andric             install_from<money_get<char> >(one);
449349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4500b57cec5SDimitry Andric             install_from<money_get<wchar_t> >(one);
451349cc55cSDimitry Andric #endif
4520b57cec5SDimitry Andric             install_from<money_put<char> >(one);
453349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4540b57cec5SDimitry Andric             install_from<money_put<wchar_t> >(one);
455349cc55cSDimitry Andric #endif
4560b57cec5SDimitry Andric         }
4570b57cec5SDimitry Andric         if (c & locale::numeric)
4580b57cec5SDimitry Andric         {
4590b57cec5SDimitry Andric             install_from<numpunct<char> >(one);
460349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4610b57cec5SDimitry Andric             install_from<numpunct<wchar_t> >(one);
462349cc55cSDimitry Andric #endif
4630b57cec5SDimitry Andric             install_from<num_get<char> >(one);
464349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4650b57cec5SDimitry Andric             install_from<num_get<wchar_t> >(one);
466349cc55cSDimitry Andric #endif
4670b57cec5SDimitry Andric             install_from<num_put<char> >(one);
468349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4690b57cec5SDimitry Andric             install_from<num_put<wchar_t> >(one);
470349cc55cSDimitry Andric #endif
4710b57cec5SDimitry Andric         }
4720b57cec5SDimitry Andric         if (c & locale::time)
4730b57cec5SDimitry Andric         {
4740b57cec5SDimitry Andric             install_from<time_get<char> >(one);
475349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4760b57cec5SDimitry Andric             install_from<time_get<wchar_t> >(one);
477349cc55cSDimitry Andric #endif
4780b57cec5SDimitry Andric             install_from<time_put<char> >(one);
479349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4800b57cec5SDimitry Andric             install_from<time_put<wchar_t> >(one);
481349cc55cSDimitry Andric #endif
4820b57cec5SDimitry Andric         }
4830b57cec5SDimitry Andric         if (c & locale::messages)
4840b57cec5SDimitry Andric         {
485*5f757f3fSDimitry Andric             install_from<std::messages<char> >(one);
486349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
487*5f757f3fSDimitry Andric             install_from<std::messages<wchar_t> >(one);
488349cc55cSDimitry Andric #endif
4890b57cec5SDimitry Andric         }
49006c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
4910b57cec5SDimitry Andric     }
4920b57cec5SDimitry Andric     catch (...)
4930b57cec5SDimitry Andric     {
4940b57cec5SDimitry Andric         for (unsigned i = 0; i < facets_.size(); ++i)
4950b57cec5SDimitry Andric             if (facets_[i])
4960b57cec5SDimitry Andric                 facets_[i]->__release_shared();
4970b57cec5SDimitry Andric         throw;
4980b57cec5SDimitry Andric     }
49906c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
5000b57cec5SDimitry Andric }
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric locale::__imp::__imp(const __imp& other, facet* f, long id)
5030b57cec5SDimitry Andric     : facets_(max<size_t>(N, other.facets_.size()+1)),
5040b57cec5SDimitry Andric       name_("*")
5050b57cec5SDimitry Andric {
5060b57cec5SDimitry Andric     f->__add_shared();
507*5f757f3fSDimitry Andric     unique_ptr<facet, releaser> hold(f);
5080b57cec5SDimitry Andric     facets_ = other.facets_;
5090b57cec5SDimitry Andric     for (unsigned i = 0; i < other.facets_.size(); ++i)
5100b57cec5SDimitry Andric         if (facets_[i])
5110b57cec5SDimitry Andric             facets_[i]->__add_shared();
5120b57cec5SDimitry Andric     install(hold.get(), id);
5130b57cec5SDimitry Andric }
5140b57cec5SDimitry Andric 
5150b57cec5SDimitry Andric locale::__imp::~__imp()
5160b57cec5SDimitry Andric {
5170b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
5180b57cec5SDimitry Andric         if (facets_[i])
5190b57cec5SDimitry Andric             facets_[i]->__release_shared();
5200b57cec5SDimitry Andric }
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric void
5230b57cec5SDimitry Andric locale::__imp::install(facet* f, long id)
5240b57cec5SDimitry Andric {
5250b57cec5SDimitry Andric     f->__add_shared();
526*5f757f3fSDimitry Andric     unique_ptr<facet, releaser> hold(f);
5270b57cec5SDimitry Andric     if (static_cast<size_t>(id) >= facets_.size())
5280b57cec5SDimitry Andric         facets_.resize(static_cast<size_t>(id+1));
5290b57cec5SDimitry Andric     if (facets_[static_cast<size_t>(id)])
5300b57cec5SDimitry Andric         facets_[static_cast<size_t>(id)]->__release_shared();
5310b57cec5SDimitry Andric     facets_[static_cast<size_t>(id)] = hold.release();
5320b57cec5SDimitry Andric }
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric const locale::facet*
5350b57cec5SDimitry Andric locale::__imp::use_facet(long id) const
5360b57cec5SDimitry Andric {
5370b57cec5SDimitry Andric     if (!has_facet(id))
5380b57cec5SDimitry Andric         __throw_bad_cast();
5390b57cec5SDimitry Andric     return facets_[static_cast<size_t>(id)];
5400b57cec5SDimitry Andric }
5410b57cec5SDimitry Andric 
5420b57cec5SDimitry Andric // locale
5430b57cec5SDimitry Andric 
544*5f757f3fSDimitry Andric // We don't do reference counting on the classic locale.
545*5f757f3fSDimitry Andric // It's never destroyed anyway, but atomic reference counting may be very
546*5f757f3fSDimitry Andric // expensive in parallel applications. The classic locale is used by default
547*5f757f3fSDimitry Andric // in all streams. Note: if a new global locale is installed, then we lose
548*5f757f3fSDimitry Andric // the benefit of no reference counting.
549*5f757f3fSDimitry Andric constinit __no_destroy<locale::__imp>
550*5f757f3fSDimitry Andric     locale::__imp::classic_locale_imp_(__uninitialized_tag{}); // initialized below in classic()
551*5f757f3fSDimitry Andric 
552*5f757f3fSDimitry Andric const locale& locale::classic() {
553*5f757f3fSDimitry Andric   static const __no_destroy<locale> classic_locale(__private_tag{}, [] {
554*5f757f3fSDimitry Andric     // executed exactly once on first initialization of `classic_locale`
555*5f757f3fSDimitry Andric     locale::__imp::classic_locale_imp_.__emplace(1u);
556*5f757f3fSDimitry Andric     return &locale::__imp::classic_locale_imp_.__get();
557*5f757f3fSDimitry Andric   }());
558*5f757f3fSDimitry Andric   return classic_locale.__get();
5590b57cec5SDimitry Andric }
5600b57cec5SDimitry Andric 
561*5f757f3fSDimitry Andric locale& locale::__global() {
562*5f757f3fSDimitry Andric   static __no_destroy<locale> g(locale::classic());
563*5f757f3fSDimitry Andric   return g.__get();
5640b57cec5SDimitry Andric }
5650b57cec5SDimitry Andric 
566*5f757f3fSDimitry Andric void locale::__imp::acquire() {
567*5f757f3fSDimitry Andric   if (this != &locale::__imp::classic_locale_imp_.__get())
568*5f757f3fSDimitry Andric     __add_shared();
5690b57cec5SDimitry Andric }
5700b57cec5SDimitry Andric 
571*5f757f3fSDimitry Andric void locale::__imp::release() {
572*5f757f3fSDimitry Andric   if (this != &locale::__imp::classic_locale_imp_.__get())
573*5f757f3fSDimitry Andric     __release_shared();
5740b57cec5SDimitry Andric }
5750b57cec5SDimitry Andric 
576*5f757f3fSDimitry Andric locale::locale() noexcept : __locale_(__global().__locale_) { __locale_->acquire(); }
5770b57cec5SDimitry Andric 
578*5f757f3fSDimitry Andric locale::locale(const locale& l) noexcept : __locale_(l.__locale_) { __locale_->acquire(); }
5790b57cec5SDimitry Andric 
580*5f757f3fSDimitry Andric locale::~locale() { __locale_->release(); }
5810b57cec5SDimitry Andric 
5820b57cec5SDimitry Andric const locale&
583fe6060f1SDimitry Andric locale::operator=(const locale& other) noexcept
5840b57cec5SDimitry Andric {
585*5f757f3fSDimitry Andric   other.__locale_->acquire();
586*5f757f3fSDimitry Andric   __locale_->release();
5870b57cec5SDimitry Andric   __locale_ = other.__locale_;
5880b57cec5SDimitry Andric   return *this;
5890b57cec5SDimitry Andric }
5900b57cec5SDimitry Andric 
5910b57cec5SDimitry Andric locale::locale(const char* name)
5920b57cec5SDimitry Andric     : __locale_(name ? new __imp(name)
5935ffd83dbSDimitry Andric                      : (__throw_runtime_error("locale constructed with null"), nullptr))
5940b57cec5SDimitry Andric {
595*5f757f3fSDimitry Andric   __locale_->acquire();
5960b57cec5SDimitry Andric }
5970b57cec5SDimitry Andric 
598*5f757f3fSDimitry Andric locale::locale(const string& name) : __locale_(new __imp(name)) { __locale_->acquire(); }
5990b57cec5SDimitry Andric 
6000b57cec5SDimitry Andric locale::locale(const locale& other, const char* name, category c)
6010b57cec5SDimitry Andric     : __locale_(name ? new __imp(*other.__locale_, name, c)
6025ffd83dbSDimitry Andric                      : (__throw_runtime_error("locale constructed with null"), nullptr))
6030b57cec5SDimitry Andric {
604*5f757f3fSDimitry Andric   __locale_->acquire();
6050b57cec5SDimitry Andric }
6060b57cec5SDimitry Andric 
6070b57cec5SDimitry Andric locale::locale(const locale& other, const string& name, category c)
6080b57cec5SDimitry Andric     : __locale_(new __imp(*other.__locale_, name, c))
6090b57cec5SDimitry Andric {
610*5f757f3fSDimitry Andric   __locale_->acquire();
6110b57cec5SDimitry Andric }
6120b57cec5SDimitry Andric 
6130b57cec5SDimitry Andric locale::locale(const locale& other, const locale& one, category c)
6140b57cec5SDimitry Andric     : __locale_(new __imp(*other.__locale_, *one.__locale_, c))
6150b57cec5SDimitry Andric {
616*5f757f3fSDimitry Andric   __locale_->acquire();
6170b57cec5SDimitry Andric }
6180b57cec5SDimitry Andric 
6190b57cec5SDimitry Andric string
6200b57cec5SDimitry Andric locale::name() const
6210b57cec5SDimitry Andric {
6220b57cec5SDimitry Andric     return __locale_->name();
6230b57cec5SDimitry Andric }
6240b57cec5SDimitry Andric 
6250b57cec5SDimitry Andric void
6260b57cec5SDimitry Andric locale::__install_ctor(const locale& other, facet* f, long id)
6270b57cec5SDimitry Andric {
6280b57cec5SDimitry Andric     if (f)
6290b57cec5SDimitry Andric         __locale_ = new __imp(*other.__locale_, f, id);
6300b57cec5SDimitry Andric     else
6310b57cec5SDimitry Andric         __locale_ = other.__locale_;
632*5f757f3fSDimitry Andric     __locale_->acquire();
6330b57cec5SDimitry Andric }
6340b57cec5SDimitry Andric 
6350b57cec5SDimitry Andric locale
6360b57cec5SDimitry Andric locale::global(const locale& loc)
6370b57cec5SDimitry Andric {
6380b57cec5SDimitry Andric     locale& g = __global();
6390b57cec5SDimitry Andric     locale r = g;
6400b57cec5SDimitry Andric     g = loc;
6410b57cec5SDimitry Andric     if (g.name() != "*")
6420b57cec5SDimitry Andric         setlocale(LC_ALL, g.name().c_str());
6430b57cec5SDimitry Andric     return r;
6440b57cec5SDimitry Andric }
6450b57cec5SDimitry Andric 
6460b57cec5SDimitry Andric bool
6470b57cec5SDimitry Andric locale::has_facet(id& x) const
6480b57cec5SDimitry Andric {
6490b57cec5SDimitry Andric     return __locale_->has_facet(x.__get());
6500b57cec5SDimitry Andric }
6510b57cec5SDimitry Andric 
6520b57cec5SDimitry Andric const locale::facet*
6530b57cec5SDimitry Andric locale::use_facet(id& x) const
6540b57cec5SDimitry Andric {
6550b57cec5SDimitry Andric     return __locale_->use_facet(x.__get());
6560b57cec5SDimitry Andric }
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric bool
6590b57cec5SDimitry Andric locale::operator==(const locale& y) const
6600b57cec5SDimitry Andric {
6610b57cec5SDimitry Andric     return (__locale_ == y.__locale_)
6620b57cec5SDimitry Andric         || (__locale_->name() != "*" && __locale_->name() == y.__locale_->name());
6630b57cec5SDimitry Andric }
6640b57cec5SDimitry Andric 
6650b57cec5SDimitry Andric // locale::facet
6660b57cec5SDimitry Andric 
6670b57cec5SDimitry Andric locale::facet::~facet()
6680b57cec5SDimitry Andric {
6690b57cec5SDimitry Andric }
6700b57cec5SDimitry Andric 
6710b57cec5SDimitry Andric void
672fe6060f1SDimitry Andric locale::facet::__on_zero_shared() noexcept
6730b57cec5SDimitry Andric {
6740b57cec5SDimitry Andric     delete this;
6750b57cec5SDimitry Andric }
6760b57cec5SDimitry Andric 
6770b57cec5SDimitry Andric // locale::id
6780b57cec5SDimitry Andric 
679*5f757f3fSDimitry Andric constinit int32_t locale::id::__next_id = 0;
6800b57cec5SDimitry Andric 
681*5f757f3fSDimitry Andric long locale::id::__get() {
682*5f757f3fSDimitry Andric     call_once(__flag_, [&] { __id_ = __libcpp_atomic_add(&__next_id, 1); });
6830b57cec5SDimitry Andric     return __id_ - 1;
6840b57cec5SDimitry Andric }
6850b57cec5SDimitry Andric 
6860b57cec5SDimitry Andric // template <> class collate_byname<char>
6870b57cec5SDimitry Andric 
6880b57cec5SDimitry Andric collate_byname<char>::collate_byname(const char* n, size_t refs)
6890b57cec5SDimitry Andric     : collate<char>(refs),
690bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, n, 0))
6910b57cec5SDimitry Andric {
692bdd1243dSDimitry Andric     if (__l_ == 0)
693*5f757f3fSDimitry Andric         __throw_runtime_error(("collate_byname<char>::collate_byname"
694*5f757f3fSDimitry Andric                                " failed to construct for " + string(n)).c_str());
6950b57cec5SDimitry Andric }
6960b57cec5SDimitry Andric 
6970b57cec5SDimitry Andric collate_byname<char>::collate_byname(const string& name, size_t refs)
6980b57cec5SDimitry Andric     : collate<char>(refs),
699bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, name.c_str(), 0))
7000b57cec5SDimitry Andric {
701bdd1243dSDimitry Andric     if (__l_ == 0)
702*5f757f3fSDimitry Andric         __throw_runtime_error(("collate_byname<char>::collate_byname"
703*5f757f3fSDimitry Andric                                " failed to construct for " + name).c_str());
7040b57cec5SDimitry Andric }
7050b57cec5SDimitry Andric 
7060b57cec5SDimitry Andric collate_byname<char>::~collate_byname()
7070b57cec5SDimitry Andric {
708bdd1243dSDimitry Andric     freelocale(__l_);
7090b57cec5SDimitry Andric }
7100b57cec5SDimitry Andric 
7110b57cec5SDimitry Andric int
7120b57cec5SDimitry Andric collate_byname<char>::do_compare(const char_type* __lo1, const char_type* __hi1,
7130b57cec5SDimitry Andric                                  const char_type* __lo2, const char_type* __hi2) const
7140b57cec5SDimitry Andric {
7150b57cec5SDimitry Andric     string_type lhs(__lo1, __hi1);
7160b57cec5SDimitry Andric     string_type rhs(__lo2, __hi2);
717bdd1243dSDimitry Andric     int r = strcoll_l(lhs.c_str(), rhs.c_str(), __l_);
7180b57cec5SDimitry Andric     if (r < 0)
7190b57cec5SDimitry Andric         return -1;
7200b57cec5SDimitry Andric     if (r > 0)
7210b57cec5SDimitry Andric         return 1;
7220b57cec5SDimitry Andric     return r;
7230b57cec5SDimitry Andric }
7240b57cec5SDimitry Andric 
7250b57cec5SDimitry Andric collate_byname<char>::string_type
7260b57cec5SDimitry Andric collate_byname<char>::do_transform(const char_type* lo, const char_type* hi) const
7270b57cec5SDimitry Andric {
7280b57cec5SDimitry Andric     const string_type in(lo, hi);
729bdd1243dSDimitry Andric     string_type out(strxfrm_l(0, in.c_str(), 0, __l_), char());
730bdd1243dSDimitry Andric     strxfrm_l(const_cast<char*>(out.c_str()), in.c_str(), out.size()+1, __l_);
7310b57cec5SDimitry Andric     return out;
7320b57cec5SDimitry Andric }
7330b57cec5SDimitry Andric 
7340b57cec5SDimitry Andric // template <> class collate_byname<wchar_t>
7350b57cec5SDimitry Andric 
736349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
7370b57cec5SDimitry Andric collate_byname<wchar_t>::collate_byname(const char* n, size_t refs)
7380b57cec5SDimitry Andric     : collate<wchar_t>(refs),
739bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, n, 0))
7400b57cec5SDimitry Andric {
741bdd1243dSDimitry Andric     if (__l_ == 0)
742*5f757f3fSDimitry Andric         __throw_runtime_error(("collate_byname<wchar_t>::collate_byname(size_t refs)"
743*5f757f3fSDimitry Andric                                " failed to construct for " + string(n)).c_str());
7440b57cec5SDimitry Andric }
7450b57cec5SDimitry Andric 
7460b57cec5SDimitry Andric collate_byname<wchar_t>::collate_byname(const string& name, size_t refs)
7470b57cec5SDimitry Andric     : collate<wchar_t>(refs),
748bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, name.c_str(), 0))
7490b57cec5SDimitry Andric {
750bdd1243dSDimitry Andric     if (__l_ == 0)
751*5f757f3fSDimitry Andric         __throw_runtime_error(("collate_byname<wchar_t>::collate_byname(size_t refs)"
752*5f757f3fSDimitry Andric                                " failed to construct for " + name).c_str());
7530b57cec5SDimitry Andric }
7540b57cec5SDimitry Andric 
7550b57cec5SDimitry Andric collate_byname<wchar_t>::~collate_byname()
7560b57cec5SDimitry Andric {
757bdd1243dSDimitry Andric     freelocale(__l_);
7580b57cec5SDimitry Andric }
7590b57cec5SDimitry Andric 
7600b57cec5SDimitry Andric int
7610b57cec5SDimitry Andric collate_byname<wchar_t>::do_compare(const char_type* __lo1, const char_type* __hi1,
7620b57cec5SDimitry Andric                                  const char_type* __lo2, const char_type* __hi2) const
7630b57cec5SDimitry Andric {
7640b57cec5SDimitry Andric     string_type lhs(__lo1, __hi1);
7650b57cec5SDimitry Andric     string_type rhs(__lo2, __hi2);
766bdd1243dSDimitry Andric     int r = wcscoll_l(lhs.c_str(), rhs.c_str(), __l_);
7670b57cec5SDimitry Andric     if (r < 0)
7680b57cec5SDimitry Andric         return -1;
7690b57cec5SDimitry Andric     if (r > 0)
7700b57cec5SDimitry Andric         return 1;
7710b57cec5SDimitry Andric     return r;
7720b57cec5SDimitry Andric }
7730b57cec5SDimitry Andric 
7740b57cec5SDimitry Andric collate_byname<wchar_t>::string_type
7750b57cec5SDimitry Andric collate_byname<wchar_t>::do_transform(const char_type* lo, const char_type* hi) const
7760b57cec5SDimitry Andric {
7770b57cec5SDimitry Andric     const string_type in(lo, hi);
778bdd1243dSDimitry Andric     string_type out(wcsxfrm_l(0, in.c_str(), 0, __l_), wchar_t());
779bdd1243dSDimitry Andric     wcsxfrm_l(const_cast<wchar_t*>(out.c_str()), in.c_str(), out.size()+1, __l_);
7800b57cec5SDimitry Andric     return out;
7810b57cec5SDimitry Andric }
782349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
7830b57cec5SDimitry Andric 
7840b57cec5SDimitry Andric const ctype_base::mask ctype_base::space;
7850b57cec5SDimitry Andric const ctype_base::mask ctype_base::print;
7860b57cec5SDimitry Andric const ctype_base::mask ctype_base::cntrl;
7870b57cec5SDimitry Andric const ctype_base::mask ctype_base::upper;
7880b57cec5SDimitry Andric const ctype_base::mask ctype_base::lower;
7890b57cec5SDimitry Andric const ctype_base::mask ctype_base::alpha;
7900b57cec5SDimitry Andric const ctype_base::mask ctype_base::digit;
7910b57cec5SDimitry Andric const ctype_base::mask ctype_base::punct;
7920b57cec5SDimitry Andric const ctype_base::mask ctype_base::xdigit;
7930b57cec5SDimitry Andric const ctype_base::mask ctype_base::blank;
7940b57cec5SDimitry Andric const ctype_base::mask ctype_base::alnum;
7950b57cec5SDimitry Andric const ctype_base::mask ctype_base::graph;
7960b57cec5SDimitry Andric 
797349cc55cSDimitry Andric // template <> class ctype<wchar_t>;
798349cc55cSDimitry Andric 
799349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
800*5f757f3fSDimitry Andric constinit locale::id ctype<wchar_t>::id;
8010b57cec5SDimitry Andric 
8020b57cec5SDimitry Andric ctype<wchar_t>::~ctype()
8030b57cec5SDimitry Andric {
8040b57cec5SDimitry Andric }
8050b57cec5SDimitry Andric 
8060b57cec5SDimitry Andric bool
8070b57cec5SDimitry Andric ctype<wchar_t>::do_is(mask m, char_type c) const
8080b57cec5SDimitry Andric {
8090b57cec5SDimitry Andric     return isascii(c) ? (ctype<char>::classic_table()[c] & m) != 0 : false;
8100b57cec5SDimitry Andric }
8110b57cec5SDimitry Andric 
8120b57cec5SDimitry Andric const wchar_t*
8130b57cec5SDimitry Andric ctype<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
8140b57cec5SDimitry Andric {
8150b57cec5SDimitry Andric     for (; low != high; ++low, ++vec)
8160b57cec5SDimitry Andric         *vec = static_cast<mask>(isascii(*low) ?
8170b57cec5SDimitry Andric                                    ctype<char>::classic_table()[*low] : 0);
8180b57cec5SDimitry Andric     return low;
8190b57cec5SDimitry Andric }
8200b57cec5SDimitry Andric 
8210b57cec5SDimitry Andric const wchar_t*
8220b57cec5SDimitry Andric ctype<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const
8230b57cec5SDimitry Andric {
8240b57cec5SDimitry Andric     for (; low != high; ++low)
8250b57cec5SDimitry Andric         if (isascii(*low) && (ctype<char>::classic_table()[*low] & m))
8260b57cec5SDimitry Andric             break;
8270b57cec5SDimitry Andric     return low;
8280b57cec5SDimitry Andric }
8290b57cec5SDimitry Andric 
8300b57cec5SDimitry Andric const wchar_t*
8310b57cec5SDimitry Andric ctype<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const
8320b57cec5SDimitry Andric {
8330b57cec5SDimitry Andric     for (; low != high; ++low)
8340b57cec5SDimitry Andric         if (!(isascii(*low) && (ctype<char>::classic_table()[*low] & m)))
8350b57cec5SDimitry Andric             break;
8360b57cec5SDimitry Andric     return low;
8370b57cec5SDimitry Andric }
8380b57cec5SDimitry Andric 
8390b57cec5SDimitry Andric wchar_t
8400b57cec5SDimitry Andric ctype<wchar_t>::do_toupper(char_type c) const
8410b57cec5SDimitry Andric {
8420b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
8430b57cec5SDimitry Andric     return isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c;
8440b57cec5SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
84504eeddc0SDimitry Andric       defined(__NetBSD__) || defined(__MVS__)
8460b57cec5SDimitry Andric     return isascii(c) ? ctype<char>::__classic_upper_table()[c] : c;
8470b57cec5SDimitry Andric #else
8480b57cec5SDimitry Andric     return (isascii(c) && iswlower_l(c, _LIBCPP_GET_C_LOCALE)) ? c-L'a'+L'A' : c;
8490b57cec5SDimitry Andric #endif
8500b57cec5SDimitry Andric }
8510b57cec5SDimitry Andric 
8520b57cec5SDimitry Andric const wchar_t*
8530b57cec5SDimitry Andric ctype<wchar_t>::do_toupper(char_type* low, const char_type* high) const
8540b57cec5SDimitry Andric {
8550b57cec5SDimitry Andric     for (; low != high; ++low)
8560b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
8570b57cec5SDimitry Andric         *low = isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low;
8580b57cec5SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
85904eeddc0SDimitry Andric       defined(__NetBSD__) || defined(__MVS__)
8600b57cec5SDimitry Andric         *low = isascii(*low) ? ctype<char>::__classic_upper_table()[*low]
8610b57cec5SDimitry Andric                              : *low;
8620b57cec5SDimitry Andric #else
8630b57cec5SDimitry Andric         *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? (*low-L'a'+L'A') : *low;
8640b57cec5SDimitry Andric #endif
8650b57cec5SDimitry Andric     return low;
8660b57cec5SDimitry Andric }
8670b57cec5SDimitry Andric 
8680b57cec5SDimitry Andric wchar_t
8690b57cec5SDimitry Andric ctype<wchar_t>::do_tolower(char_type c) const
8700b57cec5SDimitry Andric {
8710b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
8720b57cec5SDimitry Andric     return isascii(c) ? _DefaultRuneLocale.__maplower[c] : c;
8730b57cec5SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
87404eeddc0SDimitry Andric       defined(__NetBSD__) || defined(__MVS__)
8750b57cec5SDimitry Andric     return isascii(c) ? ctype<char>::__classic_lower_table()[c] : c;
8760b57cec5SDimitry Andric #else
8770b57cec5SDimitry Andric     return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c-L'A'+'a' : c;
8780b57cec5SDimitry Andric #endif
8790b57cec5SDimitry Andric }
8800b57cec5SDimitry Andric 
8810b57cec5SDimitry Andric const wchar_t*
8820b57cec5SDimitry Andric ctype<wchar_t>::do_tolower(char_type* low, const char_type* high) const
8830b57cec5SDimitry Andric {
8840b57cec5SDimitry Andric     for (; low != high; ++low)
8850b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
8860b57cec5SDimitry Andric         *low = isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low;
8870b57cec5SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
88804eeddc0SDimitry Andric       defined(__NetBSD__) || defined(__MVS__)
8890b57cec5SDimitry Andric         *low = isascii(*low) ? ctype<char>::__classic_lower_table()[*low]
8900b57cec5SDimitry Andric                              : *low;
8910b57cec5SDimitry Andric #else
8920b57cec5SDimitry Andric         *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-L'A'+L'a' : *low;
8930b57cec5SDimitry Andric #endif
8940b57cec5SDimitry Andric     return low;
8950b57cec5SDimitry Andric }
8960b57cec5SDimitry Andric 
8970b57cec5SDimitry Andric wchar_t
8980b57cec5SDimitry Andric ctype<wchar_t>::do_widen(char c) const
8990b57cec5SDimitry Andric {
9000b57cec5SDimitry Andric     return c;
9010b57cec5SDimitry Andric }
9020b57cec5SDimitry Andric 
9030b57cec5SDimitry Andric const char*
9040b57cec5SDimitry Andric ctype<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const
9050b57cec5SDimitry Andric {
9060b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
9070b57cec5SDimitry Andric         *dest = *low;
9080b57cec5SDimitry Andric     return low;
9090b57cec5SDimitry Andric }
9100b57cec5SDimitry Andric 
9110b57cec5SDimitry Andric char
9120b57cec5SDimitry Andric ctype<wchar_t>::do_narrow(char_type c, char dfault) const
9130b57cec5SDimitry Andric {
9140b57cec5SDimitry Andric     if (isascii(c))
9150b57cec5SDimitry Andric         return static_cast<char>(c);
9160b57cec5SDimitry Andric     return dfault;
9170b57cec5SDimitry Andric }
9180b57cec5SDimitry Andric 
9190b57cec5SDimitry Andric const wchar_t*
9200b57cec5SDimitry Andric ctype<wchar_t>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
9210b57cec5SDimitry Andric {
9220b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
9230b57cec5SDimitry Andric         if (isascii(*low))
9240b57cec5SDimitry Andric             *dest = static_cast<char>(*low);
9250b57cec5SDimitry Andric         else
9260b57cec5SDimitry Andric             *dest = dfault;
9270b57cec5SDimitry Andric     return low;
9280b57cec5SDimitry Andric }
929349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
9300b57cec5SDimitry Andric 
9310b57cec5SDimitry Andric // template <> class ctype<char>;
9320b57cec5SDimitry Andric 
933*5f757f3fSDimitry Andric constinit locale::id ctype<char>::id;
9340b57cec5SDimitry Andric 
935349cc55cSDimitry Andric const size_t ctype<char>::table_size;
936349cc55cSDimitry Andric 
9370b57cec5SDimitry Andric ctype<char>::ctype(const mask* tab, bool del, size_t refs)
9380b57cec5SDimitry Andric     : locale::facet(refs),
9390b57cec5SDimitry Andric       __tab_(tab),
9400b57cec5SDimitry Andric       __del_(del)
9410b57cec5SDimitry Andric {
9420b57cec5SDimitry Andric   if (__tab_ == 0)
9430b57cec5SDimitry Andric       __tab_ = classic_table();
9440b57cec5SDimitry Andric }
9450b57cec5SDimitry Andric 
9460b57cec5SDimitry Andric ctype<char>::~ctype()
9470b57cec5SDimitry Andric {
9480b57cec5SDimitry Andric     if (__tab_ && __del_)
9490b57cec5SDimitry Andric         delete [] __tab_;
9500b57cec5SDimitry Andric }
9510b57cec5SDimitry Andric 
9520b57cec5SDimitry Andric char
9530b57cec5SDimitry Andric ctype<char>::do_toupper(char_type c) const
9540b57cec5SDimitry Andric {
9550b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
9560b57cec5SDimitry Andric     return isascii(c) ?
9570b57cec5SDimitry Andric       static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(c)]) : c;
9580b57cec5SDimitry Andric #elif defined(__NetBSD__)
9590b57cec5SDimitry Andric     return static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]);
96004eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
9610b57cec5SDimitry Andric     return isascii(c) ?
9620b57cec5SDimitry Andric       static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]) : c;
9630b57cec5SDimitry Andric #else
9640b57cec5SDimitry Andric     return (isascii(c) && islower_l(c, _LIBCPP_GET_C_LOCALE)) ? c-'a'+'A' : c;
9650b57cec5SDimitry Andric #endif
9660b57cec5SDimitry Andric }
9670b57cec5SDimitry Andric 
9680b57cec5SDimitry Andric const char*
9690b57cec5SDimitry Andric ctype<char>::do_toupper(char_type* low, const char_type* high) const
9700b57cec5SDimitry Andric {
9710b57cec5SDimitry Andric     for (; low != high; ++low)
9720b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
9730b57cec5SDimitry Andric         *low = isascii(*low) ?
9740b57cec5SDimitry Andric           static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(*low)]) : *low;
9750b57cec5SDimitry Andric #elif defined(__NetBSD__)
9760b57cec5SDimitry Andric         *low = static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(*low)]);
97704eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
9780b57cec5SDimitry Andric         *low = isascii(*low) ?
9790b57cec5SDimitry Andric           static_cast<char>(__classic_upper_table()[static_cast<size_t>(*low)]) : *low;
9800b57cec5SDimitry Andric #else
9810b57cec5SDimitry Andric         *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-'a'+'A' : *low;
9820b57cec5SDimitry Andric #endif
9830b57cec5SDimitry Andric     return low;
9840b57cec5SDimitry Andric }
9850b57cec5SDimitry Andric 
9860b57cec5SDimitry Andric char
9870b57cec5SDimitry Andric ctype<char>::do_tolower(char_type c) const
9880b57cec5SDimitry Andric {
9890b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
9900b57cec5SDimitry Andric     return isascii(c) ?
9910b57cec5SDimitry Andric       static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(c)]) : c;
9920b57cec5SDimitry Andric #elif defined(__NetBSD__)
9930b57cec5SDimitry Andric     return static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(c)]);
99404eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
9950b57cec5SDimitry Andric     return isascii(c) ?
9960b57cec5SDimitry Andric       static_cast<char>(__classic_lower_table()[static_cast<size_t>(c)]) : c;
9970b57cec5SDimitry Andric #else
9980b57cec5SDimitry Andric     return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c-'A'+'a' : c;
9990b57cec5SDimitry Andric #endif
10000b57cec5SDimitry Andric }
10010b57cec5SDimitry Andric 
10020b57cec5SDimitry Andric const char*
10030b57cec5SDimitry Andric ctype<char>::do_tolower(char_type* low, const char_type* high) const
10040b57cec5SDimitry Andric {
10050b57cec5SDimitry Andric     for (; low != high; ++low)
10060b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
10070b57cec5SDimitry Andric         *low = isascii(*low) ? static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(*low)]) : *low;
10080b57cec5SDimitry Andric #elif defined(__NetBSD__)
10090b57cec5SDimitry Andric         *low = static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(*low)]);
101004eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
10110b57cec5SDimitry Andric         *low = isascii(*low) ? static_cast<char>(__classic_lower_table()[static_cast<size_t>(*low)]) : *low;
10120b57cec5SDimitry Andric #else
10130b57cec5SDimitry Andric         *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-'A'+'a' : *low;
10140b57cec5SDimitry Andric #endif
10150b57cec5SDimitry Andric     return low;
10160b57cec5SDimitry Andric }
10170b57cec5SDimitry Andric 
10180b57cec5SDimitry Andric char
10190b57cec5SDimitry Andric ctype<char>::do_widen(char c) const
10200b57cec5SDimitry Andric {
10210b57cec5SDimitry Andric     return c;
10220b57cec5SDimitry Andric }
10230b57cec5SDimitry Andric 
10240b57cec5SDimitry Andric const char*
10250b57cec5SDimitry Andric ctype<char>::do_widen(const char* low, const char* high, char_type* dest) const
10260b57cec5SDimitry Andric {
10270b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
10280b57cec5SDimitry Andric         *dest = *low;
10290b57cec5SDimitry Andric     return low;
10300b57cec5SDimitry Andric }
10310b57cec5SDimitry Andric 
10320b57cec5SDimitry Andric char
10330b57cec5SDimitry Andric ctype<char>::do_narrow(char_type c, char dfault) const
10340b57cec5SDimitry Andric {
10350b57cec5SDimitry Andric     if (isascii(c))
10360b57cec5SDimitry Andric         return static_cast<char>(c);
10370b57cec5SDimitry Andric     return dfault;
10380b57cec5SDimitry Andric }
10390b57cec5SDimitry Andric 
10400b57cec5SDimitry Andric const char*
10410b57cec5SDimitry Andric ctype<char>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
10420b57cec5SDimitry Andric {
10430b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
10440b57cec5SDimitry Andric         if (isascii(*low))
10450b57cec5SDimitry Andric             *dest = *low;
10460b57cec5SDimitry Andric         else
10470b57cec5SDimitry Andric             *dest = dfault;
10480b57cec5SDimitry Andric     return low;
10490b57cec5SDimitry Andric }
10500b57cec5SDimitry Andric 
10510b57cec5SDimitry Andric #if defined(__EMSCRIPTEN__)
10520b57cec5SDimitry Andric extern "C" const unsigned short ** __ctype_b_loc();
10530b57cec5SDimitry Andric extern "C" const int ** __ctype_tolower_loc();
10540b57cec5SDimitry Andric extern "C" const int ** __ctype_toupper_loc();
10550b57cec5SDimitry Andric #endif
10560b57cec5SDimitry Andric 
10570b57cec5SDimitry Andric #ifdef _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE
10580b57cec5SDimitry Andric const ctype<char>::mask*
1059fe6060f1SDimitry Andric ctype<char>::classic_table() noexcept
10600b57cec5SDimitry Andric {
1061*5f757f3fSDimitry Andric   // clang-format off
1062*5f757f3fSDimitry Andric     static constexpr const ctype<char>::mask builtin_table[table_size] = {
10630b57cec5SDimitry Andric         cntrl,                          cntrl,
10640b57cec5SDimitry Andric         cntrl,                          cntrl,
10650b57cec5SDimitry Andric         cntrl,                          cntrl,
10660b57cec5SDimitry Andric         cntrl,                          cntrl,
10670b57cec5SDimitry Andric         cntrl,                          cntrl | space | blank,
10680b57cec5SDimitry Andric         cntrl | space,                  cntrl | space,
10690b57cec5SDimitry Andric         cntrl | space,                  cntrl | space,
10700b57cec5SDimitry Andric         cntrl,                          cntrl,
10710b57cec5SDimitry Andric         cntrl,                          cntrl,
10720b57cec5SDimitry Andric         cntrl,                          cntrl,
10730b57cec5SDimitry Andric         cntrl,                          cntrl,
10740b57cec5SDimitry Andric         cntrl,                          cntrl,
10750b57cec5SDimitry Andric         cntrl,                          cntrl,
10760b57cec5SDimitry Andric         cntrl,                          cntrl,
10770b57cec5SDimitry Andric         cntrl,                          cntrl,
10780b57cec5SDimitry Andric         cntrl,                          cntrl,
10790b57cec5SDimitry Andric         space | blank | print,          punct | print,
10800b57cec5SDimitry Andric         punct | print,                  punct | print,
10810b57cec5SDimitry Andric         punct | print,                  punct | print,
10820b57cec5SDimitry Andric         punct | print,                  punct | print,
10830b57cec5SDimitry Andric         punct | print,                  punct | print,
10840b57cec5SDimitry Andric         punct | print,                  punct | print,
10850b57cec5SDimitry Andric         punct | print,                  punct | print,
10860b57cec5SDimitry Andric         punct | print,                  punct | print,
10870b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
10880b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
10890b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
10900b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
10910b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
10920b57cec5SDimitry Andric         punct | print,                  punct | print,
10930b57cec5SDimitry Andric         punct | print,                  punct | print,
10940b57cec5SDimitry Andric         punct | print,                  punct | print,
10950b57cec5SDimitry Andric         punct | print,                  upper | xdigit | print | alpha,
10960b57cec5SDimitry Andric         upper | xdigit | print | alpha, upper | xdigit | print | alpha,
10970b57cec5SDimitry Andric         upper | xdigit | print | alpha, upper | xdigit | print | alpha,
10980b57cec5SDimitry Andric         upper | xdigit | print | alpha, upper | print | alpha,
10990b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11000b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11010b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11020b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11030b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11040b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11050b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11060b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11070b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11080b57cec5SDimitry Andric         upper | print | alpha,          punct | print,
11090b57cec5SDimitry Andric         punct | print,                  punct | print,
11100b57cec5SDimitry Andric         punct | print,                  punct | print,
11110b57cec5SDimitry Andric         punct | print,                  lower | xdigit | print | alpha,
11120b57cec5SDimitry Andric         lower | xdigit | print | alpha, lower | xdigit | print | alpha,
11130b57cec5SDimitry Andric         lower | xdigit | print | alpha, lower | xdigit | print | alpha,
11140b57cec5SDimitry Andric         lower | xdigit | print | alpha, lower | print | alpha,
11150b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11160b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11170b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11180b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11190b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11200b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11210b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11220b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11230b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11240b57cec5SDimitry Andric         lower | print | alpha,          punct | print,
11250b57cec5SDimitry Andric         punct | print,                  punct | print,
11260b57cec5SDimitry Andric         punct | print,                  cntrl,
11270b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11280b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11290b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11300b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11310b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11320b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11330b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11340b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
11350b57cec5SDimitry Andric     };
1136*5f757f3fSDimitry Andric   // clang-format on
11370b57cec5SDimitry Andric     return builtin_table;
11380b57cec5SDimitry Andric }
11390b57cec5SDimitry Andric #else
11400b57cec5SDimitry Andric const ctype<char>::mask*
1141fe6060f1SDimitry Andric ctype<char>::classic_table() noexcept
11420b57cec5SDimitry Andric {
11430b57cec5SDimitry Andric #if defined(__APPLE__) || defined(__FreeBSD__)
11440b57cec5SDimitry Andric     return _DefaultRuneLocale.__runetype;
11450b57cec5SDimitry Andric #elif defined(__NetBSD__)
11460b57cec5SDimitry Andric     return _C_ctype_tab_ + 1;
11470b57cec5SDimitry Andric #elif defined(__GLIBC__)
11480b57cec5SDimitry Andric     return _LIBCPP_GET_C_LOCALE->__ctype_b;
11490b57cec5SDimitry Andric #elif defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
11500b57cec5SDimitry Andric     return __pctype_func();
11510b57cec5SDimitry Andric #elif defined(__EMSCRIPTEN__)
11520b57cec5SDimitry Andric     return *__ctype_b_loc();
11530b57cec5SDimitry Andric #elif defined(_NEWLIB_VERSION)
11540b57cec5SDimitry Andric     // Newlib has a 257-entry table in ctype_.c, where (char)0 starts at [1].
11550b57cec5SDimitry Andric     return _ctype_ + 1;
11560b57cec5SDimitry Andric #elif defined(_AIX)
11570b57cec5SDimitry Andric     return (const unsigned int *)__lc_ctype_ptr->obj->mask;
115804eeddc0SDimitry Andric #elif defined(__MVS__)
115904eeddc0SDimitry Andric # if defined(__NATIVE_ASCII_F)
116004eeddc0SDimitry Andric     return const_cast<const ctype<char>::mask*> (__OBJ_DATA(__lc_ctype_a)->mask);
116104eeddc0SDimitry Andric # else
116204eeddc0SDimitry Andric     return const_cast<const ctype<char>::mask*> (__ctypec);
116304eeddc0SDimitry Andric # endif
11640b57cec5SDimitry Andric #else
11650b57cec5SDimitry Andric     // Platform not supported: abort so the person doing the port knows what to
11660b57cec5SDimitry Andric     // fix
11670b57cec5SDimitry Andric # warning  ctype<char>::classic_table() is not implemented
11680b57cec5SDimitry Andric     printf("ctype<char>::classic_table() is not implemented\n");
11690b57cec5SDimitry Andric     abort();
11700b57cec5SDimitry Andric     return NULL;
11710b57cec5SDimitry Andric #endif
11720b57cec5SDimitry Andric }
11730b57cec5SDimitry Andric #endif
11740b57cec5SDimitry Andric 
11750b57cec5SDimitry Andric #if defined(__GLIBC__)
11760b57cec5SDimitry Andric const int*
1177fe6060f1SDimitry Andric ctype<char>::__classic_lower_table() noexcept
11780b57cec5SDimitry Andric {
11790b57cec5SDimitry Andric     return _LIBCPP_GET_C_LOCALE->__ctype_tolower;
11800b57cec5SDimitry Andric }
11810b57cec5SDimitry Andric 
11820b57cec5SDimitry Andric const int*
1183fe6060f1SDimitry Andric ctype<char>::__classic_upper_table() noexcept
11840b57cec5SDimitry Andric {
11850b57cec5SDimitry Andric     return _LIBCPP_GET_C_LOCALE->__ctype_toupper;
11860b57cec5SDimitry Andric }
1187e8d8bef9SDimitry Andric #elif defined(__NetBSD__)
11880b57cec5SDimitry Andric const short*
1189fe6060f1SDimitry Andric ctype<char>::__classic_lower_table() noexcept
11900b57cec5SDimitry Andric {
11910b57cec5SDimitry Andric     return _C_tolower_tab_ + 1;
11920b57cec5SDimitry Andric }
11930b57cec5SDimitry Andric 
11940b57cec5SDimitry Andric const short*
1195fe6060f1SDimitry Andric ctype<char>::__classic_upper_table() noexcept
11960b57cec5SDimitry Andric {
11970b57cec5SDimitry Andric     return _C_toupper_tab_ + 1;
11980b57cec5SDimitry Andric }
11990b57cec5SDimitry Andric 
12000b57cec5SDimitry Andric #elif defined(__EMSCRIPTEN__)
12010b57cec5SDimitry Andric const int*
1202fe6060f1SDimitry Andric ctype<char>::__classic_lower_table() noexcept
12030b57cec5SDimitry Andric {
12040b57cec5SDimitry Andric     return *__ctype_tolower_loc();
12050b57cec5SDimitry Andric }
12060b57cec5SDimitry Andric 
12070b57cec5SDimitry Andric const int*
1208fe6060f1SDimitry Andric ctype<char>::__classic_upper_table() noexcept
12090b57cec5SDimitry Andric {
12100b57cec5SDimitry Andric     return *__ctype_toupper_loc();
12110b57cec5SDimitry Andric }
121204eeddc0SDimitry Andric #elif defined(__MVS__)
121304eeddc0SDimitry Andric const unsigned short*
121404eeddc0SDimitry Andric ctype<char>::__classic_lower_table() _NOEXCEPT
121504eeddc0SDimitry Andric {
121604eeddc0SDimitry Andric # if defined(__NATIVE_ASCII_F)
121704eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__OBJ_DATA(__lc_ctype_a)->lower);
121804eeddc0SDimitry Andric # else
121904eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__ctype + __TOLOWER_INDEX);
122004eeddc0SDimitry Andric # endif
122104eeddc0SDimitry Andric }
122204eeddc0SDimitry Andric const unsigned short *
122304eeddc0SDimitry Andric ctype<char>::__classic_upper_table() _NOEXCEPT
122404eeddc0SDimitry Andric {
122504eeddc0SDimitry Andric # if defined(__NATIVE_ASCII_F)
122604eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__OBJ_DATA(__lc_ctype_a)->upper);
122704eeddc0SDimitry Andric # else
122804eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__ctype + __TOUPPER_INDEX);
122904eeddc0SDimitry Andric # endif
123004eeddc0SDimitry Andric }
123104eeddc0SDimitry Andric #endif // __GLIBC__ || __NETBSD__ || __EMSCRIPTEN__ || __MVS__
12320b57cec5SDimitry Andric 
12330b57cec5SDimitry Andric // template <> class ctype_byname<char>
12340b57cec5SDimitry Andric 
12350b57cec5SDimitry Andric ctype_byname<char>::ctype_byname(const char* name, size_t refs)
12360b57cec5SDimitry Andric     : ctype<char>(0, false, refs),
1237bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, name, 0))
12380b57cec5SDimitry Andric {
1239bdd1243dSDimitry Andric     if (__l_ == 0)
1240*5f757f3fSDimitry Andric         __throw_runtime_error(("ctype_byname<char>::ctype_byname"
1241*5f757f3fSDimitry Andric                                " failed to construct for " + string(name)).c_str());
12420b57cec5SDimitry Andric }
12430b57cec5SDimitry Andric 
12440b57cec5SDimitry Andric ctype_byname<char>::ctype_byname(const string& name, size_t refs)
12450b57cec5SDimitry Andric     : ctype<char>(0, false, refs),
1246bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, name.c_str(), 0))
12470b57cec5SDimitry Andric {
1248bdd1243dSDimitry Andric     if (__l_ == 0)
1249*5f757f3fSDimitry Andric         __throw_runtime_error(("ctype_byname<char>::ctype_byname"
1250*5f757f3fSDimitry Andric                                " failed to construct for " + name).c_str());
12510b57cec5SDimitry Andric }
12520b57cec5SDimitry Andric 
12530b57cec5SDimitry Andric ctype_byname<char>::~ctype_byname()
12540b57cec5SDimitry Andric {
1255bdd1243dSDimitry Andric     freelocale(__l_);
12560b57cec5SDimitry Andric }
12570b57cec5SDimitry Andric 
12580b57cec5SDimitry Andric char
12590b57cec5SDimitry Andric ctype_byname<char>::do_toupper(char_type c) const
12600b57cec5SDimitry Andric {
1261bdd1243dSDimitry Andric     return static_cast<char>(toupper_l(static_cast<unsigned char>(c), __l_));
12620b57cec5SDimitry Andric }
12630b57cec5SDimitry Andric 
12640b57cec5SDimitry Andric const char*
12650b57cec5SDimitry Andric ctype_byname<char>::do_toupper(char_type* low, const char_type* high) const
12660b57cec5SDimitry Andric {
12670b57cec5SDimitry Andric     for (; low != high; ++low)
1268bdd1243dSDimitry Andric         *low = static_cast<char>(toupper_l(static_cast<unsigned char>(*low), __l_));
12690b57cec5SDimitry Andric     return low;
12700b57cec5SDimitry Andric }
12710b57cec5SDimitry Andric 
12720b57cec5SDimitry Andric char
12730b57cec5SDimitry Andric ctype_byname<char>::do_tolower(char_type c) const
12740b57cec5SDimitry Andric {
1275bdd1243dSDimitry Andric     return static_cast<char>(tolower_l(static_cast<unsigned char>(c), __l_));
12760b57cec5SDimitry Andric }
12770b57cec5SDimitry Andric 
12780b57cec5SDimitry Andric const char*
12790b57cec5SDimitry Andric ctype_byname<char>::do_tolower(char_type* low, const char_type* high) const
12800b57cec5SDimitry Andric {
12810b57cec5SDimitry Andric     for (; low != high; ++low)
1282bdd1243dSDimitry Andric         *low = static_cast<char>(tolower_l(static_cast<unsigned char>(*low), __l_));
12830b57cec5SDimitry Andric     return low;
12840b57cec5SDimitry Andric }
12850b57cec5SDimitry Andric 
12860b57cec5SDimitry Andric // template <> class ctype_byname<wchar_t>
12870b57cec5SDimitry Andric 
1288349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
12890b57cec5SDimitry Andric ctype_byname<wchar_t>::ctype_byname(const char* name, size_t refs)
12900b57cec5SDimitry Andric     : ctype<wchar_t>(refs),
1291bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, name, 0))
12920b57cec5SDimitry Andric {
1293bdd1243dSDimitry Andric     if (__l_ == 0)
1294*5f757f3fSDimitry Andric         __throw_runtime_error(("ctype_byname<wchar_t>::ctype_byname"
1295*5f757f3fSDimitry Andric                                " failed to construct for " + string(name)).c_str());
12960b57cec5SDimitry Andric }
12970b57cec5SDimitry Andric 
12980b57cec5SDimitry Andric ctype_byname<wchar_t>::ctype_byname(const string& name, size_t refs)
12990b57cec5SDimitry Andric     : ctype<wchar_t>(refs),
1300bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, name.c_str(), 0))
13010b57cec5SDimitry Andric {
1302bdd1243dSDimitry Andric     if (__l_ == 0)
1303*5f757f3fSDimitry Andric         __throw_runtime_error(("ctype_byname<wchar_t>::ctype_byname"
1304*5f757f3fSDimitry Andric                                " failed to construct for " + name).c_str());
13050b57cec5SDimitry Andric }
13060b57cec5SDimitry Andric 
13070b57cec5SDimitry Andric ctype_byname<wchar_t>::~ctype_byname()
13080b57cec5SDimitry Andric {
1309bdd1243dSDimitry Andric     freelocale(__l_);
13100b57cec5SDimitry Andric }
13110b57cec5SDimitry Andric 
13120b57cec5SDimitry Andric bool
13130b57cec5SDimitry Andric ctype_byname<wchar_t>::do_is(mask m, char_type c) const
13140b57cec5SDimitry Andric {
13150b57cec5SDimitry Andric #ifdef _LIBCPP_WCTYPE_IS_MASK
1316bdd1243dSDimitry Andric     return static_cast<bool>(iswctype_l(c, m, __l_));
13170b57cec5SDimitry Andric #else
13180b57cec5SDimitry Andric     bool result = false;
13190b57cec5SDimitry Andric     wint_t ch = static_cast<wint_t>(c);
1320bdd1243dSDimitry Andric     if ((m & space) == space) result |= (iswspace_l(ch, __l_) != 0);
1321bdd1243dSDimitry Andric     if ((m & print) == print) result |= (iswprint_l(ch, __l_) != 0);
1322bdd1243dSDimitry Andric     if ((m & cntrl) == cntrl) result |= (iswcntrl_l(ch, __l_) != 0);
1323bdd1243dSDimitry Andric     if ((m & upper) == upper) result |= (iswupper_l(ch, __l_) != 0);
1324bdd1243dSDimitry Andric     if ((m & lower) == lower) result |= (iswlower_l(ch, __l_) != 0);
1325bdd1243dSDimitry Andric     if ((m & alpha) == alpha) result |= (iswalpha_l(ch, __l_) != 0);
1326bdd1243dSDimitry Andric     if ((m & digit) == digit) result |= (iswdigit_l(ch, __l_) != 0);
1327bdd1243dSDimitry Andric     if ((m & punct) == punct) result |= (iswpunct_l(ch, __l_) != 0);
1328bdd1243dSDimitry Andric     if ((m & xdigit) == xdigit) result |= (iswxdigit_l(ch, __l_) != 0);
1329bdd1243dSDimitry Andric     if ((m & blank) == blank) result |= (iswblank_l(ch, __l_) != 0);
13300b57cec5SDimitry Andric     return result;
13310b57cec5SDimitry Andric #endif
13320b57cec5SDimitry Andric }
13330b57cec5SDimitry Andric 
13340b57cec5SDimitry Andric const wchar_t*
13350b57cec5SDimitry Andric ctype_byname<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
13360b57cec5SDimitry Andric {
13370b57cec5SDimitry Andric     for (; low != high; ++low, ++vec)
13380b57cec5SDimitry Andric     {
13390b57cec5SDimitry Andric         if (isascii(*low))
13400b57cec5SDimitry Andric             *vec = static_cast<mask>(ctype<char>::classic_table()[*low]);
13410b57cec5SDimitry Andric         else
13420b57cec5SDimitry Andric         {
13430b57cec5SDimitry Andric             *vec = 0;
13440b57cec5SDimitry Andric             wint_t ch = static_cast<wint_t>(*low);
1345bdd1243dSDimitry Andric             if (iswspace_l(ch, __l_))
13460b57cec5SDimitry Andric                 *vec |= space;
13470b57cec5SDimitry Andric #ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT
1348bdd1243dSDimitry Andric             if (iswprint_l(ch, __l_))
13490b57cec5SDimitry Andric                 *vec |= print;
13500b57cec5SDimitry Andric #endif
1351bdd1243dSDimitry Andric             if (iswcntrl_l(ch, __l_))
13520b57cec5SDimitry Andric                 *vec |= cntrl;
1353bdd1243dSDimitry Andric             if (iswupper_l(ch, __l_))
13540b57cec5SDimitry Andric                 *vec |= upper;
1355bdd1243dSDimitry Andric             if (iswlower_l(ch, __l_))
13560b57cec5SDimitry Andric                 *vec |= lower;
13570b57cec5SDimitry Andric #ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA
1358bdd1243dSDimitry Andric             if (iswalpha_l(ch, __l_))
13590b57cec5SDimitry Andric                 *vec |= alpha;
13600b57cec5SDimitry Andric #endif
1361bdd1243dSDimitry Andric             if (iswdigit_l(ch, __l_))
13620b57cec5SDimitry Andric                 *vec |= digit;
1363bdd1243dSDimitry Andric             if (iswpunct_l(ch, __l_))
13640b57cec5SDimitry Andric                 *vec |= punct;
13650b57cec5SDimitry Andric #ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_XDIGIT
1366bdd1243dSDimitry Andric             if (iswxdigit_l(ch, __l_))
13670b57cec5SDimitry Andric                 *vec |= xdigit;
13680b57cec5SDimitry Andric #endif
1369bdd1243dSDimitry Andric             if (iswblank_l(ch, __l_))
13700b57cec5SDimitry Andric                 *vec |= blank;
13710b57cec5SDimitry Andric         }
13720b57cec5SDimitry Andric     }
13730b57cec5SDimitry Andric     return low;
13740b57cec5SDimitry Andric }
13750b57cec5SDimitry Andric 
13760b57cec5SDimitry Andric const wchar_t*
13770b57cec5SDimitry Andric ctype_byname<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const
13780b57cec5SDimitry Andric {
13790b57cec5SDimitry Andric     for (; low != high; ++low)
13800b57cec5SDimitry Andric     {
13810b57cec5SDimitry Andric #ifdef _LIBCPP_WCTYPE_IS_MASK
1382bdd1243dSDimitry Andric         if (iswctype_l(*low, m, __l_))
13830b57cec5SDimitry Andric             break;
13840b57cec5SDimitry Andric #else
13850b57cec5SDimitry Andric         wint_t ch = static_cast<wint_t>(*low);
1386bdd1243dSDimitry Andric         if ((m & space) == space && iswspace_l(ch, __l_)) break;
1387bdd1243dSDimitry Andric         if ((m & print) == print && iswprint_l(ch, __l_)) break;
1388bdd1243dSDimitry Andric         if ((m & cntrl) == cntrl && iswcntrl_l(ch, __l_)) break;
1389bdd1243dSDimitry Andric         if ((m & upper) == upper && iswupper_l(ch, __l_)) break;
1390bdd1243dSDimitry Andric         if ((m & lower) == lower && iswlower_l(ch, __l_)) break;
1391bdd1243dSDimitry Andric         if ((m & alpha) == alpha && iswalpha_l(ch, __l_)) break;
1392bdd1243dSDimitry Andric         if ((m & digit) == digit && iswdigit_l(ch, __l_)) break;
1393bdd1243dSDimitry Andric         if ((m & punct) == punct && iswpunct_l(ch, __l_)) break;
1394bdd1243dSDimitry Andric         if ((m & xdigit) == xdigit && iswxdigit_l(ch, __l_)) break;
1395bdd1243dSDimitry Andric         if ((m & blank) == blank && iswblank_l(ch, __l_)) break;
13960b57cec5SDimitry Andric #endif
13970b57cec5SDimitry Andric     }
13980b57cec5SDimitry Andric     return low;
13990b57cec5SDimitry Andric }
14000b57cec5SDimitry Andric 
14010b57cec5SDimitry Andric const wchar_t*
14020b57cec5SDimitry Andric ctype_byname<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const
14030b57cec5SDimitry Andric {
14040b57cec5SDimitry Andric     for (; low != high; ++low)
14050b57cec5SDimitry Andric     {
14060b57cec5SDimitry Andric #ifdef _LIBCPP_WCTYPE_IS_MASK
1407bdd1243dSDimitry Andric         if (!iswctype_l(*low, m, __l_))
14080b57cec5SDimitry Andric             break;
14090b57cec5SDimitry Andric #else
14100b57cec5SDimitry Andric         wint_t ch = static_cast<wint_t>(*low);
1411bdd1243dSDimitry Andric         if ((m & space) == space && iswspace_l(ch, __l_)) continue;
1412bdd1243dSDimitry Andric         if ((m & print) == print && iswprint_l(ch, __l_)) continue;
1413bdd1243dSDimitry Andric         if ((m & cntrl) == cntrl && iswcntrl_l(ch, __l_)) continue;
1414bdd1243dSDimitry Andric         if ((m & upper) == upper && iswupper_l(ch, __l_)) continue;
1415bdd1243dSDimitry Andric         if ((m & lower) == lower && iswlower_l(ch, __l_)) continue;
1416bdd1243dSDimitry Andric         if ((m & alpha) == alpha && iswalpha_l(ch, __l_)) continue;
1417bdd1243dSDimitry Andric         if ((m & digit) == digit && iswdigit_l(ch, __l_)) continue;
1418bdd1243dSDimitry Andric         if ((m & punct) == punct && iswpunct_l(ch, __l_)) continue;
1419bdd1243dSDimitry Andric         if ((m & xdigit) == xdigit && iswxdigit_l(ch, __l_)) continue;
1420bdd1243dSDimitry Andric         if ((m & blank) == blank && iswblank_l(ch, __l_)) continue;
14210b57cec5SDimitry Andric         break;
14220b57cec5SDimitry Andric #endif
14230b57cec5SDimitry Andric     }
14240b57cec5SDimitry Andric     return low;
14250b57cec5SDimitry Andric }
14260b57cec5SDimitry Andric 
14270b57cec5SDimitry Andric wchar_t
14280b57cec5SDimitry Andric ctype_byname<wchar_t>::do_toupper(char_type c) const
14290b57cec5SDimitry Andric {
1430bdd1243dSDimitry Andric     return towupper_l(c, __l_);
14310b57cec5SDimitry Andric }
14320b57cec5SDimitry Andric 
14330b57cec5SDimitry Andric const wchar_t*
14340b57cec5SDimitry Andric ctype_byname<wchar_t>::do_toupper(char_type* low, const char_type* high) const
14350b57cec5SDimitry Andric {
14360b57cec5SDimitry Andric     for (; low != high; ++low)
1437bdd1243dSDimitry Andric         *low = towupper_l(*low, __l_);
14380b57cec5SDimitry Andric     return low;
14390b57cec5SDimitry Andric }
14400b57cec5SDimitry Andric 
14410b57cec5SDimitry Andric wchar_t
14420b57cec5SDimitry Andric ctype_byname<wchar_t>::do_tolower(char_type c) const
14430b57cec5SDimitry Andric {
1444bdd1243dSDimitry Andric     return towlower_l(c, __l_);
14450b57cec5SDimitry Andric }
14460b57cec5SDimitry Andric 
14470b57cec5SDimitry Andric const wchar_t*
14480b57cec5SDimitry Andric ctype_byname<wchar_t>::do_tolower(char_type* low, const char_type* high) const
14490b57cec5SDimitry Andric {
14500b57cec5SDimitry Andric     for (; low != high; ++low)
1451bdd1243dSDimitry Andric         *low = towlower_l(*low, __l_);
14520b57cec5SDimitry Andric     return low;
14530b57cec5SDimitry Andric }
14540b57cec5SDimitry Andric 
14550b57cec5SDimitry Andric wchar_t
14560b57cec5SDimitry Andric ctype_byname<wchar_t>::do_widen(char c) const
14570b57cec5SDimitry Andric {
1458bdd1243dSDimitry Andric     return __libcpp_btowc_l(c, __l_);
14590b57cec5SDimitry Andric }
14600b57cec5SDimitry Andric 
14610b57cec5SDimitry Andric const char*
14620b57cec5SDimitry Andric ctype_byname<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const
14630b57cec5SDimitry Andric {
14640b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
1465bdd1243dSDimitry Andric         *dest = __libcpp_btowc_l(*low, __l_);
14660b57cec5SDimitry Andric     return low;
14670b57cec5SDimitry Andric }
14680b57cec5SDimitry Andric 
14690b57cec5SDimitry Andric char
14700b57cec5SDimitry Andric ctype_byname<wchar_t>::do_narrow(char_type c, char dfault) const
14710b57cec5SDimitry Andric {
1472bdd1243dSDimitry Andric     int r = __libcpp_wctob_l(c, __l_);
147381ad6265SDimitry Andric     return (r != EOF) ? static_cast<char>(r) : dfault;
14740b57cec5SDimitry Andric }
14750b57cec5SDimitry Andric 
14760b57cec5SDimitry Andric const wchar_t*
14770b57cec5SDimitry Andric ctype_byname<wchar_t>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
14780b57cec5SDimitry Andric {
14790b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
14800b57cec5SDimitry Andric     {
1481bdd1243dSDimitry Andric         int r = __libcpp_wctob_l(*low, __l_);
148281ad6265SDimitry Andric         *dest = (r != EOF) ? static_cast<char>(r) : dfault;
14830b57cec5SDimitry Andric     }
14840b57cec5SDimitry Andric     return low;
14850b57cec5SDimitry Andric }
1486349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
14870b57cec5SDimitry Andric 
14880b57cec5SDimitry Andric // template <> class codecvt<char, char, mbstate_t>
14890b57cec5SDimitry Andric 
1490*5f757f3fSDimitry Andric constinit locale::id codecvt<char, char, mbstate_t>::id;
14910b57cec5SDimitry Andric 
14920b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::~codecvt()
14930b57cec5SDimitry Andric {
14940b57cec5SDimitry Andric }
14950b57cec5SDimitry Andric 
14960b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::result
14970b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::do_out(state_type&,
14980b57cec5SDimitry Andric     const intern_type* frm, const intern_type*, const intern_type*& frm_nxt,
14990b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
15000b57cec5SDimitry Andric {
15010b57cec5SDimitry Andric     frm_nxt = frm;
15020b57cec5SDimitry Andric     to_nxt = to;
15030b57cec5SDimitry Andric     return noconv;
15040b57cec5SDimitry Andric }
15050b57cec5SDimitry Andric 
15060b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::result
15070b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::do_in(state_type&,
15080b57cec5SDimitry Andric     const extern_type* frm, const extern_type*, const extern_type*& frm_nxt,
15090b57cec5SDimitry Andric     intern_type* to, intern_type*, intern_type*& to_nxt) const
15100b57cec5SDimitry Andric {
15110b57cec5SDimitry Andric     frm_nxt = frm;
15120b57cec5SDimitry Andric     to_nxt = to;
15130b57cec5SDimitry Andric     return noconv;
15140b57cec5SDimitry Andric }
15150b57cec5SDimitry Andric 
15160b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::result
15170b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::do_unshift(state_type&,
15180b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
15190b57cec5SDimitry Andric {
15200b57cec5SDimitry Andric     to_nxt = to;
15210b57cec5SDimitry Andric     return noconv;
15220b57cec5SDimitry Andric }
15230b57cec5SDimitry Andric 
15240b57cec5SDimitry Andric int
1525fe6060f1SDimitry Andric codecvt<char, char, mbstate_t>::do_encoding() const noexcept
15260b57cec5SDimitry Andric {
15270b57cec5SDimitry Andric     return 1;
15280b57cec5SDimitry Andric }
15290b57cec5SDimitry Andric 
15300b57cec5SDimitry Andric bool
1531fe6060f1SDimitry Andric codecvt<char, char, mbstate_t>::do_always_noconv() const noexcept
15320b57cec5SDimitry Andric {
15330b57cec5SDimitry Andric     return true;
15340b57cec5SDimitry Andric }
15350b57cec5SDimitry Andric 
15360b57cec5SDimitry Andric int
15370b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::do_length(state_type&,
15380b57cec5SDimitry Andric     const extern_type* frm, const extern_type* end, size_t mx) const
15390b57cec5SDimitry Andric {
15400b57cec5SDimitry Andric     return static_cast<int>(min<size_t>(mx, static_cast<size_t>(end-frm)));
15410b57cec5SDimitry Andric }
15420b57cec5SDimitry Andric 
15430b57cec5SDimitry Andric int
1544fe6060f1SDimitry Andric codecvt<char, char, mbstate_t>::do_max_length() const noexcept
15450b57cec5SDimitry Andric {
15460b57cec5SDimitry Andric     return 1;
15470b57cec5SDimitry Andric }
15480b57cec5SDimitry Andric 
15490b57cec5SDimitry Andric // template <> class codecvt<wchar_t, char, mbstate_t>
15500b57cec5SDimitry Andric 
1551349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1552*5f757f3fSDimitry Andric constinit locale::id codecvt<wchar_t, char, mbstate_t>::id;
15530b57cec5SDimitry Andric 
15540b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::codecvt(size_t refs)
15550b57cec5SDimitry Andric     : locale::facet(refs),
1556bdd1243dSDimitry Andric       __l_(_LIBCPP_GET_C_LOCALE)
15570b57cec5SDimitry Andric {
15580b57cec5SDimitry Andric }
15590b57cec5SDimitry Andric 
15600b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::codecvt(const char* nm, size_t refs)
15610b57cec5SDimitry Andric     : locale::facet(refs),
1562bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, nm, 0))
15630b57cec5SDimitry Andric {
1564bdd1243dSDimitry Andric     if (__l_ == 0)
1565*5f757f3fSDimitry Andric         __throw_runtime_error(("codecvt_byname<wchar_t, char, mbstate_t>::codecvt_byname"
1566*5f757f3fSDimitry Andric                                " failed to construct for " + string(nm)).c_str());
15670b57cec5SDimitry Andric }
15680b57cec5SDimitry Andric 
15690b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::~codecvt()
15700b57cec5SDimitry Andric {
1571bdd1243dSDimitry Andric     if (__l_ != _LIBCPP_GET_C_LOCALE)
1572bdd1243dSDimitry Andric         freelocale(__l_);
15730b57cec5SDimitry Andric }
15740b57cec5SDimitry Andric 
15750b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::result
15760b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_out(state_type& st,
15770b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
15780b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
15790b57cec5SDimitry Andric {
15800b57cec5SDimitry Andric     // look for first internal null in frm
15810b57cec5SDimitry Andric     const intern_type* fend = frm;
15820b57cec5SDimitry Andric     for (; fend != frm_end; ++fend)
15830b57cec5SDimitry Andric         if (*fend == 0)
15840b57cec5SDimitry Andric             break;
15850b57cec5SDimitry Andric     // loop over all null-terminated sequences in frm
15860b57cec5SDimitry Andric     to_nxt = to;
15870b57cec5SDimitry Andric     for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt)
15880b57cec5SDimitry Andric     {
15890b57cec5SDimitry Andric         // save state in case it is needed to recover to_nxt on error
15900b57cec5SDimitry Andric         mbstate_t save_state = st;
15910b57cec5SDimitry Andric         size_t n = __libcpp_wcsnrtombs_l(to, &frm_nxt, static_cast<size_t>(fend-frm),
1592bdd1243dSDimitry Andric                                      static_cast<size_t>(to_end-to), &st, __l_);
15930b57cec5SDimitry Andric         if (n == size_t(-1))
15940b57cec5SDimitry Andric         {
15950b57cec5SDimitry Andric             // need to recover to_nxt
15960b57cec5SDimitry Andric             for (to_nxt = to; frm != frm_nxt; ++frm)
15970b57cec5SDimitry Andric             {
1598bdd1243dSDimitry Andric                 n = __libcpp_wcrtomb_l(to_nxt, *frm, &save_state, __l_);
15990b57cec5SDimitry Andric                 if (n == size_t(-1))
16000b57cec5SDimitry Andric                     break;
16010b57cec5SDimitry Andric                 to_nxt += n;
16020b57cec5SDimitry Andric             }
16030b57cec5SDimitry Andric             frm_nxt = frm;
16040b57cec5SDimitry Andric             return error;
16050b57cec5SDimitry Andric         }
16060b57cec5SDimitry Andric         if (n == 0)
16070b57cec5SDimitry Andric             return partial;
16080b57cec5SDimitry Andric         to_nxt += n;
16090b57cec5SDimitry Andric         if (to_nxt == to_end)
16100b57cec5SDimitry Andric             break;
16110b57cec5SDimitry Andric         if (fend != frm_end)  // set up next null terminated sequence
16120b57cec5SDimitry Andric         {
16130b57cec5SDimitry Andric             // Try to write the terminating null
16140b57cec5SDimitry Andric             extern_type tmp[MB_LEN_MAX];
1615bdd1243dSDimitry Andric             n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l_);
16160b57cec5SDimitry Andric             if (n == size_t(-1))  // on error
16170b57cec5SDimitry Andric                 return error;
16180b57cec5SDimitry Andric             if (n > static_cast<size_t>(to_end-to_nxt))  // is there room?
16190b57cec5SDimitry Andric                 return partial;
16200b57cec5SDimitry Andric             for (extern_type* p = tmp; n; --n)  // write it
16210b57cec5SDimitry Andric                 *to_nxt++ = *p++;
16220b57cec5SDimitry Andric             ++frm_nxt;
16230b57cec5SDimitry Andric             // look for next null in frm
16240b57cec5SDimitry Andric             for (fend = frm_nxt; fend != frm_end; ++fend)
16250b57cec5SDimitry Andric                 if (*fend == 0)
16260b57cec5SDimitry Andric                     break;
16270b57cec5SDimitry Andric         }
16280b57cec5SDimitry Andric     }
16290b57cec5SDimitry Andric     return frm_nxt == frm_end ? ok : partial;
16300b57cec5SDimitry Andric }
16310b57cec5SDimitry Andric 
16320b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::result
16330b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_in(state_type& st,
16340b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
16350b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
16360b57cec5SDimitry Andric {
16370b57cec5SDimitry Andric     // look for first internal null in frm
16380b57cec5SDimitry Andric     const extern_type* fend = frm;
16390b57cec5SDimitry Andric     for (; fend != frm_end; ++fend)
16400b57cec5SDimitry Andric         if (*fend == 0)
16410b57cec5SDimitry Andric             break;
16420b57cec5SDimitry Andric     // loop over all null-terminated sequences in frm
16430b57cec5SDimitry Andric     to_nxt = to;
16440b57cec5SDimitry Andric     for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt)
16450b57cec5SDimitry Andric     {
16460b57cec5SDimitry Andric         // save state in case it is needed to recover to_nxt on error
16470b57cec5SDimitry Andric         mbstate_t save_state = st;
16480b57cec5SDimitry Andric         size_t n = __libcpp_mbsnrtowcs_l(to, &frm_nxt, static_cast<size_t>(fend-frm),
1649bdd1243dSDimitry Andric                                      static_cast<size_t>(to_end-to), &st, __l_);
16500b57cec5SDimitry Andric         if (n == size_t(-1))
16510b57cec5SDimitry Andric         {
16520b57cec5SDimitry Andric             // need to recover to_nxt
16530b57cec5SDimitry Andric             for (to_nxt = to; frm != frm_nxt; ++to_nxt)
16540b57cec5SDimitry Andric             {
16550b57cec5SDimitry Andric                 n = __libcpp_mbrtowc_l(to_nxt, frm, static_cast<size_t>(fend-frm),
1656bdd1243dSDimitry Andric                                    &save_state, __l_);
16570b57cec5SDimitry Andric                 switch (n)
16580b57cec5SDimitry Andric                 {
16590b57cec5SDimitry Andric                 case 0:
16600b57cec5SDimitry Andric                     ++frm;
16610b57cec5SDimitry Andric                     break;
16620b57cec5SDimitry Andric                 case size_t(-1):
16630b57cec5SDimitry Andric                     frm_nxt = frm;
16640b57cec5SDimitry Andric                     return error;
16650b57cec5SDimitry Andric                 case size_t(-2):
16660b57cec5SDimitry Andric                     frm_nxt = frm;
16670b57cec5SDimitry Andric                     return partial;
16680b57cec5SDimitry Andric                 default:
16690b57cec5SDimitry Andric                     frm += n;
16700b57cec5SDimitry Andric                     break;
16710b57cec5SDimitry Andric                 }
16720b57cec5SDimitry Andric             }
16730b57cec5SDimitry Andric             frm_nxt = frm;
16740b57cec5SDimitry Andric             return frm_nxt == frm_end ? ok : partial;
16750b57cec5SDimitry Andric         }
16760b57cec5SDimitry Andric         if (n == size_t(-1))
16770b57cec5SDimitry Andric             return error;
16780b57cec5SDimitry Andric         to_nxt += n;
16790b57cec5SDimitry Andric         if (to_nxt == to_end)
16800b57cec5SDimitry Andric             break;
16810b57cec5SDimitry Andric         if (fend != frm_end)  // set up next null terminated sequence
16820b57cec5SDimitry Andric         {
16830b57cec5SDimitry Andric             // Try to write the terminating null
1684bdd1243dSDimitry Andric             n = __libcpp_mbrtowc_l(to_nxt, frm_nxt, 1, &st, __l_);
16850b57cec5SDimitry Andric             if (n != 0)  // on error
16860b57cec5SDimitry Andric                 return error;
16870b57cec5SDimitry Andric             ++to_nxt;
16880b57cec5SDimitry Andric             ++frm_nxt;
16890b57cec5SDimitry Andric             // look for next null in frm
16900b57cec5SDimitry Andric             for (fend = frm_nxt; fend != frm_end; ++fend)
16910b57cec5SDimitry Andric                 if (*fend == 0)
16920b57cec5SDimitry Andric                     break;
16930b57cec5SDimitry Andric         }
16940b57cec5SDimitry Andric     }
16950b57cec5SDimitry Andric     return frm_nxt == frm_end ? ok : partial;
16960b57cec5SDimitry Andric }
16970b57cec5SDimitry Andric 
16980b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::result
16990b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_unshift(state_type& st,
17000b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
17010b57cec5SDimitry Andric {
17020b57cec5SDimitry Andric     to_nxt = to;
17030b57cec5SDimitry Andric     extern_type tmp[MB_LEN_MAX];
1704bdd1243dSDimitry Andric     size_t n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l_);
17050b57cec5SDimitry Andric     if (n == size_t(-1) || n == 0)  // on error
17060b57cec5SDimitry Andric         return error;
17070b57cec5SDimitry Andric     --n;
17080b57cec5SDimitry Andric     if (n > static_cast<size_t>(to_end-to_nxt))  // is there room?
17090b57cec5SDimitry Andric         return partial;
17100b57cec5SDimitry Andric     for (extern_type* p = tmp; n; --n)  // write it
17110b57cec5SDimitry Andric         *to_nxt++ = *p++;
17120b57cec5SDimitry Andric     return ok;
17130b57cec5SDimitry Andric }
17140b57cec5SDimitry Andric 
17150b57cec5SDimitry Andric int
1716fe6060f1SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_encoding() const noexcept
17170b57cec5SDimitry Andric {
1718bdd1243dSDimitry Andric     if (__libcpp_mbtowc_l(nullptr, nullptr, MB_LEN_MAX, __l_) != 0)
17190b57cec5SDimitry Andric         return -1;
17200b57cec5SDimitry Andric 
17210b57cec5SDimitry Andric     // stateless encoding
1722bdd1243dSDimitry Andric     if (__l_ == 0 || __libcpp_mb_cur_max_l(__l_) == 1)  // there are no known constant length encodings
17230b57cec5SDimitry Andric         return 1;                // which take more than 1 char to form a wchar_t
17240b57cec5SDimitry Andric     return 0;
17250b57cec5SDimitry Andric }
17260b57cec5SDimitry Andric 
17270b57cec5SDimitry Andric bool
1728fe6060f1SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_always_noconv() const noexcept
17290b57cec5SDimitry Andric {
17300b57cec5SDimitry Andric     return false;
17310b57cec5SDimitry Andric }
17320b57cec5SDimitry Andric 
17330b57cec5SDimitry Andric int
17340b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_length(state_type& st,
17350b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
17360b57cec5SDimitry Andric {
17370b57cec5SDimitry Andric     int nbytes = 0;
17380b57cec5SDimitry Andric     for (size_t nwchar_t = 0; nwchar_t < mx && frm != frm_end; ++nwchar_t)
17390b57cec5SDimitry Andric     {
1740bdd1243dSDimitry Andric         size_t n = __libcpp_mbrlen_l(frm, static_cast<size_t>(frm_end-frm), &st, __l_);
17410b57cec5SDimitry Andric         switch (n)
17420b57cec5SDimitry Andric         {
17430b57cec5SDimitry Andric         case 0:
17440b57cec5SDimitry Andric             ++nbytes;
17450b57cec5SDimitry Andric             ++frm;
17460b57cec5SDimitry Andric             break;
17470b57cec5SDimitry Andric         case size_t(-1):
17480b57cec5SDimitry Andric         case size_t(-2):
17490b57cec5SDimitry Andric             return nbytes;
17500b57cec5SDimitry Andric         default:
17510b57cec5SDimitry Andric             nbytes += n;
17520b57cec5SDimitry Andric             frm += n;
17530b57cec5SDimitry Andric             break;
17540b57cec5SDimitry Andric         }
17550b57cec5SDimitry Andric     }
17560b57cec5SDimitry Andric     return nbytes;
17570b57cec5SDimitry Andric }
17580b57cec5SDimitry Andric 
17590b57cec5SDimitry Andric int
1760fe6060f1SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_max_length() const noexcept
17610b57cec5SDimitry Andric {
1762bdd1243dSDimitry Andric     return __l_ == 0 ? 1 : static_cast<int>(__libcpp_mb_cur_max_l(__l_));
17630b57cec5SDimitry Andric }
1764349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
17650b57cec5SDimitry Andric 
17660b57cec5SDimitry Andric //                                     Valid UTF ranges
17670b57cec5SDimitry Andric //     UTF-32               UTF-16                          UTF-8               # of code points
17680b57cec5SDimitry Andric //                     first      second       first   second    third   fourth
17690b57cec5SDimitry Andric // 000000 - 00007F  0000 - 007F               00 - 7F                                 127
17700b57cec5SDimitry Andric // 000080 - 0007FF  0080 - 07FF               C2 - DF, 80 - BF                       1920
17710b57cec5SDimitry Andric // 000800 - 000FFF  0800 - 0FFF               E0 - E0, A0 - BF, 80 - BF              2048
17720b57cec5SDimitry Andric // 001000 - 00CFFF  1000 - CFFF               E1 - EC, 80 - BF, 80 - BF             49152
17730b57cec5SDimitry Andric // 00D000 - 00D7FF  D000 - D7FF               ED - ED, 80 - 9F, 80 - BF              2048
17740b57cec5SDimitry Andric // 00D800 - 00DFFF                invalid
17750b57cec5SDimitry Andric // 00E000 - 00FFFF  E000 - FFFF               EE - EF, 80 - BF, 80 - BF              8192
17760b57cec5SDimitry Andric // 010000 - 03FFFF  D800 - D8BF, DC00 - DFFF  F0 - F0, 90 - BF, 80 - BF, 80 - BF   196608
17770b57cec5SDimitry Andric // 040000 - 0FFFFF  D8C0 - DBBF, DC00 - DFFF  F1 - F3, 80 - BF, 80 - BF, 80 - BF   786432
17780b57cec5SDimitry Andric // 100000 - 10FFFF  DBC0 - DBFF, DC00 - DFFF  F4 - F4, 80 - 8F, 80 - BF, 80 - BF    65536
17790b57cec5SDimitry Andric 
178081ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
17810b57cec5SDimitry Andric static
17820b57cec5SDimitry Andric codecvt_base::result
17830b57cec5SDimitry Andric utf16_to_utf8(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
17840b57cec5SDimitry Andric               uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
17850b57cec5SDimitry Andric               unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
17860b57cec5SDimitry Andric {
17870b57cec5SDimitry Andric     frm_nxt = frm;
17880b57cec5SDimitry Andric     to_nxt = to;
17890b57cec5SDimitry Andric     if (mode & generate_header)
17900b57cec5SDimitry Andric     {
17910b57cec5SDimitry Andric         if (to_end-to_nxt < 3)
17920b57cec5SDimitry Andric             return codecvt_base::partial;
17930b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xEF);
17940b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBB);
17950b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBF);
17960b57cec5SDimitry Andric     }
17970b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
17980b57cec5SDimitry Andric     {
17990b57cec5SDimitry Andric         uint16_t wc1 = *frm_nxt;
18000b57cec5SDimitry Andric         if (wc1 > Maxcode)
18010b57cec5SDimitry Andric             return codecvt_base::error;
18020b57cec5SDimitry Andric         if (wc1 < 0x0080)
18030b57cec5SDimitry Andric         {
18040b57cec5SDimitry Andric             if (to_end-to_nxt < 1)
18050b57cec5SDimitry Andric                 return codecvt_base::partial;
18060b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc1);
18070b57cec5SDimitry Andric         }
18080b57cec5SDimitry Andric         else if (wc1 < 0x0800)
18090b57cec5SDimitry Andric         {
18100b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
18110b57cec5SDimitry Andric                 return codecvt_base::partial;
18120b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc1 >> 6));
18130b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x03F));
18140b57cec5SDimitry Andric         }
18150b57cec5SDimitry Andric         else if (wc1 < 0xD800)
18160b57cec5SDimitry Andric         {
18170b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
18180b57cec5SDimitry Andric                 return codecvt_base::partial;
18190b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
18200b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
18210b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
18220b57cec5SDimitry Andric         }
18230b57cec5SDimitry Andric         else if (wc1 < 0xDC00)
18240b57cec5SDimitry Andric         {
18250b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
18260b57cec5SDimitry Andric                 return codecvt_base::partial;
18270b57cec5SDimitry Andric             uint16_t wc2 = frm_nxt[1];
18280b57cec5SDimitry Andric             if ((wc2 & 0xFC00) != 0xDC00)
18290b57cec5SDimitry Andric                 return codecvt_base::error;
18300b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
18310b57cec5SDimitry Andric                 return codecvt_base::partial;
18320b57cec5SDimitry Andric             if (((((wc1 & 0x03C0UL) >> 6) + 1) << 16) +
18330b57cec5SDimitry Andric                 ((wc1 & 0x003FUL) << 10) + (wc2 & 0x03FF) > Maxcode)
18340b57cec5SDimitry Andric                 return codecvt_base::error;
18350b57cec5SDimitry Andric             ++frm_nxt;
18360b57cec5SDimitry Andric             uint8_t z = ((wc1 & 0x03C0) >> 6) + 1;
18370b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xF0 | (z >> 2));
18380b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((z & 0x03) << 4)     | ((wc1 & 0x003C) >> 2));
18390b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6));
18400b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc2 & 0x003F));
18410b57cec5SDimitry Andric         }
18420b57cec5SDimitry Andric         else if (wc1 < 0xE000)
18430b57cec5SDimitry Andric         {
18440b57cec5SDimitry Andric             return codecvt_base::error;
18450b57cec5SDimitry Andric         }
18460b57cec5SDimitry Andric         else
18470b57cec5SDimitry Andric         {
18480b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
18490b57cec5SDimitry Andric                 return codecvt_base::partial;
18500b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
18510b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
18520b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
18530b57cec5SDimitry Andric         }
18540b57cec5SDimitry Andric     }
18550b57cec5SDimitry Andric     return codecvt_base::ok;
18560b57cec5SDimitry Andric }
18570b57cec5SDimitry Andric 
18580b57cec5SDimitry Andric static
18590b57cec5SDimitry Andric codecvt_base::result
18600b57cec5SDimitry Andric utf16_to_utf8(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
18610b57cec5SDimitry Andric               uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
18620b57cec5SDimitry Andric               unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
18630b57cec5SDimitry Andric {
18640b57cec5SDimitry Andric     frm_nxt = frm;
18650b57cec5SDimitry Andric     to_nxt = to;
18660b57cec5SDimitry Andric     if (mode & generate_header)
18670b57cec5SDimitry Andric     {
18680b57cec5SDimitry Andric         if (to_end-to_nxt < 3)
18690b57cec5SDimitry Andric             return codecvt_base::partial;
18700b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xEF);
18710b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBB);
18720b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBF);
18730b57cec5SDimitry Andric     }
18740b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
18750b57cec5SDimitry Andric     {
18760b57cec5SDimitry Andric         uint16_t wc1 = static_cast<uint16_t>(*frm_nxt);
18770b57cec5SDimitry Andric         if (wc1 > Maxcode)
18780b57cec5SDimitry Andric             return codecvt_base::error;
18790b57cec5SDimitry Andric         if (wc1 < 0x0080)
18800b57cec5SDimitry Andric         {
18810b57cec5SDimitry Andric             if (to_end-to_nxt < 1)
18820b57cec5SDimitry Andric                 return codecvt_base::partial;
18830b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc1);
18840b57cec5SDimitry Andric         }
18850b57cec5SDimitry Andric         else if (wc1 < 0x0800)
18860b57cec5SDimitry Andric         {
18870b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
18880b57cec5SDimitry Andric                 return codecvt_base::partial;
18890b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc1 >> 6));
18900b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x03F));
18910b57cec5SDimitry Andric         }
18920b57cec5SDimitry Andric         else if (wc1 < 0xD800)
18930b57cec5SDimitry Andric         {
18940b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
18950b57cec5SDimitry Andric                 return codecvt_base::partial;
18960b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
18970b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
18980b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
18990b57cec5SDimitry Andric         }
19000b57cec5SDimitry Andric         else if (wc1 < 0xDC00)
19010b57cec5SDimitry Andric         {
19020b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
19030b57cec5SDimitry Andric                 return codecvt_base::partial;
19040b57cec5SDimitry Andric             uint16_t wc2 = static_cast<uint16_t>(frm_nxt[1]);
19050b57cec5SDimitry Andric             if ((wc2 & 0xFC00) != 0xDC00)
19060b57cec5SDimitry Andric                 return codecvt_base::error;
19070b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
19080b57cec5SDimitry Andric                 return codecvt_base::partial;
19090b57cec5SDimitry Andric             if (((((wc1 & 0x03C0UL) >> 6) + 1) << 16) +
19100b57cec5SDimitry Andric                 ((wc1 & 0x003FUL) << 10) + (wc2 & 0x03FF) > Maxcode)
19110b57cec5SDimitry Andric                 return codecvt_base::error;
19120b57cec5SDimitry Andric             ++frm_nxt;
19130b57cec5SDimitry Andric             uint8_t z = ((wc1 & 0x03C0) >> 6) + 1;
19140b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xF0 | (z >> 2));
19150b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((z & 0x03) << 4)     | ((wc1 & 0x003C) >> 2));
19160b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6));
19170b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc2 & 0x003F));
19180b57cec5SDimitry Andric         }
19190b57cec5SDimitry Andric         else if (wc1 < 0xE000)
19200b57cec5SDimitry Andric         {
19210b57cec5SDimitry Andric             return codecvt_base::error;
19220b57cec5SDimitry Andric         }
19230b57cec5SDimitry Andric         else
19240b57cec5SDimitry Andric         {
19250b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
19260b57cec5SDimitry Andric                 return codecvt_base::partial;
19270b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
19280b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
19290b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
19300b57cec5SDimitry Andric         }
19310b57cec5SDimitry Andric     }
19320b57cec5SDimitry Andric     return codecvt_base::ok;
19330b57cec5SDimitry Andric }
19340b57cec5SDimitry Andric 
19350b57cec5SDimitry Andric static
19360b57cec5SDimitry Andric codecvt_base::result
19370b57cec5SDimitry Andric utf8_to_utf16(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
19380b57cec5SDimitry Andric               uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
19390b57cec5SDimitry Andric               unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
19400b57cec5SDimitry Andric {
19410b57cec5SDimitry Andric     frm_nxt = frm;
19420b57cec5SDimitry Andric     to_nxt = to;
19430b57cec5SDimitry Andric     if (mode & consume_header)
19440b57cec5SDimitry Andric     {
19450b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
19460b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
19470b57cec5SDimitry Andric             frm_nxt += 3;
19480b57cec5SDimitry Andric     }
19490b57cec5SDimitry Andric     for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
19500b57cec5SDimitry Andric     {
19510b57cec5SDimitry Andric         uint8_t c1 = *frm_nxt;
19520b57cec5SDimitry Andric         if (c1 > Maxcode)
19530b57cec5SDimitry Andric             return codecvt_base::error;
19540b57cec5SDimitry Andric         if (c1 < 0x80)
19550b57cec5SDimitry Andric         {
19560b57cec5SDimitry Andric             *to_nxt = static_cast<uint16_t>(c1);
19570b57cec5SDimitry Andric             ++frm_nxt;
19580b57cec5SDimitry Andric         }
19590b57cec5SDimitry Andric         else if (c1 < 0xC2)
19600b57cec5SDimitry Andric         {
19610b57cec5SDimitry Andric             return codecvt_base::error;
19620b57cec5SDimitry Andric         }
19630b57cec5SDimitry Andric         else if (c1 < 0xE0)
19640b57cec5SDimitry Andric         {
19650b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
19660b57cec5SDimitry Andric                 return codecvt_base::partial;
19670b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
19680b57cec5SDimitry Andric             if ((c2 & 0xC0) != 0x80)
19690b57cec5SDimitry Andric                 return codecvt_base::error;
19700b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
19710b57cec5SDimitry Andric             if (t > Maxcode)
19720b57cec5SDimitry Andric                 return codecvt_base::error;
19730b57cec5SDimitry Andric             *to_nxt = t;
19740b57cec5SDimitry Andric             frm_nxt += 2;
19750b57cec5SDimitry Andric         }
19760b57cec5SDimitry Andric         else if (c1 < 0xF0)
19770b57cec5SDimitry Andric         {
1978*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 2)
19790b57cec5SDimitry Andric                 return codecvt_base::partial;
19800b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
19810b57cec5SDimitry Andric             switch (c1)
19820b57cec5SDimitry Andric             {
19830b57cec5SDimitry Andric             case 0xE0:
19840b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
19850b57cec5SDimitry Andric                     return codecvt_base::error;
19860b57cec5SDimitry Andric                  break;
19870b57cec5SDimitry Andric             case 0xED:
19880b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
19890b57cec5SDimitry Andric                     return codecvt_base::error;
19900b57cec5SDimitry Andric                  break;
19910b57cec5SDimitry Andric             default:
19920b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
19930b57cec5SDimitry Andric                     return codecvt_base::error;
19940b57cec5SDimitry Andric                  break;
19950b57cec5SDimitry Andric             }
1996*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 3)
1997*5f757f3fSDimitry Andric                 return codecvt_base::partial;
1998*5f757f3fSDimitry Andric             uint8_t c3 = frm_nxt[2];
19990b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
20000b57cec5SDimitry Andric                 return codecvt_base::error;
20010b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
20020b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 6)
20030b57cec5SDimitry Andric                                              |  (c3 & 0x3F));
20040b57cec5SDimitry Andric             if (t > Maxcode)
20050b57cec5SDimitry Andric                 return codecvt_base::error;
20060b57cec5SDimitry Andric             *to_nxt = t;
20070b57cec5SDimitry Andric             frm_nxt += 3;
20080b57cec5SDimitry Andric         }
20090b57cec5SDimitry Andric         else if (c1 < 0xF5)
20100b57cec5SDimitry Andric         {
2011*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 2)
20120b57cec5SDimitry Andric                 return codecvt_base::partial;
20130b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
20140b57cec5SDimitry Andric             switch (c1)
20150b57cec5SDimitry Andric             {
20160b57cec5SDimitry Andric             case 0xF0:
20170b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
20180b57cec5SDimitry Andric                     return codecvt_base::error;
20190b57cec5SDimitry Andric                  break;
20200b57cec5SDimitry Andric             case 0xF4:
20210b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
20220b57cec5SDimitry Andric                     return codecvt_base::error;
20230b57cec5SDimitry Andric                  break;
20240b57cec5SDimitry Andric             default:
20250b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
20260b57cec5SDimitry Andric                     return codecvt_base::error;
20270b57cec5SDimitry Andric                  break;
20280b57cec5SDimitry Andric             }
2029*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 3)
2030*5f757f3fSDimitry Andric                  return codecvt_base::partial;
2031*5f757f3fSDimitry Andric             uint8_t c3 = frm_nxt[2];
2032*5f757f3fSDimitry Andric             if ((c3 & 0xC0) != 0x80)
2033*5f757f3fSDimitry Andric                  return codecvt_base::error;
2034*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 4)
2035*5f757f3fSDimitry Andric                  return codecvt_base::partial;
2036*5f757f3fSDimitry Andric             uint8_t c4 = frm_nxt[3];
2037*5f757f3fSDimitry Andric             if ((c4 & 0xC0) != 0x80)
20380b57cec5SDimitry Andric                  return codecvt_base::error;
20390b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
20400b57cec5SDimitry Andric                 return codecvt_base::partial;
20410b57cec5SDimitry Andric             if ((((c1 & 7UL) << 18) +
20420b57cec5SDimitry Andric                 ((c2 & 0x3FUL) << 12) +
20430b57cec5SDimitry Andric                 ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
20440b57cec5SDimitry Andric                 return codecvt_base::error;
20450b57cec5SDimitry Andric             *to_nxt = static_cast<uint16_t>(
20460b57cec5SDimitry Andric                     0xD800
20470b57cec5SDimitry Andric                   | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6)
20480b57cec5SDimitry Andric                   | ((c2 & 0x0F) << 2)
20490b57cec5SDimitry Andric                   | ((c3 & 0x30) >> 4));
20500b57cec5SDimitry Andric             *++to_nxt = static_cast<uint16_t>(
20510b57cec5SDimitry Andric                     0xDC00
20520b57cec5SDimitry Andric                   | ((c3 & 0x0F) << 6)
20530b57cec5SDimitry Andric                   |  (c4 & 0x3F));
20540b57cec5SDimitry Andric             frm_nxt += 4;
20550b57cec5SDimitry Andric         }
20560b57cec5SDimitry Andric         else
20570b57cec5SDimitry Andric         {
20580b57cec5SDimitry Andric             return codecvt_base::error;
20590b57cec5SDimitry Andric         }
20600b57cec5SDimitry Andric     }
20610b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
20620b57cec5SDimitry Andric }
20630b57cec5SDimitry Andric 
20640b57cec5SDimitry Andric static
20650b57cec5SDimitry Andric codecvt_base::result
20660b57cec5SDimitry Andric utf8_to_utf16(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
20670b57cec5SDimitry Andric               uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
20680b57cec5SDimitry Andric               unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
20690b57cec5SDimitry Andric {
20700b57cec5SDimitry Andric     frm_nxt = frm;
20710b57cec5SDimitry Andric     to_nxt = to;
20720b57cec5SDimitry Andric     if (mode & consume_header)
20730b57cec5SDimitry Andric     {
20740b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
20750b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
20760b57cec5SDimitry Andric             frm_nxt += 3;
20770b57cec5SDimitry Andric     }
20780b57cec5SDimitry Andric     for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
20790b57cec5SDimitry Andric     {
20800b57cec5SDimitry Andric         uint8_t c1 = *frm_nxt;
20810b57cec5SDimitry Andric         if (c1 > Maxcode)
20820b57cec5SDimitry Andric             return codecvt_base::error;
20830b57cec5SDimitry Andric         if (c1 < 0x80)
20840b57cec5SDimitry Andric         {
20850b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(c1);
20860b57cec5SDimitry Andric             ++frm_nxt;
20870b57cec5SDimitry Andric         }
20880b57cec5SDimitry Andric         else if (c1 < 0xC2)
20890b57cec5SDimitry Andric         {
20900b57cec5SDimitry Andric             return codecvt_base::error;
20910b57cec5SDimitry Andric         }
20920b57cec5SDimitry Andric         else if (c1 < 0xE0)
20930b57cec5SDimitry Andric         {
20940b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
20950b57cec5SDimitry Andric                 return codecvt_base::partial;
20960b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
20970b57cec5SDimitry Andric             if ((c2 & 0xC0) != 0x80)
20980b57cec5SDimitry Andric                 return codecvt_base::error;
20990b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
21000b57cec5SDimitry Andric             if (t > Maxcode)
21010b57cec5SDimitry Andric                 return codecvt_base::error;
21020b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(t);
21030b57cec5SDimitry Andric             frm_nxt += 2;
21040b57cec5SDimitry Andric         }
21050b57cec5SDimitry Andric         else if (c1 < 0xF0)
21060b57cec5SDimitry Andric         {
2107*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 2)
21080b57cec5SDimitry Andric                 return codecvt_base::partial;
21090b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
21100b57cec5SDimitry Andric             switch (c1)
21110b57cec5SDimitry Andric             {
21120b57cec5SDimitry Andric             case 0xE0:
21130b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
21140b57cec5SDimitry Andric                     return codecvt_base::error;
21150b57cec5SDimitry Andric                  break;
21160b57cec5SDimitry Andric             case 0xED:
21170b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
21180b57cec5SDimitry Andric                     return codecvt_base::error;
21190b57cec5SDimitry Andric                  break;
21200b57cec5SDimitry Andric             default:
21210b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
21220b57cec5SDimitry Andric                     return codecvt_base::error;
21230b57cec5SDimitry Andric                  break;
21240b57cec5SDimitry Andric             }
2125*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 3)
2126*5f757f3fSDimitry Andric                  return codecvt_base::partial;
2127*5f757f3fSDimitry Andric             uint8_t c3 = frm_nxt[2];
21280b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
21290b57cec5SDimitry Andric                 return codecvt_base::error;
21300b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
21310b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 6)
21320b57cec5SDimitry Andric                                              |  (c3 & 0x3F));
21330b57cec5SDimitry Andric             if (t > Maxcode)
21340b57cec5SDimitry Andric                 return codecvt_base::error;
21350b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(t);
21360b57cec5SDimitry Andric             frm_nxt += 3;
21370b57cec5SDimitry Andric         }
21380b57cec5SDimitry Andric         else if (c1 < 0xF5)
21390b57cec5SDimitry Andric         {
2140*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 2)
21410b57cec5SDimitry Andric                 return codecvt_base::partial;
21420b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
21430b57cec5SDimitry Andric             switch (c1)
21440b57cec5SDimitry Andric             {
21450b57cec5SDimitry Andric             case 0xF0:
21460b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
21470b57cec5SDimitry Andric                     return codecvt_base::error;
21480b57cec5SDimitry Andric                  break;
21490b57cec5SDimitry Andric             case 0xF4:
21500b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
21510b57cec5SDimitry Andric                     return codecvt_base::error;
21520b57cec5SDimitry Andric                  break;
21530b57cec5SDimitry Andric             default:
21540b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
21550b57cec5SDimitry Andric                     return codecvt_base::error;
21560b57cec5SDimitry Andric                  break;
21570b57cec5SDimitry Andric             }
2158*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 3)
2159*5f757f3fSDimitry Andric                  return codecvt_base::partial;
2160*5f757f3fSDimitry Andric             uint8_t c3 = frm_nxt[2];
2161*5f757f3fSDimitry Andric             if ((c3 & 0xC0) != 0x80)
2162*5f757f3fSDimitry Andric                  return codecvt_base::error;
2163*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 4)
2164*5f757f3fSDimitry Andric                  return codecvt_base::partial;
2165*5f757f3fSDimitry Andric             uint8_t c4 = frm_nxt[3];
2166*5f757f3fSDimitry Andric             if ((c4 & 0xC0) != 0x80)
21670b57cec5SDimitry Andric                  return codecvt_base::error;
21680b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
21690b57cec5SDimitry Andric                 return codecvt_base::partial;
21700b57cec5SDimitry Andric             if ((((c1 & 7UL) << 18) +
21710b57cec5SDimitry Andric                 ((c2 & 0x3FUL) << 12) +
21720b57cec5SDimitry Andric                 ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
21730b57cec5SDimitry Andric                 return codecvt_base::error;
21740b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(
21750b57cec5SDimitry Andric                     0xD800
21760b57cec5SDimitry Andric                   | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6)
21770b57cec5SDimitry Andric                   | ((c2 & 0x0F) << 2)
21780b57cec5SDimitry Andric                   | ((c3 & 0x30) >> 4));
21790b57cec5SDimitry Andric             *++to_nxt = static_cast<uint32_t>(
21800b57cec5SDimitry Andric                     0xDC00
21810b57cec5SDimitry Andric                   | ((c3 & 0x0F) << 6)
21820b57cec5SDimitry Andric                   |  (c4 & 0x3F));
21830b57cec5SDimitry Andric             frm_nxt += 4;
21840b57cec5SDimitry Andric         }
21850b57cec5SDimitry Andric         else
21860b57cec5SDimitry Andric         {
21870b57cec5SDimitry Andric             return codecvt_base::error;
21880b57cec5SDimitry Andric         }
21890b57cec5SDimitry Andric     }
21900b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
21910b57cec5SDimitry Andric }
21920b57cec5SDimitry Andric 
21930b57cec5SDimitry Andric static
21940b57cec5SDimitry Andric int
21950b57cec5SDimitry Andric utf8_to_utf16_length(const uint8_t* frm, const uint8_t* frm_end,
21960b57cec5SDimitry Andric                      size_t mx, unsigned long Maxcode = 0x10FFFF,
21970b57cec5SDimitry Andric                      codecvt_mode mode = codecvt_mode(0))
21980b57cec5SDimitry Andric {
21990b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
22000b57cec5SDimitry Andric     if (mode & consume_header)
22010b57cec5SDimitry Andric     {
22020b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
22030b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
22040b57cec5SDimitry Andric             frm_nxt += 3;
22050b57cec5SDimitry Andric     }
22060b57cec5SDimitry Andric     for (size_t nchar16_t = 0; frm_nxt < frm_end && nchar16_t < mx; ++nchar16_t)
22070b57cec5SDimitry Andric     {
22080b57cec5SDimitry Andric         uint8_t c1 = *frm_nxt;
22090b57cec5SDimitry Andric         if (c1 > Maxcode)
22100b57cec5SDimitry Andric             break;
22110b57cec5SDimitry Andric         if (c1 < 0x80)
22120b57cec5SDimitry Andric         {
22130b57cec5SDimitry Andric             ++frm_nxt;
22140b57cec5SDimitry Andric         }
22150b57cec5SDimitry Andric         else if (c1 < 0xC2)
22160b57cec5SDimitry Andric         {
22170b57cec5SDimitry Andric             break;
22180b57cec5SDimitry Andric         }
22190b57cec5SDimitry Andric         else if (c1 < 0xE0)
22200b57cec5SDimitry Andric         {
22210b57cec5SDimitry Andric             if ((frm_end-frm_nxt < 2) || (frm_nxt[1] & 0xC0) != 0x80)
22220b57cec5SDimitry Andric                 break;
22230b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (frm_nxt[1] & 0x3F));
22240b57cec5SDimitry Andric             if (t > Maxcode)
22250b57cec5SDimitry Andric                 break;
22260b57cec5SDimitry Andric             frm_nxt += 2;
22270b57cec5SDimitry Andric         }
22280b57cec5SDimitry Andric         else if (c1 < 0xF0)
22290b57cec5SDimitry Andric         {
22300b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
22310b57cec5SDimitry Andric                 break;
22320b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
22330b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
22340b57cec5SDimitry Andric             switch (c1)
22350b57cec5SDimitry Andric             {
22360b57cec5SDimitry Andric             case 0xE0:
22370b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
22380b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
22390b57cec5SDimitry Andric                 break;
22400b57cec5SDimitry Andric             case 0xED:
22410b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
22420b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
22430b57cec5SDimitry Andric                  break;
22440b57cec5SDimitry Andric             default:
22450b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
22460b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
22470b57cec5SDimitry Andric                  break;
22480b57cec5SDimitry Andric             }
22490b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
22500b57cec5SDimitry Andric                 break;
22510b57cec5SDimitry Andric             if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
22520b57cec5SDimitry Andric                 break;
22530b57cec5SDimitry Andric             frm_nxt += 3;
22540b57cec5SDimitry Andric         }
22550b57cec5SDimitry Andric         else if (c1 < 0xF5)
22560b57cec5SDimitry Andric         {
22570b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4 || mx-nchar16_t < 2)
22580b57cec5SDimitry Andric                 break;
22590b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
22600b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
22610b57cec5SDimitry Andric             uint8_t c4 = frm_nxt[3];
22620b57cec5SDimitry Andric             switch (c1)
22630b57cec5SDimitry Andric             {
22640b57cec5SDimitry Andric             case 0xF0:
22650b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
22660b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
22670b57cec5SDimitry Andric                  break;
22680b57cec5SDimitry Andric             case 0xF4:
22690b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
22700b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
22710b57cec5SDimitry Andric                  break;
22720b57cec5SDimitry Andric             default:
22730b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
22740b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
22750b57cec5SDimitry Andric                  break;
22760b57cec5SDimitry Andric             }
22770b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
22780b57cec5SDimitry Andric                 break;
22790b57cec5SDimitry Andric             if ((((c1 & 7UL) << 18) +
22800b57cec5SDimitry Andric                 ((c2 & 0x3FUL) << 12) +
22810b57cec5SDimitry Andric                 ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
22820b57cec5SDimitry Andric                 break;
22830b57cec5SDimitry Andric             ++nchar16_t;
22840b57cec5SDimitry Andric             frm_nxt += 4;
22850b57cec5SDimitry Andric         }
22860b57cec5SDimitry Andric         else
22870b57cec5SDimitry Andric         {
22880b57cec5SDimitry Andric             break;
22890b57cec5SDimitry Andric         }
22900b57cec5SDimitry Andric     }
22910b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
22920b57cec5SDimitry Andric }
22930b57cec5SDimitry Andric 
22940b57cec5SDimitry Andric static
22950b57cec5SDimitry Andric codecvt_base::result
22960b57cec5SDimitry Andric ucs4_to_utf8(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
22970b57cec5SDimitry Andric              uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
22980b57cec5SDimitry Andric              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
22990b57cec5SDimitry Andric {
23000b57cec5SDimitry Andric     frm_nxt = frm;
23010b57cec5SDimitry Andric     to_nxt = to;
23020b57cec5SDimitry Andric     if (mode & generate_header)
23030b57cec5SDimitry Andric     {
23040b57cec5SDimitry Andric         if (to_end-to_nxt < 3)
23050b57cec5SDimitry Andric             return codecvt_base::partial;
23060b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xEF);
23070b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBB);
23080b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBF);
23090b57cec5SDimitry Andric     }
23100b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
23110b57cec5SDimitry Andric     {
23120b57cec5SDimitry Andric         uint32_t wc = *frm_nxt;
23130b57cec5SDimitry Andric         if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
23140b57cec5SDimitry Andric             return codecvt_base::error;
23150b57cec5SDimitry Andric         if (wc < 0x000080)
23160b57cec5SDimitry Andric         {
23170b57cec5SDimitry Andric             if (to_end-to_nxt < 1)
23180b57cec5SDimitry Andric                 return codecvt_base::partial;
23190b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc);
23200b57cec5SDimitry Andric         }
23210b57cec5SDimitry Andric         else if (wc < 0x000800)
23220b57cec5SDimitry Andric         {
23230b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
23240b57cec5SDimitry Andric                 return codecvt_base::partial;
23250b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc >> 6));
23260b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x03F));
23270b57cec5SDimitry Andric         }
23280b57cec5SDimitry Andric         else if (wc < 0x010000)
23290b57cec5SDimitry Andric         {
23300b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
23310b57cec5SDimitry Andric                 return codecvt_base::partial;
23320b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc >> 12));
23330b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6));
23340b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc & 0x003F));
23350b57cec5SDimitry Andric         }
23360b57cec5SDimitry Andric         else // if (wc < 0x110000)
23370b57cec5SDimitry Andric         {
23380b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
23390b57cec5SDimitry Andric                 return codecvt_base::partial;
23400b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xF0 |  (wc >> 18));
23410b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x03F000) >> 12));
23420b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x000FC0) >> 6));
23430b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc & 0x00003F));
23440b57cec5SDimitry Andric         }
23450b57cec5SDimitry Andric     }
23460b57cec5SDimitry Andric     return codecvt_base::ok;
23470b57cec5SDimitry Andric }
23480b57cec5SDimitry Andric 
23490b57cec5SDimitry Andric static
23500b57cec5SDimitry Andric codecvt_base::result
23510b57cec5SDimitry Andric utf8_to_ucs4(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
23520b57cec5SDimitry Andric              uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
23530b57cec5SDimitry Andric              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
23540b57cec5SDimitry Andric {
23550b57cec5SDimitry Andric     frm_nxt = frm;
23560b57cec5SDimitry Andric     to_nxt = to;
23570b57cec5SDimitry Andric     if (mode & consume_header)
23580b57cec5SDimitry Andric     {
23590b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
23600b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
23610b57cec5SDimitry Andric             frm_nxt += 3;
23620b57cec5SDimitry Andric     }
23630b57cec5SDimitry Andric     for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
23640b57cec5SDimitry Andric     {
23650b57cec5SDimitry Andric         uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
23660b57cec5SDimitry Andric         if (c1 < 0x80)
23670b57cec5SDimitry Andric         {
23680b57cec5SDimitry Andric             if (c1 > Maxcode)
23690b57cec5SDimitry Andric                 return codecvt_base::error;
23700b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(c1);
23710b57cec5SDimitry Andric             ++frm_nxt;
23720b57cec5SDimitry Andric         }
23730b57cec5SDimitry Andric         else if (c1 < 0xC2)
23740b57cec5SDimitry Andric         {
23750b57cec5SDimitry Andric             return codecvt_base::error;
23760b57cec5SDimitry Andric         }
23770b57cec5SDimitry Andric         else if (c1 < 0xE0)
23780b57cec5SDimitry Andric         {
23790b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
23800b57cec5SDimitry Andric                 return codecvt_base::partial;
23810b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
23820b57cec5SDimitry Andric             if ((c2 & 0xC0) != 0x80)
23830b57cec5SDimitry Andric                 return codecvt_base::error;
23840b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(((c1 & 0x1F) << 6)
23850b57cec5SDimitry Andric                                               | (c2 & 0x3F));
23860b57cec5SDimitry Andric             if (t > Maxcode)
23870b57cec5SDimitry Andric                 return codecvt_base::error;
23880b57cec5SDimitry Andric             *to_nxt = t;
23890b57cec5SDimitry Andric             frm_nxt += 2;
23900b57cec5SDimitry Andric         }
23910b57cec5SDimitry Andric         else if (c1 < 0xF0)
23920b57cec5SDimitry Andric         {
2393*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 2)
23940b57cec5SDimitry Andric                 return codecvt_base::partial;
23950b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
23960b57cec5SDimitry Andric             switch (c1)
23970b57cec5SDimitry Andric             {
23980b57cec5SDimitry Andric             case 0xE0:
23990b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
24000b57cec5SDimitry Andric                     return codecvt_base::error;
24010b57cec5SDimitry Andric                  break;
24020b57cec5SDimitry Andric             case 0xED:
24030b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
24040b57cec5SDimitry Andric                     return codecvt_base::error;
24050b57cec5SDimitry Andric                  break;
24060b57cec5SDimitry Andric             default:
24070b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
24080b57cec5SDimitry Andric                     return codecvt_base::error;
24090b57cec5SDimitry Andric                  break;
24100b57cec5SDimitry Andric             }
2411*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 3)
2412*5f757f3fSDimitry Andric                  return codecvt_base::partial;
2413*5f757f3fSDimitry Andric             uint8_t c3 = frm_nxt[2];
24140b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
24150b57cec5SDimitry Andric                 return codecvt_base::error;
24160b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(((c1 & 0x0F) << 12)
24170b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 6)
24180b57cec5SDimitry Andric                                              |  (c3 & 0x3F));
24190b57cec5SDimitry Andric             if (t > Maxcode)
24200b57cec5SDimitry Andric                 return codecvt_base::error;
24210b57cec5SDimitry Andric             *to_nxt = t;
24220b57cec5SDimitry Andric             frm_nxt += 3;
24230b57cec5SDimitry Andric         }
24240b57cec5SDimitry Andric         else if (c1 < 0xF5)
24250b57cec5SDimitry Andric         {
2426*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 2)
24270b57cec5SDimitry Andric                 return codecvt_base::partial;
24280b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
24290b57cec5SDimitry Andric             switch (c1)
24300b57cec5SDimitry Andric             {
24310b57cec5SDimitry Andric             case 0xF0:
24320b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
24330b57cec5SDimitry Andric                     return codecvt_base::error;
24340b57cec5SDimitry Andric                  break;
24350b57cec5SDimitry Andric             case 0xF4:
24360b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
24370b57cec5SDimitry Andric                     return codecvt_base::error;
24380b57cec5SDimitry Andric                  break;
24390b57cec5SDimitry Andric             default:
24400b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
24410b57cec5SDimitry Andric                     return codecvt_base::error;
24420b57cec5SDimitry Andric                  break;
24430b57cec5SDimitry Andric             }
2444*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 3)
2445*5f757f3fSDimitry Andric                  return codecvt_base::partial;
2446*5f757f3fSDimitry Andric             uint8_t c3 = frm_nxt[2];
2447*5f757f3fSDimitry Andric             if ((c3 & 0xC0) != 0x80)
2448*5f757f3fSDimitry Andric                  return codecvt_base::error;
2449*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 4)
2450*5f757f3fSDimitry Andric                  return codecvt_base::partial;
2451*5f757f3fSDimitry Andric             uint8_t c4 = frm_nxt[3];
2452*5f757f3fSDimitry Andric             if ((c4 & 0xC0) != 0x80)
24530b57cec5SDimitry Andric                  return codecvt_base::error;
24540b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(((c1 & 0x07) << 18)
24550b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 12)
24560b57cec5SDimitry Andric                                              | ((c3 & 0x3F) << 6)
24570b57cec5SDimitry Andric                                              |  (c4 & 0x3F));
24580b57cec5SDimitry Andric             if (t > Maxcode)
24590b57cec5SDimitry Andric                 return codecvt_base::error;
24600b57cec5SDimitry Andric             *to_nxt = t;
24610b57cec5SDimitry Andric             frm_nxt += 4;
24620b57cec5SDimitry Andric         }
24630b57cec5SDimitry Andric         else
24640b57cec5SDimitry Andric         {
24650b57cec5SDimitry Andric             return codecvt_base::error;
24660b57cec5SDimitry Andric         }
24670b57cec5SDimitry Andric     }
24680b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
24690b57cec5SDimitry Andric }
24700b57cec5SDimitry Andric 
24710b57cec5SDimitry Andric static
24720b57cec5SDimitry Andric int
24730b57cec5SDimitry Andric utf8_to_ucs4_length(const uint8_t* frm, const uint8_t* frm_end,
24740b57cec5SDimitry Andric                     size_t mx, unsigned long Maxcode = 0x10FFFF,
24750b57cec5SDimitry Andric                     codecvt_mode mode = codecvt_mode(0))
24760b57cec5SDimitry Andric {
24770b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
24780b57cec5SDimitry Andric     if (mode & consume_header)
24790b57cec5SDimitry Andric     {
24800b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
24810b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
24820b57cec5SDimitry Andric             frm_nxt += 3;
24830b57cec5SDimitry Andric     }
24840b57cec5SDimitry Andric     for (size_t nchar32_t = 0; frm_nxt < frm_end && nchar32_t < mx; ++nchar32_t)
24850b57cec5SDimitry Andric     {
24860b57cec5SDimitry Andric         uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
24870b57cec5SDimitry Andric         if (c1 < 0x80)
24880b57cec5SDimitry Andric         {
24890b57cec5SDimitry Andric             if (c1 > Maxcode)
24900b57cec5SDimitry Andric                 break;
24910b57cec5SDimitry Andric             ++frm_nxt;
24920b57cec5SDimitry Andric         }
24930b57cec5SDimitry Andric         else if (c1 < 0xC2)
24940b57cec5SDimitry Andric         {
24950b57cec5SDimitry Andric             break;
24960b57cec5SDimitry Andric         }
24970b57cec5SDimitry Andric         else if (c1 < 0xE0)
24980b57cec5SDimitry Andric         {
24990b57cec5SDimitry Andric             if ((frm_end-frm_nxt < 2) || ((frm_nxt[1] & 0xC0) != 0x80))
25000b57cec5SDimitry Andric                 break;
25010b57cec5SDimitry Andric             if ((((c1 & 0x1Fu) << 6) | (frm_nxt[1] & 0x3Fu)) > Maxcode)
25020b57cec5SDimitry Andric                 break;
25030b57cec5SDimitry Andric             frm_nxt += 2;
25040b57cec5SDimitry Andric         }
25050b57cec5SDimitry Andric         else if (c1 < 0xF0)
25060b57cec5SDimitry Andric         {
25070b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
25080b57cec5SDimitry Andric                 break;
25090b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
25100b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
25110b57cec5SDimitry Andric             switch (c1)
25120b57cec5SDimitry Andric             {
25130b57cec5SDimitry Andric             case 0xE0:
25140b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
25150b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25160b57cec5SDimitry Andric                 break;
25170b57cec5SDimitry Andric             case 0xED:
25180b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
25190b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25200b57cec5SDimitry Andric                  break;
25210b57cec5SDimitry Andric             default:
25220b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
25230b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25240b57cec5SDimitry Andric                  break;
25250b57cec5SDimitry Andric             }
25260b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
25270b57cec5SDimitry Andric                 break;
25280b57cec5SDimitry Andric             if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
25290b57cec5SDimitry Andric                 break;
25300b57cec5SDimitry Andric             frm_nxt += 3;
25310b57cec5SDimitry Andric         }
25320b57cec5SDimitry Andric         else if (c1 < 0xF5)
25330b57cec5SDimitry Andric         {
25340b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
25350b57cec5SDimitry Andric                 break;
25360b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
25370b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
25380b57cec5SDimitry Andric             uint8_t c4 = frm_nxt[3];
25390b57cec5SDimitry Andric             switch (c1)
25400b57cec5SDimitry Andric             {
25410b57cec5SDimitry Andric             case 0xF0:
25420b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
25430b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25440b57cec5SDimitry Andric                  break;
25450b57cec5SDimitry Andric             case 0xF4:
25460b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
25470b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25480b57cec5SDimitry Andric                  break;
25490b57cec5SDimitry Andric             default:
25500b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
25510b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25520b57cec5SDimitry Andric                  break;
25530b57cec5SDimitry Andric             }
25540b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
25550b57cec5SDimitry Andric                 break;
25560b57cec5SDimitry Andric             if ((((c1 & 0x07u) << 18) | ((c2 & 0x3Fu) << 12) |
25570b57cec5SDimitry Andric                  ((c3 & 0x3Fu) << 6)  |  (c4 & 0x3Fu)) > Maxcode)
25580b57cec5SDimitry Andric                 break;
25590b57cec5SDimitry Andric             frm_nxt += 4;
25600b57cec5SDimitry Andric         }
25610b57cec5SDimitry Andric         else
25620b57cec5SDimitry Andric         {
25630b57cec5SDimitry Andric             break;
25640b57cec5SDimitry Andric         }
25650b57cec5SDimitry Andric     }
25660b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
25670b57cec5SDimitry Andric }
25680b57cec5SDimitry Andric 
25690b57cec5SDimitry Andric static
25700b57cec5SDimitry Andric codecvt_base::result
25710b57cec5SDimitry Andric ucs2_to_utf8(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
25720b57cec5SDimitry Andric              uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
25730b57cec5SDimitry Andric              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
25740b57cec5SDimitry Andric {
25750b57cec5SDimitry Andric     frm_nxt = frm;
25760b57cec5SDimitry Andric     to_nxt = to;
25770b57cec5SDimitry Andric     if (mode & generate_header)
25780b57cec5SDimitry Andric     {
25790b57cec5SDimitry Andric         if (to_end-to_nxt < 3)
25800b57cec5SDimitry Andric             return codecvt_base::partial;
25810b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xEF);
25820b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBB);
25830b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBF);
25840b57cec5SDimitry Andric     }
25850b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
25860b57cec5SDimitry Andric     {
25870b57cec5SDimitry Andric         uint16_t wc = *frm_nxt;
25880b57cec5SDimitry Andric         if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
25890b57cec5SDimitry Andric             return codecvt_base::error;
25900b57cec5SDimitry Andric         if (wc < 0x0080)
25910b57cec5SDimitry Andric         {
25920b57cec5SDimitry Andric             if (to_end-to_nxt < 1)
25930b57cec5SDimitry Andric                 return codecvt_base::partial;
25940b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc);
25950b57cec5SDimitry Andric         }
25960b57cec5SDimitry Andric         else if (wc < 0x0800)
25970b57cec5SDimitry Andric         {
25980b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
25990b57cec5SDimitry Andric                 return codecvt_base::partial;
26000b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc >> 6));
26010b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x03F));
26020b57cec5SDimitry Andric         }
26030b57cec5SDimitry Andric         else // if (wc <= 0xFFFF)
26040b57cec5SDimitry Andric         {
26050b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
26060b57cec5SDimitry Andric                 return codecvt_base::partial;
26070b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc >> 12));
26080b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6));
26090b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc & 0x003F));
26100b57cec5SDimitry Andric         }
26110b57cec5SDimitry Andric     }
26120b57cec5SDimitry Andric     return codecvt_base::ok;
26130b57cec5SDimitry Andric }
26140b57cec5SDimitry Andric 
26150b57cec5SDimitry Andric static
26160b57cec5SDimitry Andric codecvt_base::result
26170b57cec5SDimitry Andric utf8_to_ucs2(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
26180b57cec5SDimitry Andric              uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
26190b57cec5SDimitry Andric              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
26200b57cec5SDimitry Andric {
26210b57cec5SDimitry Andric     frm_nxt = frm;
26220b57cec5SDimitry Andric     to_nxt = to;
26230b57cec5SDimitry Andric     if (mode & consume_header)
26240b57cec5SDimitry Andric     {
26250b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
26260b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
26270b57cec5SDimitry Andric             frm_nxt += 3;
26280b57cec5SDimitry Andric     }
26290b57cec5SDimitry Andric     for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
26300b57cec5SDimitry Andric     {
26310b57cec5SDimitry Andric         uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
26320b57cec5SDimitry Andric         if (c1 < 0x80)
26330b57cec5SDimitry Andric         {
26340b57cec5SDimitry Andric             if (c1 > Maxcode)
26350b57cec5SDimitry Andric                 return codecvt_base::error;
26360b57cec5SDimitry Andric             *to_nxt = static_cast<uint16_t>(c1);
26370b57cec5SDimitry Andric             ++frm_nxt;
26380b57cec5SDimitry Andric         }
26390b57cec5SDimitry Andric         else if (c1 < 0xC2)
26400b57cec5SDimitry Andric         {
26410b57cec5SDimitry Andric             return codecvt_base::error;
26420b57cec5SDimitry Andric         }
26430b57cec5SDimitry Andric         else if (c1 < 0xE0)
26440b57cec5SDimitry Andric         {
26450b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
26460b57cec5SDimitry Andric                 return codecvt_base::partial;
26470b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
26480b57cec5SDimitry Andric             if ((c2 & 0xC0) != 0x80)
26490b57cec5SDimitry Andric                 return codecvt_base::error;
26500b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6)
26510b57cec5SDimitry Andric                                               | (c2 & 0x3F));
26520b57cec5SDimitry Andric             if (t > Maxcode)
26530b57cec5SDimitry Andric                 return codecvt_base::error;
26540b57cec5SDimitry Andric             *to_nxt = t;
26550b57cec5SDimitry Andric             frm_nxt += 2;
26560b57cec5SDimitry Andric         }
26570b57cec5SDimitry Andric         else if (c1 < 0xF0)
26580b57cec5SDimitry Andric         {
2659*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 2)
26600b57cec5SDimitry Andric                 return codecvt_base::partial;
26610b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
26620b57cec5SDimitry Andric             switch (c1)
26630b57cec5SDimitry Andric             {
26640b57cec5SDimitry Andric             case 0xE0:
26650b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
26660b57cec5SDimitry Andric                     return codecvt_base::error;
26670b57cec5SDimitry Andric                  break;
26680b57cec5SDimitry Andric             case 0xED:
26690b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
26700b57cec5SDimitry Andric                     return codecvt_base::error;
26710b57cec5SDimitry Andric                  break;
26720b57cec5SDimitry Andric             default:
26730b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
26740b57cec5SDimitry Andric                     return codecvt_base::error;
26750b57cec5SDimitry Andric                  break;
26760b57cec5SDimitry Andric             }
2677*5f757f3fSDimitry Andric             if (frm_end-frm_nxt < 3)
2678*5f757f3fSDimitry Andric                  return codecvt_base::partial;
2679*5f757f3fSDimitry Andric             uint8_t c3 = frm_nxt[2];
26800b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
26810b57cec5SDimitry Andric                 return codecvt_base::error;
26820b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
26830b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 6)
26840b57cec5SDimitry Andric                                              |  (c3 & 0x3F));
26850b57cec5SDimitry Andric             if (t > Maxcode)
26860b57cec5SDimitry Andric                 return codecvt_base::error;
26870b57cec5SDimitry Andric             *to_nxt = t;
26880b57cec5SDimitry Andric             frm_nxt += 3;
26890b57cec5SDimitry Andric         }
26900b57cec5SDimitry Andric         else
26910b57cec5SDimitry Andric         {
26920b57cec5SDimitry Andric             return codecvt_base::error;
26930b57cec5SDimitry Andric         }
26940b57cec5SDimitry Andric     }
26950b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
26960b57cec5SDimitry Andric }
26970b57cec5SDimitry Andric 
26980b57cec5SDimitry Andric static
26990b57cec5SDimitry Andric int
27000b57cec5SDimitry Andric utf8_to_ucs2_length(const uint8_t* frm, const uint8_t* frm_end,
27010b57cec5SDimitry Andric                     size_t mx, unsigned long Maxcode = 0x10FFFF,
27020b57cec5SDimitry Andric                     codecvt_mode mode = codecvt_mode(0))
27030b57cec5SDimitry Andric {
27040b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
27050b57cec5SDimitry Andric     if (mode & consume_header)
27060b57cec5SDimitry Andric     {
27070b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
27080b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
27090b57cec5SDimitry Andric             frm_nxt += 3;
27100b57cec5SDimitry Andric     }
27110b57cec5SDimitry Andric     for (size_t nchar32_t = 0; frm_nxt < frm_end && nchar32_t < mx; ++nchar32_t)
27120b57cec5SDimitry Andric     {
27130b57cec5SDimitry Andric         uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
27140b57cec5SDimitry Andric         if (c1 < 0x80)
27150b57cec5SDimitry Andric         {
27160b57cec5SDimitry Andric             if (c1 > Maxcode)
27170b57cec5SDimitry Andric                 break;
27180b57cec5SDimitry Andric             ++frm_nxt;
27190b57cec5SDimitry Andric         }
27200b57cec5SDimitry Andric         else if (c1 < 0xC2)
27210b57cec5SDimitry Andric         {
27220b57cec5SDimitry Andric             break;
27230b57cec5SDimitry Andric         }
27240b57cec5SDimitry Andric         else if (c1 < 0xE0)
27250b57cec5SDimitry Andric         {
27260b57cec5SDimitry Andric             if ((frm_end-frm_nxt < 2) || ((frm_nxt[1] & 0xC0) != 0x80))
27270b57cec5SDimitry Andric                 break;
27280b57cec5SDimitry Andric             if ((((c1 & 0x1Fu) << 6) | (frm_nxt[1] & 0x3Fu)) > Maxcode)
27290b57cec5SDimitry Andric                 break;
27300b57cec5SDimitry Andric             frm_nxt += 2;
27310b57cec5SDimitry Andric         }
27320b57cec5SDimitry Andric         else if (c1 < 0xF0)
27330b57cec5SDimitry Andric         {
27340b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
27350b57cec5SDimitry Andric                 break;
27360b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
27370b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
27380b57cec5SDimitry Andric             switch (c1)
27390b57cec5SDimitry Andric             {
27400b57cec5SDimitry Andric             case 0xE0:
27410b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
27420b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
27430b57cec5SDimitry Andric                 break;
27440b57cec5SDimitry Andric             case 0xED:
27450b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
27460b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
27470b57cec5SDimitry Andric                  break;
27480b57cec5SDimitry Andric             default:
27490b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
27500b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
27510b57cec5SDimitry Andric                  break;
27520b57cec5SDimitry Andric             }
27530b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
27540b57cec5SDimitry Andric                 break;
27550b57cec5SDimitry Andric             if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
27560b57cec5SDimitry Andric                 break;
27570b57cec5SDimitry Andric             frm_nxt += 3;
27580b57cec5SDimitry Andric         }
27590b57cec5SDimitry Andric         else
27600b57cec5SDimitry Andric         {
27610b57cec5SDimitry Andric             break;
27620b57cec5SDimitry Andric         }
27630b57cec5SDimitry Andric     }
27640b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
27650b57cec5SDimitry Andric }
27660b57cec5SDimitry Andric 
27670b57cec5SDimitry Andric static
27680b57cec5SDimitry Andric codecvt_base::result
27690b57cec5SDimitry Andric ucs4_to_utf16be(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
27700b57cec5SDimitry Andric                 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
27710b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
27720b57cec5SDimitry Andric {
27730b57cec5SDimitry Andric     frm_nxt = frm;
27740b57cec5SDimitry Andric     to_nxt = to;
27750b57cec5SDimitry Andric     if (mode & generate_header)
27760b57cec5SDimitry Andric     {
27770b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
27780b57cec5SDimitry Andric             return codecvt_base::partial;
27790b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFE);
27800b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFF);
27810b57cec5SDimitry Andric     }
27820b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
27830b57cec5SDimitry Andric     {
27840b57cec5SDimitry Andric         uint32_t wc = *frm_nxt;
27850b57cec5SDimitry Andric         if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
27860b57cec5SDimitry Andric             return codecvt_base::error;
27870b57cec5SDimitry Andric         if (wc < 0x010000)
27880b57cec5SDimitry Andric         {
27890b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
27900b57cec5SDimitry Andric                 return codecvt_base::partial;
27910b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc >> 8);
27920b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc);
27930b57cec5SDimitry Andric         }
27940b57cec5SDimitry Andric         else
27950b57cec5SDimitry Andric         {
27960b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
27970b57cec5SDimitry Andric                 return codecvt_base::partial;
27980b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(
27990b57cec5SDimitry Andric                     0xD800
28000b57cec5SDimitry Andric                   | ((((wc & 0x1F0000) >> 16) - 1) << 6)
28010b57cec5SDimitry Andric                   |   ((wc & 0x00FC00) >> 10));
28020b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t >> 8);
28030b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t);
28040b57cec5SDimitry Andric             t = static_cast<uint16_t>(0xDC00 | (wc & 0x03FF));
28050b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t >> 8);
28060b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t);
28070b57cec5SDimitry Andric         }
28080b57cec5SDimitry Andric     }
28090b57cec5SDimitry Andric     return codecvt_base::ok;
28100b57cec5SDimitry Andric }
28110b57cec5SDimitry Andric 
28120b57cec5SDimitry Andric static
28130b57cec5SDimitry Andric codecvt_base::result
28140b57cec5SDimitry Andric utf16be_to_ucs4(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
28150b57cec5SDimitry Andric                 uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
28160b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
28170b57cec5SDimitry Andric {
28180b57cec5SDimitry Andric     frm_nxt = frm;
28190b57cec5SDimitry Andric     to_nxt = to;
28200b57cec5SDimitry Andric     if (mode & consume_header)
28210b57cec5SDimitry Andric     {
28220b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
28230b57cec5SDimitry Andric             frm_nxt += 2;
28240b57cec5SDimitry Andric     }
28250b57cec5SDimitry Andric     for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
28260b57cec5SDimitry Andric     {
28270b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
28280b57cec5SDimitry Andric         if ((c1 & 0xFC00) == 0xDC00)
28290b57cec5SDimitry Andric             return codecvt_base::error;
28300b57cec5SDimitry Andric         if ((c1 & 0xFC00) != 0xD800)
28310b57cec5SDimitry Andric         {
28320b57cec5SDimitry Andric             if (c1 > Maxcode)
28330b57cec5SDimitry Andric                 return codecvt_base::error;
28340b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(c1);
28350b57cec5SDimitry Andric             frm_nxt += 2;
28360b57cec5SDimitry Andric         }
28370b57cec5SDimitry Andric         else
28380b57cec5SDimitry Andric         {
28390b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
28400b57cec5SDimitry Andric                 return codecvt_base::partial;
28410b57cec5SDimitry Andric             uint16_t c2 = static_cast<uint16_t>(frm_nxt[2] << 8 | frm_nxt[3]);
28420b57cec5SDimitry Andric             if ((c2 & 0xFC00) != 0xDC00)
28430b57cec5SDimitry Andric                 return codecvt_base::error;
28440b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(
28450b57cec5SDimitry Andric                     ((((c1 & 0x03C0) >> 6) + 1) << 16)
28460b57cec5SDimitry Andric                   |   ((c1 & 0x003F) << 10)
28470b57cec5SDimitry Andric                   |    (c2 & 0x03FF));
28480b57cec5SDimitry Andric             if (t > Maxcode)
28490b57cec5SDimitry Andric                 return codecvt_base::error;
28500b57cec5SDimitry Andric             *to_nxt = t;
28510b57cec5SDimitry Andric             frm_nxt += 4;
28520b57cec5SDimitry Andric         }
28530b57cec5SDimitry Andric     }
28540b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
28550b57cec5SDimitry Andric }
28560b57cec5SDimitry Andric 
28570b57cec5SDimitry Andric static
28580b57cec5SDimitry Andric int
28590b57cec5SDimitry Andric utf16be_to_ucs4_length(const uint8_t* frm, const uint8_t* frm_end,
28600b57cec5SDimitry Andric                        size_t mx, unsigned long Maxcode = 0x10FFFF,
28610b57cec5SDimitry Andric                        codecvt_mode mode = codecvt_mode(0))
28620b57cec5SDimitry Andric {
28630b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
28640b57cec5SDimitry Andric     if (mode & consume_header)
28650b57cec5SDimitry Andric     {
28660b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
28670b57cec5SDimitry Andric             frm_nxt += 2;
28680b57cec5SDimitry Andric     }
28690b57cec5SDimitry Andric     for (size_t nchar32_t = 0; frm_nxt < frm_end - 1 && nchar32_t < mx; ++nchar32_t)
28700b57cec5SDimitry Andric     {
28710b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
28720b57cec5SDimitry Andric         if ((c1 & 0xFC00) == 0xDC00)
28730b57cec5SDimitry Andric             break;
28740b57cec5SDimitry Andric         if ((c1 & 0xFC00) != 0xD800)
28750b57cec5SDimitry Andric         {
28760b57cec5SDimitry Andric             if (c1 > Maxcode)
28770b57cec5SDimitry Andric                 break;
28780b57cec5SDimitry Andric             frm_nxt += 2;
28790b57cec5SDimitry Andric         }
28800b57cec5SDimitry Andric         else
28810b57cec5SDimitry Andric         {
28820b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
28830b57cec5SDimitry Andric                 break;
28840b57cec5SDimitry Andric             uint16_t c2 = static_cast<uint16_t>(frm_nxt[2] << 8 | frm_nxt[3]);
28850b57cec5SDimitry Andric             if ((c2 & 0xFC00) != 0xDC00)
28860b57cec5SDimitry Andric                 break;
28870b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(
28880b57cec5SDimitry Andric                     ((((c1 & 0x03C0) >> 6) + 1) << 16)
28890b57cec5SDimitry Andric                   |   ((c1 & 0x003F) << 10)
28900b57cec5SDimitry Andric                   |    (c2 & 0x03FF));
28910b57cec5SDimitry Andric             if (t > Maxcode)
28920b57cec5SDimitry Andric                 break;
28930b57cec5SDimitry Andric             frm_nxt += 4;
28940b57cec5SDimitry Andric         }
28950b57cec5SDimitry Andric     }
28960b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
28970b57cec5SDimitry Andric }
28980b57cec5SDimitry Andric 
28990b57cec5SDimitry Andric static
29000b57cec5SDimitry Andric codecvt_base::result
29010b57cec5SDimitry Andric ucs4_to_utf16le(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
29020b57cec5SDimitry Andric                 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
29030b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
29040b57cec5SDimitry Andric {
29050b57cec5SDimitry Andric     frm_nxt = frm;
29060b57cec5SDimitry Andric     to_nxt = to;
29070b57cec5SDimitry Andric     if (mode & generate_header)
29080b57cec5SDimitry Andric     {
29090b57cec5SDimitry Andric         if (to_end - to_nxt < 2)
29100b57cec5SDimitry Andric             return codecvt_base::partial;
29110b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFF);
29120b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFE);
29130b57cec5SDimitry Andric     }
29140b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
29150b57cec5SDimitry Andric     {
29160b57cec5SDimitry Andric         uint32_t wc = *frm_nxt;
29170b57cec5SDimitry Andric         if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
29180b57cec5SDimitry Andric             return codecvt_base::error;
29190b57cec5SDimitry Andric         if (wc < 0x010000)
29200b57cec5SDimitry Andric         {
29210b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
29220b57cec5SDimitry Andric                 return codecvt_base::partial;
29230b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc);
29240b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc >> 8);
29250b57cec5SDimitry Andric         }
29260b57cec5SDimitry Andric         else
29270b57cec5SDimitry Andric         {
29280b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
29290b57cec5SDimitry Andric                 return codecvt_base::partial;
29300b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(
29310b57cec5SDimitry Andric                     0xD800
29320b57cec5SDimitry Andric                   | ((((wc & 0x1F0000) >> 16) - 1) << 6)
29330b57cec5SDimitry Andric                   |   ((wc & 0x00FC00) >> 10));
29340b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t);
29350b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t >> 8);
29360b57cec5SDimitry Andric             t = static_cast<uint16_t>(0xDC00 | (wc & 0x03FF));
29370b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t);
29380b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t >> 8);
29390b57cec5SDimitry Andric         }
29400b57cec5SDimitry Andric     }
29410b57cec5SDimitry Andric     return codecvt_base::ok;
29420b57cec5SDimitry Andric }
29430b57cec5SDimitry Andric 
29440b57cec5SDimitry Andric static
29450b57cec5SDimitry Andric codecvt_base::result
29460b57cec5SDimitry Andric utf16le_to_ucs4(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
29470b57cec5SDimitry Andric                 uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
29480b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
29490b57cec5SDimitry Andric {
29500b57cec5SDimitry Andric     frm_nxt = frm;
29510b57cec5SDimitry Andric     to_nxt = to;
29520b57cec5SDimitry Andric     if (mode & consume_header)
29530b57cec5SDimitry Andric     {
29540b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
29550b57cec5SDimitry Andric             frm_nxt += 2;
29560b57cec5SDimitry Andric     }
29570b57cec5SDimitry Andric     for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
29580b57cec5SDimitry Andric     {
29590b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
29600b57cec5SDimitry Andric         if ((c1 & 0xFC00) == 0xDC00)
29610b57cec5SDimitry Andric             return codecvt_base::error;
29620b57cec5SDimitry Andric         if ((c1 & 0xFC00) != 0xD800)
29630b57cec5SDimitry Andric         {
29640b57cec5SDimitry Andric             if (c1 > Maxcode)
29650b57cec5SDimitry Andric                 return codecvt_base::error;
29660b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(c1);
29670b57cec5SDimitry Andric             frm_nxt += 2;
29680b57cec5SDimitry Andric         }
29690b57cec5SDimitry Andric         else
29700b57cec5SDimitry Andric         {
29710b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
29720b57cec5SDimitry Andric                 return codecvt_base::partial;
29730b57cec5SDimitry Andric             uint16_t c2 = static_cast<uint16_t>(frm_nxt[3] << 8 | frm_nxt[2]);
29740b57cec5SDimitry Andric             if ((c2 & 0xFC00) != 0xDC00)
29750b57cec5SDimitry Andric                 return codecvt_base::error;
29760b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(
29770b57cec5SDimitry Andric                     ((((c1 & 0x03C0) >> 6) + 1) << 16)
29780b57cec5SDimitry Andric                   |   ((c1 & 0x003F) << 10)
29790b57cec5SDimitry Andric                   |    (c2 & 0x03FF));
29800b57cec5SDimitry Andric             if (t > Maxcode)
29810b57cec5SDimitry Andric                 return codecvt_base::error;
29820b57cec5SDimitry Andric             *to_nxt = t;
29830b57cec5SDimitry Andric             frm_nxt += 4;
29840b57cec5SDimitry Andric         }
29850b57cec5SDimitry Andric     }
29860b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
29870b57cec5SDimitry Andric }
29880b57cec5SDimitry Andric 
29890b57cec5SDimitry Andric static
29900b57cec5SDimitry Andric int
29910b57cec5SDimitry Andric utf16le_to_ucs4_length(const uint8_t* frm, const uint8_t* frm_end,
29920b57cec5SDimitry Andric                        size_t mx, unsigned long Maxcode = 0x10FFFF,
29930b57cec5SDimitry Andric                        codecvt_mode mode = codecvt_mode(0))
29940b57cec5SDimitry Andric {
29950b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
29960b57cec5SDimitry Andric     if (mode & consume_header)
29970b57cec5SDimitry Andric     {
29980b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
29990b57cec5SDimitry Andric             frm_nxt += 2;
30000b57cec5SDimitry Andric     }
30010b57cec5SDimitry Andric     for (size_t nchar32_t = 0; frm_nxt < frm_end - 1 && nchar32_t < mx; ++nchar32_t)
30020b57cec5SDimitry Andric     {
30030b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
30040b57cec5SDimitry Andric         if ((c1 & 0xFC00) == 0xDC00)
30050b57cec5SDimitry Andric             break;
30060b57cec5SDimitry Andric         if ((c1 & 0xFC00) != 0xD800)
30070b57cec5SDimitry Andric         {
30080b57cec5SDimitry Andric             if (c1 > Maxcode)
30090b57cec5SDimitry Andric                 break;
30100b57cec5SDimitry Andric             frm_nxt += 2;
30110b57cec5SDimitry Andric         }
30120b57cec5SDimitry Andric         else
30130b57cec5SDimitry Andric         {
30140b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
30150b57cec5SDimitry Andric                 break;
30160b57cec5SDimitry Andric             uint16_t c2 = static_cast<uint16_t>(frm_nxt[3] << 8 | frm_nxt[2]);
30170b57cec5SDimitry Andric             if ((c2 & 0xFC00) != 0xDC00)
30180b57cec5SDimitry Andric                 break;
30190b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(
30200b57cec5SDimitry Andric                     ((((c1 & 0x03C0) >> 6) + 1) << 16)
30210b57cec5SDimitry Andric                   |   ((c1 & 0x003F) << 10)
30220b57cec5SDimitry Andric                   |    (c2 & 0x03FF));
30230b57cec5SDimitry Andric             if (t > Maxcode)
30240b57cec5SDimitry Andric                 break;
30250b57cec5SDimitry Andric             frm_nxt += 4;
30260b57cec5SDimitry Andric         }
30270b57cec5SDimitry Andric     }
30280b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
30290b57cec5SDimitry Andric }
30300b57cec5SDimitry Andric 
30310b57cec5SDimitry Andric static
30320b57cec5SDimitry Andric codecvt_base::result
30330b57cec5SDimitry Andric ucs2_to_utf16be(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
30340b57cec5SDimitry Andric                 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
30350b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
30360b57cec5SDimitry Andric {
30370b57cec5SDimitry Andric     frm_nxt = frm;
30380b57cec5SDimitry Andric     to_nxt = to;
30390b57cec5SDimitry Andric     if (mode & generate_header)
30400b57cec5SDimitry Andric     {
30410b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
30420b57cec5SDimitry Andric             return codecvt_base::partial;
30430b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFE);
30440b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFF);
30450b57cec5SDimitry Andric     }
30460b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
30470b57cec5SDimitry Andric     {
30480b57cec5SDimitry Andric         uint16_t wc = *frm_nxt;
30490b57cec5SDimitry Andric         if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
30500b57cec5SDimitry Andric             return codecvt_base::error;
30510b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
30520b57cec5SDimitry Andric             return codecvt_base::partial;
30530b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(wc >> 8);
30540b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(wc);
30550b57cec5SDimitry Andric     }
30560b57cec5SDimitry Andric     return codecvt_base::ok;
30570b57cec5SDimitry Andric }
30580b57cec5SDimitry Andric 
30590b57cec5SDimitry Andric static
30600b57cec5SDimitry Andric codecvt_base::result
30610b57cec5SDimitry Andric utf16be_to_ucs2(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
30620b57cec5SDimitry Andric                 uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
30630b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
30640b57cec5SDimitry Andric {
30650b57cec5SDimitry Andric     frm_nxt = frm;
30660b57cec5SDimitry Andric     to_nxt = to;
30670b57cec5SDimitry Andric     if (mode & consume_header)
30680b57cec5SDimitry Andric     {
30690b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
30700b57cec5SDimitry Andric             frm_nxt += 2;
30710b57cec5SDimitry Andric     }
30720b57cec5SDimitry Andric     for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
30730b57cec5SDimitry Andric     {
30740b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
30750b57cec5SDimitry Andric         if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
30760b57cec5SDimitry Andric             return codecvt_base::error;
30770b57cec5SDimitry Andric         *to_nxt = c1;
30780b57cec5SDimitry Andric         frm_nxt += 2;
30790b57cec5SDimitry Andric     }
30800b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
30810b57cec5SDimitry Andric }
30820b57cec5SDimitry Andric 
30830b57cec5SDimitry Andric static
30840b57cec5SDimitry Andric int
30850b57cec5SDimitry Andric utf16be_to_ucs2_length(const uint8_t* frm, const uint8_t* frm_end,
30860b57cec5SDimitry Andric                        size_t mx, unsigned long Maxcode = 0x10FFFF,
30870b57cec5SDimitry Andric                        codecvt_mode mode = codecvt_mode(0))
30880b57cec5SDimitry Andric {
30890b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
30900b57cec5SDimitry Andric     if (mode & consume_header)
30910b57cec5SDimitry Andric     {
30920b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
30930b57cec5SDimitry Andric             frm_nxt += 2;
30940b57cec5SDimitry Andric     }
30950b57cec5SDimitry Andric     for (size_t nchar16_t = 0; frm_nxt < frm_end - 1 && nchar16_t < mx; ++nchar16_t)
30960b57cec5SDimitry Andric     {
30970b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
30980b57cec5SDimitry Andric         if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
30990b57cec5SDimitry Andric             break;
31000b57cec5SDimitry Andric         frm_nxt += 2;
31010b57cec5SDimitry Andric     }
31020b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
31030b57cec5SDimitry Andric }
31040b57cec5SDimitry Andric 
31050b57cec5SDimitry Andric static
31060b57cec5SDimitry Andric codecvt_base::result
31070b57cec5SDimitry Andric ucs2_to_utf16le(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
31080b57cec5SDimitry Andric                 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
31090b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
31100b57cec5SDimitry Andric {
31110b57cec5SDimitry Andric     frm_nxt = frm;
31120b57cec5SDimitry Andric     to_nxt = to;
31130b57cec5SDimitry Andric     if (mode & generate_header)
31140b57cec5SDimitry Andric     {
31150b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
31160b57cec5SDimitry Andric             return codecvt_base::partial;
31170b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFF);
31180b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFE);
31190b57cec5SDimitry Andric     }
31200b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
31210b57cec5SDimitry Andric     {
31220b57cec5SDimitry Andric         uint16_t wc = *frm_nxt;
31230b57cec5SDimitry Andric         if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
31240b57cec5SDimitry Andric             return codecvt_base::error;
31250b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
31260b57cec5SDimitry Andric             return codecvt_base::partial;
31270b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(wc);
31280b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(wc >> 8);
31290b57cec5SDimitry Andric     }
31300b57cec5SDimitry Andric     return codecvt_base::ok;
31310b57cec5SDimitry Andric }
31320b57cec5SDimitry Andric 
31330b57cec5SDimitry Andric static
31340b57cec5SDimitry Andric codecvt_base::result
31350b57cec5SDimitry Andric utf16le_to_ucs2(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
31360b57cec5SDimitry Andric                 uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
31370b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
31380b57cec5SDimitry Andric {
31390b57cec5SDimitry Andric     frm_nxt = frm;
31400b57cec5SDimitry Andric     to_nxt = to;
31410b57cec5SDimitry Andric     if (mode & consume_header)
31420b57cec5SDimitry Andric     {
31430b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
31440b57cec5SDimitry Andric             frm_nxt += 2;
31450b57cec5SDimitry Andric     }
31460b57cec5SDimitry Andric     for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
31470b57cec5SDimitry Andric     {
31480b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
31490b57cec5SDimitry Andric         if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
31500b57cec5SDimitry Andric             return codecvt_base::error;
31510b57cec5SDimitry Andric         *to_nxt = c1;
31520b57cec5SDimitry Andric         frm_nxt += 2;
31530b57cec5SDimitry Andric     }
31540b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
31550b57cec5SDimitry Andric }
31560b57cec5SDimitry Andric 
31570b57cec5SDimitry Andric static
31580b57cec5SDimitry Andric int
31590b57cec5SDimitry Andric utf16le_to_ucs2_length(const uint8_t* frm, const uint8_t* frm_end,
31600b57cec5SDimitry Andric                        size_t mx, unsigned long Maxcode = 0x10FFFF,
31610b57cec5SDimitry Andric                        codecvt_mode mode = codecvt_mode(0))
31620b57cec5SDimitry Andric {
31630b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
31640b57cec5SDimitry Andric     frm_nxt = frm;
31650b57cec5SDimitry Andric     if (mode & consume_header)
31660b57cec5SDimitry Andric     {
31670b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
31680b57cec5SDimitry Andric             frm_nxt += 2;
31690b57cec5SDimitry Andric     }
31700b57cec5SDimitry Andric     for (size_t nchar16_t = 0; frm_nxt < frm_end - 1 && nchar16_t < mx; ++nchar16_t)
31710b57cec5SDimitry Andric     {
31720b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
31730b57cec5SDimitry Andric         if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
31740b57cec5SDimitry Andric             break;
31750b57cec5SDimitry Andric         frm_nxt += 2;
31760b57cec5SDimitry Andric     }
31770b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
31780b57cec5SDimitry Andric }
31790b57cec5SDimitry Andric 
318081ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
318181ad6265SDimitry Andric 
31820b57cec5SDimitry Andric // template <> class codecvt<char16_t, char, mbstate_t>
31830b57cec5SDimitry Andric 
3184*5f757f3fSDimitry Andric constinit locale::id codecvt<char16_t, char, mbstate_t>::id;
31850b57cec5SDimitry Andric 
31860b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::~codecvt()
31870b57cec5SDimitry Andric {
31880b57cec5SDimitry Andric }
31890b57cec5SDimitry Andric 
31900b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::result
31910b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_out(state_type&,
31920b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
31930b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
31940b57cec5SDimitry Andric {
31950b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
31960b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
31970b57cec5SDimitry Andric     const uint16_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;
32010b57cec5SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
32020b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
32030b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
32040b57cec5SDimitry Andric     return r;
32050b57cec5SDimitry Andric }
32060b57cec5SDimitry Andric 
32070b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::result
32080b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_in(state_type&,
32090b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
32100b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
32110b57cec5SDimitry Andric {
32120b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
32130b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
32140b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
32150b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
32160b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
32170b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
32180b57cec5SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
32190b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
32200b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
32210b57cec5SDimitry Andric     return r;
32220b57cec5SDimitry Andric }
32230b57cec5SDimitry Andric 
32240b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::result
32250b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_unshift(state_type&,
32260b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
32270b57cec5SDimitry Andric {
32280b57cec5SDimitry Andric     to_nxt = to;
32290b57cec5SDimitry Andric     return noconv;
32300b57cec5SDimitry Andric }
32310b57cec5SDimitry Andric 
32320b57cec5SDimitry Andric int
3233fe6060f1SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_encoding() const noexcept
32340b57cec5SDimitry Andric {
32350b57cec5SDimitry Andric     return 0;
32360b57cec5SDimitry Andric }
32370b57cec5SDimitry Andric 
32380b57cec5SDimitry Andric bool
3239fe6060f1SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_always_noconv() const noexcept
32400b57cec5SDimitry Andric {
32410b57cec5SDimitry Andric     return false;
32420b57cec5SDimitry Andric }
32430b57cec5SDimitry Andric 
32440b57cec5SDimitry Andric int
32450b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_length(state_type&,
32460b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
32470b57cec5SDimitry Andric {
32480b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
32490b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
32500b57cec5SDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx);
32510b57cec5SDimitry Andric }
32520b57cec5SDimitry Andric 
32530b57cec5SDimitry Andric int
3254fe6060f1SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_max_length() const noexcept
32550b57cec5SDimitry Andric {
32560b57cec5SDimitry Andric     return 4;
32570b57cec5SDimitry Andric }
32580b57cec5SDimitry Andric 
3259fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
3260e8d8bef9SDimitry Andric 
3261e8d8bef9SDimitry Andric // template <> class codecvt<char16_t, char8_t, mbstate_t>
3262e8d8bef9SDimitry Andric 
3263*5f757f3fSDimitry Andric constinit locale::id codecvt<char16_t, char8_t, mbstate_t>::id;
3264e8d8bef9SDimitry Andric 
3265e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::~codecvt()
3266e8d8bef9SDimitry Andric {
3267e8d8bef9SDimitry Andric }
3268e8d8bef9SDimitry Andric 
3269e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::result
3270e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_out(state_type&,
3271e8d8bef9SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3272e8d8bef9SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3273e8d8bef9SDimitry Andric {
3274e8d8bef9SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3275e8d8bef9SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3276e8d8bef9SDimitry Andric     const uint16_t* _frm_nxt = _frm;
3277e8d8bef9SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3278e8d8bef9SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3279e8d8bef9SDimitry Andric     uint8_t* _to_nxt = _to;
3280e8d8bef9SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3281e8d8bef9SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
3282e8d8bef9SDimitry Andric     to_nxt = to + (_to_nxt - _to);
3283e8d8bef9SDimitry Andric     return r;
3284e8d8bef9SDimitry Andric }
3285e8d8bef9SDimitry Andric 
3286e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::result
3287e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_in(state_type&,
3288e8d8bef9SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3289e8d8bef9SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3290e8d8bef9SDimitry Andric {
3291e8d8bef9SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3292e8d8bef9SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3293e8d8bef9SDimitry Andric     const uint8_t* _frm_nxt = _frm;
3294e8d8bef9SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3295e8d8bef9SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3296e8d8bef9SDimitry Andric     uint16_t* _to_nxt = _to;
3297e8d8bef9SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3298e8d8bef9SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
3299e8d8bef9SDimitry Andric     to_nxt = to + (_to_nxt - _to);
3300e8d8bef9SDimitry Andric     return r;
3301e8d8bef9SDimitry Andric }
3302e8d8bef9SDimitry Andric 
3303e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::result
3304e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_unshift(state_type&,
3305e8d8bef9SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
3306e8d8bef9SDimitry Andric {
3307e8d8bef9SDimitry Andric     to_nxt = to;
3308e8d8bef9SDimitry Andric     return noconv;
3309e8d8bef9SDimitry Andric }
3310e8d8bef9SDimitry Andric 
3311e8d8bef9SDimitry Andric int
3312fe6060f1SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_encoding() const noexcept
3313e8d8bef9SDimitry Andric {
3314e8d8bef9SDimitry Andric     return 0;
3315e8d8bef9SDimitry Andric }
3316e8d8bef9SDimitry Andric 
3317e8d8bef9SDimitry Andric bool
3318fe6060f1SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_always_noconv() const noexcept
3319e8d8bef9SDimitry Andric {
3320e8d8bef9SDimitry Andric     return false;
3321e8d8bef9SDimitry Andric }
3322e8d8bef9SDimitry Andric 
3323e8d8bef9SDimitry Andric int
3324e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_length(state_type&,
3325e8d8bef9SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
3326e8d8bef9SDimitry Andric {
3327e8d8bef9SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3328e8d8bef9SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3329e8d8bef9SDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx);
3330e8d8bef9SDimitry Andric }
3331e8d8bef9SDimitry Andric 
3332e8d8bef9SDimitry Andric int
3333fe6060f1SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_max_length() const noexcept
3334e8d8bef9SDimitry Andric {
3335e8d8bef9SDimitry Andric     return 4;
3336e8d8bef9SDimitry Andric }
3337e8d8bef9SDimitry Andric 
3338e8d8bef9SDimitry Andric #endif
3339e8d8bef9SDimitry Andric 
33400b57cec5SDimitry Andric // template <> class codecvt<char32_t, char, mbstate_t>
33410b57cec5SDimitry Andric 
3342*5f757f3fSDimitry Andric constinit locale::id codecvt<char32_t, char, mbstate_t>::id;
33430b57cec5SDimitry Andric 
33440b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::~codecvt()
33450b57cec5SDimitry Andric {
33460b57cec5SDimitry Andric }
33470b57cec5SDimitry Andric 
33480b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::result
33490b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_out(state_type&,
33500b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
33510b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
33520b57cec5SDimitry Andric {
33530b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
33540b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
33550b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
33560b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
33570b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
33580b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
33590b57cec5SDimitry Andric     result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
33600b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
33610b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
33620b57cec5SDimitry Andric     return r;
33630b57cec5SDimitry Andric }
33640b57cec5SDimitry Andric 
33650b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::result
33660b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_in(state_type&,
33670b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
33680b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
33690b57cec5SDimitry Andric {
33700b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
33710b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
33720b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
33730b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
33740b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
33750b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
33760b57cec5SDimitry Andric     result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
33770b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
33780b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
33790b57cec5SDimitry Andric     return r;
33800b57cec5SDimitry Andric }
33810b57cec5SDimitry Andric 
33820b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::result
33830b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_unshift(state_type&,
33840b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
33850b57cec5SDimitry Andric {
33860b57cec5SDimitry Andric     to_nxt = to;
33870b57cec5SDimitry Andric     return noconv;
33880b57cec5SDimitry Andric }
33890b57cec5SDimitry Andric 
33900b57cec5SDimitry Andric int
3391fe6060f1SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_encoding() const noexcept
33920b57cec5SDimitry Andric {
33930b57cec5SDimitry Andric     return 0;
33940b57cec5SDimitry Andric }
33950b57cec5SDimitry Andric 
33960b57cec5SDimitry Andric bool
3397fe6060f1SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_always_noconv() const noexcept
33980b57cec5SDimitry Andric {
33990b57cec5SDimitry Andric     return false;
34000b57cec5SDimitry Andric }
34010b57cec5SDimitry Andric 
34020b57cec5SDimitry Andric int
34030b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_length(state_type&,
34040b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
34050b57cec5SDimitry Andric {
34060b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
34070b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
34080b57cec5SDimitry Andric     return utf8_to_ucs4_length(_frm, _frm_end, mx);
34090b57cec5SDimitry Andric }
34100b57cec5SDimitry Andric 
34110b57cec5SDimitry Andric int
3412fe6060f1SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_max_length() const noexcept
34130b57cec5SDimitry Andric {
34140b57cec5SDimitry Andric     return 4;
34150b57cec5SDimitry Andric }
34160b57cec5SDimitry Andric 
3417fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
3418e8d8bef9SDimitry Andric 
3419e8d8bef9SDimitry Andric // template <> class codecvt<char32_t, char8_t, mbstate_t>
3420e8d8bef9SDimitry Andric 
3421*5f757f3fSDimitry Andric constinit locale::id codecvt<char32_t, char8_t, mbstate_t>::id;
3422e8d8bef9SDimitry Andric 
3423e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::~codecvt()
3424e8d8bef9SDimitry Andric {
3425e8d8bef9SDimitry Andric }
3426e8d8bef9SDimitry Andric 
3427e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::result
3428e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_out(state_type&,
3429e8d8bef9SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3430e8d8bef9SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3431e8d8bef9SDimitry Andric {
3432e8d8bef9SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
3433e8d8bef9SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
3434e8d8bef9SDimitry Andric     const uint32_t* _frm_nxt = _frm;
3435e8d8bef9SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3436e8d8bef9SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3437e8d8bef9SDimitry Andric     uint8_t* _to_nxt = _to;
3438e8d8bef9SDimitry Andric     result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3439e8d8bef9SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
3440e8d8bef9SDimitry Andric     to_nxt = to + (_to_nxt - _to);
3441e8d8bef9SDimitry Andric     return r;
3442e8d8bef9SDimitry Andric }
3443e8d8bef9SDimitry Andric 
3444e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::result
3445e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_in(state_type&,
3446e8d8bef9SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3447e8d8bef9SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3448e8d8bef9SDimitry Andric {
3449e8d8bef9SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3450e8d8bef9SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3451e8d8bef9SDimitry Andric     const uint8_t* _frm_nxt = _frm;
3452e8d8bef9SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
3453e8d8bef9SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
3454e8d8bef9SDimitry Andric     uint32_t* _to_nxt = _to;
3455e8d8bef9SDimitry Andric     result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3456e8d8bef9SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
3457e8d8bef9SDimitry Andric     to_nxt = to + (_to_nxt - _to);
3458e8d8bef9SDimitry Andric     return r;
3459e8d8bef9SDimitry Andric }
3460e8d8bef9SDimitry Andric 
3461e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::result
3462e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_unshift(state_type&,
3463e8d8bef9SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
3464e8d8bef9SDimitry Andric {
3465e8d8bef9SDimitry Andric     to_nxt = to;
3466e8d8bef9SDimitry Andric     return noconv;
3467e8d8bef9SDimitry Andric }
3468e8d8bef9SDimitry Andric 
3469e8d8bef9SDimitry Andric int
3470fe6060f1SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_encoding() const noexcept
3471e8d8bef9SDimitry Andric {
3472e8d8bef9SDimitry Andric     return 0;
3473e8d8bef9SDimitry Andric }
3474e8d8bef9SDimitry Andric 
3475e8d8bef9SDimitry Andric bool
3476fe6060f1SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_always_noconv() const noexcept
3477e8d8bef9SDimitry Andric {
3478e8d8bef9SDimitry Andric     return false;
3479e8d8bef9SDimitry Andric }
3480e8d8bef9SDimitry Andric 
3481e8d8bef9SDimitry Andric int
3482e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_length(state_type&,
3483e8d8bef9SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
3484e8d8bef9SDimitry Andric {
3485e8d8bef9SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3486e8d8bef9SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3487e8d8bef9SDimitry Andric     return utf8_to_ucs4_length(_frm, _frm_end, mx);
3488e8d8bef9SDimitry Andric }
3489e8d8bef9SDimitry Andric 
3490e8d8bef9SDimitry Andric int
3491fe6060f1SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_max_length() const noexcept
3492e8d8bef9SDimitry Andric {
3493e8d8bef9SDimitry Andric     return 4;
3494e8d8bef9SDimitry Andric }
3495e8d8bef9SDimitry Andric 
3496e8d8bef9SDimitry Andric #endif
3497e8d8bef9SDimitry Andric 
34980b57cec5SDimitry Andric // __codecvt_utf8<wchar_t>
34990b57cec5SDimitry Andric 
3500349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
35010b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::result
35020b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::do_out(state_type&,
35030b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
35040b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
35050b57cec5SDimitry Andric {
35060b57cec5SDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
35070b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
35080b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
35090b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
35100b57cec5SDimitry Andric #else
35110b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
35120b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
35130b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
35140b57cec5SDimitry Andric #endif
35150b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
35160b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
35170b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
35180b57cec5SDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
35190b57cec5SDimitry Andric     result r = ucs2_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3520bdd1243dSDimitry Andric                             __maxcode_, __mode_);
35210b57cec5SDimitry Andric #else
35220b57cec5SDimitry Andric     result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3523bdd1243dSDimitry Andric                             __maxcode_, __mode_);
35240b57cec5SDimitry Andric #endif
35250b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
35260b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
35270b57cec5SDimitry Andric     return r;
35280b57cec5SDimitry Andric }
35290b57cec5SDimitry Andric 
35300b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::result
35310b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::do_in(state_type&,
35320b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
35330b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
35340b57cec5SDimitry Andric {
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 #if defined(_LIBCPP_SHORT_WCHAR)
35390b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
35400b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
35410b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
35420b57cec5SDimitry Andric     result r = utf8_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3543bdd1243dSDimitry Andric                             __maxcode_, __mode_);
35440b57cec5SDimitry Andric #else
35450b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
35460b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
35470b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
35480b57cec5SDimitry Andric     result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3549bdd1243dSDimitry Andric                             __maxcode_, __mode_);
35500b57cec5SDimitry Andric #endif
35510b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
35520b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
35530b57cec5SDimitry Andric     return r;
35540b57cec5SDimitry Andric }
35550b57cec5SDimitry Andric 
35560b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::result
35570b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::do_unshift(state_type&,
35580b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
35590b57cec5SDimitry Andric {
35600b57cec5SDimitry Andric     to_nxt = to;
35610b57cec5SDimitry Andric     return noconv;
35620b57cec5SDimitry Andric }
35630b57cec5SDimitry Andric 
35640b57cec5SDimitry Andric int
3565fe6060f1SDimitry Andric __codecvt_utf8<wchar_t>::do_encoding() const noexcept
35660b57cec5SDimitry Andric {
35670b57cec5SDimitry Andric     return 0;
35680b57cec5SDimitry Andric }
35690b57cec5SDimitry Andric 
35700b57cec5SDimitry Andric bool
3571fe6060f1SDimitry Andric __codecvt_utf8<wchar_t>::do_always_noconv() const noexcept
35720b57cec5SDimitry Andric {
35730b57cec5SDimitry Andric     return false;
35740b57cec5SDimitry Andric }
35750b57cec5SDimitry Andric 
35760b57cec5SDimitry Andric int
35770b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::do_length(state_type&,
35780b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
35790b57cec5SDimitry Andric {
35800b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
35810b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3582349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3583bdd1243dSDimitry Andric     return utf8_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3584349cc55cSDimitry Andric #else
3585bdd1243dSDimitry Andric     return utf8_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3586349cc55cSDimitry Andric #endif
35870b57cec5SDimitry Andric }
35880b57cec5SDimitry Andric 
358981ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
35900b57cec5SDimitry Andric int
3591fe6060f1SDimitry Andric __codecvt_utf8<wchar_t>::do_max_length() const noexcept
35920b57cec5SDimitry Andric {
3593349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3594bdd1243dSDimitry Andric     if (__mode_ & consume_header)
3595349cc55cSDimitry Andric         return 6;
3596349cc55cSDimitry Andric     return 3;
3597349cc55cSDimitry Andric #else
3598bdd1243dSDimitry Andric     if (__mode_ & consume_header)
35990b57cec5SDimitry Andric         return 7;
36000b57cec5SDimitry Andric     return 4;
3601349cc55cSDimitry Andric #endif
36020b57cec5SDimitry Andric }
3603349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
36040b57cec5SDimitry Andric 
36050b57cec5SDimitry Andric // __codecvt_utf8<char16_t>
36060b57cec5SDimitry Andric 
36070b57cec5SDimitry Andric __codecvt_utf8<char16_t>::result
36080b57cec5SDimitry Andric __codecvt_utf8<char16_t>::do_out(state_type&,
36090b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
36100b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
36110b57cec5SDimitry Andric {
36120b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
36130b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
36140b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
36150b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
36160b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
36170b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
36180b57cec5SDimitry Andric     result r = ucs2_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3619bdd1243dSDimitry Andric                             __maxcode_, __mode_);
36200b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
36210b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
36220b57cec5SDimitry Andric     return r;
36230b57cec5SDimitry Andric }
36240b57cec5SDimitry Andric 
36250b57cec5SDimitry Andric __codecvt_utf8<char16_t>::result
36260b57cec5SDimitry Andric __codecvt_utf8<char16_t>::do_in(state_type&,
36270b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
36280b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
36290b57cec5SDimitry Andric {
36300b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
36310b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
36320b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
36330b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
36340b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
36350b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
36360b57cec5SDimitry Andric     result r = utf8_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3637bdd1243dSDimitry Andric                             __maxcode_, __mode_);
36380b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
36390b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
36400b57cec5SDimitry Andric     return r;
36410b57cec5SDimitry Andric }
36420b57cec5SDimitry Andric 
36430b57cec5SDimitry Andric __codecvt_utf8<char16_t>::result
36440b57cec5SDimitry Andric __codecvt_utf8<char16_t>::do_unshift(state_type&,
36450b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
36460b57cec5SDimitry Andric {
36470b57cec5SDimitry Andric     to_nxt = to;
36480b57cec5SDimitry Andric     return noconv;
36490b57cec5SDimitry Andric }
36500b57cec5SDimitry Andric 
36510b57cec5SDimitry Andric int
3652fe6060f1SDimitry Andric __codecvt_utf8<char16_t>::do_encoding() const noexcept
36530b57cec5SDimitry Andric {
36540b57cec5SDimitry Andric     return 0;
36550b57cec5SDimitry Andric }
36560b57cec5SDimitry Andric 
36570b57cec5SDimitry Andric bool
3658fe6060f1SDimitry Andric __codecvt_utf8<char16_t>::do_always_noconv() const noexcept
36590b57cec5SDimitry Andric {
36600b57cec5SDimitry Andric     return false;
36610b57cec5SDimitry Andric }
36620b57cec5SDimitry Andric 
36630b57cec5SDimitry Andric int
36640b57cec5SDimitry Andric __codecvt_utf8<char16_t>::do_length(state_type&,
36650b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
36660b57cec5SDimitry Andric {
36670b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
36680b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3669bdd1243dSDimitry Andric     return utf8_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
36700b57cec5SDimitry Andric }
36710b57cec5SDimitry Andric 
367281ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
36730b57cec5SDimitry Andric int
3674fe6060f1SDimitry Andric __codecvt_utf8<char16_t>::do_max_length() const noexcept
36750b57cec5SDimitry Andric {
3676bdd1243dSDimitry Andric     if (__mode_ & consume_header)
36770b57cec5SDimitry Andric         return 6;
36780b57cec5SDimitry Andric     return 3;
36790b57cec5SDimitry Andric }
368081ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
36810b57cec5SDimitry Andric 
36820b57cec5SDimitry Andric // __codecvt_utf8<char32_t>
36830b57cec5SDimitry Andric 
36840b57cec5SDimitry Andric __codecvt_utf8<char32_t>::result
36850b57cec5SDimitry Andric __codecvt_utf8<char32_t>::do_out(state_type&,
36860b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
36870b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
36880b57cec5SDimitry Andric {
36890b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
36900b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
36910b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
36920b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
36930b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
36940b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
36950b57cec5SDimitry Andric     result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3696bdd1243dSDimitry Andric                             __maxcode_, __mode_);
36970b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
36980b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
36990b57cec5SDimitry Andric     return r;
37000b57cec5SDimitry Andric }
37010b57cec5SDimitry Andric 
37020b57cec5SDimitry Andric __codecvt_utf8<char32_t>::result
37030b57cec5SDimitry Andric __codecvt_utf8<char32_t>::do_in(state_type&,
37040b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
37050b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
37060b57cec5SDimitry Andric {
37070b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
37080b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
37090b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
37100b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
37110b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
37120b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
37130b57cec5SDimitry Andric     result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3714bdd1243dSDimitry Andric                             __maxcode_, __mode_);
37150b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
37160b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
37170b57cec5SDimitry Andric     return r;
37180b57cec5SDimitry Andric }
37190b57cec5SDimitry Andric 
37200b57cec5SDimitry Andric __codecvt_utf8<char32_t>::result
37210b57cec5SDimitry Andric __codecvt_utf8<char32_t>::do_unshift(state_type&,
37220b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
37230b57cec5SDimitry Andric {
37240b57cec5SDimitry Andric     to_nxt = to;
37250b57cec5SDimitry Andric     return noconv;
37260b57cec5SDimitry Andric }
37270b57cec5SDimitry Andric 
37280b57cec5SDimitry Andric int
3729fe6060f1SDimitry Andric __codecvt_utf8<char32_t>::do_encoding() const noexcept
37300b57cec5SDimitry Andric {
37310b57cec5SDimitry Andric     return 0;
37320b57cec5SDimitry Andric }
37330b57cec5SDimitry Andric 
37340b57cec5SDimitry Andric bool
3735fe6060f1SDimitry Andric __codecvt_utf8<char32_t>::do_always_noconv() const noexcept
37360b57cec5SDimitry Andric {
37370b57cec5SDimitry Andric     return false;
37380b57cec5SDimitry Andric }
37390b57cec5SDimitry Andric 
37400b57cec5SDimitry Andric int
37410b57cec5SDimitry Andric __codecvt_utf8<char32_t>::do_length(state_type&,
37420b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
37430b57cec5SDimitry Andric {
37440b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
37450b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3746bdd1243dSDimitry Andric     return utf8_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
37470b57cec5SDimitry Andric }
37480b57cec5SDimitry Andric 
374981ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
37500b57cec5SDimitry Andric int
3751fe6060f1SDimitry Andric __codecvt_utf8<char32_t>::do_max_length() const noexcept
37520b57cec5SDimitry Andric {
3753bdd1243dSDimitry Andric     if (__mode_ & consume_header)
37540b57cec5SDimitry Andric         return 7;
37550b57cec5SDimitry Andric     return 4;
37560b57cec5SDimitry Andric }
375781ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
37580b57cec5SDimitry Andric 
37590b57cec5SDimitry Andric // __codecvt_utf16<wchar_t, false>
37600b57cec5SDimitry Andric 
3761349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
37620b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::result
37630b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::do_out(state_type&,
37640b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
37650b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
37660b57cec5SDimitry Andric {
3767349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3768349cc55cSDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3769349cc55cSDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3770349cc55cSDimitry Andric     const uint16_t* _frm_nxt = _frm;
3771349cc55cSDimitry Andric #else
37720b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
37730b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
37740b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
3775349cc55cSDimitry Andric #endif
37760b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
37770b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
37780b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
3779349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3780349cc55cSDimitry Andric     result r = ucs2_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3781bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3782349cc55cSDimitry Andric #else
37830b57cec5SDimitry Andric     result r = ucs4_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3784bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3785349cc55cSDimitry Andric #endif
37860b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
37870b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
37880b57cec5SDimitry Andric     return r;
37890b57cec5SDimitry Andric }
37900b57cec5SDimitry Andric 
37910b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::result
37920b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::do_in(state_type&,
37930b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
37940b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
37950b57cec5SDimitry Andric {
37960b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
37970b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
37980b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
3799349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3800349cc55cSDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3801349cc55cSDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3802349cc55cSDimitry Andric     uint16_t* _to_nxt = _to;
3803349cc55cSDimitry Andric     result r = utf16be_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3804bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3805349cc55cSDimitry Andric #else
38060b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
38070b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
38080b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
38090b57cec5SDimitry Andric     result r = utf16be_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3810bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3811349cc55cSDimitry Andric #endif
38120b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
38130b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
38140b57cec5SDimitry Andric     return r;
38150b57cec5SDimitry Andric }
38160b57cec5SDimitry Andric 
38170b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::result
38180b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::do_unshift(state_type&,
38190b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
38200b57cec5SDimitry Andric {
38210b57cec5SDimitry Andric     to_nxt = to;
38220b57cec5SDimitry Andric     return noconv;
38230b57cec5SDimitry Andric }
38240b57cec5SDimitry Andric 
38250b57cec5SDimitry Andric int
3826fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, false>::do_encoding() const noexcept
38270b57cec5SDimitry Andric {
38280b57cec5SDimitry Andric     return 0;
38290b57cec5SDimitry Andric }
38300b57cec5SDimitry Andric 
38310b57cec5SDimitry Andric bool
3832fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, false>::do_always_noconv() const noexcept
38330b57cec5SDimitry Andric {
38340b57cec5SDimitry Andric     return false;
38350b57cec5SDimitry Andric }
38360b57cec5SDimitry Andric 
38370b57cec5SDimitry Andric int
38380b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::do_length(state_type&,
38390b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
38400b57cec5SDimitry Andric {
38410b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
38420b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3843349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3844bdd1243dSDimitry Andric     return utf16be_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3845349cc55cSDimitry Andric #else
3846bdd1243dSDimitry Andric     return utf16be_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3847349cc55cSDimitry Andric #endif
38480b57cec5SDimitry Andric }
38490b57cec5SDimitry Andric 
38500b57cec5SDimitry Andric int
3851fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, false>::do_max_length() const noexcept
38520b57cec5SDimitry Andric {
3853349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3854bdd1243dSDimitry Andric     if (__mode_ & consume_header)
3855349cc55cSDimitry Andric         return 4;
3856349cc55cSDimitry Andric     return 2;
3857349cc55cSDimitry Andric #else
3858bdd1243dSDimitry Andric     if (__mode_ & consume_header)
38590b57cec5SDimitry Andric         return 6;
38600b57cec5SDimitry Andric     return 4;
3861349cc55cSDimitry Andric #endif
38620b57cec5SDimitry Andric }
38630b57cec5SDimitry Andric 
38640b57cec5SDimitry Andric // __codecvt_utf16<wchar_t, true>
38650b57cec5SDimitry Andric 
38660b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::result
38670b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::do_out(state_type&,
38680b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
38690b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
38700b57cec5SDimitry Andric {
3871349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3872349cc55cSDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3873349cc55cSDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3874349cc55cSDimitry Andric     const uint16_t* _frm_nxt = _frm;
3875349cc55cSDimitry Andric #else
38760b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
38770b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
38780b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
3879349cc55cSDimitry Andric #endif
38800b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
38810b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
38820b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
3883349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3884349cc55cSDimitry Andric     result r = ucs2_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3885bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3886349cc55cSDimitry Andric #else
38870b57cec5SDimitry Andric     result r = ucs4_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3888bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3889349cc55cSDimitry Andric #endif
38900b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
38910b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
38920b57cec5SDimitry Andric     return r;
38930b57cec5SDimitry Andric }
38940b57cec5SDimitry Andric 
38950b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::result
38960b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::do_in(state_type&,
38970b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
38980b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
38990b57cec5SDimitry Andric {
39000b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
39010b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
39020b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
3903349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3904349cc55cSDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3905349cc55cSDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3906349cc55cSDimitry Andric     uint16_t* _to_nxt = _to;
3907349cc55cSDimitry Andric     result r = utf16le_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3908bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3909349cc55cSDimitry Andric #else
39100b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
39110b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
39120b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
39130b57cec5SDimitry Andric     result r = utf16le_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3914bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3915349cc55cSDimitry Andric #endif
39160b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
39170b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
39180b57cec5SDimitry Andric     return r;
39190b57cec5SDimitry Andric }
39200b57cec5SDimitry Andric 
39210b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::result
39220b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::do_unshift(state_type&,
39230b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
39240b57cec5SDimitry Andric {
39250b57cec5SDimitry Andric     to_nxt = to;
39260b57cec5SDimitry Andric     return noconv;
39270b57cec5SDimitry Andric }
39280b57cec5SDimitry Andric 
39290b57cec5SDimitry Andric int
3930fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, true>::do_encoding() const noexcept
39310b57cec5SDimitry Andric {
39320b57cec5SDimitry Andric     return 0;
39330b57cec5SDimitry Andric }
39340b57cec5SDimitry Andric 
39350b57cec5SDimitry Andric bool
3936fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, true>::do_always_noconv() const noexcept
39370b57cec5SDimitry Andric {
39380b57cec5SDimitry Andric     return false;
39390b57cec5SDimitry Andric }
39400b57cec5SDimitry Andric 
39410b57cec5SDimitry Andric int
39420b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::do_length(state_type&,
39430b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
39440b57cec5SDimitry Andric {
39450b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
39460b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3947349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3948bdd1243dSDimitry Andric     return utf16le_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3949349cc55cSDimitry Andric #else
3950bdd1243dSDimitry Andric     return utf16le_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3951349cc55cSDimitry Andric #endif
39520b57cec5SDimitry Andric }
39530b57cec5SDimitry Andric 
39540b57cec5SDimitry Andric int
3955fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, true>::do_max_length() const noexcept
39560b57cec5SDimitry Andric {
3957349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3958bdd1243dSDimitry Andric     if (__mode_ & consume_header)
3959349cc55cSDimitry Andric         return 4;
3960349cc55cSDimitry Andric     return 2;
3961349cc55cSDimitry Andric #else
3962bdd1243dSDimitry Andric     if (__mode_ & consume_header)
39630b57cec5SDimitry Andric         return 6;
39640b57cec5SDimitry Andric     return 4;
3965349cc55cSDimitry Andric #endif
39660b57cec5SDimitry Andric }
3967349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
39680b57cec5SDimitry Andric 
39690b57cec5SDimitry Andric // __codecvt_utf16<char16_t, false>
39700b57cec5SDimitry Andric 
39710b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::result
39720b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::do_out(state_type&,
39730b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
39740b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
39750b57cec5SDimitry Andric {
39760b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
39770b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
39780b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
39790b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
39800b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
39810b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
39820b57cec5SDimitry Andric     result r = ucs2_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3983bdd1243dSDimitry Andric                                __maxcode_, __mode_);
39840b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
39850b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
39860b57cec5SDimitry Andric     return r;
39870b57cec5SDimitry Andric }
39880b57cec5SDimitry Andric 
39890b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::result
39900b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::do_in(state_type&,
39910b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
39920b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
39930b57cec5SDimitry Andric {
39940b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
39950b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
39960b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
39970b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
39980b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
39990b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
40000b57cec5SDimitry Andric     result r = utf16be_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4001bdd1243dSDimitry Andric                                __maxcode_, __mode_);
40020b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
40030b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
40040b57cec5SDimitry Andric     return r;
40050b57cec5SDimitry Andric }
40060b57cec5SDimitry Andric 
40070b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::result
40080b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::do_unshift(state_type&,
40090b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
40100b57cec5SDimitry Andric {
40110b57cec5SDimitry Andric     to_nxt = to;
40120b57cec5SDimitry Andric     return noconv;
40130b57cec5SDimitry Andric }
40140b57cec5SDimitry Andric 
40150b57cec5SDimitry Andric int
4016fe6060f1SDimitry Andric __codecvt_utf16<char16_t, false>::do_encoding() const noexcept
40170b57cec5SDimitry Andric {
40180b57cec5SDimitry Andric     return 0;
40190b57cec5SDimitry Andric }
40200b57cec5SDimitry Andric 
40210b57cec5SDimitry Andric bool
4022fe6060f1SDimitry Andric __codecvt_utf16<char16_t, false>::do_always_noconv() const noexcept
40230b57cec5SDimitry Andric {
40240b57cec5SDimitry Andric     return false;
40250b57cec5SDimitry Andric }
40260b57cec5SDimitry Andric 
40270b57cec5SDimitry Andric int
40280b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::do_length(state_type&,
40290b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
40300b57cec5SDimitry Andric {
40310b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
40320b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4033bdd1243dSDimitry Andric     return utf16be_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
40340b57cec5SDimitry Andric }
40350b57cec5SDimitry Andric 
403681ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
40370b57cec5SDimitry Andric int
4038fe6060f1SDimitry Andric __codecvt_utf16<char16_t, false>::do_max_length() const noexcept
40390b57cec5SDimitry Andric {
4040bdd1243dSDimitry Andric     if (__mode_ & consume_header)
40410b57cec5SDimitry Andric         return 4;
40420b57cec5SDimitry Andric     return 2;
40430b57cec5SDimitry Andric }
404481ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
40450b57cec5SDimitry Andric 
40460b57cec5SDimitry Andric // __codecvt_utf16<char16_t, true>
40470b57cec5SDimitry Andric 
40480b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::result
40490b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::do_out(state_type&,
40500b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
40510b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
40520b57cec5SDimitry Andric {
40530b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
40540b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
40550b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
40560b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
40570b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
40580b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
40590b57cec5SDimitry Andric     result r = ucs2_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4060bdd1243dSDimitry Andric                                __maxcode_, __mode_);
40610b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
40620b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
40630b57cec5SDimitry Andric     return r;
40640b57cec5SDimitry Andric }
40650b57cec5SDimitry Andric 
40660b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::result
40670b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::do_in(state_type&,
40680b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
40690b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
40700b57cec5SDimitry Andric {
40710b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
40720b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
40730b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
40740b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
40750b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
40760b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
40770b57cec5SDimitry Andric     result r = utf16le_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4078bdd1243dSDimitry Andric                                __maxcode_, __mode_);
40790b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
40800b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
40810b57cec5SDimitry Andric     return r;
40820b57cec5SDimitry Andric }
40830b57cec5SDimitry Andric 
40840b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::result
40850b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::do_unshift(state_type&,
40860b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
40870b57cec5SDimitry Andric {
40880b57cec5SDimitry Andric     to_nxt = to;
40890b57cec5SDimitry Andric     return noconv;
40900b57cec5SDimitry Andric }
40910b57cec5SDimitry Andric 
40920b57cec5SDimitry Andric int
4093fe6060f1SDimitry Andric __codecvt_utf16<char16_t, true>::do_encoding() const noexcept
40940b57cec5SDimitry Andric {
40950b57cec5SDimitry Andric     return 0;
40960b57cec5SDimitry Andric }
40970b57cec5SDimitry Andric 
40980b57cec5SDimitry Andric bool
4099fe6060f1SDimitry Andric __codecvt_utf16<char16_t, true>::do_always_noconv() const noexcept
41000b57cec5SDimitry Andric {
41010b57cec5SDimitry Andric     return false;
41020b57cec5SDimitry Andric }
41030b57cec5SDimitry Andric 
41040b57cec5SDimitry Andric int
41050b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::do_length(state_type&,
41060b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
41070b57cec5SDimitry Andric {
41080b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
41090b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4110bdd1243dSDimitry Andric     return utf16le_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
41110b57cec5SDimitry Andric }
41120b57cec5SDimitry Andric 
411381ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
41140b57cec5SDimitry Andric int
4115fe6060f1SDimitry Andric __codecvt_utf16<char16_t, true>::do_max_length() const noexcept
41160b57cec5SDimitry Andric {
4117bdd1243dSDimitry Andric     if (__mode_ & consume_header)
41180b57cec5SDimitry Andric         return 4;
41190b57cec5SDimitry Andric     return 2;
41200b57cec5SDimitry Andric }
412181ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
41220b57cec5SDimitry Andric 
41230b57cec5SDimitry Andric // __codecvt_utf16<char32_t, false>
41240b57cec5SDimitry Andric 
41250b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::result
41260b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::do_out(state_type&,
41270b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
41280b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
41290b57cec5SDimitry Andric {
41300b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
41310b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
41320b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
41330b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
41340b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
41350b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
41360b57cec5SDimitry Andric     result r = ucs4_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4137bdd1243dSDimitry Andric                                __maxcode_, __mode_);
41380b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
41390b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
41400b57cec5SDimitry Andric     return r;
41410b57cec5SDimitry Andric }
41420b57cec5SDimitry Andric 
41430b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::result
41440b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::do_in(state_type&,
41450b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
41460b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
41470b57cec5SDimitry Andric {
41480b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
41490b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
41500b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
41510b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
41520b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
41530b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
41540b57cec5SDimitry Andric     result r = utf16be_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4155bdd1243dSDimitry Andric                                __maxcode_, __mode_);
41560b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
41570b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
41580b57cec5SDimitry Andric     return r;
41590b57cec5SDimitry Andric }
41600b57cec5SDimitry Andric 
41610b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::result
41620b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::do_unshift(state_type&,
41630b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
41640b57cec5SDimitry Andric {
41650b57cec5SDimitry Andric     to_nxt = to;
41660b57cec5SDimitry Andric     return noconv;
41670b57cec5SDimitry Andric }
41680b57cec5SDimitry Andric 
41690b57cec5SDimitry Andric int
4170fe6060f1SDimitry Andric __codecvt_utf16<char32_t, false>::do_encoding() const noexcept
41710b57cec5SDimitry Andric {
41720b57cec5SDimitry Andric     return 0;
41730b57cec5SDimitry Andric }
41740b57cec5SDimitry Andric 
41750b57cec5SDimitry Andric bool
4176fe6060f1SDimitry Andric __codecvt_utf16<char32_t, false>::do_always_noconv() const noexcept
41770b57cec5SDimitry Andric {
41780b57cec5SDimitry Andric     return false;
41790b57cec5SDimitry Andric }
41800b57cec5SDimitry Andric 
41810b57cec5SDimitry Andric int
41820b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::do_length(state_type&,
41830b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
41840b57cec5SDimitry Andric {
41850b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
41860b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4187bdd1243dSDimitry Andric     return utf16be_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
41880b57cec5SDimitry Andric }
41890b57cec5SDimitry Andric 
419081ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
41910b57cec5SDimitry Andric int
4192fe6060f1SDimitry Andric __codecvt_utf16<char32_t, false>::do_max_length() const noexcept
41930b57cec5SDimitry Andric {
4194bdd1243dSDimitry Andric     if (__mode_ & consume_header)
41950b57cec5SDimitry Andric         return 6;
41960b57cec5SDimitry Andric     return 4;
41970b57cec5SDimitry Andric }
419881ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
41990b57cec5SDimitry Andric 
42000b57cec5SDimitry Andric // __codecvt_utf16<char32_t, true>
42010b57cec5SDimitry Andric 
42020b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::result
42030b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::do_out(state_type&,
42040b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
42050b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
42060b57cec5SDimitry Andric {
42070b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
42080b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
42090b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
42100b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
42110b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
42120b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
42130b57cec5SDimitry Andric     result r = ucs4_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4214bdd1243dSDimitry Andric                                __maxcode_, __mode_);
42150b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
42160b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
42170b57cec5SDimitry Andric     return r;
42180b57cec5SDimitry Andric }
42190b57cec5SDimitry Andric 
42200b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::result
42210b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::do_in(state_type&,
42220b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
42230b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
42240b57cec5SDimitry Andric {
42250b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
42260b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
42270b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
42280b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
42290b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
42300b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
42310b57cec5SDimitry Andric     result r = utf16le_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4232bdd1243dSDimitry Andric                                __maxcode_, __mode_);
42330b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
42340b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
42350b57cec5SDimitry Andric     return r;
42360b57cec5SDimitry Andric }
42370b57cec5SDimitry Andric 
42380b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::result
42390b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::do_unshift(state_type&,
42400b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
42410b57cec5SDimitry Andric {
42420b57cec5SDimitry Andric     to_nxt = to;
42430b57cec5SDimitry Andric     return noconv;
42440b57cec5SDimitry Andric }
42450b57cec5SDimitry Andric 
42460b57cec5SDimitry Andric int
4247fe6060f1SDimitry Andric __codecvt_utf16<char32_t, true>::do_encoding() const noexcept
42480b57cec5SDimitry Andric {
42490b57cec5SDimitry Andric     return 0;
42500b57cec5SDimitry Andric }
42510b57cec5SDimitry Andric 
42520b57cec5SDimitry Andric bool
4253fe6060f1SDimitry Andric __codecvt_utf16<char32_t, true>::do_always_noconv() const noexcept
42540b57cec5SDimitry Andric {
42550b57cec5SDimitry Andric     return false;
42560b57cec5SDimitry Andric }
42570b57cec5SDimitry Andric 
42580b57cec5SDimitry Andric int
42590b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::do_length(state_type&,
42600b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
42610b57cec5SDimitry Andric {
42620b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
42630b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4264bdd1243dSDimitry Andric     return utf16le_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
42650b57cec5SDimitry Andric }
42660b57cec5SDimitry Andric 
426781ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
42680b57cec5SDimitry Andric int
4269fe6060f1SDimitry Andric __codecvt_utf16<char32_t, true>::do_max_length() const noexcept
42700b57cec5SDimitry Andric {
4271bdd1243dSDimitry Andric     if (__mode_ & consume_header)
42720b57cec5SDimitry Andric         return 6;
42730b57cec5SDimitry Andric     return 4;
42740b57cec5SDimitry Andric }
427581ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
42760b57cec5SDimitry Andric 
42770b57cec5SDimitry Andric // __codecvt_utf8_utf16<wchar_t>
42780b57cec5SDimitry Andric 
4279349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
42800b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::result
42810b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_out(state_type&,
42820b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
42830b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
42840b57cec5SDimitry Andric {
4285349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
4286349cc55cSDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
4287349cc55cSDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
4288349cc55cSDimitry Andric     const uint16_t* _frm_nxt = _frm;
4289349cc55cSDimitry Andric #else
42900b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
42910b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
42920b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
4293349cc55cSDimitry Andric #endif
42940b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
42950b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
42960b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
42970b57cec5SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4298bdd1243dSDimitry Andric                              __maxcode_, __mode_);
42990b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
43000b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
43010b57cec5SDimitry Andric     return r;
43020b57cec5SDimitry Andric }
43030b57cec5SDimitry Andric 
43040b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::result
43050b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_in(state_type&,
43060b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
43070b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
43080b57cec5SDimitry Andric {
43090b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
43100b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
43110b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
4312349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
4313349cc55cSDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
4314349cc55cSDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
4315349cc55cSDimitry Andric     uint16_t* _to_nxt = _to;
4316349cc55cSDimitry Andric #else
43170b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
43180b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
43190b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
4320349cc55cSDimitry Andric #endif
43210b57cec5SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4322bdd1243dSDimitry Andric                              __maxcode_, __mode_);
43230b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
43240b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
43250b57cec5SDimitry Andric     return r;
43260b57cec5SDimitry Andric }
43270b57cec5SDimitry Andric 
43280b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::result
43290b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_unshift(state_type&,
43300b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
43310b57cec5SDimitry Andric {
43320b57cec5SDimitry Andric     to_nxt = to;
43330b57cec5SDimitry Andric     return noconv;
43340b57cec5SDimitry Andric }
43350b57cec5SDimitry Andric 
43360b57cec5SDimitry Andric int
4337fe6060f1SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_encoding() const noexcept
43380b57cec5SDimitry Andric {
43390b57cec5SDimitry Andric     return 0;
43400b57cec5SDimitry Andric }
43410b57cec5SDimitry Andric 
43420b57cec5SDimitry Andric bool
4343fe6060f1SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_always_noconv() const noexcept
43440b57cec5SDimitry Andric {
43450b57cec5SDimitry Andric     return false;
43460b57cec5SDimitry Andric }
43470b57cec5SDimitry Andric 
43480b57cec5SDimitry Andric int
43490b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_length(state_type&,
43500b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
43510b57cec5SDimitry Andric {
43520b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
43530b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4354bdd1243dSDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx, __maxcode_, __mode_);
43550b57cec5SDimitry Andric }
43560b57cec5SDimitry Andric 
43570b57cec5SDimitry Andric int
4358fe6060f1SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_max_length() const noexcept
43590b57cec5SDimitry Andric {
4360bdd1243dSDimitry Andric     if (__mode_ & consume_header)
43610b57cec5SDimitry Andric         return 7;
43620b57cec5SDimitry Andric     return 4;
43630b57cec5SDimitry Andric }
4364349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
43650b57cec5SDimitry Andric 
43660b57cec5SDimitry Andric // __codecvt_utf8_utf16<char16_t>
43670b57cec5SDimitry Andric 
43680b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::result
43690b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_out(state_type&,
43700b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
43710b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
43720b57cec5SDimitry Andric {
43730b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
43740b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
43750b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
43760b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
43770b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
43780b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
43790b57cec5SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4380bdd1243dSDimitry Andric                              __maxcode_, __mode_);
43810b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
43820b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
43830b57cec5SDimitry Andric     return r;
43840b57cec5SDimitry Andric }
43850b57cec5SDimitry Andric 
43860b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::result
43870b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_in(state_type&,
43880b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
43890b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
43900b57cec5SDimitry Andric {
43910b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
43920b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
43930b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
43940b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
43950b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
43960b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
43970b57cec5SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4398bdd1243dSDimitry Andric                              __maxcode_, __mode_);
43990b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
44000b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
44010b57cec5SDimitry Andric     return r;
44020b57cec5SDimitry Andric }
44030b57cec5SDimitry Andric 
44040b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::result
44050b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_unshift(state_type&,
44060b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
44070b57cec5SDimitry Andric {
44080b57cec5SDimitry Andric     to_nxt = to;
44090b57cec5SDimitry Andric     return noconv;
44100b57cec5SDimitry Andric }
44110b57cec5SDimitry Andric 
44120b57cec5SDimitry Andric int
4413fe6060f1SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_encoding() const noexcept
44140b57cec5SDimitry Andric {
44150b57cec5SDimitry Andric     return 0;
44160b57cec5SDimitry Andric }
44170b57cec5SDimitry Andric 
44180b57cec5SDimitry Andric bool
4419fe6060f1SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_always_noconv() const noexcept
44200b57cec5SDimitry Andric {
44210b57cec5SDimitry Andric     return false;
44220b57cec5SDimitry Andric }
44230b57cec5SDimitry Andric 
44240b57cec5SDimitry Andric int
44250b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_length(state_type&,
44260b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
44270b57cec5SDimitry Andric {
44280b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
44290b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4430bdd1243dSDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx, __maxcode_, __mode_);
44310b57cec5SDimitry Andric }
44320b57cec5SDimitry Andric 
443381ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
44340b57cec5SDimitry Andric int
4435fe6060f1SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_max_length() const noexcept
44360b57cec5SDimitry Andric {
4437bdd1243dSDimitry Andric     if (__mode_ & consume_header)
44380b57cec5SDimitry Andric         return 7;
44390b57cec5SDimitry Andric     return 4;
44400b57cec5SDimitry Andric }
444181ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
44420b57cec5SDimitry Andric 
44430b57cec5SDimitry Andric // __codecvt_utf8_utf16<char32_t>
44440b57cec5SDimitry Andric 
44450b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::result
44460b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_out(state_type&,
44470b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
44480b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
44490b57cec5SDimitry Andric {
44500b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
44510b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
44520b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
44530b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
44540b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
44550b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
44560b57cec5SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4457bdd1243dSDimitry Andric                              __maxcode_, __mode_);
44580b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
44590b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
44600b57cec5SDimitry Andric     return r;
44610b57cec5SDimitry Andric }
44620b57cec5SDimitry Andric 
44630b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::result
44640b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_in(state_type&,
44650b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
44660b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
44670b57cec5SDimitry Andric {
44680b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
44690b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
44700b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
44710b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
44720b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
44730b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
44740b57cec5SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4475bdd1243dSDimitry Andric                              __maxcode_, __mode_);
44760b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
44770b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
44780b57cec5SDimitry Andric     return r;
44790b57cec5SDimitry Andric }
44800b57cec5SDimitry Andric 
44810b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::result
44820b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_unshift(state_type&,
44830b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
44840b57cec5SDimitry Andric {
44850b57cec5SDimitry Andric     to_nxt = to;
44860b57cec5SDimitry Andric     return noconv;
44870b57cec5SDimitry Andric }
44880b57cec5SDimitry Andric 
44890b57cec5SDimitry Andric int
4490fe6060f1SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_encoding() const noexcept
44910b57cec5SDimitry Andric {
44920b57cec5SDimitry Andric     return 0;
44930b57cec5SDimitry Andric }
44940b57cec5SDimitry Andric 
44950b57cec5SDimitry Andric bool
4496fe6060f1SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_always_noconv() const noexcept
44970b57cec5SDimitry Andric {
44980b57cec5SDimitry Andric     return false;
44990b57cec5SDimitry Andric }
45000b57cec5SDimitry Andric 
45010b57cec5SDimitry Andric int
45020b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_length(state_type&,
45030b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
45040b57cec5SDimitry Andric {
45050b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
45060b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4507bdd1243dSDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx, __maxcode_, __mode_);
45080b57cec5SDimitry Andric }
45090b57cec5SDimitry Andric 
451081ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
45110b57cec5SDimitry Andric int
4512fe6060f1SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_max_length() const noexcept
45130b57cec5SDimitry Andric {
4514bdd1243dSDimitry Andric     if (__mode_ & consume_header)
45150b57cec5SDimitry Andric         return 7;
45160b57cec5SDimitry Andric     return 4;
45170b57cec5SDimitry Andric }
451881ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
45190b57cec5SDimitry Andric 
45200b57cec5SDimitry Andric // __narrow_to_utf8<16>
45210b57cec5SDimitry Andric 
45220b57cec5SDimitry Andric __narrow_to_utf8<16>::~__narrow_to_utf8()
45230b57cec5SDimitry Andric {
45240b57cec5SDimitry Andric }
45250b57cec5SDimitry Andric 
45260b57cec5SDimitry Andric // __narrow_to_utf8<32>
45270b57cec5SDimitry Andric 
45280b57cec5SDimitry Andric __narrow_to_utf8<32>::~__narrow_to_utf8()
45290b57cec5SDimitry Andric {
45300b57cec5SDimitry Andric }
45310b57cec5SDimitry Andric 
45320b57cec5SDimitry Andric // __widen_from_utf8<16>
45330b57cec5SDimitry Andric 
45340b57cec5SDimitry Andric __widen_from_utf8<16>::~__widen_from_utf8()
45350b57cec5SDimitry Andric {
45360b57cec5SDimitry Andric }
45370b57cec5SDimitry Andric 
45380b57cec5SDimitry Andric // __widen_from_utf8<32>
45390b57cec5SDimitry Andric 
45400b57cec5SDimitry Andric __widen_from_utf8<32>::~__widen_from_utf8()
45410b57cec5SDimitry Andric {
45420b57cec5SDimitry Andric }
45430b57cec5SDimitry Andric 
4544349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
45450b57cec5SDimitry Andric static bool checked_string_to_wchar_convert(wchar_t& dest,
45460b57cec5SDimitry Andric                                             const char* ptr,
45470b57cec5SDimitry Andric                                             locale_t loc) {
45480b57cec5SDimitry Andric   if (*ptr == '\0')
45490b57cec5SDimitry Andric     return false;
45500b57cec5SDimitry Andric   mbstate_t mb = {};
45510b57cec5SDimitry Andric   wchar_t out;
45520b57cec5SDimitry Andric   size_t ret = __libcpp_mbrtowc_l(&out, ptr, strlen(ptr), &mb, loc);
45530b57cec5SDimitry Andric   if (ret == static_cast<size_t>(-1) || ret == static_cast<size_t>(-2)) {
45540b57cec5SDimitry Andric     return false;
45550b57cec5SDimitry Andric   }
45560b57cec5SDimitry Andric   dest = out;
45570b57cec5SDimitry Andric   return true;
45580b57cec5SDimitry Andric }
4559349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
4560349cc55cSDimitry Andric 
4561349cc55cSDimitry Andric #ifdef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4562349cc55cSDimitry Andric static bool is_narrow_non_breaking_space(const char* ptr) {
4563349cc55cSDimitry Andric   // https://www.fileformat.info/info/unicode/char/202f/index.htm
4564349cc55cSDimitry Andric   return ptr[0] == '\xe2' && ptr[1] == '\x80' && ptr[2] == '\xaf';
4565349cc55cSDimitry Andric }
4566349cc55cSDimitry Andric 
4567349cc55cSDimitry Andric static bool is_non_breaking_space(const char* ptr) {
4568349cc55cSDimitry Andric   // https://www.fileformat.info/info/unicode/char/0a/index.htm
4569349cc55cSDimitry Andric   return ptr[0] == '\xc2' && ptr[1] == '\xa0';
4570349cc55cSDimitry Andric }
4571349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
45720b57cec5SDimitry Andric 
45730b57cec5SDimitry Andric static bool checked_string_to_char_convert(char& dest,
45740b57cec5SDimitry Andric                                            const char* ptr,
45750b57cec5SDimitry Andric                                            locale_t __loc) {
45760b57cec5SDimitry Andric   if (*ptr == '\0')
45770b57cec5SDimitry Andric     return false;
45780b57cec5SDimitry Andric   if (!ptr[1]) {
45790b57cec5SDimitry Andric     dest = *ptr;
45800b57cec5SDimitry Andric     return true;
45810b57cec5SDimitry Andric   }
4582349cc55cSDimitry Andric 
4583349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
45840b57cec5SDimitry Andric   // First convert the MBS into a wide char then attempt to narrow it using
45850b57cec5SDimitry Andric   // wctob_l.
45860b57cec5SDimitry Andric   wchar_t wout;
45870b57cec5SDimitry Andric   if (!checked_string_to_wchar_convert(wout, ptr, __loc))
45880b57cec5SDimitry Andric     return false;
45890b57cec5SDimitry Andric   int res;
45900b57cec5SDimitry Andric   if ((res = __libcpp_wctob_l(wout, __loc)) != char_traits<char>::eof()) {
45910b57cec5SDimitry Andric     dest = res;
45920b57cec5SDimitry Andric     return true;
45930b57cec5SDimitry Andric   }
4594349cc55cSDimitry Andric   // FIXME: Work around specific multibyte sequences that we can reasonably
45950b57cec5SDimitry Andric   // translate into a different single byte.
45960b57cec5SDimitry Andric   switch (wout) {
45970b57cec5SDimitry Andric   case L'\u202F': // narrow non-breaking space
45980b57cec5SDimitry Andric   case L'\u00A0': // non-breaking space
45990b57cec5SDimitry Andric     dest = ' ';
46000b57cec5SDimitry Andric     return true;
46010b57cec5SDimitry Andric   default:
46020b57cec5SDimitry Andric     return false;
46030b57cec5SDimitry Andric   }
4604349cc55cSDimitry Andric #else // _LIBCPP_HAS_NO_WIDE_CHARACTERS
4605349cc55cSDimitry Andric   // FIXME: Work around specific multibyte sequences that we can reasonably
4606349cc55cSDimitry Andric   // translate into a different single byte.
4607349cc55cSDimitry Andric   if (is_narrow_non_breaking_space(ptr) || is_non_breaking_space(ptr)) {
4608349cc55cSDimitry Andric     dest = ' ';
4609349cc55cSDimitry Andric     return true;
4610349cc55cSDimitry Andric   }
4611349cc55cSDimitry Andric 
4612349cc55cSDimitry Andric   return false;
4613349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
461481ad6265SDimitry Andric   __libcpp_unreachable();
46150b57cec5SDimitry Andric }
46160b57cec5SDimitry Andric 
46170b57cec5SDimitry Andric 
46180b57cec5SDimitry Andric // numpunct<char> && numpunct<wchar_t>
46190b57cec5SDimitry Andric 
4620*5f757f3fSDimitry Andric constinit locale::id numpunct<char>::id;
4621349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4622*5f757f3fSDimitry Andric constinit locale::id numpunct<wchar_t>::id;
4623349cc55cSDimitry Andric #endif
46240b57cec5SDimitry Andric 
46250b57cec5SDimitry Andric numpunct<char>::numpunct(size_t refs)
46260b57cec5SDimitry Andric     : locale::facet(refs),
46270b57cec5SDimitry Andric       __decimal_point_('.'),
46280b57cec5SDimitry Andric       __thousands_sep_(',')
46290b57cec5SDimitry Andric {
46300b57cec5SDimitry Andric }
46310b57cec5SDimitry Andric 
4632349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46330b57cec5SDimitry Andric numpunct<wchar_t>::numpunct(size_t refs)
46340b57cec5SDimitry Andric     : locale::facet(refs),
46350b57cec5SDimitry Andric       __decimal_point_(L'.'),
46360b57cec5SDimitry Andric       __thousands_sep_(L',')
46370b57cec5SDimitry Andric {
46380b57cec5SDimitry Andric }
4639349cc55cSDimitry Andric #endif
46400b57cec5SDimitry Andric 
46410b57cec5SDimitry Andric numpunct<char>::~numpunct()
46420b57cec5SDimitry Andric {
46430b57cec5SDimitry Andric }
46440b57cec5SDimitry Andric 
4645349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46460b57cec5SDimitry Andric numpunct<wchar_t>::~numpunct()
46470b57cec5SDimitry Andric {
46480b57cec5SDimitry Andric }
4649349cc55cSDimitry Andric #endif
46500b57cec5SDimitry Andric 
46510b57cec5SDimitry Andric  char   numpunct< char  >::do_decimal_point() const {return __decimal_point_;}
4652349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46530b57cec5SDimitry Andric wchar_t numpunct<wchar_t>::do_decimal_point() const {return __decimal_point_;}
4654349cc55cSDimitry Andric #endif
46550b57cec5SDimitry Andric 
46560b57cec5SDimitry Andric  char   numpunct< char  >::do_thousands_sep() const {return __thousands_sep_;}
4657349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46580b57cec5SDimitry Andric wchar_t numpunct<wchar_t>::do_thousands_sep() const {return __thousands_sep_;}
4659349cc55cSDimitry Andric #endif
46600b57cec5SDimitry Andric 
46610b57cec5SDimitry Andric string numpunct< char  >::do_grouping() const {return __grouping_;}
4662349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46630b57cec5SDimitry Andric string numpunct<wchar_t>::do_grouping() const {return __grouping_;}
4664349cc55cSDimitry Andric #endif
46650b57cec5SDimitry Andric 
46660b57cec5SDimitry Andric  string numpunct< char  >::do_truename() const {return "true";}
4667349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46680b57cec5SDimitry Andric wstring numpunct<wchar_t>::do_truename() const {return L"true";}
4669349cc55cSDimitry Andric #endif
46700b57cec5SDimitry Andric 
46710b57cec5SDimitry Andric  string numpunct< char  >::do_falsename() const {return "false";}
4672349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46730b57cec5SDimitry Andric wstring numpunct<wchar_t>::do_falsename() const {return L"false";}
4674349cc55cSDimitry Andric #endif
46750b57cec5SDimitry Andric 
46760b57cec5SDimitry Andric // numpunct_byname<char>
46770b57cec5SDimitry Andric 
46780b57cec5SDimitry Andric numpunct_byname<char>::numpunct_byname(const char* nm, size_t refs)
46790b57cec5SDimitry Andric     : numpunct<char>(refs)
46800b57cec5SDimitry Andric {
46810b57cec5SDimitry Andric     __init(nm);
46820b57cec5SDimitry Andric }
46830b57cec5SDimitry Andric 
46840b57cec5SDimitry Andric numpunct_byname<char>::numpunct_byname(const string& nm, size_t refs)
46850b57cec5SDimitry Andric     : numpunct<char>(refs)
46860b57cec5SDimitry Andric {
46870b57cec5SDimitry Andric     __init(nm.c_str());
46880b57cec5SDimitry Andric }
46890b57cec5SDimitry Andric 
46900b57cec5SDimitry Andric numpunct_byname<char>::~numpunct_byname()
46910b57cec5SDimitry Andric {
46920b57cec5SDimitry Andric }
46930b57cec5SDimitry Andric 
46940b57cec5SDimitry Andric void
46950b57cec5SDimitry Andric numpunct_byname<char>::__init(const char* nm)
46960b57cec5SDimitry Andric {
4697349cc55cSDimitry Andric     typedef numpunct<char> base;
46980b57cec5SDimitry Andric     if (strcmp(nm, "C") != 0)
46990b57cec5SDimitry Andric     {
47000b57cec5SDimitry Andric         __libcpp_unique_locale loc(nm);
47010b57cec5SDimitry Andric         if (!loc)
4702*5f757f3fSDimitry Andric             __throw_runtime_error(("numpunct_byname<char>::numpunct_byname"
4703*5f757f3fSDimitry Andric                                    " failed to construct for " + string(nm)).c_str());
47040b57cec5SDimitry Andric 
47050b57cec5SDimitry Andric         lconv* lc = __libcpp_localeconv_l(loc.get());
4706349cc55cSDimitry Andric         if (!checked_string_to_char_convert(__decimal_point_, lc->decimal_point,
4707349cc55cSDimitry Andric                                             loc.get()))
4708349cc55cSDimitry Andric             __decimal_point_ = base::do_decimal_point();
4709349cc55cSDimitry Andric         if (!checked_string_to_char_convert(__thousands_sep_, lc->thousands_sep,
4710349cc55cSDimitry Andric                                             loc.get()))
4711349cc55cSDimitry Andric             __thousands_sep_ = base::do_thousands_sep();
47120b57cec5SDimitry Andric         __grouping_ = lc->grouping;
47130b57cec5SDimitry Andric         // localization for truename and falsename is not available
47140b57cec5SDimitry Andric     }
47150b57cec5SDimitry Andric }
47160b57cec5SDimitry Andric 
47170b57cec5SDimitry Andric // numpunct_byname<wchar_t>
47180b57cec5SDimitry Andric 
4719349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
47200b57cec5SDimitry Andric numpunct_byname<wchar_t>::numpunct_byname(const char* nm, size_t refs)
47210b57cec5SDimitry Andric     : numpunct<wchar_t>(refs)
47220b57cec5SDimitry Andric {
47230b57cec5SDimitry Andric     __init(nm);
47240b57cec5SDimitry Andric }
47250b57cec5SDimitry Andric 
47260b57cec5SDimitry Andric numpunct_byname<wchar_t>::numpunct_byname(const string& nm, size_t refs)
47270b57cec5SDimitry Andric     : numpunct<wchar_t>(refs)
47280b57cec5SDimitry Andric {
47290b57cec5SDimitry Andric     __init(nm.c_str());
47300b57cec5SDimitry Andric }
47310b57cec5SDimitry Andric 
47320b57cec5SDimitry Andric numpunct_byname<wchar_t>::~numpunct_byname()
47330b57cec5SDimitry Andric {
47340b57cec5SDimitry Andric }
47350b57cec5SDimitry Andric 
47360b57cec5SDimitry Andric void
47370b57cec5SDimitry Andric numpunct_byname<wchar_t>::__init(const char* nm)
47380b57cec5SDimitry Andric {
47390b57cec5SDimitry Andric     if (strcmp(nm, "C") != 0)
47400b57cec5SDimitry Andric     {
47410b57cec5SDimitry Andric         __libcpp_unique_locale loc(nm);
47420b57cec5SDimitry Andric         if (!loc)
4743*5f757f3fSDimitry Andric             __throw_runtime_error(("numpunct_byname<wchar_t>::numpunct_byname"
4744*5f757f3fSDimitry Andric                                    " failed to construct for " + string(nm)).c_str());
47450b57cec5SDimitry Andric 
47460b57cec5SDimitry Andric         lconv* lc = __libcpp_localeconv_l(loc.get());
47470b57cec5SDimitry Andric         checked_string_to_wchar_convert(__decimal_point_, lc->decimal_point,
47480b57cec5SDimitry Andric                                         loc.get());
47490b57cec5SDimitry Andric         checked_string_to_wchar_convert(__thousands_sep_, lc->thousands_sep,
47500b57cec5SDimitry Andric                                         loc.get());
47510b57cec5SDimitry Andric         __grouping_ = lc->grouping;
47520b57cec5SDimitry Andric         // localization for truename and falsename is not available
47530b57cec5SDimitry Andric     }
47540b57cec5SDimitry Andric }
4755349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
47560b57cec5SDimitry Andric 
47570b57cec5SDimitry Andric // num_get helpers
47580b57cec5SDimitry Andric 
47590b57cec5SDimitry Andric int
47600b57cec5SDimitry Andric __num_get_base::__get_base(ios_base& iob)
47610b57cec5SDimitry Andric {
47620b57cec5SDimitry Andric     ios_base::fmtflags __basefield = iob.flags() & ios_base::basefield;
47630b57cec5SDimitry Andric     if (__basefield == ios_base::oct)
47640b57cec5SDimitry Andric         return 8;
47650b57cec5SDimitry Andric     else if (__basefield == ios_base::hex)
47660b57cec5SDimitry Andric         return 16;
47670b57cec5SDimitry Andric     else if (__basefield == 0)
47680b57cec5SDimitry Andric         return 0;
47690b57cec5SDimitry Andric     return 10;
47700b57cec5SDimitry Andric }
47710b57cec5SDimitry Andric 
47720b57cec5SDimitry Andric const char __num_get_base::__src[33] = "0123456789abcdefABCDEFxX+-pPiInN";
47730b57cec5SDimitry Andric 
47740b57cec5SDimitry Andric void
47750b57cec5SDimitry Andric __check_grouping(const string& __grouping, unsigned* __g, unsigned* __g_end,
47760b57cec5SDimitry Andric                  ios_base::iostate& __err)
47770b57cec5SDimitry Andric {
47780b57cec5SDimitry Andric //  if the grouping pattern is empty _or_ there are no grouping bits, then do nothing
47790b57cec5SDimitry Andric //  we always have at least a single entry in [__g, __g_end); the end of the input sequence
47800b57cec5SDimitry Andric     if (__grouping.size() != 0 && __g_end - __g > 1)
47810b57cec5SDimitry Andric     {
47820b57cec5SDimitry Andric         reverse(__g, __g_end);
47830b57cec5SDimitry Andric         const char* __ig = __grouping.data();
47840b57cec5SDimitry Andric         const char* __eg = __ig + __grouping.size();
47850b57cec5SDimitry Andric         for (unsigned* __r = __g; __r < __g_end-1; ++__r)
47860b57cec5SDimitry Andric         {
47870b57cec5SDimitry Andric             if (0 < *__ig && *__ig < numeric_limits<char>::max())
47880b57cec5SDimitry Andric             {
47890b57cec5SDimitry Andric                 if (static_cast<unsigned>(*__ig) != *__r)
47900b57cec5SDimitry Andric                 {
47910b57cec5SDimitry Andric                     __err = ios_base::failbit;
47920b57cec5SDimitry Andric                     return;
47930b57cec5SDimitry Andric                 }
47940b57cec5SDimitry Andric             }
47950b57cec5SDimitry Andric             if (__eg - __ig > 1)
47960b57cec5SDimitry Andric                 ++__ig;
47970b57cec5SDimitry Andric         }
47980b57cec5SDimitry Andric         if (0 < *__ig && *__ig < numeric_limits<char>::max())
47990b57cec5SDimitry Andric         {
48000b57cec5SDimitry Andric             if (static_cast<unsigned>(*__ig) < __g_end[-1] || __g_end[-1] == 0)
48010b57cec5SDimitry Andric                 __err = ios_base::failbit;
48020b57cec5SDimitry Andric         }
48030b57cec5SDimitry Andric     }
48040b57cec5SDimitry Andric }
48050b57cec5SDimitry Andric 
48060b57cec5SDimitry Andric void
48070b57cec5SDimitry Andric __num_put_base::__format_int(char* __fmtp, const char* __len, bool __signd,
48080b57cec5SDimitry Andric                              ios_base::fmtflags __flags)
48090b57cec5SDimitry Andric {
4810fe6060f1SDimitry Andric     if ((__flags & ios_base::showpos) &&
4811fe6060f1SDimitry Andric         (__flags & ios_base::basefield) != ios_base::oct &&
4812fe6060f1SDimitry Andric         (__flags & ios_base::basefield) != ios_base::hex &&
4813fe6060f1SDimitry Andric         __signd)
48140b57cec5SDimitry Andric         *__fmtp++ = '+';
48150b57cec5SDimitry Andric     if (__flags & ios_base::showbase)
48160b57cec5SDimitry Andric         *__fmtp++ = '#';
48170b57cec5SDimitry Andric     while(*__len)
48180b57cec5SDimitry Andric         *__fmtp++ = *__len++;
48190b57cec5SDimitry Andric     if ((__flags & ios_base::basefield) == ios_base::oct)
48200b57cec5SDimitry Andric         *__fmtp = 'o';
48210b57cec5SDimitry Andric     else if ((__flags & ios_base::basefield) == ios_base::hex)
48220b57cec5SDimitry Andric     {
48230b57cec5SDimitry Andric         if (__flags & ios_base::uppercase)
48240b57cec5SDimitry Andric             *__fmtp = 'X';
48250b57cec5SDimitry Andric         else
48260b57cec5SDimitry Andric             *__fmtp = 'x';
48270b57cec5SDimitry Andric     }
48280b57cec5SDimitry Andric     else if (__signd)
48290b57cec5SDimitry Andric         *__fmtp = 'd';
48300b57cec5SDimitry Andric     else
48310b57cec5SDimitry Andric         *__fmtp = 'u';
48320b57cec5SDimitry Andric }
48330b57cec5SDimitry Andric 
48340b57cec5SDimitry Andric bool
48350b57cec5SDimitry Andric __num_put_base::__format_float(char* __fmtp, const char* __len,
48360b57cec5SDimitry Andric                                ios_base::fmtflags __flags)
48370b57cec5SDimitry Andric {
48380b57cec5SDimitry Andric     bool specify_precision = true;
48390b57cec5SDimitry Andric     if (__flags & ios_base::showpos)
48400b57cec5SDimitry Andric         *__fmtp++ = '+';
48410b57cec5SDimitry Andric     if (__flags & ios_base::showpoint)
48420b57cec5SDimitry Andric         *__fmtp++ = '#';
48430b57cec5SDimitry Andric     ios_base::fmtflags floatfield = __flags & ios_base::floatfield;
48440b57cec5SDimitry Andric     bool uppercase = (__flags & ios_base::uppercase) != 0;
48450b57cec5SDimitry Andric     if (floatfield == (ios_base::fixed | ios_base::scientific))
48460b57cec5SDimitry Andric         specify_precision = false;
48470b57cec5SDimitry Andric     else
48480b57cec5SDimitry Andric     {
48490b57cec5SDimitry Andric         *__fmtp++ = '.';
48500b57cec5SDimitry Andric         *__fmtp++ = '*';
48510b57cec5SDimitry Andric     }
48520b57cec5SDimitry Andric     while(*__len)
48530b57cec5SDimitry Andric         *__fmtp++ = *__len++;
48540b57cec5SDimitry Andric     if (floatfield == ios_base::fixed)
48550b57cec5SDimitry Andric     {
48560b57cec5SDimitry Andric         if (uppercase)
48570b57cec5SDimitry Andric             *__fmtp = 'F';
48580b57cec5SDimitry Andric         else
48590b57cec5SDimitry Andric             *__fmtp = 'f';
48600b57cec5SDimitry Andric     }
48610b57cec5SDimitry Andric     else if (floatfield == ios_base::scientific)
48620b57cec5SDimitry Andric     {
48630b57cec5SDimitry Andric         if (uppercase)
48640b57cec5SDimitry Andric             *__fmtp = 'E';
48650b57cec5SDimitry Andric         else
48660b57cec5SDimitry Andric             *__fmtp = 'e';
48670b57cec5SDimitry Andric     }
48680b57cec5SDimitry Andric     else if (floatfield == (ios_base::fixed | ios_base::scientific))
48690b57cec5SDimitry Andric     {
48700b57cec5SDimitry Andric         if (uppercase)
48710b57cec5SDimitry Andric             *__fmtp = 'A';
48720b57cec5SDimitry Andric         else
48730b57cec5SDimitry Andric             *__fmtp = 'a';
48740b57cec5SDimitry Andric     }
48750b57cec5SDimitry Andric     else
48760b57cec5SDimitry Andric     {
48770b57cec5SDimitry Andric         if (uppercase)
48780b57cec5SDimitry Andric             *__fmtp = 'G';
48790b57cec5SDimitry Andric         else
48800b57cec5SDimitry Andric             *__fmtp = 'g';
48810b57cec5SDimitry Andric     }
48820b57cec5SDimitry Andric     return specify_precision;
48830b57cec5SDimitry Andric }
48840b57cec5SDimitry Andric 
48850b57cec5SDimitry Andric char*
48860b57cec5SDimitry Andric __num_put_base::__identify_padding(char* __nb, char* __ne,
48870b57cec5SDimitry Andric                                    const ios_base& __iob)
48880b57cec5SDimitry Andric {
48890b57cec5SDimitry Andric     switch (__iob.flags() & ios_base::adjustfield)
48900b57cec5SDimitry Andric     {
48910b57cec5SDimitry Andric     case ios_base::internal:
48920b57cec5SDimitry Andric         if (__nb[0] == '-' || __nb[0] == '+')
48930b57cec5SDimitry Andric             return __nb+1;
48940b57cec5SDimitry Andric         if (__ne - __nb >= 2 && __nb[0] == '0'
48950b57cec5SDimitry Andric                             && (__nb[1] == 'x' || __nb[1] == 'X'))
48960b57cec5SDimitry Andric             return __nb+2;
48970b57cec5SDimitry Andric         break;
48980b57cec5SDimitry Andric     case ios_base::left:
48990b57cec5SDimitry Andric         return __ne;
49000b57cec5SDimitry Andric     case ios_base::right:
49010b57cec5SDimitry Andric     default:
49020b57cec5SDimitry Andric         break;
49030b57cec5SDimitry Andric     }
49040b57cec5SDimitry Andric     return __nb;
49050b57cec5SDimitry Andric }
49060b57cec5SDimitry Andric 
49070b57cec5SDimitry Andric // time_get
49080b57cec5SDimitry Andric 
49090b57cec5SDimitry Andric static
49100b57cec5SDimitry Andric string*
49110b57cec5SDimitry Andric init_weeks()
49120b57cec5SDimitry Andric {
49130b57cec5SDimitry Andric     static string weeks[14];
49140b57cec5SDimitry Andric     weeks[0]  = "Sunday";
49150b57cec5SDimitry Andric     weeks[1]  = "Monday";
49160b57cec5SDimitry Andric     weeks[2]  = "Tuesday";
49170b57cec5SDimitry Andric     weeks[3]  = "Wednesday";
49180b57cec5SDimitry Andric     weeks[4]  = "Thursday";
49190b57cec5SDimitry Andric     weeks[5]  = "Friday";
49200b57cec5SDimitry Andric     weeks[6]  = "Saturday";
49210b57cec5SDimitry Andric     weeks[7]  = "Sun";
49220b57cec5SDimitry Andric     weeks[8]  = "Mon";
49230b57cec5SDimitry Andric     weeks[9]  = "Tue";
49240b57cec5SDimitry Andric     weeks[10] = "Wed";
49250b57cec5SDimitry Andric     weeks[11] = "Thu";
49260b57cec5SDimitry Andric     weeks[12] = "Fri";
49270b57cec5SDimitry Andric     weeks[13] = "Sat";
49280b57cec5SDimitry Andric     return weeks;
49290b57cec5SDimitry Andric }
49300b57cec5SDimitry Andric 
4931349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
49320b57cec5SDimitry Andric static
49330b57cec5SDimitry Andric wstring*
49340b57cec5SDimitry Andric init_wweeks()
49350b57cec5SDimitry Andric {
49360b57cec5SDimitry Andric     static wstring weeks[14];
49370b57cec5SDimitry Andric     weeks[0]  = L"Sunday";
49380b57cec5SDimitry Andric     weeks[1]  = L"Monday";
49390b57cec5SDimitry Andric     weeks[2]  = L"Tuesday";
49400b57cec5SDimitry Andric     weeks[3]  = L"Wednesday";
49410b57cec5SDimitry Andric     weeks[4]  = L"Thursday";
49420b57cec5SDimitry Andric     weeks[5]  = L"Friday";
49430b57cec5SDimitry Andric     weeks[6]  = L"Saturday";
49440b57cec5SDimitry Andric     weeks[7]  = L"Sun";
49450b57cec5SDimitry Andric     weeks[8]  = L"Mon";
49460b57cec5SDimitry Andric     weeks[9]  = L"Tue";
49470b57cec5SDimitry Andric     weeks[10] = L"Wed";
49480b57cec5SDimitry Andric     weeks[11] = L"Thu";
49490b57cec5SDimitry Andric     weeks[12] = L"Fri";
49500b57cec5SDimitry Andric     weeks[13] = L"Sat";
49510b57cec5SDimitry Andric     return weeks;
49520b57cec5SDimitry Andric }
4953349cc55cSDimitry Andric #endif
49540b57cec5SDimitry Andric 
49550b57cec5SDimitry Andric template <>
49560b57cec5SDimitry Andric const string*
49570b57cec5SDimitry Andric __time_get_c_storage<char>::__weeks() const
49580b57cec5SDimitry Andric {
49590b57cec5SDimitry Andric     static const string* weeks = init_weeks();
49600b57cec5SDimitry Andric     return weeks;
49610b57cec5SDimitry Andric }
49620b57cec5SDimitry Andric 
4963349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
49640b57cec5SDimitry Andric template <>
49650b57cec5SDimitry Andric const wstring*
49660b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__weeks() const
49670b57cec5SDimitry Andric {
49680b57cec5SDimitry Andric     static const wstring* weeks = init_wweeks();
49690b57cec5SDimitry Andric     return weeks;
49700b57cec5SDimitry Andric }
4971349cc55cSDimitry Andric #endif
49720b57cec5SDimitry Andric 
49730b57cec5SDimitry Andric static
49740b57cec5SDimitry Andric string*
49750b57cec5SDimitry Andric init_months()
49760b57cec5SDimitry Andric {
49770b57cec5SDimitry Andric     static string months[24];
49780b57cec5SDimitry Andric     months[0]  = "January";
49790b57cec5SDimitry Andric     months[1]  = "February";
49800b57cec5SDimitry Andric     months[2]  = "March";
49810b57cec5SDimitry Andric     months[3]  = "April";
49820b57cec5SDimitry Andric     months[4]  = "May";
49830b57cec5SDimitry Andric     months[5]  = "June";
49840b57cec5SDimitry Andric     months[6]  = "July";
49850b57cec5SDimitry Andric     months[7]  = "August";
49860b57cec5SDimitry Andric     months[8]  = "September";
49870b57cec5SDimitry Andric     months[9]  = "October";
49880b57cec5SDimitry Andric     months[10] = "November";
49890b57cec5SDimitry Andric     months[11] = "December";
49900b57cec5SDimitry Andric     months[12] = "Jan";
49910b57cec5SDimitry Andric     months[13] = "Feb";
49920b57cec5SDimitry Andric     months[14] = "Mar";
49930b57cec5SDimitry Andric     months[15] = "Apr";
49940b57cec5SDimitry Andric     months[16] = "May";
49950b57cec5SDimitry Andric     months[17] = "Jun";
49960b57cec5SDimitry Andric     months[18] = "Jul";
49970b57cec5SDimitry Andric     months[19] = "Aug";
49980b57cec5SDimitry Andric     months[20] = "Sep";
49990b57cec5SDimitry Andric     months[21] = "Oct";
50000b57cec5SDimitry Andric     months[22] = "Nov";
50010b57cec5SDimitry Andric     months[23] = "Dec";
50020b57cec5SDimitry Andric     return months;
50030b57cec5SDimitry Andric }
50040b57cec5SDimitry Andric 
5005349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
50060b57cec5SDimitry Andric static
50070b57cec5SDimitry Andric wstring*
50080b57cec5SDimitry Andric init_wmonths()
50090b57cec5SDimitry Andric {
50100b57cec5SDimitry Andric     static wstring months[24];
50110b57cec5SDimitry Andric     months[0]  = L"January";
50120b57cec5SDimitry Andric     months[1]  = L"February";
50130b57cec5SDimitry Andric     months[2]  = L"March";
50140b57cec5SDimitry Andric     months[3]  = L"April";
50150b57cec5SDimitry Andric     months[4]  = L"May";
50160b57cec5SDimitry Andric     months[5]  = L"June";
50170b57cec5SDimitry Andric     months[6]  = L"July";
50180b57cec5SDimitry Andric     months[7]  = L"August";
50190b57cec5SDimitry Andric     months[8]  = L"September";
50200b57cec5SDimitry Andric     months[9]  = L"October";
50210b57cec5SDimitry Andric     months[10] = L"November";
50220b57cec5SDimitry Andric     months[11] = L"December";
50230b57cec5SDimitry Andric     months[12] = L"Jan";
50240b57cec5SDimitry Andric     months[13] = L"Feb";
50250b57cec5SDimitry Andric     months[14] = L"Mar";
50260b57cec5SDimitry Andric     months[15] = L"Apr";
50270b57cec5SDimitry Andric     months[16] = L"May";
50280b57cec5SDimitry Andric     months[17] = L"Jun";
50290b57cec5SDimitry Andric     months[18] = L"Jul";
50300b57cec5SDimitry Andric     months[19] = L"Aug";
50310b57cec5SDimitry Andric     months[20] = L"Sep";
50320b57cec5SDimitry Andric     months[21] = L"Oct";
50330b57cec5SDimitry Andric     months[22] = L"Nov";
50340b57cec5SDimitry Andric     months[23] = L"Dec";
50350b57cec5SDimitry Andric     return months;
50360b57cec5SDimitry Andric }
5037349cc55cSDimitry Andric #endif
50380b57cec5SDimitry Andric 
50390b57cec5SDimitry Andric template <>
50400b57cec5SDimitry Andric const string*
50410b57cec5SDimitry Andric __time_get_c_storage<char>::__months() const
50420b57cec5SDimitry Andric {
50430b57cec5SDimitry Andric     static const string* months = init_months();
50440b57cec5SDimitry Andric     return months;
50450b57cec5SDimitry Andric }
50460b57cec5SDimitry Andric 
5047349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
50480b57cec5SDimitry Andric template <>
50490b57cec5SDimitry Andric const wstring*
50500b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__months() const
50510b57cec5SDimitry Andric {
50520b57cec5SDimitry Andric     static const wstring* months = init_wmonths();
50530b57cec5SDimitry Andric     return months;
50540b57cec5SDimitry Andric }
5055349cc55cSDimitry Andric #endif
50560b57cec5SDimitry Andric 
50570b57cec5SDimitry Andric static
50580b57cec5SDimitry Andric string*
50590b57cec5SDimitry Andric init_am_pm()
50600b57cec5SDimitry Andric {
50610b57cec5SDimitry Andric     static string am_pm[2];
50620b57cec5SDimitry Andric     am_pm[0]  = "AM";
50630b57cec5SDimitry Andric     am_pm[1]  = "PM";
50640b57cec5SDimitry Andric     return am_pm;
50650b57cec5SDimitry Andric }
50660b57cec5SDimitry Andric 
5067349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
50680b57cec5SDimitry Andric static
50690b57cec5SDimitry Andric wstring*
50700b57cec5SDimitry Andric init_wam_pm()
50710b57cec5SDimitry Andric {
50720b57cec5SDimitry Andric     static wstring am_pm[2];
50730b57cec5SDimitry Andric     am_pm[0]  = L"AM";
50740b57cec5SDimitry Andric     am_pm[1]  = L"PM";
50750b57cec5SDimitry Andric     return am_pm;
50760b57cec5SDimitry Andric }
5077349cc55cSDimitry Andric #endif
50780b57cec5SDimitry Andric 
50790b57cec5SDimitry Andric template <>
50800b57cec5SDimitry Andric const string*
50810b57cec5SDimitry Andric __time_get_c_storage<char>::__am_pm() const
50820b57cec5SDimitry Andric {
50830b57cec5SDimitry Andric     static const string* am_pm = init_am_pm();
50840b57cec5SDimitry Andric     return am_pm;
50850b57cec5SDimitry Andric }
50860b57cec5SDimitry Andric 
5087349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
50880b57cec5SDimitry Andric template <>
50890b57cec5SDimitry Andric const wstring*
50900b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__am_pm() const
50910b57cec5SDimitry Andric {
50920b57cec5SDimitry Andric     static const wstring* am_pm = init_wam_pm();
50930b57cec5SDimitry Andric     return am_pm;
50940b57cec5SDimitry Andric }
5095349cc55cSDimitry Andric #endif
50960b57cec5SDimitry Andric 
50970b57cec5SDimitry Andric template <>
50980b57cec5SDimitry Andric const string&
50990b57cec5SDimitry Andric __time_get_c_storage<char>::__x() const
51000b57cec5SDimitry Andric {
51010b57cec5SDimitry Andric     static string s("%m/%d/%y");
51020b57cec5SDimitry Andric     return s;
51030b57cec5SDimitry Andric }
51040b57cec5SDimitry Andric 
5105349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51060b57cec5SDimitry Andric template <>
51070b57cec5SDimitry Andric const wstring&
51080b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__x() const
51090b57cec5SDimitry Andric {
51100b57cec5SDimitry Andric     static wstring s(L"%m/%d/%y");
51110b57cec5SDimitry Andric     return s;
51120b57cec5SDimitry Andric }
5113349cc55cSDimitry Andric #endif
51140b57cec5SDimitry Andric 
51150b57cec5SDimitry Andric template <>
51160b57cec5SDimitry Andric const string&
51170b57cec5SDimitry Andric __time_get_c_storage<char>::__X() const
51180b57cec5SDimitry Andric {
51190b57cec5SDimitry Andric     static string s("%H:%M:%S");
51200b57cec5SDimitry Andric     return s;
51210b57cec5SDimitry Andric }
51220b57cec5SDimitry Andric 
5123349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51240b57cec5SDimitry Andric template <>
51250b57cec5SDimitry Andric const wstring&
51260b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__X() const
51270b57cec5SDimitry Andric {
51280b57cec5SDimitry Andric     static wstring s(L"%H:%M:%S");
51290b57cec5SDimitry Andric     return s;
51300b57cec5SDimitry Andric }
5131349cc55cSDimitry Andric #endif
51320b57cec5SDimitry Andric 
51330b57cec5SDimitry Andric template <>
51340b57cec5SDimitry Andric const string&
51350b57cec5SDimitry Andric __time_get_c_storage<char>::__c() const
51360b57cec5SDimitry Andric {
51370b57cec5SDimitry Andric     static string s("%a %b %d %H:%M:%S %Y");
51380b57cec5SDimitry Andric     return s;
51390b57cec5SDimitry Andric }
51400b57cec5SDimitry Andric 
5141349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51420b57cec5SDimitry Andric template <>
51430b57cec5SDimitry Andric const wstring&
51440b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__c() const
51450b57cec5SDimitry Andric {
51460b57cec5SDimitry Andric     static wstring s(L"%a %b %d %H:%M:%S %Y");
51470b57cec5SDimitry Andric     return s;
51480b57cec5SDimitry Andric }
5149349cc55cSDimitry Andric #endif
51500b57cec5SDimitry Andric 
51510b57cec5SDimitry Andric template <>
51520b57cec5SDimitry Andric const string&
51530b57cec5SDimitry Andric __time_get_c_storage<char>::__r() const
51540b57cec5SDimitry Andric {
51550b57cec5SDimitry Andric     static string s("%I:%M:%S %p");
51560b57cec5SDimitry Andric     return s;
51570b57cec5SDimitry Andric }
51580b57cec5SDimitry Andric 
5159349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51600b57cec5SDimitry Andric template <>
51610b57cec5SDimitry Andric const wstring&
51620b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__r() const
51630b57cec5SDimitry Andric {
51640b57cec5SDimitry Andric     static wstring s(L"%I:%M:%S %p");
51650b57cec5SDimitry Andric     return s;
51660b57cec5SDimitry Andric }
5167349cc55cSDimitry Andric #endif
51680b57cec5SDimitry Andric 
51690b57cec5SDimitry Andric // time_get_byname
51700b57cec5SDimitry Andric 
51710b57cec5SDimitry Andric __time_get::__time_get(const char* nm)
51720b57cec5SDimitry Andric     : __loc_(newlocale(LC_ALL_MASK, nm, 0))
51730b57cec5SDimitry Andric {
51740b57cec5SDimitry Andric     if (__loc_ == 0)
5175*5f757f3fSDimitry Andric         __throw_runtime_error(("time_get_byname failed to construct for " + string(nm)).c_str());
51760b57cec5SDimitry Andric }
51770b57cec5SDimitry Andric 
51780b57cec5SDimitry Andric __time_get::__time_get(const string& nm)
51790b57cec5SDimitry Andric     : __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0))
51800b57cec5SDimitry Andric {
51810b57cec5SDimitry Andric     if (__loc_ == 0)
5182*5f757f3fSDimitry Andric         __throw_runtime_error(("time_get_byname failed to construct for " + nm).c_str());
51830b57cec5SDimitry Andric }
51840b57cec5SDimitry Andric 
51850b57cec5SDimitry Andric __time_get::~__time_get()
51860b57cec5SDimitry Andric {
51870b57cec5SDimitry Andric     freelocale(__loc_);
51880b57cec5SDimitry Andric }
518981ad6265SDimitry Andric 
519081ad6265SDimitry Andric _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-field-initializers")
51910b57cec5SDimitry Andric 
51920b57cec5SDimitry Andric template <>
51930b57cec5SDimitry Andric string
51940b57cec5SDimitry Andric __time_get_storage<char>::__analyze(char fmt, const ctype<char>& ct)
51950b57cec5SDimitry Andric {
51960b57cec5SDimitry Andric     tm t = {0};
51970b57cec5SDimitry Andric     t.tm_sec = 59;
51980b57cec5SDimitry Andric     t.tm_min = 55;
51990b57cec5SDimitry Andric     t.tm_hour = 23;
52000b57cec5SDimitry Andric     t.tm_mday = 31;
52010b57cec5SDimitry Andric     t.tm_mon = 11;
52020b57cec5SDimitry Andric     t.tm_year = 161;
52030b57cec5SDimitry Andric     t.tm_wday = 6;
52040b57cec5SDimitry Andric     t.tm_yday = 364;
52050b57cec5SDimitry Andric     t.tm_isdst = -1;
52060b57cec5SDimitry Andric     char buf[100];
52070b57cec5SDimitry Andric     char f[3] = {0};
52080b57cec5SDimitry Andric     f[0] = '%';
52090b57cec5SDimitry Andric     f[1] = fmt;
52100b57cec5SDimitry Andric     size_t n = strftime_l(buf, countof(buf), f, &t, __loc_);
52110b57cec5SDimitry Andric     char* bb = buf;
52120b57cec5SDimitry Andric     char* be = buf + n;
52130b57cec5SDimitry Andric     string result;
52140b57cec5SDimitry Andric     while (bb != be)
52150b57cec5SDimitry Andric     {
52160b57cec5SDimitry Andric         if (ct.is(ctype_base::space, *bb))
52170b57cec5SDimitry Andric         {
52180b57cec5SDimitry Andric             result.push_back(' ');
52190b57cec5SDimitry Andric             for (++bb; bb != be && ct.is(ctype_base::space, *bb); ++bb)
52200b57cec5SDimitry Andric                 ;
52210b57cec5SDimitry Andric             continue;
52220b57cec5SDimitry Andric         }
52230b57cec5SDimitry Andric         char* w = bb;
52240b57cec5SDimitry Andric         ios_base::iostate err = ios_base::goodbit;
52250b57cec5SDimitry Andric         ptrdiff_t i = __scan_keyword(w, be, this->__weeks_, this->__weeks_+14,
52260b57cec5SDimitry Andric                                ct, err, false)
52270b57cec5SDimitry Andric                                - this->__weeks_;
52280b57cec5SDimitry Andric         if (i < 14)
52290b57cec5SDimitry Andric         {
52300b57cec5SDimitry Andric             result.push_back('%');
52310b57cec5SDimitry Andric             if (i < 7)
52320b57cec5SDimitry Andric                 result.push_back('A');
52330b57cec5SDimitry Andric             else
52340b57cec5SDimitry Andric                 result.push_back('a');
52350b57cec5SDimitry Andric             bb = w;
52360b57cec5SDimitry Andric             continue;
52370b57cec5SDimitry Andric         }
52380b57cec5SDimitry Andric         w = bb;
52390b57cec5SDimitry Andric         i = __scan_keyword(w, be, this->__months_, this->__months_+24,
52400b57cec5SDimitry Andric                            ct, err, false)
52410b57cec5SDimitry Andric                            - this->__months_;
52420b57cec5SDimitry Andric         if (i < 24)
52430b57cec5SDimitry Andric         {
52440b57cec5SDimitry Andric             result.push_back('%');
52450b57cec5SDimitry Andric             if (i < 12)
52460b57cec5SDimitry Andric                 result.push_back('B');
52470b57cec5SDimitry Andric             else
52480b57cec5SDimitry Andric                 result.push_back('b');
52490b57cec5SDimitry Andric             if (fmt == 'x' && ct.is(ctype_base::digit, this->__months_[i][0]))
52500b57cec5SDimitry Andric                 result.back() = 'm';
52510b57cec5SDimitry Andric             bb = w;
52520b57cec5SDimitry Andric             continue;
52530b57cec5SDimitry Andric         }
52540b57cec5SDimitry Andric         if (this->__am_pm_[0].size() + this->__am_pm_[1].size() > 0)
52550b57cec5SDimitry Andric         {
52560b57cec5SDimitry Andric             w = bb;
52570b57cec5SDimitry Andric             i = __scan_keyword(w, be, this->__am_pm_, this->__am_pm_+2,
52580b57cec5SDimitry Andric                                ct, err, false) - this->__am_pm_;
52590b57cec5SDimitry Andric             if (i < 2)
52600b57cec5SDimitry Andric             {
52610b57cec5SDimitry Andric                 result.push_back('%');
52620b57cec5SDimitry Andric                 result.push_back('p');
52630b57cec5SDimitry Andric                 bb = w;
52640b57cec5SDimitry Andric                 continue;
52650b57cec5SDimitry Andric             }
52660b57cec5SDimitry Andric         }
52670b57cec5SDimitry Andric         w = bb;
52680b57cec5SDimitry Andric         if (ct.is(ctype_base::digit, *bb))
52690b57cec5SDimitry Andric         {
52700b57cec5SDimitry Andric             switch(__get_up_to_n_digits(bb, be, err, ct, 4))
52710b57cec5SDimitry Andric             {
52720b57cec5SDimitry Andric             case 6:
52730b57cec5SDimitry Andric                 result.push_back('%');
52740b57cec5SDimitry Andric                 result.push_back('w');
52750b57cec5SDimitry Andric                 break;
52760b57cec5SDimitry Andric             case 7:
52770b57cec5SDimitry Andric                 result.push_back('%');
52780b57cec5SDimitry Andric                 result.push_back('u');
52790b57cec5SDimitry Andric                 break;
52800b57cec5SDimitry Andric             case 11:
52810b57cec5SDimitry Andric                 result.push_back('%');
52820b57cec5SDimitry Andric                 result.push_back('I');
52830b57cec5SDimitry Andric                 break;
52840b57cec5SDimitry Andric             case 12:
52850b57cec5SDimitry Andric                 result.push_back('%');
52860b57cec5SDimitry Andric                 result.push_back('m');
52870b57cec5SDimitry Andric                 break;
52880b57cec5SDimitry Andric             case 23:
52890b57cec5SDimitry Andric                 result.push_back('%');
52900b57cec5SDimitry Andric                 result.push_back('H');
52910b57cec5SDimitry Andric                 break;
52920b57cec5SDimitry Andric             case 31:
52930b57cec5SDimitry Andric                 result.push_back('%');
52940b57cec5SDimitry Andric                 result.push_back('d');
52950b57cec5SDimitry Andric                 break;
52960b57cec5SDimitry Andric             case 55:
52970b57cec5SDimitry Andric                 result.push_back('%');
52980b57cec5SDimitry Andric                 result.push_back('M');
52990b57cec5SDimitry Andric                 break;
53000b57cec5SDimitry Andric             case 59:
53010b57cec5SDimitry Andric                 result.push_back('%');
53020b57cec5SDimitry Andric                 result.push_back('S');
53030b57cec5SDimitry Andric                 break;
53040b57cec5SDimitry Andric             case 61:
53050b57cec5SDimitry Andric                 result.push_back('%');
53060b57cec5SDimitry Andric                 result.push_back('y');
53070b57cec5SDimitry Andric                 break;
53080b57cec5SDimitry Andric             case 364:
53090b57cec5SDimitry Andric                 result.push_back('%');
53100b57cec5SDimitry Andric                 result.push_back('j');
53110b57cec5SDimitry Andric                 break;
53120b57cec5SDimitry Andric             case 2061:
53130b57cec5SDimitry Andric                 result.push_back('%');
53140b57cec5SDimitry Andric                 result.push_back('Y');
53150b57cec5SDimitry Andric                 break;
53160b57cec5SDimitry Andric             default:
53170b57cec5SDimitry Andric                 for (; w != bb; ++w)
53180b57cec5SDimitry Andric                     result.push_back(*w);
53190b57cec5SDimitry Andric                 break;
53200b57cec5SDimitry Andric             }
53210b57cec5SDimitry Andric             continue;
53220b57cec5SDimitry Andric         }
53230b57cec5SDimitry Andric         if (*bb == '%')
53240b57cec5SDimitry Andric         {
53250b57cec5SDimitry Andric             result.push_back('%');
53260b57cec5SDimitry Andric             result.push_back('%');
53270b57cec5SDimitry Andric             ++bb;
53280b57cec5SDimitry Andric             continue;
53290b57cec5SDimitry Andric         }
53300b57cec5SDimitry Andric         result.push_back(*bb);
53310b57cec5SDimitry Andric         ++bb;
53320b57cec5SDimitry Andric     }
53330b57cec5SDimitry Andric     return result;
53340b57cec5SDimitry Andric }
53350b57cec5SDimitry Andric 
533681ad6265SDimitry Andric _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-braces")
53370b57cec5SDimitry Andric 
5338349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
53390b57cec5SDimitry Andric template <>
53400b57cec5SDimitry Andric wstring
53410b57cec5SDimitry Andric __time_get_storage<wchar_t>::__analyze(char fmt, const ctype<wchar_t>& ct)
53420b57cec5SDimitry Andric {
53430b57cec5SDimitry Andric     tm t = {0};
53440b57cec5SDimitry Andric     t.tm_sec = 59;
53450b57cec5SDimitry Andric     t.tm_min = 55;
53460b57cec5SDimitry Andric     t.tm_hour = 23;
53470b57cec5SDimitry Andric     t.tm_mday = 31;
53480b57cec5SDimitry Andric     t.tm_mon = 11;
53490b57cec5SDimitry Andric     t.tm_year = 161;
53500b57cec5SDimitry Andric     t.tm_wday = 6;
53510b57cec5SDimitry Andric     t.tm_yday = 364;
53520b57cec5SDimitry Andric     t.tm_isdst = -1;
53530b57cec5SDimitry Andric     char buf[100];
53540b57cec5SDimitry Andric     char f[3] = {0};
53550b57cec5SDimitry Andric     f[0] = '%';
53560b57cec5SDimitry Andric     f[1] = fmt;
53570b57cec5SDimitry Andric     strftime_l(buf, countof(buf), f, &t, __loc_);
53580b57cec5SDimitry Andric     wchar_t wbuf[100];
53590b57cec5SDimitry Andric     wchar_t* wbb = wbuf;
53600b57cec5SDimitry Andric     mbstate_t mb = {0};
53610b57cec5SDimitry Andric     const char* bb = buf;
53620b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l( wbb, &bb, countof(wbuf), &mb, __loc_);
53630b57cec5SDimitry Andric     if (j == size_t(-1))
53640b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
53650b57cec5SDimitry Andric     wchar_t* wbe = wbb + j;
53660b57cec5SDimitry Andric     wstring result;
53670b57cec5SDimitry Andric     while (wbb != wbe)
53680b57cec5SDimitry Andric     {
53690b57cec5SDimitry Andric         if (ct.is(ctype_base::space, *wbb))
53700b57cec5SDimitry Andric         {
53710b57cec5SDimitry Andric             result.push_back(L' ');
53720b57cec5SDimitry Andric             for (++wbb; wbb != wbe && ct.is(ctype_base::space, *wbb); ++wbb)
53730b57cec5SDimitry Andric                 ;
53740b57cec5SDimitry Andric             continue;
53750b57cec5SDimitry Andric         }
53760b57cec5SDimitry Andric         wchar_t* w = wbb;
53770b57cec5SDimitry Andric         ios_base::iostate err = ios_base::goodbit;
53780b57cec5SDimitry Andric         ptrdiff_t i = __scan_keyword(w, wbe, this->__weeks_, this->__weeks_+14,
53790b57cec5SDimitry Andric                                ct, err, false)
53800b57cec5SDimitry Andric                                - this->__weeks_;
53810b57cec5SDimitry Andric         if (i < 14)
53820b57cec5SDimitry Andric         {
53830b57cec5SDimitry Andric             result.push_back(L'%');
53840b57cec5SDimitry Andric             if (i < 7)
53850b57cec5SDimitry Andric                 result.push_back(L'A');
53860b57cec5SDimitry Andric             else
53870b57cec5SDimitry Andric                 result.push_back(L'a');
53880b57cec5SDimitry Andric             wbb = w;
53890b57cec5SDimitry Andric             continue;
53900b57cec5SDimitry Andric         }
53910b57cec5SDimitry Andric         w = wbb;
53920b57cec5SDimitry Andric         i = __scan_keyword(w, wbe, this->__months_, this->__months_+24,
53930b57cec5SDimitry Andric                            ct, err, false)
53940b57cec5SDimitry Andric                            - this->__months_;
53950b57cec5SDimitry Andric         if (i < 24)
53960b57cec5SDimitry Andric         {
53970b57cec5SDimitry Andric             result.push_back(L'%');
53980b57cec5SDimitry Andric             if (i < 12)
53990b57cec5SDimitry Andric                 result.push_back(L'B');
54000b57cec5SDimitry Andric             else
54010b57cec5SDimitry Andric                 result.push_back(L'b');
54020b57cec5SDimitry Andric             if (fmt == 'x' && ct.is(ctype_base::digit, this->__months_[i][0]))
54030b57cec5SDimitry Andric                 result.back() = L'm';
54040b57cec5SDimitry Andric             wbb = w;
54050b57cec5SDimitry Andric             continue;
54060b57cec5SDimitry Andric         }
54070b57cec5SDimitry Andric         if (this->__am_pm_[0].size() + this->__am_pm_[1].size() > 0)
54080b57cec5SDimitry Andric         {
54090b57cec5SDimitry Andric             w = wbb;
54100b57cec5SDimitry Andric             i = __scan_keyword(w, wbe, this->__am_pm_, this->__am_pm_+2,
54110b57cec5SDimitry Andric                                ct, err, false) - this->__am_pm_;
54120b57cec5SDimitry Andric             if (i < 2)
54130b57cec5SDimitry Andric             {
54140b57cec5SDimitry Andric                 result.push_back(L'%');
54150b57cec5SDimitry Andric                 result.push_back(L'p');
54160b57cec5SDimitry Andric                 wbb = w;
54170b57cec5SDimitry Andric                 continue;
54180b57cec5SDimitry Andric             }
54190b57cec5SDimitry Andric         }
54200b57cec5SDimitry Andric         w = wbb;
54210b57cec5SDimitry Andric         if (ct.is(ctype_base::digit, *wbb))
54220b57cec5SDimitry Andric         {
54230b57cec5SDimitry Andric             switch(__get_up_to_n_digits(wbb, wbe, err, ct, 4))
54240b57cec5SDimitry Andric             {
54250b57cec5SDimitry Andric             case 6:
54260b57cec5SDimitry Andric                 result.push_back(L'%');
54270b57cec5SDimitry Andric                 result.push_back(L'w');
54280b57cec5SDimitry Andric                 break;
54290b57cec5SDimitry Andric             case 7:
54300b57cec5SDimitry Andric                 result.push_back(L'%');
54310b57cec5SDimitry Andric                 result.push_back(L'u');
54320b57cec5SDimitry Andric                 break;
54330b57cec5SDimitry Andric             case 11:
54340b57cec5SDimitry Andric                 result.push_back(L'%');
54350b57cec5SDimitry Andric                 result.push_back(L'I');
54360b57cec5SDimitry Andric                 break;
54370b57cec5SDimitry Andric             case 12:
54380b57cec5SDimitry Andric                 result.push_back(L'%');
54390b57cec5SDimitry Andric                 result.push_back(L'm');
54400b57cec5SDimitry Andric                 break;
54410b57cec5SDimitry Andric             case 23:
54420b57cec5SDimitry Andric                 result.push_back(L'%');
54430b57cec5SDimitry Andric                 result.push_back(L'H');
54440b57cec5SDimitry Andric                 break;
54450b57cec5SDimitry Andric             case 31:
54460b57cec5SDimitry Andric                 result.push_back(L'%');
54470b57cec5SDimitry Andric                 result.push_back(L'd');
54480b57cec5SDimitry Andric                 break;
54490b57cec5SDimitry Andric             case 55:
54500b57cec5SDimitry Andric                 result.push_back(L'%');
54510b57cec5SDimitry Andric                 result.push_back(L'M');
54520b57cec5SDimitry Andric                 break;
54530b57cec5SDimitry Andric             case 59:
54540b57cec5SDimitry Andric                 result.push_back(L'%');
54550b57cec5SDimitry Andric                 result.push_back(L'S');
54560b57cec5SDimitry Andric                 break;
54570b57cec5SDimitry Andric             case 61:
54580b57cec5SDimitry Andric                 result.push_back(L'%');
54590b57cec5SDimitry Andric                 result.push_back(L'y');
54600b57cec5SDimitry Andric                 break;
54610b57cec5SDimitry Andric             case 364:
54620b57cec5SDimitry Andric                 result.push_back(L'%');
54630b57cec5SDimitry Andric                 result.push_back(L'j');
54640b57cec5SDimitry Andric                 break;
54650b57cec5SDimitry Andric             case 2061:
54660b57cec5SDimitry Andric                 result.push_back(L'%');
54670b57cec5SDimitry Andric                 result.push_back(L'Y');
54680b57cec5SDimitry Andric                 break;
54690b57cec5SDimitry Andric             default:
54700b57cec5SDimitry Andric                 for (; w != wbb; ++w)
54710b57cec5SDimitry Andric                     result.push_back(*w);
54720b57cec5SDimitry Andric                 break;
54730b57cec5SDimitry Andric             }
54740b57cec5SDimitry Andric             continue;
54750b57cec5SDimitry Andric         }
54760b57cec5SDimitry Andric         if (ct.narrow(*wbb, 0) == '%')
54770b57cec5SDimitry Andric         {
54780b57cec5SDimitry Andric             result.push_back(L'%');
54790b57cec5SDimitry Andric             result.push_back(L'%');
54800b57cec5SDimitry Andric             ++wbb;
54810b57cec5SDimitry Andric             continue;
54820b57cec5SDimitry Andric         }
54830b57cec5SDimitry Andric         result.push_back(*wbb);
54840b57cec5SDimitry Andric         ++wbb;
54850b57cec5SDimitry Andric     }
54860b57cec5SDimitry Andric     return result;
54870b57cec5SDimitry Andric }
5488349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
54890b57cec5SDimitry Andric 
54900b57cec5SDimitry Andric template <>
54910b57cec5SDimitry Andric void
54920b57cec5SDimitry Andric __time_get_storage<char>::init(const ctype<char>& ct)
54930b57cec5SDimitry Andric {
54940b57cec5SDimitry Andric     tm t = {0};
54950b57cec5SDimitry Andric     char buf[100];
54960b57cec5SDimitry Andric     // __weeks_
54970b57cec5SDimitry Andric     for (int i = 0; i < 7; ++i)
54980b57cec5SDimitry Andric     {
54990b57cec5SDimitry Andric         t.tm_wday = i;
55000b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%A", &t, __loc_);
55010b57cec5SDimitry Andric         __weeks_[i] = buf;
55020b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%a", &t, __loc_);
55030b57cec5SDimitry Andric         __weeks_[i+7] = buf;
55040b57cec5SDimitry Andric     }
55050b57cec5SDimitry Andric     // __months_
55060b57cec5SDimitry Andric     for (int i = 0; i < 12; ++i)
55070b57cec5SDimitry Andric     {
55080b57cec5SDimitry Andric         t.tm_mon = i;
55090b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%B", &t, __loc_);
55100b57cec5SDimitry Andric         __months_[i] = buf;
55110b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%b", &t, __loc_);
55120b57cec5SDimitry Andric         __months_[i+12] = buf;
55130b57cec5SDimitry Andric     }
55140b57cec5SDimitry Andric     // __am_pm_
55150b57cec5SDimitry Andric     t.tm_hour = 1;
55160b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%p", &t, __loc_);
55170b57cec5SDimitry Andric     __am_pm_[0] = buf;
55180b57cec5SDimitry Andric     t.tm_hour = 13;
55190b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%p", &t, __loc_);
55200b57cec5SDimitry Andric     __am_pm_[1] = buf;
55210b57cec5SDimitry Andric     __c_ = __analyze('c', ct);
55220b57cec5SDimitry Andric     __r_ = __analyze('r', ct);
55230b57cec5SDimitry Andric     __x_ = __analyze('x', ct);
55240b57cec5SDimitry Andric     __X_ = __analyze('X', ct);
55250b57cec5SDimitry Andric }
55260b57cec5SDimitry Andric 
5527349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
55280b57cec5SDimitry Andric template <>
55290b57cec5SDimitry Andric void
55300b57cec5SDimitry Andric __time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct)
55310b57cec5SDimitry Andric {
55320b57cec5SDimitry Andric     tm t = {0};
55330b57cec5SDimitry Andric     char buf[100];
55340b57cec5SDimitry Andric     wchar_t wbuf[100];
55350b57cec5SDimitry Andric     wchar_t* wbe;
55360b57cec5SDimitry Andric     mbstate_t mb = {0};
55370b57cec5SDimitry Andric     // __weeks_
55380b57cec5SDimitry Andric     for (int i = 0; i < 7; ++i)
55390b57cec5SDimitry Andric     {
55400b57cec5SDimitry Andric         t.tm_wday = i;
55410b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%A", &t, __loc_);
55420b57cec5SDimitry Andric         mb = mbstate_t();
55430b57cec5SDimitry Andric         const char* bb = buf;
55440b57cec5SDimitry Andric         size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5545e8d8bef9SDimitry Andric         if (j == size_t(-1) || j == 0)
55460b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
55470b57cec5SDimitry Andric         wbe = wbuf + j;
55480b57cec5SDimitry Andric         __weeks_[i].assign(wbuf, wbe);
55490b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%a", &t, __loc_);
55500b57cec5SDimitry Andric         mb = mbstate_t();
55510b57cec5SDimitry Andric         bb = buf;
55520b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5553e8d8bef9SDimitry Andric         if (j == size_t(-1) || j == 0)
55540b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
55550b57cec5SDimitry Andric         wbe = wbuf + j;
55560b57cec5SDimitry Andric         __weeks_[i+7].assign(wbuf, wbe);
55570b57cec5SDimitry Andric     }
55580b57cec5SDimitry Andric     // __months_
55590b57cec5SDimitry Andric     for (int i = 0; i < 12; ++i)
55600b57cec5SDimitry Andric     {
55610b57cec5SDimitry Andric         t.tm_mon = i;
55620b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%B", &t, __loc_);
55630b57cec5SDimitry Andric         mb = mbstate_t();
55640b57cec5SDimitry Andric         const char* bb = buf;
55650b57cec5SDimitry Andric         size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5566e8d8bef9SDimitry Andric         if (j == size_t(-1) || j == 0)
55670b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
55680b57cec5SDimitry Andric         wbe = wbuf + j;
55690b57cec5SDimitry Andric         __months_[i].assign(wbuf, wbe);
55700b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%b", &t, __loc_);
55710b57cec5SDimitry Andric         mb = mbstate_t();
55720b57cec5SDimitry Andric         bb = buf;
55730b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5574e8d8bef9SDimitry Andric         if (j == size_t(-1) || j == 0)
55750b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
55760b57cec5SDimitry Andric         wbe = wbuf + j;
55770b57cec5SDimitry Andric         __months_[i+12].assign(wbuf, wbe);
55780b57cec5SDimitry Andric     }
55790b57cec5SDimitry Andric     // __am_pm_
55800b57cec5SDimitry Andric     t.tm_hour = 1;
55810b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%p", &t, __loc_);
55820b57cec5SDimitry Andric     mb = mbstate_t();
55830b57cec5SDimitry Andric     const char* bb = buf;
55840b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
55850b57cec5SDimitry Andric     if (j == size_t(-1))
55860b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
55870b57cec5SDimitry Andric     wbe = wbuf + j;
55880b57cec5SDimitry Andric     __am_pm_[0].assign(wbuf, wbe);
55890b57cec5SDimitry Andric     t.tm_hour = 13;
55900b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%p", &t, __loc_);
55910b57cec5SDimitry Andric     mb = mbstate_t();
55920b57cec5SDimitry Andric     bb = buf;
55930b57cec5SDimitry Andric     j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
55940b57cec5SDimitry Andric     if (j == size_t(-1))
55950b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
55960b57cec5SDimitry Andric     wbe = wbuf + j;
55970b57cec5SDimitry Andric     __am_pm_[1].assign(wbuf, wbe);
55980b57cec5SDimitry Andric     __c_ = __analyze('c', ct);
55990b57cec5SDimitry Andric     __r_ = __analyze('r', ct);
56000b57cec5SDimitry Andric     __x_ = __analyze('x', ct);
56010b57cec5SDimitry Andric     __X_ = __analyze('X', ct);
56020b57cec5SDimitry Andric }
5603349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
56040b57cec5SDimitry Andric 
56050b57cec5SDimitry Andric template <class CharT>
56060b57cec5SDimitry Andric struct _LIBCPP_HIDDEN __time_get_temp
56070b57cec5SDimitry Andric     : public ctype_byname<CharT>
56080b57cec5SDimitry Andric {
56090b57cec5SDimitry Andric     explicit __time_get_temp(const char* nm)
56100b57cec5SDimitry Andric         : ctype_byname<CharT>(nm, 1) {}
56110b57cec5SDimitry Andric     explicit __time_get_temp(const string& nm)
56120b57cec5SDimitry Andric         : ctype_byname<CharT>(nm, 1) {}
56130b57cec5SDimitry Andric };
56140b57cec5SDimitry Andric 
56150b57cec5SDimitry Andric template <>
56160b57cec5SDimitry Andric __time_get_storage<char>::__time_get_storage(const char* __nm)
56170b57cec5SDimitry Andric     : __time_get(__nm)
56180b57cec5SDimitry Andric {
56190b57cec5SDimitry Andric     const __time_get_temp<char> ct(__nm);
56200b57cec5SDimitry Andric     init(ct);
56210b57cec5SDimitry Andric }
56220b57cec5SDimitry Andric 
56230b57cec5SDimitry Andric template <>
56240b57cec5SDimitry Andric __time_get_storage<char>::__time_get_storage(const string& __nm)
56250b57cec5SDimitry Andric     : __time_get(__nm)
56260b57cec5SDimitry Andric {
56270b57cec5SDimitry Andric     const __time_get_temp<char> ct(__nm);
56280b57cec5SDimitry Andric     init(ct);
56290b57cec5SDimitry Andric }
56300b57cec5SDimitry Andric 
5631349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
56320b57cec5SDimitry Andric template <>
56330b57cec5SDimitry Andric __time_get_storage<wchar_t>::__time_get_storage(const char* __nm)
56340b57cec5SDimitry Andric     : __time_get(__nm)
56350b57cec5SDimitry Andric {
56360b57cec5SDimitry Andric     const __time_get_temp<wchar_t> ct(__nm);
56370b57cec5SDimitry Andric     init(ct);
56380b57cec5SDimitry Andric }
56390b57cec5SDimitry Andric 
56400b57cec5SDimitry Andric template <>
56410b57cec5SDimitry Andric __time_get_storage<wchar_t>::__time_get_storage(const string& __nm)
56420b57cec5SDimitry Andric     : __time_get(__nm)
56430b57cec5SDimitry Andric {
56440b57cec5SDimitry Andric     const __time_get_temp<wchar_t> ct(__nm);
56450b57cec5SDimitry Andric     init(ct);
56460b57cec5SDimitry Andric }
5647349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
56480b57cec5SDimitry Andric 
56490b57cec5SDimitry Andric template <>
56500b57cec5SDimitry Andric time_base::dateorder
56510b57cec5SDimitry Andric __time_get_storage<char>::__do_date_order() const
56520b57cec5SDimitry Andric {
56530b57cec5SDimitry Andric     unsigned i;
56540b57cec5SDimitry Andric     for (i = 0; i < __x_.size(); ++i)
56550b57cec5SDimitry Andric         if (__x_[i] == '%')
56560b57cec5SDimitry Andric             break;
56570b57cec5SDimitry Andric     ++i;
56580b57cec5SDimitry Andric     switch (__x_[i])
56590b57cec5SDimitry Andric     {
56600b57cec5SDimitry Andric     case 'y':
56610b57cec5SDimitry Andric     case 'Y':
56620b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
56630b57cec5SDimitry Andric             if (__x_[i] == '%')
56640b57cec5SDimitry Andric                 break;
56650b57cec5SDimitry Andric         if (i == __x_.size())
56660b57cec5SDimitry Andric             break;
56670b57cec5SDimitry Andric         ++i;
56680b57cec5SDimitry Andric         switch (__x_[i])
56690b57cec5SDimitry Andric         {
56700b57cec5SDimitry Andric         case 'm':
56710b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
56720b57cec5SDimitry Andric                 if (__x_[i] == '%')
56730b57cec5SDimitry Andric                     break;
56740b57cec5SDimitry Andric             if (i == __x_.size())
56750b57cec5SDimitry Andric                 break;
56760b57cec5SDimitry Andric             ++i;
56770b57cec5SDimitry Andric             if (__x_[i] == 'd')
56780b57cec5SDimitry Andric                 return time_base::ymd;
56790b57cec5SDimitry Andric             break;
56800b57cec5SDimitry Andric         case 'd':
56810b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
56820b57cec5SDimitry Andric                 if (__x_[i] == '%')
56830b57cec5SDimitry Andric                     break;
56840b57cec5SDimitry Andric             if (i == __x_.size())
56850b57cec5SDimitry Andric                 break;
56860b57cec5SDimitry Andric             ++i;
56870b57cec5SDimitry Andric             if (__x_[i] == 'm')
56880b57cec5SDimitry Andric                 return time_base::ydm;
56890b57cec5SDimitry Andric             break;
56900b57cec5SDimitry Andric         }
56910b57cec5SDimitry Andric         break;
56920b57cec5SDimitry Andric     case 'm':
56930b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
56940b57cec5SDimitry Andric             if (__x_[i] == '%')
56950b57cec5SDimitry Andric                 break;
56960b57cec5SDimitry Andric         if (i == __x_.size())
56970b57cec5SDimitry Andric             break;
56980b57cec5SDimitry Andric         ++i;
56990b57cec5SDimitry Andric         if (__x_[i] == 'd')
57000b57cec5SDimitry Andric         {
57010b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57020b57cec5SDimitry Andric                 if (__x_[i] == '%')
57030b57cec5SDimitry Andric                     break;
57040b57cec5SDimitry Andric             if (i == __x_.size())
57050b57cec5SDimitry Andric                 break;
57060b57cec5SDimitry Andric             ++i;
57070b57cec5SDimitry Andric             if (__x_[i] == 'y' || __x_[i] == 'Y')
57080b57cec5SDimitry Andric                 return time_base::mdy;
57090b57cec5SDimitry Andric             break;
57100b57cec5SDimitry Andric         }
57110b57cec5SDimitry Andric         break;
57120b57cec5SDimitry Andric     case 'd':
57130b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
57140b57cec5SDimitry Andric             if (__x_[i] == '%')
57150b57cec5SDimitry Andric                 break;
57160b57cec5SDimitry Andric         if (i == __x_.size())
57170b57cec5SDimitry Andric             break;
57180b57cec5SDimitry Andric         ++i;
57190b57cec5SDimitry Andric         if (__x_[i] == 'm')
57200b57cec5SDimitry Andric         {
57210b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57220b57cec5SDimitry Andric                 if (__x_[i] == '%')
57230b57cec5SDimitry Andric                     break;
57240b57cec5SDimitry Andric             if (i == __x_.size())
57250b57cec5SDimitry Andric                 break;
57260b57cec5SDimitry Andric             ++i;
57270b57cec5SDimitry Andric             if (__x_[i] == 'y' || __x_[i] == 'Y')
57280b57cec5SDimitry Andric                 return time_base::dmy;
57290b57cec5SDimitry Andric             break;
57300b57cec5SDimitry Andric         }
57310b57cec5SDimitry Andric         break;
57320b57cec5SDimitry Andric     }
57330b57cec5SDimitry Andric     return time_base::no_order;
57340b57cec5SDimitry Andric }
57350b57cec5SDimitry Andric 
5736349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
57370b57cec5SDimitry Andric template <>
57380b57cec5SDimitry Andric time_base::dateorder
57390b57cec5SDimitry Andric __time_get_storage<wchar_t>::__do_date_order() const
57400b57cec5SDimitry Andric {
57410b57cec5SDimitry Andric     unsigned i;
57420b57cec5SDimitry Andric     for (i = 0; i < __x_.size(); ++i)
57430b57cec5SDimitry Andric         if (__x_[i] == L'%')
57440b57cec5SDimitry Andric             break;
57450b57cec5SDimitry Andric     ++i;
57460b57cec5SDimitry Andric     switch (__x_[i])
57470b57cec5SDimitry Andric     {
57480b57cec5SDimitry Andric     case L'y':
57490b57cec5SDimitry Andric     case L'Y':
57500b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
57510b57cec5SDimitry Andric             if (__x_[i] == L'%')
57520b57cec5SDimitry Andric                 break;
57530b57cec5SDimitry Andric         if (i == __x_.size())
57540b57cec5SDimitry Andric             break;
57550b57cec5SDimitry Andric         ++i;
57560b57cec5SDimitry Andric         switch (__x_[i])
57570b57cec5SDimitry Andric         {
57580b57cec5SDimitry Andric         case L'm':
57590b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57600b57cec5SDimitry Andric                 if (__x_[i] == L'%')
57610b57cec5SDimitry Andric                     break;
57620b57cec5SDimitry Andric             if (i == __x_.size())
57630b57cec5SDimitry Andric                 break;
57640b57cec5SDimitry Andric             ++i;
57650b57cec5SDimitry Andric             if (__x_[i] == L'd')
57660b57cec5SDimitry Andric                 return time_base::ymd;
57670b57cec5SDimitry Andric             break;
57680b57cec5SDimitry Andric         case L'd':
57690b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57700b57cec5SDimitry Andric                 if (__x_[i] == L'%')
57710b57cec5SDimitry Andric                     break;
57720b57cec5SDimitry Andric             if (i == __x_.size())
57730b57cec5SDimitry Andric                 break;
57740b57cec5SDimitry Andric             ++i;
57750b57cec5SDimitry Andric             if (__x_[i] == L'm')
57760b57cec5SDimitry Andric                 return time_base::ydm;
57770b57cec5SDimitry Andric             break;
57780b57cec5SDimitry Andric         }
57790b57cec5SDimitry Andric         break;
57800b57cec5SDimitry Andric     case L'm':
57810b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
57820b57cec5SDimitry Andric             if (__x_[i] == L'%')
57830b57cec5SDimitry Andric                 break;
57840b57cec5SDimitry Andric         if (i == __x_.size())
57850b57cec5SDimitry Andric             break;
57860b57cec5SDimitry Andric         ++i;
57870b57cec5SDimitry Andric         if (__x_[i] == L'd')
57880b57cec5SDimitry Andric         {
57890b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57900b57cec5SDimitry Andric                 if (__x_[i] == L'%')
57910b57cec5SDimitry Andric                     break;
57920b57cec5SDimitry Andric             if (i == __x_.size())
57930b57cec5SDimitry Andric                 break;
57940b57cec5SDimitry Andric             ++i;
57950b57cec5SDimitry Andric             if (__x_[i] == L'y' || __x_[i] == L'Y')
57960b57cec5SDimitry Andric                 return time_base::mdy;
57970b57cec5SDimitry Andric             break;
57980b57cec5SDimitry Andric         }
57990b57cec5SDimitry Andric         break;
58000b57cec5SDimitry Andric     case L'd':
58010b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
58020b57cec5SDimitry Andric             if (__x_[i] == L'%')
58030b57cec5SDimitry Andric                 break;
58040b57cec5SDimitry Andric         if (i == __x_.size())
58050b57cec5SDimitry Andric             break;
58060b57cec5SDimitry Andric         ++i;
58070b57cec5SDimitry Andric         if (__x_[i] == L'm')
58080b57cec5SDimitry Andric         {
58090b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
58100b57cec5SDimitry Andric                 if (__x_[i] == L'%')
58110b57cec5SDimitry Andric                     break;
58120b57cec5SDimitry Andric             if (i == __x_.size())
58130b57cec5SDimitry Andric                 break;
58140b57cec5SDimitry Andric             ++i;
58150b57cec5SDimitry Andric             if (__x_[i] == L'y' || __x_[i] == L'Y')
58160b57cec5SDimitry Andric                 return time_base::dmy;
58170b57cec5SDimitry Andric             break;
58180b57cec5SDimitry Andric         }
58190b57cec5SDimitry Andric         break;
58200b57cec5SDimitry Andric     }
58210b57cec5SDimitry Andric     return time_base::no_order;
58220b57cec5SDimitry Andric }
5823349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
58240b57cec5SDimitry Andric 
58250b57cec5SDimitry Andric // time_put
58260b57cec5SDimitry Andric 
58270b57cec5SDimitry Andric __time_put::__time_put(const char* nm)
58280b57cec5SDimitry Andric     : __loc_(newlocale(LC_ALL_MASK, nm, 0))
58290b57cec5SDimitry Andric {
58300b57cec5SDimitry Andric     if (__loc_ == 0)
5831*5f757f3fSDimitry Andric         __throw_runtime_error(("time_put_byname failed to construct for " + string(nm)).c_str());
58320b57cec5SDimitry Andric }
58330b57cec5SDimitry Andric 
58340b57cec5SDimitry Andric __time_put::__time_put(const string& nm)
58350b57cec5SDimitry Andric     : __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0))
58360b57cec5SDimitry Andric {
58370b57cec5SDimitry Andric     if (__loc_ == 0)
5838*5f757f3fSDimitry Andric         __throw_runtime_error(("time_put_byname failed to construct for " + nm).c_str());
58390b57cec5SDimitry Andric }
58400b57cec5SDimitry Andric 
58410b57cec5SDimitry Andric __time_put::~__time_put()
58420b57cec5SDimitry Andric {
58430b57cec5SDimitry Andric     if (__loc_ != _LIBCPP_GET_C_LOCALE)
58440b57cec5SDimitry Andric         freelocale(__loc_);
58450b57cec5SDimitry Andric }
58460b57cec5SDimitry Andric 
58470b57cec5SDimitry Andric void
58480b57cec5SDimitry Andric __time_put::__do_put(char* __nb, char*& __ne, const tm* __tm,
58490b57cec5SDimitry Andric                      char __fmt, char __mod) const
58500b57cec5SDimitry Andric {
58510b57cec5SDimitry Andric     char fmt[] = {'%', __fmt, __mod, 0};
58520b57cec5SDimitry Andric     if (__mod != 0)
58530b57cec5SDimitry Andric         swap(fmt[1], fmt[2]);
58540b57cec5SDimitry Andric     size_t n = strftime_l(__nb, countof(__nb, __ne), fmt, __tm, __loc_);
58550b57cec5SDimitry Andric     __ne = __nb + n;
58560b57cec5SDimitry Andric }
58570b57cec5SDimitry Andric 
5858349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
58590b57cec5SDimitry Andric void
58600b57cec5SDimitry Andric __time_put::__do_put(wchar_t* __wb, wchar_t*& __we, const tm* __tm,
58610b57cec5SDimitry Andric                      char __fmt, char __mod) const
58620b57cec5SDimitry Andric {
58630b57cec5SDimitry Andric     char __nar[100];
58640b57cec5SDimitry Andric     char* __ne = __nar + 100;
58650b57cec5SDimitry Andric     __do_put(__nar, __ne, __tm, __fmt, __mod);
58660b57cec5SDimitry Andric     mbstate_t mb = {0};
58670b57cec5SDimitry Andric     const char* __nb = __nar;
58680b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l(__wb, &__nb, countof(__wb, __we), &mb, __loc_);
58690b57cec5SDimitry Andric     if (j == size_t(-1))
58700b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
58710b57cec5SDimitry Andric     __we = __wb + j;
58720b57cec5SDimitry Andric }
5873349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
58740b57cec5SDimitry Andric 
58750b57cec5SDimitry Andric // moneypunct_byname
58760b57cec5SDimitry Andric 
58770b57cec5SDimitry Andric template <class charT>
58780b57cec5SDimitry Andric static
58790b57cec5SDimitry Andric void
58800b57cec5SDimitry Andric __init_pat(money_base::pattern& pat, basic_string<charT>& __curr_symbol_,
58810b57cec5SDimitry Andric            bool intl, char cs_precedes, char sep_by_space, char sign_posn,
58820b57cec5SDimitry Andric            charT space_char)
58830b57cec5SDimitry Andric {
58840b57cec5SDimitry Andric     const char sign = static_cast<char>(money_base::sign);
58850b57cec5SDimitry Andric     const char space = static_cast<char>(money_base::space);
58860b57cec5SDimitry Andric     const char none = static_cast<char>(money_base::none);
58870b57cec5SDimitry Andric     const char symbol = static_cast<char>(money_base::symbol);
58880b57cec5SDimitry Andric     const char value = static_cast<char>(money_base::value);
58890b57cec5SDimitry Andric     const bool symbol_contains_sep = intl && __curr_symbol_.size() == 4;
58900b57cec5SDimitry Andric 
58910b57cec5SDimitry Andric     // Comments on case branches reflect 'C11 7.11.2.1 The localeconv
58920b57cec5SDimitry Andric     // function'. "Space between sign and symbol or value" means that
58930b57cec5SDimitry Andric     // if the sign is adjacent to the symbol, there's a space between
58940b57cec5SDimitry Andric     // them, and otherwise there's a space between the sign and value.
58950b57cec5SDimitry Andric     //
58960b57cec5SDimitry Andric     // C11's localeconv specifies that the fourth character of an
58970b57cec5SDimitry Andric     // international curr_symbol is used to separate the sign and
58980b57cec5SDimitry Andric     // value when sep_by_space says to do so. C++ can't represent
58990b57cec5SDimitry Andric     // that, so we just use a space.  When sep_by_space says to
59000b57cec5SDimitry Andric     // separate the symbol and value-or-sign with a space, we rearrange the
59010b57cec5SDimitry Andric     // curr_symbol to put its spacing character on the correct side of
59020b57cec5SDimitry Andric     // the symbol.
59030b57cec5SDimitry Andric     //
59040b57cec5SDimitry Andric     // We also need to avoid adding an extra space between the sign
59050b57cec5SDimitry Andric     // and value when the currency symbol is suppressed (by not
59060b57cec5SDimitry Andric     // setting showbase).  We match glibc's strfmon by interpreting
59070b57cec5SDimitry Andric     // sep_by_space==1 as "omit the space when the currency symbol is
59080b57cec5SDimitry Andric     // absent".
59090b57cec5SDimitry Andric     //
59100b57cec5SDimitry Andric     // Users who want to get this right should use ICU instead.
59110b57cec5SDimitry Andric 
59120b57cec5SDimitry Andric     switch (cs_precedes)
59130b57cec5SDimitry Andric     {
59140b57cec5SDimitry Andric     case 0:  // value before curr_symbol
59150b57cec5SDimitry Andric         if (symbol_contains_sep) {
59160b57cec5SDimitry Andric             // Move the separator to before the symbol, to place it
59170b57cec5SDimitry Andric             // between the value and symbol.
59180b57cec5SDimitry Andric             rotate(__curr_symbol_.begin(), __curr_symbol_.begin() + 3,
59190b57cec5SDimitry Andric                    __curr_symbol_.end());
59200b57cec5SDimitry Andric         }
59210b57cec5SDimitry Andric         switch (sign_posn)
59220b57cec5SDimitry Andric         {
59230b57cec5SDimitry Andric         case 0:  // Parentheses surround the quantity and currency symbol.
59240b57cec5SDimitry Andric             pat.field[0] = sign;
59250b57cec5SDimitry Andric             pat.field[1] = value;
59260b57cec5SDimitry Andric             pat.field[2] = none;  // Any space appears in the symbol.
59270b57cec5SDimitry Andric             pat.field[3] = symbol;
59280b57cec5SDimitry Andric             switch (sep_by_space)
59290b57cec5SDimitry Andric             {
59300b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
59310b57cec5SDimitry Andric                 // This case may have changed between C99 and C11;
59320b57cec5SDimitry Andric                 // assume the currency symbol matches the intention.
59330b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
59340b57cec5SDimitry Andric                 // The "sign" is two parentheses, so no space here either.
59350b57cec5SDimitry Andric                 return;
59360b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
59370b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
59380b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
59390b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
59400b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
59410b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
59420b57cec5SDimitry Andric                 }
59430b57cec5SDimitry Andric                 return;
59440b57cec5SDimitry Andric             default:
59450b57cec5SDimitry Andric                 break;
59460b57cec5SDimitry Andric             }
59470b57cec5SDimitry Andric             break;
59480b57cec5SDimitry Andric         case 1:  // The sign string precedes the quantity and currency symbol.
59490b57cec5SDimitry Andric             pat.field[0] = sign;
59500b57cec5SDimitry Andric             pat.field[3] = symbol;
59510b57cec5SDimitry Andric             switch (sep_by_space)
59520b57cec5SDimitry Andric             {
59530b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
59540b57cec5SDimitry Andric                 pat.field[1] = value;
59550b57cec5SDimitry Andric                 pat.field[2] = none;
59560b57cec5SDimitry Andric                 return;
59570b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
59580b57cec5SDimitry Andric                 pat.field[1] = value;
59590b57cec5SDimitry Andric                 pat.field[2] = none;
59600b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
59610b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
59620b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
59630b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
59640b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
59650b57cec5SDimitry Andric                 }
59660b57cec5SDimitry Andric                 return;
59670b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
59680b57cec5SDimitry Andric                 pat.field[1] = space;
59690b57cec5SDimitry Andric                 pat.field[2] = value;
59700b57cec5SDimitry Andric                 if (symbol_contains_sep) {
59710b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
59720b57cec5SDimitry Andric                     // has already appeared after the sign.
59730b57cec5SDimitry Andric                     __curr_symbol_.erase(__curr_symbol_.begin());
59740b57cec5SDimitry Andric                 }
59750b57cec5SDimitry Andric                 return;
59760b57cec5SDimitry Andric             default:
59770b57cec5SDimitry Andric                 break;
59780b57cec5SDimitry Andric             }
59790b57cec5SDimitry Andric             break;
59800b57cec5SDimitry Andric         case 2:  // The sign string succeeds the quantity and currency symbol.
59810b57cec5SDimitry Andric             pat.field[0] = value;
59820b57cec5SDimitry Andric             pat.field[3] = sign;
59830b57cec5SDimitry Andric             switch (sep_by_space)
59840b57cec5SDimitry Andric             {
59850b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
59860b57cec5SDimitry Andric                 pat.field[1] = none;
59870b57cec5SDimitry Andric                 pat.field[2] = symbol;
59880b57cec5SDimitry Andric                 return;
59890b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
59900b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
59910b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
59920b57cec5SDimitry Andric                     // setting pat.field[1]=space so that when
59930b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
59940b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
59950b57cec5SDimitry Andric                 }
59960b57cec5SDimitry Andric                 pat.field[1] = none;
59970b57cec5SDimitry Andric                 pat.field[2] = symbol;
59980b57cec5SDimitry Andric                 return;
59990b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
60000b57cec5SDimitry Andric                 pat.field[1] = symbol;
60010b57cec5SDimitry Andric                 pat.field[2] = space;
60020b57cec5SDimitry Andric                 if (symbol_contains_sep) {
60030b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
60040b57cec5SDimitry Andric                     // should not be removed if showbase is absent.
60050b57cec5SDimitry Andric                     __curr_symbol_.erase(__curr_symbol_.begin());
60060b57cec5SDimitry Andric                 }
60070b57cec5SDimitry Andric                 return;
60080b57cec5SDimitry Andric             default:
60090b57cec5SDimitry Andric                 break;
60100b57cec5SDimitry Andric             }
60110b57cec5SDimitry Andric             break;
60120b57cec5SDimitry Andric         case 3:  // The sign string immediately precedes the currency symbol.
60130b57cec5SDimitry Andric             pat.field[0] = value;
60140b57cec5SDimitry Andric             pat.field[3] = symbol;
60150b57cec5SDimitry Andric             switch (sep_by_space)
60160b57cec5SDimitry Andric             {
60170b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
60180b57cec5SDimitry Andric                 pat.field[1] = none;
60190b57cec5SDimitry Andric                 pat.field[2] = sign;
60200b57cec5SDimitry Andric                 return;
60210b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
60220b57cec5SDimitry Andric                 pat.field[1] = space;
60230b57cec5SDimitry Andric                 pat.field[2] = sign;
60240b57cec5SDimitry Andric                 if (symbol_contains_sep) {
60250b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
60260b57cec5SDimitry Andric                     // has already appeared before the sign.
60270b57cec5SDimitry Andric                     __curr_symbol_.erase(__curr_symbol_.begin());
60280b57cec5SDimitry Andric                 }
60290b57cec5SDimitry Andric                 return;
60300b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
60310b57cec5SDimitry Andric                 pat.field[1] = sign;
60320b57cec5SDimitry Andric                 pat.field[2] = none;
60330b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
60340b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
60350b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
60360b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
60370b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
60380b57cec5SDimitry Andric                 }
60390b57cec5SDimitry Andric                 return;
60400b57cec5SDimitry Andric             default:
60410b57cec5SDimitry Andric                 break;
60420b57cec5SDimitry Andric             }
60430b57cec5SDimitry Andric             break;
60440b57cec5SDimitry Andric         case 4:  // The sign string immediately succeeds the currency symbol.
60450b57cec5SDimitry Andric             pat.field[0] = value;
60460b57cec5SDimitry Andric             pat.field[3] = sign;
60470b57cec5SDimitry Andric             switch (sep_by_space)
60480b57cec5SDimitry Andric             {
60490b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
60500b57cec5SDimitry Andric                 pat.field[1] = none;
60510b57cec5SDimitry Andric                 pat.field[2] = symbol;
60520b57cec5SDimitry Andric                 return;
60530b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
60540b57cec5SDimitry Andric                 pat.field[1] = none;
60550b57cec5SDimitry Andric                 pat.field[2] = symbol;
60560b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
60570b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
60580b57cec5SDimitry Andric                     // setting pat.field[1]=space so that when
60590b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
60600b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
60610b57cec5SDimitry Andric                 }
60620b57cec5SDimitry Andric                 return;
60630b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
60640b57cec5SDimitry Andric                 pat.field[1] = symbol;
60650b57cec5SDimitry Andric                 pat.field[2] = space;
60660b57cec5SDimitry Andric                 if (symbol_contains_sep) {
60670b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
60680b57cec5SDimitry Andric                     // should not disappear when showbase is absent.
60690b57cec5SDimitry Andric                     __curr_symbol_.erase(__curr_symbol_.begin());
60700b57cec5SDimitry Andric                 }
60710b57cec5SDimitry Andric                 return;
60720b57cec5SDimitry Andric             default:
60730b57cec5SDimitry Andric                 break;
60740b57cec5SDimitry Andric             }
60750b57cec5SDimitry Andric             break;
60760b57cec5SDimitry Andric         default:
60770b57cec5SDimitry Andric             break;
60780b57cec5SDimitry Andric         }
60790b57cec5SDimitry Andric         break;
60800b57cec5SDimitry Andric     case 1:  // curr_symbol before value
60810b57cec5SDimitry Andric         switch (sign_posn)
60820b57cec5SDimitry Andric         {
60830b57cec5SDimitry Andric         case 0:  // Parentheses surround the quantity and currency symbol.
60840b57cec5SDimitry Andric             pat.field[0] = sign;
60850b57cec5SDimitry Andric             pat.field[1] = symbol;
60860b57cec5SDimitry Andric             pat.field[2] = none;  // Any space appears in the symbol.
60870b57cec5SDimitry Andric             pat.field[3] = value;
60880b57cec5SDimitry Andric             switch (sep_by_space)
60890b57cec5SDimitry Andric             {
60900b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
60910b57cec5SDimitry Andric                 // This case may have changed between C99 and C11;
60920b57cec5SDimitry Andric                 // assume the currency symbol matches the intention.
60930b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
60940b57cec5SDimitry Andric                 // The "sign" is two parentheses, so no space here either.
60950b57cec5SDimitry Andric                 return;
60960b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
60970b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
60980b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
60990b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
61000b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
61010b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
61020b57cec5SDimitry Andric                 }
61030b57cec5SDimitry Andric                 return;
61040b57cec5SDimitry Andric             default:
61050b57cec5SDimitry Andric                 break;
61060b57cec5SDimitry Andric             }
61070b57cec5SDimitry Andric             break;
61080b57cec5SDimitry Andric         case 1:  // The sign string precedes the quantity and currency symbol.
61090b57cec5SDimitry Andric             pat.field[0] = sign;
61100b57cec5SDimitry Andric             pat.field[3] = value;
61110b57cec5SDimitry Andric             switch (sep_by_space)
61120b57cec5SDimitry Andric             {
61130b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
61140b57cec5SDimitry Andric                 pat.field[1] = symbol;
61150b57cec5SDimitry Andric                 pat.field[2] = none;
61160b57cec5SDimitry Andric                 return;
61170b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
61180b57cec5SDimitry Andric                 pat.field[1] = symbol;
61190b57cec5SDimitry Andric                 pat.field[2] = none;
61200b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
61210b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
61220b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
61230b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
61240b57cec5SDimitry Andric                     __curr_symbol_.push_back(space_char);
61250b57cec5SDimitry Andric                 }
61260b57cec5SDimitry Andric                 return;
61270b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
61280b57cec5SDimitry Andric                 pat.field[1] = space;
61290b57cec5SDimitry Andric                 pat.field[2] = symbol;
61300b57cec5SDimitry Andric                 if (symbol_contains_sep) {
61310b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
61320b57cec5SDimitry Andric                     // has already appeared after the sign.
61330b57cec5SDimitry Andric                     __curr_symbol_.pop_back();
61340b57cec5SDimitry Andric                 }
61350b57cec5SDimitry Andric                 return;
61360b57cec5SDimitry Andric             default:
61370b57cec5SDimitry Andric                 break;
61380b57cec5SDimitry Andric             }
61390b57cec5SDimitry Andric             break;
61400b57cec5SDimitry Andric         case 2:  // The sign string succeeds the quantity and currency symbol.
61410b57cec5SDimitry Andric             pat.field[0] = symbol;
61420b57cec5SDimitry Andric             pat.field[3] = sign;
61430b57cec5SDimitry Andric             switch (sep_by_space)
61440b57cec5SDimitry Andric             {
61450b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
61460b57cec5SDimitry Andric                 pat.field[1] = none;
61470b57cec5SDimitry Andric                 pat.field[2] = value;
61480b57cec5SDimitry Andric                 return;
61490b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
61500b57cec5SDimitry Andric                 pat.field[1] = none;
61510b57cec5SDimitry Andric                 pat.field[2] = value;
61520b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
61530b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
61540b57cec5SDimitry Andric                     // setting pat.field[1]=space so that when
61550b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
61560b57cec5SDimitry Andric                     __curr_symbol_.push_back(space_char);
61570b57cec5SDimitry Andric                 }
61580b57cec5SDimitry Andric                 return;
61590b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
61600b57cec5SDimitry Andric                 pat.field[1] = value;
61610b57cec5SDimitry Andric                 pat.field[2] = space;
61620b57cec5SDimitry Andric                 if (symbol_contains_sep) {
61630b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
61640b57cec5SDimitry Andric                     // will appear before the sign.
61650b57cec5SDimitry Andric                     __curr_symbol_.pop_back();
61660b57cec5SDimitry Andric                 }
61670b57cec5SDimitry Andric                 return;
61680b57cec5SDimitry Andric             default:
61690b57cec5SDimitry Andric                 break;
61700b57cec5SDimitry Andric             }
61710b57cec5SDimitry Andric             break;
61720b57cec5SDimitry Andric         case 3:  // The sign string immediately precedes the currency symbol.
61730b57cec5SDimitry Andric             pat.field[0] = sign;
61740b57cec5SDimitry Andric             pat.field[3] = value;
61750b57cec5SDimitry Andric             switch (sep_by_space)
61760b57cec5SDimitry Andric             {
61770b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
61780b57cec5SDimitry Andric                 pat.field[1] = symbol;
61790b57cec5SDimitry Andric                 pat.field[2] = none;
61800b57cec5SDimitry Andric                 return;
61810b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
61820b57cec5SDimitry Andric                 pat.field[1] = symbol;
61830b57cec5SDimitry Andric                 pat.field[2] = none;
61840b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
61850b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
61860b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
61870b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
61880b57cec5SDimitry Andric                     __curr_symbol_.push_back(space_char);
61890b57cec5SDimitry Andric                 }
61900b57cec5SDimitry Andric                 return;
61910b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
61920b57cec5SDimitry Andric                 pat.field[1] = space;
61930b57cec5SDimitry Andric                 pat.field[2] = symbol;
61940b57cec5SDimitry Andric                 if (symbol_contains_sep) {
61950b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
61960b57cec5SDimitry Andric                     // has already appeared after the sign.
61970b57cec5SDimitry Andric                     __curr_symbol_.pop_back();
61980b57cec5SDimitry Andric                 }
61990b57cec5SDimitry Andric                 return;
62000b57cec5SDimitry Andric             default:
62010b57cec5SDimitry Andric                 break;
62020b57cec5SDimitry Andric             }
62030b57cec5SDimitry Andric             break;
62040b57cec5SDimitry Andric         case 4:  // The sign string immediately succeeds the currency symbol.
62050b57cec5SDimitry Andric             pat.field[0] = symbol;
62060b57cec5SDimitry Andric             pat.field[3] = value;
62070b57cec5SDimitry Andric             switch (sep_by_space)
62080b57cec5SDimitry Andric             {
62090b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
62100b57cec5SDimitry Andric                 pat.field[1] = sign;
62110b57cec5SDimitry Andric                 pat.field[2] = none;
62120b57cec5SDimitry Andric                 return;
62130b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
62140b57cec5SDimitry Andric                 pat.field[1] = sign;
62150b57cec5SDimitry Andric                 pat.field[2] = space;
62160b57cec5SDimitry Andric                 if (symbol_contains_sep) {
62170b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
62180b57cec5SDimitry Andric                     // should not disappear when showbase is absent.
62190b57cec5SDimitry Andric                     __curr_symbol_.pop_back();
62200b57cec5SDimitry Andric                 }
62210b57cec5SDimitry Andric                 return;
62220b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
62230b57cec5SDimitry Andric                 pat.field[1] = none;
62240b57cec5SDimitry Andric                 pat.field[2] = sign;
62250b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
62260b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
62270b57cec5SDimitry Andric                     // setting pat.field[1]=space so that when
62280b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
62290b57cec5SDimitry Andric                     __curr_symbol_.push_back(space_char);
62300b57cec5SDimitry Andric                 }
62310b57cec5SDimitry Andric                 return;
62320b57cec5SDimitry Andric            default:
62330b57cec5SDimitry Andric                 break;
62340b57cec5SDimitry Andric             }
62350b57cec5SDimitry Andric             break;
62360b57cec5SDimitry Andric         default:
62370b57cec5SDimitry Andric             break;
62380b57cec5SDimitry Andric         }
62390b57cec5SDimitry Andric         break;
62400b57cec5SDimitry Andric     default:
62410b57cec5SDimitry Andric         break;
62420b57cec5SDimitry Andric     }
62430b57cec5SDimitry Andric     pat.field[0] = symbol;
62440b57cec5SDimitry Andric     pat.field[1] = sign;
62450b57cec5SDimitry Andric     pat.field[2] = none;
62460b57cec5SDimitry Andric     pat.field[3] = value;
62470b57cec5SDimitry Andric }
62480b57cec5SDimitry Andric 
62490b57cec5SDimitry Andric template<>
62500b57cec5SDimitry Andric void
62510b57cec5SDimitry Andric moneypunct_byname<char, false>::init(const char* nm)
62520b57cec5SDimitry Andric {
62530b57cec5SDimitry Andric     typedef moneypunct<char, false> base;
62540b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
62550b57cec5SDimitry Andric     if (!loc)
6256*5f757f3fSDimitry Andric         __throw_runtime_error(("moneypunct_byname failed to construct for " + string(nm)).c_str());
62570b57cec5SDimitry Andric 
62580b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
62590b57cec5SDimitry Andric     if (!checked_string_to_char_convert(__decimal_point_,
62600b57cec5SDimitry Andric                                         lc->mon_decimal_point,
62610b57cec5SDimitry Andric                                         loc.get()))
62620b57cec5SDimitry Andric       __decimal_point_ = base::do_decimal_point();
62630b57cec5SDimitry Andric     if (!checked_string_to_char_convert(__thousands_sep_,
62640b57cec5SDimitry Andric                                         lc->mon_thousands_sep,
62650b57cec5SDimitry Andric                                         loc.get()))
62660b57cec5SDimitry Andric       __thousands_sep_ = base::do_thousands_sep();
62670b57cec5SDimitry Andric 
62680b57cec5SDimitry Andric     __grouping_ = lc->mon_grouping;
62690b57cec5SDimitry Andric     __curr_symbol_ = lc->currency_symbol;
62700b57cec5SDimitry Andric     if (lc->frac_digits != CHAR_MAX)
62710b57cec5SDimitry Andric         __frac_digits_ = lc->frac_digits;
62720b57cec5SDimitry Andric     else
62730b57cec5SDimitry Andric         __frac_digits_ = base::do_frac_digits();
62740b57cec5SDimitry Andric     if (lc->p_sign_posn == 0)
62750b57cec5SDimitry Andric         __positive_sign_ = "()";
62760b57cec5SDimitry Andric     else
62770b57cec5SDimitry Andric         __positive_sign_ = lc->positive_sign;
62780b57cec5SDimitry Andric     if (lc->n_sign_posn == 0)
62790b57cec5SDimitry Andric         __negative_sign_ = "()";
62800b57cec5SDimitry Andric     else
62810b57cec5SDimitry Andric         __negative_sign_ = lc->negative_sign;
62820b57cec5SDimitry Andric     // Assume the positive and negative formats will want spaces in
62830b57cec5SDimitry Andric     // the same places in curr_symbol since there's no way to
62840b57cec5SDimitry Andric     // represent anything else.
62850b57cec5SDimitry Andric     string_type __dummy_curr_symbol = __curr_symbol_;
62860b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, false,
62870b57cec5SDimitry Andric                lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, ' ');
62880b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, false,
62890b57cec5SDimitry Andric                lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, ' ');
62900b57cec5SDimitry Andric }
62910b57cec5SDimitry Andric 
62920b57cec5SDimitry Andric template<>
62930b57cec5SDimitry Andric void
62940b57cec5SDimitry Andric moneypunct_byname<char, true>::init(const char* nm)
62950b57cec5SDimitry Andric {
62960b57cec5SDimitry Andric     typedef moneypunct<char, true> base;
62970b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
62980b57cec5SDimitry Andric     if (!loc)
6299*5f757f3fSDimitry Andric         __throw_runtime_error(("moneypunct_byname failed to construct for " + string(nm)).c_str());
63000b57cec5SDimitry Andric 
63010b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
63020b57cec5SDimitry Andric     if (!checked_string_to_char_convert(__decimal_point_,
63030b57cec5SDimitry Andric                                         lc->mon_decimal_point,
63040b57cec5SDimitry Andric                                         loc.get()))
63050b57cec5SDimitry Andric       __decimal_point_ = base::do_decimal_point();
63060b57cec5SDimitry Andric     if (!checked_string_to_char_convert(__thousands_sep_,
63070b57cec5SDimitry Andric                                         lc->mon_thousands_sep,
63080b57cec5SDimitry Andric                                         loc.get()))
63090b57cec5SDimitry Andric       __thousands_sep_ = base::do_thousands_sep();
63100b57cec5SDimitry Andric     __grouping_ = lc->mon_grouping;
63110b57cec5SDimitry Andric     __curr_symbol_ = lc->int_curr_symbol;
63120b57cec5SDimitry Andric     if (lc->int_frac_digits != CHAR_MAX)
63130b57cec5SDimitry Andric         __frac_digits_ = lc->int_frac_digits;
63140b57cec5SDimitry Andric     else
63150b57cec5SDimitry Andric         __frac_digits_ = base::do_frac_digits();
63160b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
63170b57cec5SDimitry Andric     if (lc->p_sign_posn == 0)
63180b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
63190b57cec5SDimitry Andric     if (lc->int_p_sign_posn == 0)
63200b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
63210b57cec5SDimitry Andric         __positive_sign_ = "()";
63220b57cec5SDimitry Andric     else
63230b57cec5SDimitry Andric         __positive_sign_ = lc->positive_sign;
63240b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
63250b57cec5SDimitry Andric     if(lc->n_sign_posn == 0)
63260b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
63270b57cec5SDimitry Andric     if (lc->int_n_sign_posn == 0)
63280b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
63290b57cec5SDimitry Andric         __negative_sign_ = "()";
63300b57cec5SDimitry Andric     else
63310b57cec5SDimitry Andric         __negative_sign_ = lc->negative_sign;
63320b57cec5SDimitry Andric     // Assume the positive and negative formats will want spaces in
63330b57cec5SDimitry Andric     // the same places in curr_symbol since there's no way to
63340b57cec5SDimitry Andric     // represent anything else.
63350b57cec5SDimitry Andric     string_type __dummy_curr_symbol = __curr_symbol_;
63360b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
63370b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, true,
63380b57cec5SDimitry Andric                lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, ' ');
63390b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, true,
63400b57cec5SDimitry Andric                lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, ' ');
63410b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
63420b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, true,
63430b57cec5SDimitry Andric                lc->int_p_cs_precedes, lc->int_p_sep_by_space,
63440b57cec5SDimitry Andric                lc->int_p_sign_posn, ' ');
63450b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, true,
63460b57cec5SDimitry Andric                lc->int_n_cs_precedes, lc->int_n_sep_by_space,
63470b57cec5SDimitry Andric                lc->int_n_sign_posn, ' ');
63480b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
63490b57cec5SDimitry Andric }
63500b57cec5SDimitry Andric 
6351349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
63520b57cec5SDimitry Andric template<>
63530b57cec5SDimitry Andric void
63540b57cec5SDimitry Andric moneypunct_byname<wchar_t, false>::init(const char* nm)
63550b57cec5SDimitry Andric {
63560b57cec5SDimitry Andric     typedef moneypunct<wchar_t, false> base;
63570b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
63580b57cec5SDimitry Andric     if (!loc)
6359*5f757f3fSDimitry Andric         __throw_runtime_error(("moneypunct_byname failed to construct for " + string(nm)).c_str());
63600b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
63610b57cec5SDimitry Andric     if (!checked_string_to_wchar_convert(__decimal_point_,
63620b57cec5SDimitry Andric                                          lc->mon_decimal_point,
63630b57cec5SDimitry Andric                                          loc.get()))
63640b57cec5SDimitry Andric       __decimal_point_ = base::do_decimal_point();
63650b57cec5SDimitry Andric     if (!checked_string_to_wchar_convert(__thousands_sep_,
63660b57cec5SDimitry Andric                                          lc->mon_thousands_sep,
63670b57cec5SDimitry Andric                                          loc.get()))
63680b57cec5SDimitry Andric       __thousands_sep_ = base::do_thousands_sep();
63690b57cec5SDimitry Andric     __grouping_ = lc->mon_grouping;
63700b57cec5SDimitry Andric     wchar_t wbuf[100];
63710b57cec5SDimitry Andric     mbstate_t mb = {0};
63720b57cec5SDimitry Andric     const char* bb = lc->currency_symbol;
63730b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
63740b57cec5SDimitry Andric     if (j == size_t(-1))
63750b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
63760b57cec5SDimitry Andric     wchar_t* wbe = wbuf + j;
63770b57cec5SDimitry Andric     __curr_symbol_.assign(wbuf, wbe);
63780b57cec5SDimitry Andric     if (lc->frac_digits != CHAR_MAX)
63790b57cec5SDimitry Andric         __frac_digits_ = lc->frac_digits;
63800b57cec5SDimitry Andric     else
63810b57cec5SDimitry Andric         __frac_digits_ = base::do_frac_digits();
63820b57cec5SDimitry Andric     if (lc->p_sign_posn == 0)
63830b57cec5SDimitry Andric         __positive_sign_ = L"()";
63840b57cec5SDimitry Andric     else
63850b57cec5SDimitry Andric     {
63860b57cec5SDimitry Andric         mb = mbstate_t();
63870b57cec5SDimitry Andric         bb = lc->positive_sign;
63880b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
63890b57cec5SDimitry Andric         if (j == size_t(-1))
63900b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
63910b57cec5SDimitry Andric         wbe = wbuf + j;
63920b57cec5SDimitry Andric         __positive_sign_.assign(wbuf, wbe);
63930b57cec5SDimitry Andric     }
63940b57cec5SDimitry Andric     if (lc->n_sign_posn == 0)
63950b57cec5SDimitry Andric         __negative_sign_ = L"()";
63960b57cec5SDimitry Andric     else
63970b57cec5SDimitry Andric     {
63980b57cec5SDimitry Andric         mb = mbstate_t();
63990b57cec5SDimitry Andric         bb = lc->negative_sign;
64000b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
64010b57cec5SDimitry Andric         if (j == size_t(-1))
64020b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
64030b57cec5SDimitry Andric         wbe = wbuf + j;
64040b57cec5SDimitry Andric         __negative_sign_.assign(wbuf, wbe);
64050b57cec5SDimitry Andric     }
64060b57cec5SDimitry Andric     // Assume the positive and negative formats will want spaces in
64070b57cec5SDimitry Andric     // the same places in curr_symbol since there's no way to
64080b57cec5SDimitry Andric     // represent anything else.
64090b57cec5SDimitry Andric     string_type __dummy_curr_symbol = __curr_symbol_;
64100b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, false,
64110b57cec5SDimitry Andric                lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, L' ');
64120b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, false,
64130b57cec5SDimitry Andric                lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, L' ');
64140b57cec5SDimitry Andric }
64150b57cec5SDimitry Andric 
64160b57cec5SDimitry Andric template<>
64170b57cec5SDimitry Andric void
64180b57cec5SDimitry Andric moneypunct_byname<wchar_t, true>::init(const char* nm)
64190b57cec5SDimitry Andric {
64200b57cec5SDimitry Andric     typedef moneypunct<wchar_t, true> base;
64210b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
64220b57cec5SDimitry Andric     if (!loc)
6423*5f757f3fSDimitry Andric         __throw_runtime_error(("moneypunct_byname failed to construct for " + string(nm)).c_str());
64240b57cec5SDimitry Andric 
64250b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
64260b57cec5SDimitry Andric     if (!checked_string_to_wchar_convert(__decimal_point_,
64270b57cec5SDimitry Andric                                          lc->mon_decimal_point,
64280b57cec5SDimitry Andric                                          loc.get()))
64290b57cec5SDimitry Andric       __decimal_point_ = base::do_decimal_point();
64300b57cec5SDimitry Andric     if (!checked_string_to_wchar_convert(__thousands_sep_,
64310b57cec5SDimitry Andric                                          lc->mon_thousands_sep,
64320b57cec5SDimitry Andric                                          loc.get()))
64330b57cec5SDimitry Andric       __thousands_sep_ = base::do_thousands_sep();
64340b57cec5SDimitry Andric     __grouping_ = lc->mon_grouping;
64350b57cec5SDimitry Andric     wchar_t wbuf[100];
64360b57cec5SDimitry Andric     mbstate_t mb = {0};
64370b57cec5SDimitry Andric     const char* bb = lc->int_curr_symbol;
64380b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
64390b57cec5SDimitry Andric     if (j == size_t(-1))
64400b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
64410b57cec5SDimitry Andric     wchar_t* wbe = wbuf + j;
64420b57cec5SDimitry Andric     __curr_symbol_.assign(wbuf, wbe);
64430b57cec5SDimitry Andric     if (lc->int_frac_digits != CHAR_MAX)
64440b57cec5SDimitry Andric         __frac_digits_ = lc->int_frac_digits;
64450b57cec5SDimitry Andric     else
64460b57cec5SDimitry Andric         __frac_digits_ = base::do_frac_digits();
64470b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
64480b57cec5SDimitry Andric     if (lc->p_sign_posn == 0)
64490b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
64500b57cec5SDimitry Andric     if (lc->int_p_sign_posn == 0)
64510b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
64520b57cec5SDimitry Andric         __positive_sign_ = L"()";
64530b57cec5SDimitry Andric     else
64540b57cec5SDimitry Andric     {
64550b57cec5SDimitry Andric         mb = mbstate_t();
64560b57cec5SDimitry Andric         bb = lc->positive_sign;
64570b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
64580b57cec5SDimitry Andric         if (j == size_t(-1))
64590b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
64600b57cec5SDimitry Andric         wbe = wbuf + j;
64610b57cec5SDimitry Andric         __positive_sign_.assign(wbuf, wbe);
64620b57cec5SDimitry Andric     }
64630b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
64640b57cec5SDimitry Andric     if (lc->n_sign_posn == 0)
64650b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
64660b57cec5SDimitry Andric     if (lc->int_n_sign_posn == 0)
64670b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
64680b57cec5SDimitry Andric         __negative_sign_ = L"()";
64690b57cec5SDimitry Andric     else
64700b57cec5SDimitry Andric     {
64710b57cec5SDimitry Andric         mb = mbstate_t();
64720b57cec5SDimitry Andric         bb = lc->negative_sign;
64730b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
64740b57cec5SDimitry Andric         if (j == size_t(-1))
64750b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
64760b57cec5SDimitry Andric         wbe = wbuf + j;
64770b57cec5SDimitry Andric         __negative_sign_.assign(wbuf, wbe);
64780b57cec5SDimitry Andric     }
64790b57cec5SDimitry Andric     // Assume the positive and negative formats will want spaces in
64800b57cec5SDimitry Andric     // the same places in curr_symbol since there's no way to
64810b57cec5SDimitry Andric     // represent anything else.
64820b57cec5SDimitry Andric     string_type __dummy_curr_symbol = __curr_symbol_;
64830b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
64840b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, true,
64850b57cec5SDimitry Andric                lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, L' ');
64860b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, true,
64870b57cec5SDimitry Andric                lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, L' ');
64880b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
64890b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, true,
64900b57cec5SDimitry Andric                lc->int_p_cs_precedes, lc->int_p_sep_by_space,
64910b57cec5SDimitry Andric                lc->int_p_sign_posn, L' ');
64920b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, true,
64930b57cec5SDimitry Andric                lc->int_n_cs_precedes, lc->int_n_sep_by_space,
64940b57cec5SDimitry Andric                lc->int_n_sign_posn, L' ');
64950b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
64960b57cec5SDimitry Andric }
6497349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
64980b57cec5SDimitry Andric 
64990b57cec5SDimitry Andric void __do_nothing(void*) {}
65000b57cec5SDimitry Andric 
65010b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<char>;
6502349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<wchar_t>;)
65030b57cec5SDimitry Andric 
65040b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<char>;
6505349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<wchar_t>;)
65060b57cec5SDimitry Andric 
65070b57cec5SDimitry Andric                            template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<char>;
6508349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<wchar_t>;)
65090b57cec5SDimitry Andric 
65100b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<char>;
6511349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<wchar_t>;)
65120b57cec5SDimitry Andric 
65130b57cec5SDimitry Andric                            template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<char>;
6514349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<wchar_t>;)
65150b57cec5SDimitry Andric 
65160b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<char>;
6517349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<wchar_t>;)
65180b57cec5SDimitry Andric 
65190b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<char>;
6520349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<wchar_t>;)
65210b57cec5SDimitry Andric 
65220b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<char>;
6523349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<wchar_t>;)
65240b57cec5SDimitry Andric 
65250b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<char>;
6526349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<wchar_t>;)
65270b57cec5SDimitry Andric 
65280b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, false>;
65290b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, true>;
6530349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, false>;)
6531349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, true>;)
65320b57cec5SDimitry Andric 
65330b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, false>;
65340b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, true>;
6535349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, false>;)
6536349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, true>;)
65370b57cec5SDimitry Andric 
65380b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<char>;
6539349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<wchar_t>;)
65400b57cec5SDimitry Andric 
65410b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<char>;
6542349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<wchar_t>;)
65430b57cec5SDimitry Andric 
65440b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<char>;
6545349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<wchar_t>;)
65460b57cec5SDimitry Andric 
65470b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<char>;
6548349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<wchar_t>;)
65490b57cec5SDimitry Andric 
65500b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<char>;
6551349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<wchar_t>;)
65520b57cec5SDimitry Andric 
65530b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<char>;
6554349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<wchar_t>;)
65550b57cec5SDimitry Andric 
65560b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char, char, mbstate_t>;
6557349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<wchar_t, char, mbstate_t>;)
6558e8d8bef9SDimitry Andric template class _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char16_t, char, mbstate_t>;
6559e8d8bef9SDimitry Andric template class _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char32_t, char, mbstate_t>;
6560fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
6561e8d8bef9SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char16_t, char8_t, mbstate_t>;
6562e8d8bef9SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char32_t, char8_t, mbstate_t>;
6563e8d8bef9SDimitry Andric #endif
65640b57cec5SDimitry Andric 
65650b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
656681ad6265SDimitry Andric 
656781ad6265SDimitry Andric _LIBCPP_POP_MACROS
6568