xref: /freebsd/contrib/llvm-project/libcxx/src/locale.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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 
90b57cec5SDimitry Andric // On Solaris, we need to define something to make the C99 parts of localeconv
100b57cec5SDimitry Andric // visible.
110b57cec5SDimitry Andric #ifdef __sun__
120b57cec5SDimitry Andric #define _LCONV_C99
130b57cec5SDimitry Andric #endif
140b57cec5SDimitry Andric 
1581ad6265SDimitry Andric #include <__utility/unreachable.h>
1681ad6265SDimitry Andric #include <algorithm>
1781ad6265SDimitry Andric #include <clocale>
1881ad6265SDimitry Andric #include <codecvt>
1981ad6265SDimitry Andric #include <cstdio>
2081ad6265SDimitry Andric #include <cstdlib>
2181ad6265SDimitry Andric #include <cstring>
2281ad6265SDimitry Andric #include <locale>
2381ad6265SDimitry Andric #include <string>
2481ad6265SDimitry Andric #include <type_traits>
2581ad6265SDimitry Andric #include <typeinfo>
2681ad6265SDimitry Andric #include <vector>
27349cc55cSDimitry Andric 
28349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2981ad6265SDimitry Andric #   include <cwctype>
30349cc55cSDimitry Andric #endif
31349cc55cSDimitry Andric 
32349cc55cSDimitry Andric #if defined(_AIX)
33349cc55cSDimitry Andric #   include <sys/localedef.h> // for __lc_ctype_ptr
34349cc55cSDimitry Andric #endif
35349cc55cSDimitry Andric 
360b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT)
370b57cec5SDimitry Andric #   define _CTYPE_DISABLE_MACROS
380b57cec5SDimitry Andric #endif
39349cc55cSDimitry Andric 
400b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
41d409305fSDimitry Andric #   include "__support/win32/locale_win32.h"
42e8d8bef9SDimitry Andric #elif !defined(__BIONIC__) && !defined(__NuttX__)
430b57cec5SDimitry Andric #   include <langinfo.h>
440b57cec5SDimitry Andric #endif
45349cc55cSDimitry Andric 
460b57cec5SDimitry Andric #include "include/atomic_support.h"
47fe6060f1SDimitry Andric #include "include/sso_allocator.h"
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric // On Linux, wint_t and wchar_t have different signed-ness, and this causes
500b57cec5SDimitry Andric // lots of noise in the build log, but no bugs that I know of.
5181ad6265SDimitry Andric _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wsign-conversion")
5281ad6265SDimitry Andric 
5381ad6265SDimitry Andric _LIBCPP_PUSH_MACROS
5481ad6265SDimitry Andric #include <__undef_macros>
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric struct __libcpp_unique_locale {
590b57cec5SDimitry Andric   __libcpp_unique_locale(const char* nm) : __loc_(newlocale(LC_ALL_MASK, nm, 0)) {}
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   ~__libcpp_unique_locale() {
620b57cec5SDimitry Andric     if (__loc_)
630b57cec5SDimitry Andric       freelocale(__loc_);
640b57cec5SDimitry Andric   }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   explicit operator bool() const { return __loc_; }
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   locale_t& get() { return __loc_; }
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   locale_t __loc_;
710b57cec5SDimitry Andric private:
720b57cec5SDimitry Andric   __libcpp_unique_locale(__libcpp_unique_locale const&);
730b57cec5SDimitry Andric   __libcpp_unique_locale& operator=(__libcpp_unique_locale const&);
740b57cec5SDimitry Andric };
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric #ifdef __cloc_defined
770b57cec5SDimitry Andric locale_t __cloc() {
780b57cec5SDimitry Andric   // In theory this could create a race condition. In practice
790b57cec5SDimitry Andric   // the race condition is non-fatal since it will just create
800b57cec5SDimitry Andric   // a little resource leak. Better approach would be appreciated.
810b57cec5SDimitry Andric   static locale_t result = newlocale(LC_ALL_MASK, "C", 0);
820b57cec5SDimitry Andric   return result;
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric #endif // __cloc_defined
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric namespace {
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric struct release
890b57cec5SDimitry Andric {
900b57cec5SDimitry Andric     void operator()(locale::facet* p) {p->__release_shared();}
910b57cec5SDimitry Andric };
920b57cec5SDimitry Andric 
93349cc55cSDimitry Andric template <class T, class ...Args>
94349cc55cSDimitry Andric T& make(Args ...args)
950b57cec5SDimitry Andric {
960b57cec5SDimitry Andric     static typename aligned_storage<sizeof(T)>::type buf;
97349cc55cSDimitry Andric     auto *obj = ::new (&buf) T(args...);
980b57cec5SDimitry Andric     return *obj;
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric template <typename T, size_t N>
1020b57cec5SDimitry Andric inline
1030b57cec5SDimitry Andric _LIBCPP_CONSTEXPR
1040b57cec5SDimitry Andric size_t
1050b57cec5SDimitry Andric countof(const T (&)[N])
1060b57cec5SDimitry Andric {
1070b57cec5SDimitry Andric     return N;
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric template <typename T>
1110b57cec5SDimitry Andric inline
1120b57cec5SDimitry Andric _LIBCPP_CONSTEXPR
1130b57cec5SDimitry Andric size_t
1140b57cec5SDimitry Andric countof(const T * const begin, const T * const end)
1150b57cec5SDimitry Andric {
1160b57cec5SDimitry Andric     return static_cast<size_t>(end - begin);
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric _LIBCPP_NORETURN static void __throw_runtime_error(const string &msg)
1200b57cec5SDimitry Andric {
1210b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
1220b57cec5SDimitry Andric     throw runtime_error(msg);
1230b57cec5SDimitry Andric #else
1240b57cec5SDimitry Andric     (void)msg;
1250b57cec5SDimitry Andric     _VSTD::abort();
1260b57cec5SDimitry Andric #endif
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric const locale::category locale::none;
1320b57cec5SDimitry Andric const locale::category locale::collate;
1330b57cec5SDimitry Andric const locale::category locale::ctype;
1340b57cec5SDimitry Andric const locale::category locale::monetary;
1350b57cec5SDimitry Andric const locale::category locale::numeric;
1360b57cec5SDimitry Andric const locale::category locale::time;
1370b57cec5SDimitry Andric const locale::category locale::messages;
1380b57cec5SDimitry Andric const locale::category locale::all;
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric class _LIBCPP_HIDDEN locale::__imp
1410b57cec5SDimitry Andric     : public facet
1420b57cec5SDimitry Andric {
143e8d8bef9SDimitry Andric     enum {N = 30};
1440b57cec5SDimitry Andric     vector<facet*, __sso_allocator<facet*, N> > facets_;
1450b57cec5SDimitry Andric     string         name_;
1460b57cec5SDimitry Andric public:
1470b57cec5SDimitry Andric     explicit __imp(size_t refs = 0);
1480b57cec5SDimitry Andric     explicit __imp(const string& name, size_t refs = 0);
1490b57cec5SDimitry Andric     __imp(const __imp&);
1500b57cec5SDimitry Andric     __imp(const __imp&, const string&, locale::category c);
1510b57cec5SDimitry Andric     __imp(const __imp& other, const __imp& one, locale::category c);
1520b57cec5SDimitry Andric     __imp(const __imp&, facet* f, long id);
1530b57cec5SDimitry Andric     ~__imp();
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric     const string& name() const {return name_;}
1560b57cec5SDimitry Andric     bool has_facet(long id) const
1570b57cec5SDimitry Andric         {return static_cast<size_t>(id) < facets_.size() && facets_[static_cast<size_t>(id)];}
1580b57cec5SDimitry Andric     const locale::facet* use_facet(long id) const;
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric     static const locale& make_classic();
1610b57cec5SDimitry Andric     static       locale& make_global();
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();
1740b57cec5SDimitry Andric     install(&make<_VSTD::collate<char> >(1u));
175349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1760b57cec5SDimitry Andric     install(&make<_VSTD::collate<wchar_t> >(1u));
177349cc55cSDimitry Andric #endif
1780b57cec5SDimitry Andric     install(&make<_VSTD::ctype<char> >(nullptr, false, 1u));
179349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1800b57cec5SDimitry Andric     install(&make<_VSTD::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
2280b57cec5SDimitry Andric     install(&make<_VSTD::messages<char> >(1u));
229349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2300b57cec5SDimitry Andric     install(&make<_VSTD::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 {
2390b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
2400b57cec5SDimitry Andric     try
2410b57cec5SDimitry Andric     {
2420b57cec5SDimitry Andric #endif // _LIBCPP_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
2890b57cec5SDimitry Andric #ifndef _LIBCPP_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     }
2980b57cec5SDimitry Andric #endif // _LIBCPP_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)
3120b57cec5SDimitry Andric     : facets_(N),
3130b57cec5SDimitry Andric       name_("*")
3140b57cec5SDimitry Andric {
3150b57cec5SDimitry Andric     facets_ = other.facets_;
3160b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
3170b57cec5SDimitry Andric         if (facets_[i])
3180b57cec5SDimitry Andric             facets_[i]->__add_shared();
3190b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
3200b57cec5SDimitry Andric     try
3210b57cec5SDimitry Andric     {
3220b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS
3230b57cec5SDimitry Andric         if (c & locale::collate)
3240b57cec5SDimitry Andric         {
3250b57cec5SDimitry Andric             install(new collate_byname<char>(name));
326349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3270b57cec5SDimitry Andric             install(new collate_byname<wchar_t>(name));
328349cc55cSDimitry Andric #endif
3290b57cec5SDimitry Andric         }
3300b57cec5SDimitry Andric         if (c & locale::ctype)
3310b57cec5SDimitry Andric         {
3320b57cec5SDimitry Andric             install(new ctype_byname<char>(name));
333349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3340b57cec5SDimitry Andric             install(new ctype_byname<wchar_t>(name));
335349cc55cSDimitry Andric #endif
3360b57cec5SDimitry Andric             install(new codecvt_byname<char, char, mbstate_t>(name));
337349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3380b57cec5SDimitry Andric             install(new codecvt_byname<wchar_t, char, mbstate_t>(name));
339349cc55cSDimitry Andric #endif
340e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3410b57cec5SDimitry Andric             install(new codecvt_byname<char16_t, char, mbstate_t>(name));
3420b57cec5SDimitry Andric             install(new codecvt_byname<char32_t, char, mbstate_t>(name));
343e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
344fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
345e8d8bef9SDimitry Andric             install(new codecvt_byname<char16_t, char8_t, mbstate_t>(name));
346e8d8bef9SDimitry Andric             install(new codecvt_byname<char32_t, char8_t, mbstate_t>(name));
347e8d8bef9SDimitry Andric #endif
3480b57cec5SDimitry Andric         }
3490b57cec5SDimitry Andric         if (c & locale::monetary)
3500b57cec5SDimitry Andric         {
3510b57cec5SDimitry Andric             install(new moneypunct_byname<char, false>(name));
3520b57cec5SDimitry Andric             install(new moneypunct_byname<char, true>(name));
353349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3540b57cec5SDimitry Andric             install(new moneypunct_byname<wchar_t, false>(name));
3550b57cec5SDimitry Andric             install(new moneypunct_byname<wchar_t, true>(name));
356349cc55cSDimitry Andric #endif
3570b57cec5SDimitry Andric         }
3580b57cec5SDimitry Andric         if (c & locale::numeric)
3590b57cec5SDimitry Andric         {
3600b57cec5SDimitry Andric             install(new numpunct_byname<char>(name));
361349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3620b57cec5SDimitry Andric             install(new numpunct_byname<wchar_t>(name));
363349cc55cSDimitry Andric #endif
3640b57cec5SDimitry Andric         }
3650b57cec5SDimitry Andric         if (c & locale::time)
3660b57cec5SDimitry Andric         {
3670b57cec5SDimitry Andric             install(new time_get_byname<char>(name));
368349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3690b57cec5SDimitry Andric             install(new time_get_byname<wchar_t>(name));
370349cc55cSDimitry Andric #endif
3710b57cec5SDimitry Andric             install(new time_put_byname<char>(name));
372349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3730b57cec5SDimitry Andric             install(new time_put_byname<wchar_t>(name));
374349cc55cSDimitry Andric #endif
3750b57cec5SDimitry Andric         }
3760b57cec5SDimitry Andric         if (c & locale::messages)
3770b57cec5SDimitry Andric         {
3780b57cec5SDimitry Andric             install(new messages_byname<char>(name));
379349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3800b57cec5SDimitry Andric             install(new messages_byname<wchar_t>(name));
381349cc55cSDimitry Andric #endif
3820b57cec5SDimitry Andric         }
3830b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
3840b57cec5SDimitry Andric     }
3850b57cec5SDimitry Andric     catch (...)
3860b57cec5SDimitry Andric     {
3870b57cec5SDimitry Andric         for (unsigned i = 0; i < facets_.size(); ++i)
3880b57cec5SDimitry Andric             if (facets_[i])
3890b57cec5SDimitry Andric                 facets_[i]->__release_shared();
3900b57cec5SDimitry Andric         throw;
3910b57cec5SDimitry Andric     }
3920b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS
3930b57cec5SDimitry Andric }
3940b57cec5SDimitry Andric 
3950b57cec5SDimitry Andric template<class F>
3960b57cec5SDimitry Andric inline
3970b57cec5SDimitry Andric void
3980b57cec5SDimitry Andric locale::__imp::install_from(const locale::__imp& one)
3990b57cec5SDimitry Andric {
4000b57cec5SDimitry Andric     long id = F::id.__get();
4010b57cec5SDimitry Andric     install(const_cast<F*>(static_cast<const F*>(one.use_facet(id))), id);
4020b57cec5SDimitry Andric }
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric locale::__imp::__imp(const __imp& other, const __imp& one, locale::category c)
4050b57cec5SDimitry Andric     : facets_(N),
4060b57cec5SDimitry Andric       name_("*")
4070b57cec5SDimitry Andric {
4080b57cec5SDimitry Andric     facets_ = other.facets_;
4090b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
4100b57cec5SDimitry Andric         if (facets_[i])
4110b57cec5SDimitry Andric             facets_[i]->__add_shared();
4120b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
4130b57cec5SDimitry Andric     try
4140b57cec5SDimitry Andric     {
4150b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS
4160b57cec5SDimitry Andric         if (c & locale::collate)
4170b57cec5SDimitry Andric         {
4180b57cec5SDimitry Andric             install_from<_VSTD::collate<char> >(one);
419349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4200b57cec5SDimitry Andric             install_from<_VSTD::collate<wchar_t> >(one);
421349cc55cSDimitry Andric #endif
4220b57cec5SDimitry Andric         }
4230b57cec5SDimitry Andric         if (c & locale::ctype)
4240b57cec5SDimitry Andric         {
4250b57cec5SDimitry Andric             install_from<_VSTD::ctype<char> >(one);
426349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4270b57cec5SDimitry Andric             install_from<_VSTD::ctype<wchar_t> >(one);
428349cc55cSDimitry Andric #endif
4290b57cec5SDimitry Andric             install_from<_VSTD::codecvt<char, char, mbstate_t> >(one);
430e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
4310b57cec5SDimitry Andric             install_from<_VSTD::codecvt<char16_t, char, mbstate_t> >(one);
4320b57cec5SDimitry Andric             install_from<_VSTD::codecvt<char32_t, char, mbstate_t> >(one);
433e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
434fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
435e8d8bef9SDimitry Andric             install_from<_VSTD::codecvt<char16_t, char8_t, mbstate_t> >(one);
436e8d8bef9SDimitry Andric             install_from<_VSTD::codecvt<char32_t, char8_t, mbstate_t> >(one);
437e8d8bef9SDimitry Andric #endif
438349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4390b57cec5SDimitry Andric             install_from<_VSTD::codecvt<wchar_t, char, mbstate_t> >(one);
440349cc55cSDimitry Andric #endif
4410b57cec5SDimitry Andric         }
4420b57cec5SDimitry Andric         if (c & locale::monetary)
4430b57cec5SDimitry Andric         {
4440b57cec5SDimitry Andric             install_from<moneypunct<char, false> >(one);
4450b57cec5SDimitry Andric             install_from<moneypunct<char, true> >(one);
446349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4470b57cec5SDimitry Andric             install_from<moneypunct<wchar_t, false> >(one);
4480b57cec5SDimitry Andric             install_from<moneypunct<wchar_t, true> >(one);
449349cc55cSDimitry Andric #endif
4500b57cec5SDimitry Andric             install_from<money_get<char> >(one);
451349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4520b57cec5SDimitry Andric             install_from<money_get<wchar_t> >(one);
453349cc55cSDimitry Andric #endif
4540b57cec5SDimitry Andric             install_from<money_put<char> >(one);
455349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4560b57cec5SDimitry Andric             install_from<money_put<wchar_t> >(one);
457349cc55cSDimitry Andric #endif
4580b57cec5SDimitry Andric         }
4590b57cec5SDimitry Andric         if (c & locale::numeric)
4600b57cec5SDimitry Andric         {
4610b57cec5SDimitry Andric             install_from<numpunct<char> >(one);
462349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4630b57cec5SDimitry Andric             install_from<numpunct<wchar_t> >(one);
464349cc55cSDimitry Andric #endif
4650b57cec5SDimitry Andric             install_from<num_get<char> >(one);
466349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4670b57cec5SDimitry Andric             install_from<num_get<wchar_t> >(one);
468349cc55cSDimitry Andric #endif
4690b57cec5SDimitry Andric             install_from<num_put<char> >(one);
470349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4710b57cec5SDimitry Andric             install_from<num_put<wchar_t> >(one);
472349cc55cSDimitry Andric #endif
4730b57cec5SDimitry Andric         }
4740b57cec5SDimitry Andric         if (c & locale::time)
4750b57cec5SDimitry Andric         {
4760b57cec5SDimitry Andric             install_from<time_get<char> >(one);
477349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4780b57cec5SDimitry Andric             install_from<time_get<wchar_t> >(one);
479349cc55cSDimitry Andric #endif
4800b57cec5SDimitry Andric             install_from<time_put<char> >(one);
481349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4820b57cec5SDimitry Andric             install_from<time_put<wchar_t> >(one);
483349cc55cSDimitry Andric #endif
4840b57cec5SDimitry Andric         }
4850b57cec5SDimitry Andric         if (c & locale::messages)
4860b57cec5SDimitry Andric         {
4870b57cec5SDimitry Andric             install_from<_VSTD::messages<char> >(one);
488349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4890b57cec5SDimitry Andric             install_from<_VSTD::messages<wchar_t> >(one);
490349cc55cSDimitry Andric #endif
4910b57cec5SDimitry Andric         }
4920b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
4930b57cec5SDimitry Andric     }
4940b57cec5SDimitry Andric     catch (...)
4950b57cec5SDimitry Andric     {
4960b57cec5SDimitry Andric         for (unsigned i = 0; i < facets_.size(); ++i)
4970b57cec5SDimitry Andric             if (facets_[i])
4980b57cec5SDimitry Andric                 facets_[i]->__release_shared();
4990b57cec5SDimitry Andric         throw;
5000b57cec5SDimitry Andric     }
5010b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS
5020b57cec5SDimitry Andric }
5030b57cec5SDimitry Andric 
5040b57cec5SDimitry Andric locale::__imp::__imp(const __imp& other, facet* f, long id)
5050b57cec5SDimitry Andric     : facets_(max<size_t>(N, other.facets_.size()+1)),
5060b57cec5SDimitry Andric       name_("*")
5070b57cec5SDimitry Andric {
5080b57cec5SDimitry Andric     f->__add_shared();
5090b57cec5SDimitry Andric     unique_ptr<facet, release> hold(f);
5100b57cec5SDimitry Andric     facets_ = other.facets_;
5110b57cec5SDimitry Andric     for (unsigned i = 0; i < other.facets_.size(); ++i)
5120b57cec5SDimitry Andric         if (facets_[i])
5130b57cec5SDimitry Andric             facets_[i]->__add_shared();
5140b57cec5SDimitry Andric     install(hold.get(), id);
5150b57cec5SDimitry Andric }
5160b57cec5SDimitry Andric 
5170b57cec5SDimitry Andric locale::__imp::~__imp()
5180b57cec5SDimitry Andric {
5190b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
5200b57cec5SDimitry Andric         if (facets_[i])
5210b57cec5SDimitry Andric             facets_[i]->__release_shared();
5220b57cec5SDimitry Andric }
5230b57cec5SDimitry Andric 
5240b57cec5SDimitry Andric void
5250b57cec5SDimitry Andric locale::__imp::install(facet* f, long id)
5260b57cec5SDimitry Andric {
5270b57cec5SDimitry Andric     f->__add_shared();
5280b57cec5SDimitry Andric     unique_ptr<facet, release> hold(f);
5290b57cec5SDimitry Andric     if (static_cast<size_t>(id) >= facets_.size())
5300b57cec5SDimitry Andric         facets_.resize(static_cast<size_t>(id+1));
5310b57cec5SDimitry Andric     if (facets_[static_cast<size_t>(id)])
5320b57cec5SDimitry Andric         facets_[static_cast<size_t>(id)]->__release_shared();
5330b57cec5SDimitry Andric     facets_[static_cast<size_t>(id)] = hold.release();
5340b57cec5SDimitry Andric }
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric const locale::facet*
5370b57cec5SDimitry Andric locale::__imp::use_facet(long id) const
5380b57cec5SDimitry Andric {
5390b57cec5SDimitry Andric     if (!has_facet(id))
5400b57cec5SDimitry Andric         __throw_bad_cast();
5410b57cec5SDimitry Andric     return facets_[static_cast<size_t>(id)];
5420b57cec5SDimitry Andric }
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric // locale
5450b57cec5SDimitry Andric 
5460b57cec5SDimitry Andric const locale&
5470b57cec5SDimitry Andric locale::__imp::make_classic()
5480b57cec5SDimitry Andric {
5490b57cec5SDimitry Andric     // only one thread can get in here and it only gets in once
5500b57cec5SDimitry Andric     static aligned_storage<sizeof(locale)>::type buf;
5510b57cec5SDimitry Andric     locale* c = reinterpret_cast<locale*>(&buf);
5520b57cec5SDimitry Andric     c->__locale_ = &make<__imp>(1u);
5530b57cec5SDimitry Andric     return *c;
5540b57cec5SDimitry Andric }
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric const locale&
5570b57cec5SDimitry Andric locale::classic()
5580b57cec5SDimitry Andric {
5590b57cec5SDimitry Andric     static const locale& c = __imp::make_classic();
5600b57cec5SDimitry Andric     return c;
5610b57cec5SDimitry Andric }
5620b57cec5SDimitry Andric 
5630b57cec5SDimitry Andric locale&
5640b57cec5SDimitry Andric locale::__imp::make_global()
5650b57cec5SDimitry Andric {
5660b57cec5SDimitry Andric     // only one thread can get in here and it only gets in once
5670b57cec5SDimitry Andric     static aligned_storage<sizeof(locale)>::type buf;
5680b57cec5SDimitry Andric     auto *obj = ::new (&buf) locale(locale::classic());
5690b57cec5SDimitry Andric     return *obj;
5700b57cec5SDimitry Andric }
5710b57cec5SDimitry Andric 
5720b57cec5SDimitry Andric locale&
5730b57cec5SDimitry Andric locale::__global()
5740b57cec5SDimitry Andric {
5750b57cec5SDimitry Andric     static locale& g = __imp::make_global();
5760b57cec5SDimitry Andric     return g;
5770b57cec5SDimitry Andric }
5780b57cec5SDimitry Andric 
579fe6060f1SDimitry Andric locale::locale() noexcept
5800b57cec5SDimitry Andric     : __locale_(__global().__locale_)
5810b57cec5SDimitry Andric {
5820b57cec5SDimitry Andric     __locale_->__add_shared();
5830b57cec5SDimitry Andric }
5840b57cec5SDimitry Andric 
585fe6060f1SDimitry Andric locale::locale(const locale& l) noexcept
5860b57cec5SDimitry Andric     : __locale_(l.__locale_)
5870b57cec5SDimitry Andric {
5880b57cec5SDimitry Andric     __locale_->__add_shared();
5890b57cec5SDimitry Andric }
5900b57cec5SDimitry Andric 
5910b57cec5SDimitry Andric locale::~locale()
5920b57cec5SDimitry Andric {
5930b57cec5SDimitry Andric     __locale_->__release_shared();
5940b57cec5SDimitry Andric }
5950b57cec5SDimitry Andric 
5960b57cec5SDimitry Andric const locale&
597fe6060f1SDimitry Andric locale::operator=(const locale& other) noexcept
5980b57cec5SDimitry Andric {
5990b57cec5SDimitry Andric     other.__locale_->__add_shared();
6000b57cec5SDimitry Andric     __locale_->__release_shared();
6010b57cec5SDimitry Andric     __locale_ = other.__locale_;
6020b57cec5SDimitry Andric     return *this;
6030b57cec5SDimitry Andric }
6040b57cec5SDimitry Andric 
6050b57cec5SDimitry Andric locale::locale(const char* name)
6060b57cec5SDimitry Andric     : __locale_(name ? new __imp(name)
6075ffd83dbSDimitry Andric                      : (__throw_runtime_error("locale constructed with null"), nullptr))
6080b57cec5SDimitry Andric {
6090b57cec5SDimitry Andric     __locale_->__add_shared();
6100b57cec5SDimitry Andric }
6110b57cec5SDimitry Andric 
6120b57cec5SDimitry Andric locale::locale(const string& name)
6130b57cec5SDimitry Andric     : __locale_(new __imp(name))
6140b57cec5SDimitry Andric {
6150b57cec5SDimitry Andric     __locale_->__add_shared();
6160b57cec5SDimitry Andric }
6170b57cec5SDimitry Andric 
6180b57cec5SDimitry Andric locale::locale(const locale& other, const char* name, category c)
6190b57cec5SDimitry Andric     : __locale_(name ? new __imp(*other.__locale_, name, c)
6205ffd83dbSDimitry Andric                      : (__throw_runtime_error("locale constructed with null"), nullptr))
6210b57cec5SDimitry Andric {
6220b57cec5SDimitry Andric     __locale_->__add_shared();
6230b57cec5SDimitry Andric }
6240b57cec5SDimitry Andric 
6250b57cec5SDimitry Andric locale::locale(const locale& other, const string& name, category c)
6260b57cec5SDimitry Andric     : __locale_(new __imp(*other.__locale_, name, c))
6270b57cec5SDimitry Andric {
6280b57cec5SDimitry Andric     __locale_->__add_shared();
6290b57cec5SDimitry Andric }
6300b57cec5SDimitry Andric 
6310b57cec5SDimitry Andric locale::locale(const locale& other, const locale& one, category c)
6320b57cec5SDimitry Andric     : __locale_(new __imp(*other.__locale_, *one.__locale_, c))
6330b57cec5SDimitry Andric {
6340b57cec5SDimitry Andric     __locale_->__add_shared();
6350b57cec5SDimitry Andric }
6360b57cec5SDimitry Andric 
6370b57cec5SDimitry Andric string
6380b57cec5SDimitry Andric locale::name() const
6390b57cec5SDimitry Andric {
6400b57cec5SDimitry Andric     return __locale_->name();
6410b57cec5SDimitry Andric }
6420b57cec5SDimitry Andric 
6430b57cec5SDimitry Andric void
6440b57cec5SDimitry Andric locale::__install_ctor(const locale& other, facet* f, long id)
6450b57cec5SDimitry Andric {
6460b57cec5SDimitry Andric     if (f)
6470b57cec5SDimitry Andric         __locale_ = new __imp(*other.__locale_, f, id);
6480b57cec5SDimitry Andric     else
6490b57cec5SDimitry Andric         __locale_ = other.__locale_;
6500b57cec5SDimitry Andric     __locale_->__add_shared();
6510b57cec5SDimitry Andric }
6520b57cec5SDimitry Andric 
6530b57cec5SDimitry Andric locale
6540b57cec5SDimitry Andric locale::global(const locale& loc)
6550b57cec5SDimitry Andric {
6560b57cec5SDimitry Andric     locale& g = __global();
6570b57cec5SDimitry Andric     locale r = g;
6580b57cec5SDimitry Andric     g = loc;
6590b57cec5SDimitry Andric     if (g.name() != "*")
6600b57cec5SDimitry Andric         setlocale(LC_ALL, g.name().c_str());
6610b57cec5SDimitry Andric     return r;
6620b57cec5SDimitry Andric }
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric bool
6650b57cec5SDimitry Andric locale::has_facet(id& x) const
6660b57cec5SDimitry Andric {
6670b57cec5SDimitry Andric     return __locale_->has_facet(x.__get());
6680b57cec5SDimitry Andric }
6690b57cec5SDimitry Andric 
6700b57cec5SDimitry Andric const locale::facet*
6710b57cec5SDimitry Andric locale::use_facet(id& x) const
6720b57cec5SDimitry Andric {
6730b57cec5SDimitry Andric     return __locale_->use_facet(x.__get());
6740b57cec5SDimitry Andric }
6750b57cec5SDimitry Andric 
6760b57cec5SDimitry Andric bool
6770b57cec5SDimitry Andric locale::operator==(const locale& y) const
6780b57cec5SDimitry Andric {
6790b57cec5SDimitry Andric     return (__locale_ == y.__locale_)
6800b57cec5SDimitry Andric         || (__locale_->name() != "*" && __locale_->name() == y.__locale_->name());
6810b57cec5SDimitry Andric }
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric // locale::facet
6840b57cec5SDimitry Andric 
6850b57cec5SDimitry Andric locale::facet::~facet()
6860b57cec5SDimitry Andric {
6870b57cec5SDimitry Andric }
6880b57cec5SDimitry Andric 
6890b57cec5SDimitry Andric void
690fe6060f1SDimitry Andric locale::facet::__on_zero_shared() noexcept
6910b57cec5SDimitry Andric {
6920b57cec5SDimitry Andric     delete this;
6930b57cec5SDimitry Andric }
6940b57cec5SDimitry Andric 
6950b57cec5SDimitry Andric // locale::id
6960b57cec5SDimitry Andric 
6970b57cec5SDimitry Andric int32_t locale::id::__next_id = 0;
6980b57cec5SDimitry Andric 
6990b57cec5SDimitry Andric namespace
7000b57cec5SDimitry Andric {
7010b57cec5SDimitry Andric 
7020b57cec5SDimitry Andric class __fake_bind
7030b57cec5SDimitry Andric {
7040b57cec5SDimitry Andric     locale::id* id_;
7050b57cec5SDimitry Andric     void (locale::id::* pmf_)();
7060b57cec5SDimitry Andric public:
7070b57cec5SDimitry Andric     __fake_bind(void (locale::id::* pmf)(), locale::id* id)
7080b57cec5SDimitry Andric         : id_(id), pmf_(pmf) {}
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric     void operator()() const
7110b57cec5SDimitry Andric     {
7120b57cec5SDimitry Andric         (id_->*pmf_)();
7130b57cec5SDimitry Andric     }
7140b57cec5SDimitry Andric };
7150b57cec5SDimitry Andric 
7160b57cec5SDimitry Andric }
7170b57cec5SDimitry Andric 
7180b57cec5SDimitry Andric long
7190b57cec5SDimitry Andric locale::id::__get()
7200b57cec5SDimitry Andric {
7210b57cec5SDimitry Andric     call_once(__flag_, __fake_bind(&locale::id::__init, this));
7220b57cec5SDimitry Andric     return __id_ - 1;
7230b57cec5SDimitry Andric }
7240b57cec5SDimitry Andric 
7250b57cec5SDimitry Andric void
7260b57cec5SDimitry Andric locale::id::__init()
7270b57cec5SDimitry Andric {
7280b57cec5SDimitry Andric     __id_ = __libcpp_atomic_add(&__next_id, 1);
7290b57cec5SDimitry Andric }
7300b57cec5SDimitry Andric 
7310b57cec5SDimitry Andric // template <> class collate_byname<char>
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric collate_byname<char>::collate_byname(const char* n, size_t refs)
7340b57cec5SDimitry Andric     : collate<char>(refs),
735*bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, n, 0))
7360b57cec5SDimitry Andric {
737*bdd1243dSDimitry Andric     if (__l_ == 0)
7380b57cec5SDimitry Andric         __throw_runtime_error("collate_byname<char>::collate_byname"
7390b57cec5SDimitry Andric                             " failed to construct for " + string(n));
7400b57cec5SDimitry Andric }
7410b57cec5SDimitry Andric 
7420b57cec5SDimitry Andric collate_byname<char>::collate_byname(const string& name, size_t refs)
7430b57cec5SDimitry Andric     : collate<char>(refs),
744*bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, name.c_str(), 0))
7450b57cec5SDimitry Andric {
746*bdd1243dSDimitry Andric     if (__l_ == 0)
7470b57cec5SDimitry Andric         __throw_runtime_error("collate_byname<char>::collate_byname"
7480b57cec5SDimitry Andric                             " failed to construct for " + name);
7490b57cec5SDimitry Andric }
7500b57cec5SDimitry Andric 
7510b57cec5SDimitry Andric collate_byname<char>::~collate_byname()
7520b57cec5SDimitry Andric {
753*bdd1243dSDimitry Andric     freelocale(__l_);
7540b57cec5SDimitry Andric }
7550b57cec5SDimitry Andric 
7560b57cec5SDimitry Andric int
7570b57cec5SDimitry Andric collate_byname<char>::do_compare(const char_type* __lo1, const char_type* __hi1,
7580b57cec5SDimitry Andric                                  const char_type* __lo2, const char_type* __hi2) const
7590b57cec5SDimitry Andric {
7600b57cec5SDimitry Andric     string_type lhs(__lo1, __hi1);
7610b57cec5SDimitry Andric     string_type rhs(__lo2, __hi2);
762*bdd1243dSDimitry Andric     int r = strcoll_l(lhs.c_str(), rhs.c_str(), __l_);
7630b57cec5SDimitry Andric     if (r < 0)
7640b57cec5SDimitry Andric         return -1;
7650b57cec5SDimitry Andric     if (r > 0)
7660b57cec5SDimitry Andric         return 1;
7670b57cec5SDimitry Andric     return r;
7680b57cec5SDimitry Andric }
7690b57cec5SDimitry Andric 
7700b57cec5SDimitry Andric collate_byname<char>::string_type
7710b57cec5SDimitry Andric collate_byname<char>::do_transform(const char_type* lo, const char_type* hi) const
7720b57cec5SDimitry Andric {
7730b57cec5SDimitry Andric     const string_type in(lo, hi);
774*bdd1243dSDimitry Andric     string_type out(strxfrm_l(0, in.c_str(), 0, __l_), char());
775*bdd1243dSDimitry Andric     strxfrm_l(const_cast<char*>(out.c_str()), in.c_str(), out.size()+1, __l_);
7760b57cec5SDimitry Andric     return out;
7770b57cec5SDimitry Andric }
7780b57cec5SDimitry Andric 
7790b57cec5SDimitry Andric // template <> class collate_byname<wchar_t>
7800b57cec5SDimitry Andric 
781349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
7820b57cec5SDimitry Andric collate_byname<wchar_t>::collate_byname(const char* n, size_t refs)
7830b57cec5SDimitry Andric     : collate<wchar_t>(refs),
784*bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, n, 0))
7850b57cec5SDimitry Andric {
786*bdd1243dSDimitry Andric     if (__l_ == 0)
7870b57cec5SDimitry Andric         __throw_runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)"
7880b57cec5SDimitry Andric                             " failed to construct for " + string(n));
7890b57cec5SDimitry Andric }
7900b57cec5SDimitry Andric 
7910b57cec5SDimitry Andric collate_byname<wchar_t>::collate_byname(const string& name, size_t refs)
7920b57cec5SDimitry Andric     : collate<wchar_t>(refs),
793*bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, name.c_str(), 0))
7940b57cec5SDimitry Andric {
795*bdd1243dSDimitry Andric     if (__l_ == 0)
7960b57cec5SDimitry Andric         __throw_runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)"
7970b57cec5SDimitry Andric                             " failed to construct for " + name);
7980b57cec5SDimitry Andric }
7990b57cec5SDimitry Andric 
8000b57cec5SDimitry Andric collate_byname<wchar_t>::~collate_byname()
8010b57cec5SDimitry Andric {
802*bdd1243dSDimitry Andric     freelocale(__l_);
8030b57cec5SDimitry Andric }
8040b57cec5SDimitry Andric 
8050b57cec5SDimitry Andric int
8060b57cec5SDimitry Andric collate_byname<wchar_t>::do_compare(const char_type* __lo1, const char_type* __hi1,
8070b57cec5SDimitry Andric                                  const char_type* __lo2, const char_type* __hi2) const
8080b57cec5SDimitry Andric {
8090b57cec5SDimitry Andric     string_type lhs(__lo1, __hi1);
8100b57cec5SDimitry Andric     string_type rhs(__lo2, __hi2);
811*bdd1243dSDimitry Andric     int r = wcscoll_l(lhs.c_str(), rhs.c_str(), __l_);
8120b57cec5SDimitry Andric     if (r < 0)
8130b57cec5SDimitry Andric         return -1;
8140b57cec5SDimitry Andric     if (r > 0)
8150b57cec5SDimitry Andric         return 1;
8160b57cec5SDimitry Andric     return r;
8170b57cec5SDimitry Andric }
8180b57cec5SDimitry Andric 
8190b57cec5SDimitry Andric collate_byname<wchar_t>::string_type
8200b57cec5SDimitry Andric collate_byname<wchar_t>::do_transform(const char_type* lo, const char_type* hi) const
8210b57cec5SDimitry Andric {
8220b57cec5SDimitry Andric     const string_type in(lo, hi);
823*bdd1243dSDimitry Andric     string_type out(wcsxfrm_l(0, in.c_str(), 0, __l_), wchar_t());
824*bdd1243dSDimitry Andric     wcsxfrm_l(const_cast<wchar_t*>(out.c_str()), in.c_str(), out.size()+1, __l_);
8250b57cec5SDimitry Andric     return out;
8260b57cec5SDimitry Andric }
827349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
8280b57cec5SDimitry Andric 
8290b57cec5SDimitry Andric const ctype_base::mask ctype_base::space;
8300b57cec5SDimitry Andric const ctype_base::mask ctype_base::print;
8310b57cec5SDimitry Andric const ctype_base::mask ctype_base::cntrl;
8320b57cec5SDimitry Andric const ctype_base::mask ctype_base::upper;
8330b57cec5SDimitry Andric const ctype_base::mask ctype_base::lower;
8340b57cec5SDimitry Andric const ctype_base::mask ctype_base::alpha;
8350b57cec5SDimitry Andric const ctype_base::mask ctype_base::digit;
8360b57cec5SDimitry Andric const ctype_base::mask ctype_base::punct;
8370b57cec5SDimitry Andric const ctype_base::mask ctype_base::xdigit;
8380b57cec5SDimitry Andric const ctype_base::mask ctype_base::blank;
8390b57cec5SDimitry Andric const ctype_base::mask ctype_base::alnum;
8400b57cec5SDimitry Andric const ctype_base::mask ctype_base::graph;
8410b57cec5SDimitry Andric 
842349cc55cSDimitry Andric // template <> class ctype<wchar_t>;
843349cc55cSDimitry Andric 
844349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
8450b57cec5SDimitry Andric locale::id ctype<wchar_t>::id;
8460b57cec5SDimitry Andric 
8470b57cec5SDimitry Andric ctype<wchar_t>::~ctype()
8480b57cec5SDimitry Andric {
8490b57cec5SDimitry Andric }
8500b57cec5SDimitry Andric 
8510b57cec5SDimitry Andric bool
8520b57cec5SDimitry Andric ctype<wchar_t>::do_is(mask m, char_type c) const
8530b57cec5SDimitry Andric {
8540b57cec5SDimitry Andric     return isascii(c) ? (ctype<char>::classic_table()[c] & m) != 0 : false;
8550b57cec5SDimitry Andric }
8560b57cec5SDimitry Andric 
8570b57cec5SDimitry Andric const wchar_t*
8580b57cec5SDimitry Andric ctype<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
8590b57cec5SDimitry Andric {
8600b57cec5SDimitry Andric     for (; low != high; ++low, ++vec)
8610b57cec5SDimitry Andric         *vec = static_cast<mask>(isascii(*low) ?
8620b57cec5SDimitry Andric                                    ctype<char>::classic_table()[*low] : 0);
8630b57cec5SDimitry Andric     return low;
8640b57cec5SDimitry Andric }
8650b57cec5SDimitry Andric 
8660b57cec5SDimitry Andric const wchar_t*
8670b57cec5SDimitry Andric ctype<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const
8680b57cec5SDimitry Andric {
8690b57cec5SDimitry Andric     for (; low != high; ++low)
8700b57cec5SDimitry Andric         if (isascii(*low) && (ctype<char>::classic_table()[*low] & m))
8710b57cec5SDimitry Andric             break;
8720b57cec5SDimitry Andric     return low;
8730b57cec5SDimitry Andric }
8740b57cec5SDimitry Andric 
8750b57cec5SDimitry Andric const wchar_t*
8760b57cec5SDimitry Andric ctype<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const
8770b57cec5SDimitry Andric {
8780b57cec5SDimitry Andric     for (; low != high; ++low)
8790b57cec5SDimitry Andric         if (!(isascii(*low) && (ctype<char>::classic_table()[*low] & m)))
8800b57cec5SDimitry Andric             break;
8810b57cec5SDimitry Andric     return low;
8820b57cec5SDimitry Andric }
8830b57cec5SDimitry Andric 
8840b57cec5SDimitry Andric wchar_t
8850b57cec5SDimitry Andric ctype<wchar_t>::do_toupper(char_type c) const
8860b57cec5SDimitry Andric {
8870b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
8880b57cec5SDimitry Andric     return isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c;
8890b57cec5SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
89004eeddc0SDimitry Andric       defined(__NetBSD__) || defined(__MVS__)
8910b57cec5SDimitry Andric     return isascii(c) ? ctype<char>::__classic_upper_table()[c] : c;
8920b57cec5SDimitry Andric #else
8930b57cec5SDimitry Andric     return (isascii(c) && iswlower_l(c, _LIBCPP_GET_C_LOCALE)) ? c-L'a'+L'A' : c;
8940b57cec5SDimitry Andric #endif
8950b57cec5SDimitry Andric }
8960b57cec5SDimitry Andric 
8970b57cec5SDimitry Andric const wchar_t*
8980b57cec5SDimitry Andric ctype<wchar_t>::do_toupper(char_type* low, const char_type* high) const
8990b57cec5SDimitry Andric {
9000b57cec5SDimitry Andric     for (; low != high; ++low)
9010b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
9020b57cec5SDimitry Andric         *low = isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low;
9030b57cec5SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
90404eeddc0SDimitry Andric       defined(__NetBSD__) || defined(__MVS__)
9050b57cec5SDimitry Andric         *low = isascii(*low) ? ctype<char>::__classic_upper_table()[*low]
9060b57cec5SDimitry Andric                              : *low;
9070b57cec5SDimitry Andric #else
9080b57cec5SDimitry Andric         *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? (*low-L'a'+L'A') : *low;
9090b57cec5SDimitry Andric #endif
9100b57cec5SDimitry Andric     return low;
9110b57cec5SDimitry Andric }
9120b57cec5SDimitry Andric 
9130b57cec5SDimitry Andric wchar_t
9140b57cec5SDimitry Andric ctype<wchar_t>::do_tolower(char_type c) const
9150b57cec5SDimitry Andric {
9160b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
9170b57cec5SDimitry Andric     return isascii(c) ? _DefaultRuneLocale.__maplower[c] : c;
9180b57cec5SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
91904eeddc0SDimitry Andric       defined(__NetBSD__) || defined(__MVS__)
9200b57cec5SDimitry Andric     return isascii(c) ? ctype<char>::__classic_lower_table()[c] : c;
9210b57cec5SDimitry Andric #else
9220b57cec5SDimitry Andric     return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c-L'A'+'a' : c;
9230b57cec5SDimitry Andric #endif
9240b57cec5SDimitry Andric }
9250b57cec5SDimitry Andric 
9260b57cec5SDimitry Andric const wchar_t*
9270b57cec5SDimitry Andric ctype<wchar_t>::do_tolower(char_type* low, const char_type* high) const
9280b57cec5SDimitry Andric {
9290b57cec5SDimitry Andric     for (; low != high; ++low)
9300b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
9310b57cec5SDimitry Andric         *low = isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low;
9320b57cec5SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
93304eeddc0SDimitry Andric       defined(__NetBSD__) || defined(__MVS__)
9340b57cec5SDimitry Andric         *low = isascii(*low) ? ctype<char>::__classic_lower_table()[*low]
9350b57cec5SDimitry Andric                              : *low;
9360b57cec5SDimitry Andric #else
9370b57cec5SDimitry Andric         *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-L'A'+L'a' : *low;
9380b57cec5SDimitry Andric #endif
9390b57cec5SDimitry Andric     return low;
9400b57cec5SDimitry Andric }
9410b57cec5SDimitry Andric 
9420b57cec5SDimitry Andric wchar_t
9430b57cec5SDimitry Andric ctype<wchar_t>::do_widen(char c) const
9440b57cec5SDimitry Andric {
9450b57cec5SDimitry Andric     return c;
9460b57cec5SDimitry Andric }
9470b57cec5SDimitry Andric 
9480b57cec5SDimitry Andric const char*
9490b57cec5SDimitry Andric ctype<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const
9500b57cec5SDimitry Andric {
9510b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
9520b57cec5SDimitry Andric         *dest = *low;
9530b57cec5SDimitry Andric     return low;
9540b57cec5SDimitry Andric }
9550b57cec5SDimitry Andric 
9560b57cec5SDimitry Andric char
9570b57cec5SDimitry Andric ctype<wchar_t>::do_narrow(char_type c, char dfault) const
9580b57cec5SDimitry Andric {
9590b57cec5SDimitry Andric     if (isascii(c))
9600b57cec5SDimitry Andric         return static_cast<char>(c);
9610b57cec5SDimitry Andric     return dfault;
9620b57cec5SDimitry Andric }
9630b57cec5SDimitry Andric 
9640b57cec5SDimitry Andric const wchar_t*
9650b57cec5SDimitry Andric ctype<wchar_t>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
9660b57cec5SDimitry Andric {
9670b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
9680b57cec5SDimitry Andric         if (isascii(*low))
9690b57cec5SDimitry Andric             *dest = static_cast<char>(*low);
9700b57cec5SDimitry Andric         else
9710b57cec5SDimitry Andric             *dest = dfault;
9720b57cec5SDimitry Andric     return low;
9730b57cec5SDimitry Andric }
974349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
9750b57cec5SDimitry Andric 
9760b57cec5SDimitry Andric // template <> class ctype<char>;
9770b57cec5SDimitry Andric 
9780b57cec5SDimitry Andric locale::id ctype<char>::id;
9790b57cec5SDimitry Andric 
980349cc55cSDimitry Andric const size_t ctype<char>::table_size;
981349cc55cSDimitry Andric 
9820b57cec5SDimitry Andric ctype<char>::ctype(const mask* tab, bool del, size_t refs)
9830b57cec5SDimitry Andric     : locale::facet(refs),
9840b57cec5SDimitry Andric       __tab_(tab),
9850b57cec5SDimitry Andric       __del_(del)
9860b57cec5SDimitry Andric {
9870b57cec5SDimitry Andric   if (__tab_ == 0)
9880b57cec5SDimitry Andric       __tab_ = classic_table();
9890b57cec5SDimitry Andric }
9900b57cec5SDimitry Andric 
9910b57cec5SDimitry Andric ctype<char>::~ctype()
9920b57cec5SDimitry Andric {
9930b57cec5SDimitry Andric     if (__tab_ && __del_)
9940b57cec5SDimitry Andric         delete [] __tab_;
9950b57cec5SDimitry Andric }
9960b57cec5SDimitry Andric 
9970b57cec5SDimitry Andric char
9980b57cec5SDimitry Andric ctype<char>::do_toupper(char_type c) const
9990b57cec5SDimitry Andric {
10000b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
10010b57cec5SDimitry Andric     return isascii(c) ?
10020b57cec5SDimitry Andric       static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(c)]) : c;
10030b57cec5SDimitry Andric #elif defined(__NetBSD__)
10040b57cec5SDimitry Andric     return static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]);
100504eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
10060b57cec5SDimitry Andric     return isascii(c) ?
10070b57cec5SDimitry Andric       static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]) : c;
10080b57cec5SDimitry Andric #else
10090b57cec5SDimitry Andric     return (isascii(c) && islower_l(c, _LIBCPP_GET_C_LOCALE)) ? c-'a'+'A' : c;
10100b57cec5SDimitry Andric #endif
10110b57cec5SDimitry Andric }
10120b57cec5SDimitry Andric 
10130b57cec5SDimitry Andric const char*
10140b57cec5SDimitry Andric ctype<char>::do_toupper(char_type* low, const char_type* high) const
10150b57cec5SDimitry Andric {
10160b57cec5SDimitry Andric     for (; low != high; ++low)
10170b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
10180b57cec5SDimitry Andric         *low = isascii(*low) ?
10190b57cec5SDimitry Andric           static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(*low)]) : *low;
10200b57cec5SDimitry Andric #elif defined(__NetBSD__)
10210b57cec5SDimitry Andric         *low = static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(*low)]);
102204eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
10230b57cec5SDimitry Andric         *low = isascii(*low) ?
10240b57cec5SDimitry Andric           static_cast<char>(__classic_upper_table()[static_cast<size_t>(*low)]) : *low;
10250b57cec5SDimitry Andric #else
10260b57cec5SDimitry Andric         *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-'a'+'A' : *low;
10270b57cec5SDimitry Andric #endif
10280b57cec5SDimitry Andric     return low;
10290b57cec5SDimitry Andric }
10300b57cec5SDimitry Andric 
10310b57cec5SDimitry Andric char
10320b57cec5SDimitry Andric ctype<char>::do_tolower(char_type c) const
10330b57cec5SDimitry Andric {
10340b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
10350b57cec5SDimitry Andric     return isascii(c) ?
10360b57cec5SDimitry Andric       static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(c)]) : c;
10370b57cec5SDimitry Andric #elif defined(__NetBSD__)
10380b57cec5SDimitry Andric     return static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(c)]);
103904eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
10400b57cec5SDimitry Andric     return isascii(c) ?
10410b57cec5SDimitry Andric       static_cast<char>(__classic_lower_table()[static_cast<size_t>(c)]) : c;
10420b57cec5SDimitry Andric #else
10430b57cec5SDimitry Andric     return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c-'A'+'a' : c;
10440b57cec5SDimitry Andric #endif
10450b57cec5SDimitry Andric }
10460b57cec5SDimitry Andric 
10470b57cec5SDimitry Andric const char*
10480b57cec5SDimitry Andric ctype<char>::do_tolower(char_type* low, const char_type* high) const
10490b57cec5SDimitry Andric {
10500b57cec5SDimitry Andric     for (; low != high; ++low)
10510b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
10520b57cec5SDimitry Andric         *low = isascii(*low) ? static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(*low)]) : *low;
10530b57cec5SDimitry Andric #elif defined(__NetBSD__)
10540b57cec5SDimitry Andric         *low = static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(*low)]);
105504eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
10560b57cec5SDimitry Andric         *low = isascii(*low) ? static_cast<char>(__classic_lower_table()[static_cast<size_t>(*low)]) : *low;
10570b57cec5SDimitry Andric #else
10580b57cec5SDimitry Andric         *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-'A'+'a' : *low;
10590b57cec5SDimitry Andric #endif
10600b57cec5SDimitry Andric     return low;
10610b57cec5SDimitry Andric }
10620b57cec5SDimitry Andric 
10630b57cec5SDimitry Andric char
10640b57cec5SDimitry Andric ctype<char>::do_widen(char c) const
10650b57cec5SDimitry Andric {
10660b57cec5SDimitry Andric     return c;
10670b57cec5SDimitry Andric }
10680b57cec5SDimitry Andric 
10690b57cec5SDimitry Andric const char*
10700b57cec5SDimitry Andric ctype<char>::do_widen(const char* low, const char* high, char_type* dest) const
10710b57cec5SDimitry Andric {
10720b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
10730b57cec5SDimitry Andric         *dest = *low;
10740b57cec5SDimitry Andric     return low;
10750b57cec5SDimitry Andric }
10760b57cec5SDimitry Andric 
10770b57cec5SDimitry Andric char
10780b57cec5SDimitry Andric ctype<char>::do_narrow(char_type c, char dfault) const
10790b57cec5SDimitry Andric {
10800b57cec5SDimitry Andric     if (isascii(c))
10810b57cec5SDimitry Andric         return static_cast<char>(c);
10820b57cec5SDimitry Andric     return dfault;
10830b57cec5SDimitry Andric }
10840b57cec5SDimitry Andric 
10850b57cec5SDimitry Andric const char*
10860b57cec5SDimitry Andric ctype<char>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
10870b57cec5SDimitry Andric {
10880b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
10890b57cec5SDimitry Andric         if (isascii(*low))
10900b57cec5SDimitry Andric             *dest = *low;
10910b57cec5SDimitry Andric         else
10920b57cec5SDimitry Andric             *dest = dfault;
10930b57cec5SDimitry Andric     return low;
10940b57cec5SDimitry Andric }
10950b57cec5SDimitry Andric 
10960b57cec5SDimitry Andric #if defined(__EMSCRIPTEN__)
10970b57cec5SDimitry Andric extern "C" const unsigned short ** __ctype_b_loc();
10980b57cec5SDimitry Andric extern "C" const int ** __ctype_tolower_loc();
10990b57cec5SDimitry Andric extern "C" const int ** __ctype_toupper_loc();
11000b57cec5SDimitry Andric #endif
11010b57cec5SDimitry Andric 
11020b57cec5SDimitry Andric #ifdef _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE
11030b57cec5SDimitry Andric const ctype<char>::mask*
1104fe6060f1SDimitry Andric ctype<char>::classic_table() noexcept
11050b57cec5SDimitry Andric {
11060b57cec5SDimitry Andric     static _LIBCPP_CONSTEXPR const ctype<char>::mask builtin_table[table_size] = {
11070b57cec5SDimitry Andric         cntrl,                          cntrl,
11080b57cec5SDimitry Andric         cntrl,                          cntrl,
11090b57cec5SDimitry Andric         cntrl,                          cntrl,
11100b57cec5SDimitry Andric         cntrl,                          cntrl,
11110b57cec5SDimitry Andric         cntrl,                          cntrl | space | blank,
11120b57cec5SDimitry Andric         cntrl | space,                  cntrl | space,
11130b57cec5SDimitry Andric         cntrl | space,                  cntrl | space,
11140b57cec5SDimitry Andric         cntrl,                          cntrl,
11150b57cec5SDimitry Andric         cntrl,                          cntrl,
11160b57cec5SDimitry Andric         cntrl,                          cntrl,
11170b57cec5SDimitry Andric         cntrl,                          cntrl,
11180b57cec5SDimitry Andric         cntrl,                          cntrl,
11190b57cec5SDimitry Andric         cntrl,                          cntrl,
11200b57cec5SDimitry Andric         cntrl,                          cntrl,
11210b57cec5SDimitry Andric         cntrl,                          cntrl,
11220b57cec5SDimitry Andric         cntrl,                          cntrl,
11230b57cec5SDimitry Andric         space | blank | print,          punct | print,
11240b57cec5SDimitry Andric         punct | print,                  punct | print,
11250b57cec5SDimitry Andric         punct | print,                  punct | print,
11260b57cec5SDimitry Andric         punct | print,                  punct | print,
11270b57cec5SDimitry Andric         punct | print,                  punct | print,
11280b57cec5SDimitry Andric         punct | print,                  punct | print,
11290b57cec5SDimitry Andric         punct | print,                  punct | print,
11300b57cec5SDimitry Andric         punct | print,                  punct | print,
11310b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
11320b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
11330b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
11340b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
11350b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
11360b57cec5SDimitry Andric         punct | print,                  punct | print,
11370b57cec5SDimitry Andric         punct | print,                  punct | print,
11380b57cec5SDimitry Andric         punct | print,                  punct | print,
11390b57cec5SDimitry Andric         punct | print,                  upper | xdigit | print | alpha,
11400b57cec5SDimitry Andric         upper | xdigit | print | alpha, upper | xdigit | print | alpha,
11410b57cec5SDimitry Andric         upper | xdigit | print | alpha, upper | xdigit | print | alpha,
11420b57cec5SDimitry Andric         upper | xdigit | print | alpha, upper | print | alpha,
11430b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11440b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11450b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11460b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11470b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11480b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11490b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11500b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11510b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11520b57cec5SDimitry Andric         upper | print | alpha,          punct | print,
11530b57cec5SDimitry Andric         punct | print,                  punct | print,
11540b57cec5SDimitry Andric         punct | print,                  punct | print,
11550b57cec5SDimitry Andric         punct | print,                  lower | xdigit | print | alpha,
11560b57cec5SDimitry Andric         lower | xdigit | print | alpha, lower | xdigit | print | alpha,
11570b57cec5SDimitry Andric         lower | xdigit | print | alpha, lower | xdigit | print | alpha,
11580b57cec5SDimitry Andric         lower | xdigit | print | alpha, lower | print | alpha,
11590b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11600b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11610b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11620b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11630b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11640b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11650b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11660b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11670b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11680b57cec5SDimitry Andric         lower | print | alpha,          punct | print,
11690b57cec5SDimitry Andric         punct | print,                  punct | print,
11700b57cec5SDimitry Andric         punct | print,                  cntrl,
11710b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11720b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11730b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11740b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11750b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11760b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11770b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11780b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
11790b57cec5SDimitry Andric     };
11800b57cec5SDimitry Andric     return builtin_table;
11810b57cec5SDimitry Andric }
11820b57cec5SDimitry Andric #else
11830b57cec5SDimitry Andric const ctype<char>::mask*
1184fe6060f1SDimitry Andric ctype<char>::classic_table() noexcept
11850b57cec5SDimitry Andric {
11860b57cec5SDimitry Andric #if defined(__APPLE__) || defined(__FreeBSD__)
11870b57cec5SDimitry Andric     return _DefaultRuneLocale.__runetype;
11880b57cec5SDimitry Andric #elif defined(__NetBSD__)
11890b57cec5SDimitry Andric     return _C_ctype_tab_ + 1;
11900b57cec5SDimitry Andric #elif defined(__GLIBC__)
11910b57cec5SDimitry Andric     return _LIBCPP_GET_C_LOCALE->__ctype_b;
1192fe6060f1SDimitry Andric #elif defined(__sun__)
11930b57cec5SDimitry Andric     return __ctype_mask;
11940b57cec5SDimitry Andric #elif defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
11950b57cec5SDimitry Andric     return __pctype_func();
11960b57cec5SDimitry Andric #elif defined(__EMSCRIPTEN__)
11970b57cec5SDimitry Andric     return *__ctype_b_loc();
11980b57cec5SDimitry Andric #elif defined(_NEWLIB_VERSION)
11990b57cec5SDimitry Andric     // Newlib has a 257-entry table in ctype_.c, where (char)0 starts at [1].
12000b57cec5SDimitry Andric     return _ctype_ + 1;
12010b57cec5SDimitry Andric #elif defined(_AIX)
12020b57cec5SDimitry Andric     return (const unsigned int *)__lc_ctype_ptr->obj->mask;
120304eeddc0SDimitry Andric #elif defined(__MVS__)
120404eeddc0SDimitry Andric # if defined(__NATIVE_ASCII_F)
120504eeddc0SDimitry Andric     return const_cast<const ctype<char>::mask*> (__OBJ_DATA(__lc_ctype_a)->mask);
120604eeddc0SDimitry Andric # else
120704eeddc0SDimitry Andric     return const_cast<const ctype<char>::mask*> (__ctypec);
120804eeddc0SDimitry Andric # endif
12090b57cec5SDimitry Andric #else
12100b57cec5SDimitry Andric     // Platform not supported: abort so the person doing the port knows what to
12110b57cec5SDimitry Andric     // fix
12120b57cec5SDimitry Andric # warning  ctype<char>::classic_table() is not implemented
12130b57cec5SDimitry Andric     printf("ctype<char>::classic_table() is not implemented\n");
12140b57cec5SDimitry Andric     abort();
12150b57cec5SDimitry Andric     return NULL;
12160b57cec5SDimitry Andric #endif
12170b57cec5SDimitry Andric }
12180b57cec5SDimitry Andric #endif
12190b57cec5SDimitry Andric 
12200b57cec5SDimitry Andric #if defined(__GLIBC__)
12210b57cec5SDimitry Andric const int*
1222fe6060f1SDimitry Andric ctype<char>::__classic_lower_table() noexcept
12230b57cec5SDimitry Andric {
12240b57cec5SDimitry Andric     return _LIBCPP_GET_C_LOCALE->__ctype_tolower;
12250b57cec5SDimitry Andric }
12260b57cec5SDimitry Andric 
12270b57cec5SDimitry Andric const int*
1228fe6060f1SDimitry Andric ctype<char>::__classic_upper_table() noexcept
12290b57cec5SDimitry Andric {
12300b57cec5SDimitry Andric     return _LIBCPP_GET_C_LOCALE->__ctype_toupper;
12310b57cec5SDimitry Andric }
1232e8d8bef9SDimitry Andric #elif defined(__NetBSD__)
12330b57cec5SDimitry Andric const short*
1234fe6060f1SDimitry Andric ctype<char>::__classic_lower_table() noexcept
12350b57cec5SDimitry Andric {
12360b57cec5SDimitry Andric     return _C_tolower_tab_ + 1;
12370b57cec5SDimitry Andric }
12380b57cec5SDimitry Andric 
12390b57cec5SDimitry Andric const short*
1240fe6060f1SDimitry Andric ctype<char>::__classic_upper_table() noexcept
12410b57cec5SDimitry Andric {
12420b57cec5SDimitry Andric     return _C_toupper_tab_ + 1;
12430b57cec5SDimitry Andric }
12440b57cec5SDimitry Andric 
12450b57cec5SDimitry Andric #elif defined(__EMSCRIPTEN__)
12460b57cec5SDimitry Andric const int*
1247fe6060f1SDimitry Andric ctype<char>::__classic_lower_table() noexcept
12480b57cec5SDimitry Andric {
12490b57cec5SDimitry Andric     return *__ctype_tolower_loc();
12500b57cec5SDimitry Andric }
12510b57cec5SDimitry Andric 
12520b57cec5SDimitry Andric const int*
1253fe6060f1SDimitry Andric ctype<char>::__classic_upper_table() noexcept
12540b57cec5SDimitry Andric {
12550b57cec5SDimitry Andric     return *__ctype_toupper_loc();
12560b57cec5SDimitry Andric }
125704eeddc0SDimitry Andric #elif defined(__MVS__)
125804eeddc0SDimitry Andric const unsigned short*
125904eeddc0SDimitry Andric ctype<char>::__classic_lower_table() _NOEXCEPT
126004eeddc0SDimitry Andric {
126104eeddc0SDimitry Andric # if defined(__NATIVE_ASCII_F)
126204eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__OBJ_DATA(__lc_ctype_a)->lower);
126304eeddc0SDimitry Andric # else
126404eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__ctype + __TOLOWER_INDEX);
126504eeddc0SDimitry Andric # endif
126604eeddc0SDimitry Andric }
126704eeddc0SDimitry Andric const unsigned short *
126804eeddc0SDimitry Andric ctype<char>::__classic_upper_table() _NOEXCEPT
126904eeddc0SDimitry Andric {
127004eeddc0SDimitry Andric # if defined(__NATIVE_ASCII_F)
127104eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__OBJ_DATA(__lc_ctype_a)->upper);
127204eeddc0SDimitry Andric # else
127304eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__ctype + __TOUPPER_INDEX);
127404eeddc0SDimitry Andric # endif
127504eeddc0SDimitry Andric }
127604eeddc0SDimitry Andric #endif // __GLIBC__ || __NETBSD__ || __EMSCRIPTEN__ || __MVS__
12770b57cec5SDimitry Andric 
12780b57cec5SDimitry Andric // template <> class ctype_byname<char>
12790b57cec5SDimitry Andric 
12800b57cec5SDimitry Andric ctype_byname<char>::ctype_byname(const char* name, size_t refs)
12810b57cec5SDimitry Andric     : ctype<char>(0, false, refs),
1282*bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, name, 0))
12830b57cec5SDimitry Andric {
1284*bdd1243dSDimitry Andric     if (__l_ == 0)
12850b57cec5SDimitry Andric         __throw_runtime_error("ctype_byname<char>::ctype_byname"
12860b57cec5SDimitry Andric                             " failed to construct for " + string(name));
12870b57cec5SDimitry Andric }
12880b57cec5SDimitry Andric 
12890b57cec5SDimitry Andric ctype_byname<char>::ctype_byname(const string& name, size_t refs)
12900b57cec5SDimitry Andric     : ctype<char>(0, false, refs),
1291*bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, name.c_str(), 0))
12920b57cec5SDimitry Andric {
1293*bdd1243dSDimitry Andric     if (__l_ == 0)
12940b57cec5SDimitry Andric         __throw_runtime_error("ctype_byname<char>::ctype_byname"
12950b57cec5SDimitry Andric                             " failed to construct for " + name);
12960b57cec5SDimitry Andric }
12970b57cec5SDimitry Andric 
12980b57cec5SDimitry Andric ctype_byname<char>::~ctype_byname()
12990b57cec5SDimitry Andric {
1300*bdd1243dSDimitry Andric     freelocale(__l_);
13010b57cec5SDimitry Andric }
13020b57cec5SDimitry Andric 
13030b57cec5SDimitry Andric char
13040b57cec5SDimitry Andric ctype_byname<char>::do_toupper(char_type c) const
13050b57cec5SDimitry Andric {
1306*bdd1243dSDimitry Andric     return static_cast<char>(toupper_l(static_cast<unsigned char>(c), __l_));
13070b57cec5SDimitry Andric }
13080b57cec5SDimitry Andric 
13090b57cec5SDimitry Andric const char*
13100b57cec5SDimitry Andric ctype_byname<char>::do_toupper(char_type* low, const char_type* high) const
13110b57cec5SDimitry Andric {
13120b57cec5SDimitry Andric     for (; low != high; ++low)
1313*bdd1243dSDimitry Andric         *low = static_cast<char>(toupper_l(static_cast<unsigned char>(*low), __l_));
13140b57cec5SDimitry Andric     return low;
13150b57cec5SDimitry Andric }
13160b57cec5SDimitry Andric 
13170b57cec5SDimitry Andric char
13180b57cec5SDimitry Andric ctype_byname<char>::do_tolower(char_type c) const
13190b57cec5SDimitry Andric {
1320*bdd1243dSDimitry Andric     return static_cast<char>(tolower_l(static_cast<unsigned char>(c), __l_));
13210b57cec5SDimitry Andric }
13220b57cec5SDimitry Andric 
13230b57cec5SDimitry Andric const char*
13240b57cec5SDimitry Andric ctype_byname<char>::do_tolower(char_type* low, const char_type* high) const
13250b57cec5SDimitry Andric {
13260b57cec5SDimitry Andric     for (; low != high; ++low)
1327*bdd1243dSDimitry Andric         *low = static_cast<char>(tolower_l(static_cast<unsigned char>(*low), __l_));
13280b57cec5SDimitry Andric     return low;
13290b57cec5SDimitry Andric }
13300b57cec5SDimitry Andric 
13310b57cec5SDimitry Andric // template <> class ctype_byname<wchar_t>
13320b57cec5SDimitry Andric 
1333349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
13340b57cec5SDimitry Andric ctype_byname<wchar_t>::ctype_byname(const char* name, size_t refs)
13350b57cec5SDimitry Andric     : ctype<wchar_t>(refs),
1336*bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, name, 0))
13370b57cec5SDimitry Andric {
1338*bdd1243dSDimitry Andric     if (__l_ == 0)
13390b57cec5SDimitry Andric         __throw_runtime_error("ctype_byname<wchar_t>::ctype_byname"
13400b57cec5SDimitry Andric                             " failed to construct for " + string(name));
13410b57cec5SDimitry Andric }
13420b57cec5SDimitry Andric 
13430b57cec5SDimitry Andric ctype_byname<wchar_t>::ctype_byname(const string& name, size_t refs)
13440b57cec5SDimitry Andric     : ctype<wchar_t>(refs),
1345*bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, name.c_str(), 0))
13460b57cec5SDimitry Andric {
1347*bdd1243dSDimitry Andric     if (__l_ == 0)
13480b57cec5SDimitry Andric         __throw_runtime_error("ctype_byname<wchar_t>::ctype_byname"
13490b57cec5SDimitry Andric                             " failed to construct for " + name);
13500b57cec5SDimitry Andric }
13510b57cec5SDimitry Andric 
13520b57cec5SDimitry Andric ctype_byname<wchar_t>::~ctype_byname()
13530b57cec5SDimitry Andric {
1354*bdd1243dSDimitry Andric     freelocale(__l_);
13550b57cec5SDimitry Andric }
13560b57cec5SDimitry Andric 
13570b57cec5SDimitry Andric bool
13580b57cec5SDimitry Andric ctype_byname<wchar_t>::do_is(mask m, char_type c) const
13590b57cec5SDimitry Andric {
13600b57cec5SDimitry Andric #ifdef _LIBCPP_WCTYPE_IS_MASK
1361*bdd1243dSDimitry Andric     return static_cast<bool>(iswctype_l(c, m, __l_));
13620b57cec5SDimitry Andric #else
13630b57cec5SDimitry Andric     bool result = false;
13640b57cec5SDimitry Andric     wint_t ch = static_cast<wint_t>(c);
1365*bdd1243dSDimitry Andric     if ((m & space) == space) result |= (iswspace_l(ch, __l_) != 0);
1366*bdd1243dSDimitry Andric     if ((m & print) == print) result |= (iswprint_l(ch, __l_) != 0);
1367*bdd1243dSDimitry Andric     if ((m & cntrl) == cntrl) result |= (iswcntrl_l(ch, __l_) != 0);
1368*bdd1243dSDimitry Andric     if ((m & upper) == upper) result |= (iswupper_l(ch, __l_) != 0);
1369*bdd1243dSDimitry Andric     if ((m & lower) == lower) result |= (iswlower_l(ch, __l_) != 0);
1370*bdd1243dSDimitry Andric     if ((m & alpha) == alpha) result |= (iswalpha_l(ch, __l_) != 0);
1371*bdd1243dSDimitry Andric     if ((m & digit) == digit) result |= (iswdigit_l(ch, __l_) != 0);
1372*bdd1243dSDimitry Andric     if ((m & punct) == punct) result |= (iswpunct_l(ch, __l_) != 0);
1373*bdd1243dSDimitry Andric     if ((m & xdigit) == xdigit) result |= (iswxdigit_l(ch, __l_) != 0);
1374*bdd1243dSDimitry Andric     if ((m & blank) == blank) result |= (iswblank_l(ch, __l_) != 0);
13750b57cec5SDimitry Andric     return result;
13760b57cec5SDimitry Andric #endif
13770b57cec5SDimitry Andric }
13780b57cec5SDimitry Andric 
13790b57cec5SDimitry Andric const wchar_t*
13800b57cec5SDimitry Andric ctype_byname<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
13810b57cec5SDimitry Andric {
13820b57cec5SDimitry Andric     for (; low != high; ++low, ++vec)
13830b57cec5SDimitry Andric     {
13840b57cec5SDimitry Andric         if (isascii(*low))
13850b57cec5SDimitry Andric             *vec = static_cast<mask>(ctype<char>::classic_table()[*low]);
13860b57cec5SDimitry Andric         else
13870b57cec5SDimitry Andric         {
13880b57cec5SDimitry Andric             *vec = 0;
13890b57cec5SDimitry Andric             wint_t ch = static_cast<wint_t>(*low);
1390*bdd1243dSDimitry Andric             if (iswspace_l(ch, __l_))
13910b57cec5SDimitry Andric                 *vec |= space;
13920b57cec5SDimitry Andric #ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT
1393*bdd1243dSDimitry Andric             if (iswprint_l(ch, __l_))
13940b57cec5SDimitry Andric                 *vec |= print;
13950b57cec5SDimitry Andric #endif
1396*bdd1243dSDimitry Andric             if (iswcntrl_l(ch, __l_))
13970b57cec5SDimitry Andric                 *vec |= cntrl;
1398*bdd1243dSDimitry Andric             if (iswupper_l(ch, __l_))
13990b57cec5SDimitry Andric                 *vec |= upper;
1400*bdd1243dSDimitry Andric             if (iswlower_l(ch, __l_))
14010b57cec5SDimitry Andric                 *vec |= lower;
14020b57cec5SDimitry Andric #ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA
1403*bdd1243dSDimitry Andric             if (iswalpha_l(ch, __l_))
14040b57cec5SDimitry Andric                 *vec |= alpha;
14050b57cec5SDimitry Andric #endif
1406*bdd1243dSDimitry Andric             if (iswdigit_l(ch, __l_))
14070b57cec5SDimitry Andric                 *vec |= digit;
1408*bdd1243dSDimitry Andric             if (iswpunct_l(ch, __l_))
14090b57cec5SDimitry Andric                 *vec |= punct;
14100b57cec5SDimitry Andric #ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_XDIGIT
1411*bdd1243dSDimitry Andric             if (iswxdigit_l(ch, __l_))
14120b57cec5SDimitry Andric                 *vec |= xdigit;
14130b57cec5SDimitry Andric #endif
14140b57cec5SDimitry Andric #if !defined(__sun__)
1415*bdd1243dSDimitry Andric             if (iswblank_l(ch, __l_))
14160b57cec5SDimitry Andric                 *vec |= blank;
14170b57cec5SDimitry Andric #endif
14180b57cec5SDimitry Andric         }
14190b57cec5SDimitry Andric     }
14200b57cec5SDimitry Andric     return low;
14210b57cec5SDimitry Andric }
14220b57cec5SDimitry Andric 
14230b57cec5SDimitry Andric const wchar_t*
14240b57cec5SDimitry Andric ctype_byname<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const
14250b57cec5SDimitry Andric {
14260b57cec5SDimitry Andric     for (; low != high; ++low)
14270b57cec5SDimitry Andric     {
14280b57cec5SDimitry Andric #ifdef _LIBCPP_WCTYPE_IS_MASK
1429*bdd1243dSDimitry Andric         if (iswctype_l(*low, m, __l_))
14300b57cec5SDimitry Andric             break;
14310b57cec5SDimitry Andric #else
14320b57cec5SDimitry Andric         wint_t ch = static_cast<wint_t>(*low);
1433*bdd1243dSDimitry Andric         if ((m & space) == space && iswspace_l(ch, __l_)) break;
1434*bdd1243dSDimitry Andric         if ((m & print) == print && iswprint_l(ch, __l_)) break;
1435*bdd1243dSDimitry Andric         if ((m & cntrl) == cntrl && iswcntrl_l(ch, __l_)) break;
1436*bdd1243dSDimitry Andric         if ((m & upper) == upper && iswupper_l(ch, __l_)) break;
1437*bdd1243dSDimitry Andric         if ((m & lower) == lower && iswlower_l(ch, __l_)) break;
1438*bdd1243dSDimitry Andric         if ((m & alpha) == alpha && iswalpha_l(ch, __l_)) break;
1439*bdd1243dSDimitry Andric         if ((m & digit) == digit && iswdigit_l(ch, __l_)) break;
1440*bdd1243dSDimitry Andric         if ((m & punct) == punct && iswpunct_l(ch, __l_)) break;
1441*bdd1243dSDimitry Andric         if ((m & xdigit) == xdigit && iswxdigit_l(ch, __l_)) break;
1442*bdd1243dSDimitry Andric         if ((m & blank) == blank && iswblank_l(ch, __l_)) break;
14430b57cec5SDimitry Andric #endif
14440b57cec5SDimitry Andric     }
14450b57cec5SDimitry Andric     return low;
14460b57cec5SDimitry Andric }
14470b57cec5SDimitry Andric 
14480b57cec5SDimitry Andric const wchar_t*
14490b57cec5SDimitry Andric ctype_byname<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const
14500b57cec5SDimitry Andric {
14510b57cec5SDimitry Andric     for (; low != high; ++low)
14520b57cec5SDimitry Andric     {
14530b57cec5SDimitry Andric #ifdef _LIBCPP_WCTYPE_IS_MASK
1454*bdd1243dSDimitry Andric         if (!iswctype_l(*low, m, __l_))
14550b57cec5SDimitry Andric             break;
14560b57cec5SDimitry Andric #else
14570b57cec5SDimitry Andric         wint_t ch = static_cast<wint_t>(*low);
1458*bdd1243dSDimitry Andric         if ((m & space) == space && iswspace_l(ch, __l_)) continue;
1459*bdd1243dSDimitry Andric         if ((m & print) == print && iswprint_l(ch, __l_)) continue;
1460*bdd1243dSDimitry Andric         if ((m & cntrl) == cntrl && iswcntrl_l(ch, __l_)) continue;
1461*bdd1243dSDimitry Andric         if ((m & upper) == upper && iswupper_l(ch, __l_)) continue;
1462*bdd1243dSDimitry Andric         if ((m & lower) == lower && iswlower_l(ch, __l_)) continue;
1463*bdd1243dSDimitry Andric         if ((m & alpha) == alpha && iswalpha_l(ch, __l_)) continue;
1464*bdd1243dSDimitry Andric         if ((m & digit) == digit && iswdigit_l(ch, __l_)) continue;
1465*bdd1243dSDimitry Andric         if ((m & punct) == punct && iswpunct_l(ch, __l_)) continue;
1466*bdd1243dSDimitry Andric         if ((m & xdigit) == xdigit && iswxdigit_l(ch, __l_)) continue;
1467*bdd1243dSDimitry Andric         if ((m & blank) == blank && iswblank_l(ch, __l_)) continue;
14680b57cec5SDimitry Andric         break;
14690b57cec5SDimitry Andric #endif
14700b57cec5SDimitry Andric     }
14710b57cec5SDimitry Andric     return low;
14720b57cec5SDimitry Andric }
14730b57cec5SDimitry Andric 
14740b57cec5SDimitry Andric wchar_t
14750b57cec5SDimitry Andric ctype_byname<wchar_t>::do_toupper(char_type c) const
14760b57cec5SDimitry Andric {
1477*bdd1243dSDimitry Andric     return towupper_l(c, __l_);
14780b57cec5SDimitry Andric }
14790b57cec5SDimitry Andric 
14800b57cec5SDimitry Andric const wchar_t*
14810b57cec5SDimitry Andric ctype_byname<wchar_t>::do_toupper(char_type* low, const char_type* high) const
14820b57cec5SDimitry Andric {
14830b57cec5SDimitry Andric     for (; low != high; ++low)
1484*bdd1243dSDimitry Andric         *low = towupper_l(*low, __l_);
14850b57cec5SDimitry Andric     return low;
14860b57cec5SDimitry Andric }
14870b57cec5SDimitry Andric 
14880b57cec5SDimitry Andric wchar_t
14890b57cec5SDimitry Andric ctype_byname<wchar_t>::do_tolower(char_type c) const
14900b57cec5SDimitry Andric {
1491*bdd1243dSDimitry Andric     return towlower_l(c, __l_);
14920b57cec5SDimitry Andric }
14930b57cec5SDimitry Andric 
14940b57cec5SDimitry Andric const wchar_t*
14950b57cec5SDimitry Andric ctype_byname<wchar_t>::do_tolower(char_type* low, const char_type* high) const
14960b57cec5SDimitry Andric {
14970b57cec5SDimitry Andric     for (; low != high; ++low)
1498*bdd1243dSDimitry Andric         *low = towlower_l(*low, __l_);
14990b57cec5SDimitry Andric     return low;
15000b57cec5SDimitry Andric }
15010b57cec5SDimitry Andric 
15020b57cec5SDimitry Andric wchar_t
15030b57cec5SDimitry Andric ctype_byname<wchar_t>::do_widen(char c) const
15040b57cec5SDimitry Andric {
1505*bdd1243dSDimitry Andric     return __libcpp_btowc_l(c, __l_);
15060b57cec5SDimitry Andric }
15070b57cec5SDimitry Andric 
15080b57cec5SDimitry Andric const char*
15090b57cec5SDimitry Andric ctype_byname<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const
15100b57cec5SDimitry Andric {
15110b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
1512*bdd1243dSDimitry Andric         *dest = __libcpp_btowc_l(*low, __l_);
15130b57cec5SDimitry Andric     return low;
15140b57cec5SDimitry Andric }
15150b57cec5SDimitry Andric 
15160b57cec5SDimitry Andric char
15170b57cec5SDimitry Andric ctype_byname<wchar_t>::do_narrow(char_type c, char dfault) const
15180b57cec5SDimitry Andric {
1519*bdd1243dSDimitry Andric     int r = __libcpp_wctob_l(c, __l_);
152081ad6265SDimitry Andric     return (r != EOF) ? static_cast<char>(r) : dfault;
15210b57cec5SDimitry Andric }
15220b57cec5SDimitry Andric 
15230b57cec5SDimitry Andric const wchar_t*
15240b57cec5SDimitry Andric ctype_byname<wchar_t>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
15250b57cec5SDimitry Andric {
15260b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
15270b57cec5SDimitry Andric     {
1528*bdd1243dSDimitry Andric         int r = __libcpp_wctob_l(*low, __l_);
152981ad6265SDimitry Andric         *dest = (r != EOF) ? static_cast<char>(r) : dfault;
15300b57cec5SDimitry Andric     }
15310b57cec5SDimitry Andric     return low;
15320b57cec5SDimitry Andric }
1533349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
15340b57cec5SDimitry Andric 
15350b57cec5SDimitry Andric // template <> class codecvt<char, char, mbstate_t>
15360b57cec5SDimitry Andric 
15370b57cec5SDimitry Andric locale::id codecvt<char, char, mbstate_t>::id;
15380b57cec5SDimitry Andric 
15390b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::~codecvt()
15400b57cec5SDimitry Andric {
15410b57cec5SDimitry Andric }
15420b57cec5SDimitry Andric 
15430b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::result
15440b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::do_out(state_type&,
15450b57cec5SDimitry Andric     const intern_type* frm, const intern_type*, const intern_type*& frm_nxt,
15460b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
15470b57cec5SDimitry Andric {
15480b57cec5SDimitry Andric     frm_nxt = frm;
15490b57cec5SDimitry Andric     to_nxt = to;
15500b57cec5SDimitry Andric     return noconv;
15510b57cec5SDimitry Andric }
15520b57cec5SDimitry Andric 
15530b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::result
15540b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::do_in(state_type&,
15550b57cec5SDimitry Andric     const extern_type* frm, const extern_type*, const extern_type*& frm_nxt,
15560b57cec5SDimitry Andric     intern_type* to, intern_type*, intern_type*& to_nxt) const
15570b57cec5SDimitry Andric {
15580b57cec5SDimitry Andric     frm_nxt = frm;
15590b57cec5SDimitry Andric     to_nxt = to;
15600b57cec5SDimitry Andric     return noconv;
15610b57cec5SDimitry Andric }
15620b57cec5SDimitry Andric 
15630b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::result
15640b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::do_unshift(state_type&,
15650b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
15660b57cec5SDimitry Andric {
15670b57cec5SDimitry Andric     to_nxt = to;
15680b57cec5SDimitry Andric     return noconv;
15690b57cec5SDimitry Andric }
15700b57cec5SDimitry Andric 
15710b57cec5SDimitry Andric int
1572fe6060f1SDimitry Andric codecvt<char, char, mbstate_t>::do_encoding() const noexcept
15730b57cec5SDimitry Andric {
15740b57cec5SDimitry Andric     return 1;
15750b57cec5SDimitry Andric }
15760b57cec5SDimitry Andric 
15770b57cec5SDimitry Andric bool
1578fe6060f1SDimitry Andric codecvt<char, char, mbstate_t>::do_always_noconv() const noexcept
15790b57cec5SDimitry Andric {
15800b57cec5SDimitry Andric     return true;
15810b57cec5SDimitry Andric }
15820b57cec5SDimitry Andric 
15830b57cec5SDimitry Andric int
15840b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::do_length(state_type&,
15850b57cec5SDimitry Andric     const extern_type* frm, const extern_type* end, size_t mx) const
15860b57cec5SDimitry Andric {
15870b57cec5SDimitry Andric     return static_cast<int>(min<size_t>(mx, static_cast<size_t>(end-frm)));
15880b57cec5SDimitry Andric }
15890b57cec5SDimitry Andric 
15900b57cec5SDimitry Andric int
1591fe6060f1SDimitry Andric codecvt<char, char, mbstate_t>::do_max_length() const noexcept
15920b57cec5SDimitry Andric {
15930b57cec5SDimitry Andric     return 1;
15940b57cec5SDimitry Andric }
15950b57cec5SDimitry Andric 
15960b57cec5SDimitry Andric // template <> class codecvt<wchar_t, char, mbstate_t>
15970b57cec5SDimitry Andric 
1598349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
15990b57cec5SDimitry Andric locale::id codecvt<wchar_t, char, mbstate_t>::id;
16000b57cec5SDimitry Andric 
16010b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::codecvt(size_t refs)
16020b57cec5SDimitry Andric     : locale::facet(refs),
1603*bdd1243dSDimitry Andric       __l_(_LIBCPP_GET_C_LOCALE)
16040b57cec5SDimitry Andric {
16050b57cec5SDimitry Andric }
16060b57cec5SDimitry Andric 
16070b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::codecvt(const char* nm, size_t refs)
16080b57cec5SDimitry Andric     : locale::facet(refs),
1609*bdd1243dSDimitry Andric       __l_(newlocale(LC_ALL_MASK, nm, 0))
16100b57cec5SDimitry Andric {
1611*bdd1243dSDimitry Andric     if (__l_ == 0)
16120b57cec5SDimitry Andric         __throw_runtime_error("codecvt_byname<wchar_t, char, mbstate_t>::codecvt_byname"
16130b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
16140b57cec5SDimitry Andric }
16150b57cec5SDimitry Andric 
16160b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::~codecvt()
16170b57cec5SDimitry Andric {
1618*bdd1243dSDimitry Andric     if (__l_ != _LIBCPP_GET_C_LOCALE)
1619*bdd1243dSDimitry Andric         freelocale(__l_);
16200b57cec5SDimitry Andric }
16210b57cec5SDimitry Andric 
16220b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::result
16230b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_out(state_type& st,
16240b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
16250b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
16260b57cec5SDimitry Andric {
16270b57cec5SDimitry Andric     // look for first internal null in frm
16280b57cec5SDimitry Andric     const intern_type* fend = frm;
16290b57cec5SDimitry Andric     for (; fend != frm_end; ++fend)
16300b57cec5SDimitry Andric         if (*fend == 0)
16310b57cec5SDimitry Andric             break;
16320b57cec5SDimitry Andric     // loop over all null-terminated sequences in frm
16330b57cec5SDimitry Andric     to_nxt = to;
16340b57cec5SDimitry Andric     for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt)
16350b57cec5SDimitry Andric     {
16360b57cec5SDimitry Andric         // save state in case it is needed to recover to_nxt on error
16370b57cec5SDimitry Andric         mbstate_t save_state = st;
16380b57cec5SDimitry Andric         size_t n = __libcpp_wcsnrtombs_l(to, &frm_nxt, static_cast<size_t>(fend-frm),
1639*bdd1243dSDimitry Andric                                      static_cast<size_t>(to_end-to), &st, __l_);
16400b57cec5SDimitry Andric         if (n == size_t(-1))
16410b57cec5SDimitry Andric         {
16420b57cec5SDimitry Andric             // need to recover to_nxt
16430b57cec5SDimitry Andric             for (to_nxt = to; frm != frm_nxt; ++frm)
16440b57cec5SDimitry Andric             {
1645*bdd1243dSDimitry Andric                 n = __libcpp_wcrtomb_l(to_nxt, *frm, &save_state, __l_);
16460b57cec5SDimitry Andric                 if (n == size_t(-1))
16470b57cec5SDimitry Andric                     break;
16480b57cec5SDimitry Andric                 to_nxt += n;
16490b57cec5SDimitry Andric             }
16500b57cec5SDimitry Andric             frm_nxt = frm;
16510b57cec5SDimitry Andric             return error;
16520b57cec5SDimitry Andric         }
16530b57cec5SDimitry Andric         if (n == 0)
16540b57cec5SDimitry Andric             return partial;
16550b57cec5SDimitry Andric         to_nxt += n;
16560b57cec5SDimitry Andric         if (to_nxt == to_end)
16570b57cec5SDimitry Andric             break;
16580b57cec5SDimitry Andric         if (fend != frm_end)  // set up next null terminated sequence
16590b57cec5SDimitry Andric         {
16600b57cec5SDimitry Andric             // Try to write the terminating null
16610b57cec5SDimitry Andric             extern_type tmp[MB_LEN_MAX];
1662*bdd1243dSDimitry Andric             n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l_);
16630b57cec5SDimitry Andric             if (n == size_t(-1))  // on error
16640b57cec5SDimitry Andric                 return error;
16650b57cec5SDimitry Andric             if (n > static_cast<size_t>(to_end-to_nxt))  // is there room?
16660b57cec5SDimitry Andric                 return partial;
16670b57cec5SDimitry Andric             for (extern_type* p = tmp; n; --n)  // write it
16680b57cec5SDimitry Andric                 *to_nxt++ = *p++;
16690b57cec5SDimitry Andric             ++frm_nxt;
16700b57cec5SDimitry Andric             // look for next null in frm
16710b57cec5SDimitry Andric             for (fend = frm_nxt; fend != frm_end; ++fend)
16720b57cec5SDimitry Andric                 if (*fend == 0)
16730b57cec5SDimitry Andric                     break;
16740b57cec5SDimitry Andric         }
16750b57cec5SDimitry Andric     }
16760b57cec5SDimitry Andric     return frm_nxt == frm_end ? ok : partial;
16770b57cec5SDimitry Andric }
16780b57cec5SDimitry Andric 
16790b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::result
16800b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_in(state_type& st,
16810b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
16820b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
16830b57cec5SDimitry Andric {
16840b57cec5SDimitry Andric     // look for first internal null in frm
16850b57cec5SDimitry Andric     const extern_type* fend = frm;
16860b57cec5SDimitry Andric     for (; fend != frm_end; ++fend)
16870b57cec5SDimitry Andric         if (*fend == 0)
16880b57cec5SDimitry Andric             break;
16890b57cec5SDimitry Andric     // loop over all null-terminated sequences in frm
16900b57cec5SDimitry Andric     to_nxt = to;
16910b57cec5SDimitry Andric     for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt)
16920b57cec5SDimitry Andric     {
16930b57cec5SDimitry Andric         // save state in case it is needed to recover to_nxt on error
16940b57cec5SDimitry Andric         mbstate_t save_state = st;
16950b57cec5SDimitry Andric         size_t n = __libcpp_mbsnrtowcs_l(to, &frm_nxt, static_cast<size_t>(fend-frm),
1696*bdd1243dSDimitry Andric                                      static_cast<size_t>(to_end-to), &st, __l_);
16970b57cec5SDimitry Andric         if (n == size_t(-1))
16980b57cec5SDimitry Andric         {
16990b57cec5SDimitry Andric             // need to recover to_nxt
17000b57cec5SDimitry Andric             for (to_nxt = to; frm != frm_nxt; ++to_nxt)
17010b57cec5SDimitry Andric             {
17020b57cec5SDimitry Andric                 n = __libcpp_mbrtowc_l(to_nxt, frm, static_cast<size_t>(fend-frm),
1703*bdd1243dSDimitry Andric                                    &save_state, __l_);
17040b57cec5SDimitry Andric                 switch (n)
17050b57cec5SDimitry Andric                 {
17060b57cec5SDimitry Andric                 case 0:
17070b57cec5SDimitry Andric                     ++frm;
17080b57cec5SDimitry Andric                     break;
17090b57cec5SDimitry Andric                 case size_t(-1):
17100b57cec5SDimitry Andric                     frm_nxt = frm;
17110b57cec5SDimitry Andric                     return error;
17120b57cec5SDimitry Andric                 case size_t(-2):
17130b57cec5SDimitry Andric                     frm_nxt = frm;
17140b57cec5SDimitry Andric                     return partial;
17150b57cec5SDimitry Andric                 default:
17160b57cec5SDimitry Andric                     frm += n;
17170b57cec5SDimitry Andric                     break;
17180b57cec5SDimitry Andric                 }
17190b57cec5SDimitry Andric             }
17200b57cec5SDimitry Andric             frm_nxt = frm;
17210b57cec5SDimitry Andric             return frm_nxt == frm_end ? ok : partial;
17220b57cec5SDimitry Andric         }
17230b57cec5SDimitry Andric         if (n == size_t(-1))
17240b57cec5SDimitry Andric             return error;
17250b57cec5SDimitry Andric         to_nxt += n;
17260b57cec5SDimitry Andric         if (to_nxt == to_end)
17270b57cec5SDimitry Andric             break;
17280b57cec5SDimitry Andric         if (fend != frm_end)  // set up next null terminated sequence
17290b57cec5SDimitry Andric         {
17300b57cec5SDimitry Andric             // Try to write the terminating null
1731*bdd1243dSDimitry Andric             n = __libcpp_mbrtowc_l(to_nxt, frm_nxt, 1, &st, __l_);
17320b57cec5SDimitry Andric             if (n != 0)  // on error
17330b57cec5SDimitry Andric                 return error;
17340b57cec5SDimitry Andric             ++to_nxt;
17350b57cec5SDimitry Andric             ++frm_nxt;
17360b57cec5SDimitry Andric             // look for next null in frm
17370b57cec5SDimitry Andric             for (fend = frm_nxt; fend != frm_end; ++fend)
17380b57cec5SDimitry Andric                 if (*fend == 0)
17390b57cec5SDimitry Andric                     break;
17400b57cec5SDimitry Andric         }
17410b57cec5SDimitry Andric     }
17420b57cec5SDimitry Andric     return frm_nxt == frm_end ? ok : partial;
17430b57cec5SDimitry Andric }
17440b57cec5SDimitry Andric 
17450b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::result
17460b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_unshift(state_type& st,
17470b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
17480b57cec5SDimitry Andric {
17490b57cec5SDimitry Andric     to_nxt = to;
17500b57cec5SDimitry Andric     extern_type tmp[MB_LEN_MAX];
1751*bdd1243dSDimitry Andric     size_t n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l_);
17520b57cec5SDimitry Andric     if (n == size_t(-1) || n == 0)  // on error
17530b57cec5SDimitry Andric         return error;
17540b57cec5SDimitry Andric     --n;
17550b57cec5SDimitry Andric     if (n > static_cast<size_t>(to_end-to_nxt))  // is there room?
17560b57cec5SDimitry Andric         return partial;
17570b57cec5SDimitry Andric     for (extern_type* p = tmp; n; --n)  // write it
17580b57cec5SDimitry Andric         *to_nxt++ = *p++;
17590b57cec5SDimitry Andric     return ok;
17600b57cec5SDimitry Andric }
17610b57cec5SDimitry Andric 
17620b57cec5SDimitry Andric int
1763fe6060f1SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_encoding() const noexcept
17640b57cec5SDimitry Andric {
1765*bdd1243dSDimitry Andric     if (__libcpp_mbtowc_l(nullptr, nullptr, MB_LEN_MAX, __l_) != 0)
17660b57cec5SDimitry Andric         return -1;
17670b57cec5SDimitry Andric 
17680b57cec5SDimitry Andric     // stateless encoding
1769*bdd1243dSDimitry Andric     if (__l_ == 0 || __libcpp_mb_cur_max_l(__l_) == 1)  // there are no known constant length encodings
17700b57cec5SDimitry Andric         return 1;                // which take more than 1 char to form a wchar_t
17710b57cec5SDimitry Andric     return 0;
17720b57cec5SDimitry Andric }
17730b57cec5SDimitry Andric 
17740b57cec5SDimitry Andric bool
1775fe6060f1SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_always_noconv() const noexcept
17760b57cec5SDimitry Andric {
17770b57cec5SDimitry Andric     return false;
17780b57cec5SDimitry Andric }
17790b57cec5SDimitry Andric 
17800b57cec5SDimitry Andric int
17810b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_length(state_type& st,
17820b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
17830b57cec5SDimitry Andric {
17840b57cec5SDimitry Andric     int nbytes = 0;
17850b57cec5SDimitry Andric     for (size_t nwchar_t = 0; nwchar_t < mx && frm != frm_end; ++nwchar_t)
17860b57cec5SDimitry Andric     {
1787*bdd1243dSDimitry Andric         size_t n = __libcpp_mbrlen_l(frm, static_cast<size_t>(frm_end-frm), &st, __l_);
17880b57cec5SDimitry Andric         switch (n)
17890b57cec5SDimitry Andric         {
17900b57cec5SDimitry Andric         case 0:
17910b57cec5SDimitry Andric             ++nbytes;
17920b57cec5SDimitry Andric             ++frm;
17930b57cec5SDimitry Andric             break;
17940b57cec5SDimitry Andric         case size_t(-1):
17950b57cec5SDimitry Andric         case size_t(-2):
17960b57cec5SDimitry Andric             return nbytes;
17970b57cec5SDimitry Andric         default:
17980b57cec5SDimitry Andric             nbytes += n;
17990b57cec5SDimitry Andric             frm += n;
18000b57cec5SDimitry Andric             break;
18010b57cec5SDimitry Andric         }
18020b57cec5SDimitry Andric     }
18030b57cec5SDimitry Andric     return nbytes;
18040b57cec5SDimitry Andric }
18050b57cec5SDimitry Andric 
18060b57cec5SDimitry Andric int
1807fe6060f1SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_max_length() const noexcept
18080b57cec5SDimitry Andric {
1809*bdd1243dSDimitry Andric     return __l_ == 0 ? 1 : static_cast<int>(__libcpp_mb_cur_max_l(__l_));
18100b57cec5SDimitry Andric }
1811349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
18120b57cec5SDimitry Andric 
18130b57cec5SDimitry Andric //                                     Valid UTF ranges
18140b57cec5SDimitry Andric //     UTF-32               UTF-16                          UTF-8               # of code points
18150b57cec5SDimitry Andric //                     first      second       first   second    third   fourth
18160b57cec5SDimitry Andric // 000000 - 00007F  0000 - 007F               00 - 7F                                 127
18170b57cec5SDimitry Andric // 000080 - 0007FF  0080 - 07FF               C2 - DF, 80 - BF                       1920
18180b57cec5SDimitry Andric // 000800 - 000FFF  0800 - 0FFF               E0 - E0, A0 - BF, 80 - BF              2048
18190b57cec5SDimitry Andric // 001000 - 00CFFF  1000 - CFFF               E1 - EC, 80 - BF, 80 - BF             49152
18200b57cec5SDimitry Andric // 00D000 - 00D7FF  D000 - D7FF               ED - ED, 80 - 9F, 80 - BF              2048
18210b57cec5SDimitry Andric // 00D800 - 00DFFF                invalid
18220b57cec5SDimitry Andric // 00E000 - 00FFFF  E000 - FFFF               EE - EF, 80 - BF, 80 - BF              8192
18230b57cec5SDimitry Andric // 010000 - 03FFFF  D800 - D8BF, DC00 - DFFF  F0 - F0, 90 - BF, 80 - BF, 80 - BF   196608
18240b57cec5SDimitry Andric // 040000 - 0FFFFF  D8C0 - DBBF, DC00 - DFFF  F1 - F3, 80 - BF, 80 - BF, 80 - BF   786432
18250b57cec5SDimitry Andric // 100000 - 10FFFF  DBC0 - DBFF, DC00 - DFFF  F4 - F4, 80 - 8F, 80 - BF, 80 - BF    65536
18260b57cec5SDimitry Andric 
182781ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
18280b57cec5SDimitry Andric static
18290b57cec5SDimitry Andric codecvt_base::result
18300b57cec5SDimitry Andric utf16_to_utf8(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
18310b57cec5SDimitry Andric               uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
18320b57cec5SDimitry Andric               unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
18330b57cec5SDimitry Andric {
18340b57cec5SDimitry Andric     frm_nxt = frm;
18350b57cec5SDimitry Andric     to_nxt = to;
18360b57cec5SDimitry Andric     if (mode & generate_header)
18370b57cec5SDimitry Andric     {
18380b57cec5SDimitry Andric         if (to_end-to_nxt < 3)
18390b57cec5SDimitry Andric             return codecvt_base::partial;
18400b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xEF);
18410b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBB);
18420b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBF);
18430b57cec5SDimitry Andric     }
18440b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
18450b57cec5SDimitry Andric     {
18460b57cec5SDimitry Andric         uint16_t wc1 = *frm_nxt;
18470b57cec5SDimitry Andric         if (wc1 > Maxcode)
18480b57cec5SDimitry Andric             return codecvt_base::error;
18490b57cec5SDimitry Andric         if (wc1 < 0x0080)
18500b57cec5SDimitry Andric         {
18510b57cec5SDimitry Andric             if (to_end-to_nxt < 1)
18520b57cec5SDimitry Andric                 return codecvt_base::partial;
18530b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc1);
18540b57cec5SDimitry Andric         }
18550b57cec5SDimitry Andric         else if (wc1 < 0x0800)
18560b57cec5SDimitry Andric         {
18570b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
18580b57cec5SDimitry Andric                 return codecvt_base::partial;
18590b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc1 >> 6));
18600b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x03F));
18610b57cec5SDimitry Andric         }
18620b57cec5SDimitry Andric         else if (wc1 < 0xD800)
18630b57cec5SDimitry Andric         {
18640b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
18650b57cec5SDimitry Andric                 return codecvt_base::partial;
18660b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
18670b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
18680b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
18690b57cec5SDimitry Andric         }
18700b57cec5SDimitry Andric         else if (wc1 < 0xDC00)
18710b57cec5SDimitry Andric         {
18720b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
18730b57cec5SDimitry Andric                 return codecvt_base::partial;
18740b57cec5SDimitry Andric             uint16_t wc2 = frm_nxt[1];
18750b57cec5SDimitry Andric             if ((wc2 & 0xFC00) != 0xDC00)
18760b57cec5SDimitry Andric                 return codecvt_base::error;
18770b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
18780b57cec5SDimitry Andric                 return codecvt_base::partial;
18790b57cec5SDimitry Andric             if (((((wc1 & 0x03C0UL) >> 6) + 1) << 16) +
18800b57cec5SDimitry Andric                 ((wc1 & 0x003FUL) << 10) + (wc2 & 0x03FF) > Maxcode)
18810b57cec5SDimitry Andric                 return codecvt_base::error;
18820b57cec5SDimitry Andric             ++frm_nxt;
18830b57cec5SDimitry Andric             uint8_t z = ((wc1 & 0x03C0) >> 6) + 1;
18840b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xF0 | (z >> 2));
18850b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((z & 0x03) << 4)     | ((wc1 & 0x003C) >> 2));
18860b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6));
18870b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc2 & 0x003F));
18880b57cec5SDimitry Andric         }
18890b57cec5SDimitry Andric         else if (wc1 < 0xE000)
18900b57cec5SDimitry Andric         {
18910b57cec5SDimitry Andric             return codecvt_base::error;
18920b57cec5SDimitry Andric         }
18930b57cec5SDimitry Andric         else
18940b57cec5SDimitry Andric         {
18950b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
18960b57cec5SDimitry Andric                 return codecvt_base::partial;
18970b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
18980b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
18990b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
19000b57cec5SDimitry Andric         }
19010b57cec5SDimitry Andric     }
19020b57cec5SDimitry Andric     return codecvt_base::ok;
19030b57cec5SDimitry Andric }
19040b57cec5SDimitry Andric 
19050b57cec5SDimitry Andric static
19060b57cec5SDimitry Andric codecvt_base::result
19070b57cec5SDimitry Andric utf16_to_utf8(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
19080b57cec5SDimitry Andric               uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
19090b57cec5SDimitry Andric               unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
19100b57cec5SDimitry Andric {
19110b57cec5SDimitry Andric     frm_nxt = frm;
19120b57cec5SDimitry Andric     to_nxt = to;
19130b57cec5SDimitry Andric     if (mode & generate_header)
19140b57cec5SDimitry Andric     {
19150b57cec5SDimitry Andric         if (to_end-to_nxt < 3)
19160b57cec5SDimitry Andric             return codecvt_base::partial;
19170b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xEF);
19180b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBB);
19190b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBF);
19200b57cec5SDimitry Andric     }
19210b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
19220b57cec5SDimitry Andric     {
19230b57cec5SDimitry Andric         uint16_t wc1 = static_cast<uint16_t>(*frm_nxt);
19240b57cec5SDimitry Andric         if (wc1 > Maxcode)
19250b57cec5SDimitry Andric             return codecvt_base::error;
19260b57cec5SDimitry Andric         if (wc1 < 0x0080)
19270b57cec5SDimitry Andric         {
19280b57cec5SDimitry Andric             if (to_end-to_nxt < 1)
19290b57cec5SDimitry Andric                 return codecvt_base::partial;
19300b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc1);
19310b57cec5SDimitry Andric         }
19320b57cec5SDimitry Andric         else if (wc1 < 0x0800)
19330b57cec5SDimitry Andric         {
19340b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
19350b57cec5SDimitry Andric                 return codecvt_base::partial;
19360b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc1 >> 6));
19370b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x03F));
19380b57cec5SDimitry Andric         }
19390b57cec5SDimitry Andric         else if (wc1 < 0xD800)
19400b57cec5SDimitry Andric         {
19410b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
19420b57cec5SDimitry Andric                 return codecvt_base::partial;
19430b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
19440b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
19450b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
19460b57cec5SDimitry Andric         }
19470b57cec5SDimitry Andric         else if (wc1 < 0xDC00)
19480b57cec5SDimitry Andric         {
19490b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
19500b57cec5SDimitry Andric                 return codecvt_base::partial;
19510b57cec5SDimitry Andric             uint16_t wc2 = static_cast<uint16_t>(frm_nxt[1]);
19520b57cec5SDimitry Andric             if ((wc2 & 0xFC00) != 0xDC00)
19530b57cec5SDimitry Andric                 return codecvt_base::error;
19540b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
19550b57cec5SDimitry Andric                 return codecvt_base::partial;
19560b57cec5SDimitry Andric             if (((((wc1 & 0x03C0UL) >> 6) + 1) << 16) +
19570b57cec5SDimitry Andric                 ((wc1 & 0x003FUL) << 10) + (wc2 & 0x03FF) > Maxcode)
19580b57cec5SDimitry Andric                 return codecvt_base::error;
19590b57cec5SDimitry Andric             ++frm_nxt;
19600b57cec5SDimitry Andric             uint8_t z = ((wc1 & 0x03C0) >> 6) + 1;
19610b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xF0 | (z >> 2));
19620b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((z & 0x03) << 4)     | ((wc1 & 0x003C) >> 2));
19630b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6));
19640b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc2 & 0x003F));
19650b57cec5SDimitry Andric         }
19660b57cec5SDimitry Andric         else if (wc1 < 0xE000)
19670b57cec5SDimitry Andric         {
19680b57cec5SDimitry Andric             return codecvt_base::error;
19690b57cec5SDimitry Andric         }
19700b57cec5SDimitry Andric         else
19710b57cec5SDimitry Andric         {
19720b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
19730b57cec5SDimitry Andric                 return codecvt_base::partial;
19740b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
19750b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
19760b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
19770b57cec5SDimitry Andric         }
19780b57cec5SDimitry Andric     }
19790b57cec5SDimitry Andric     return codecvt_base::ok;
19800b57cec5SDimitry Andric }
19810b57cec5SDimitry Andric 
19820b57cec5SDimitry Andric static
19830b57cec5SDimitry Andric codecvt_base::result
19840b57cec5SDimitry Andric utf8_to_utf16(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
19850b57cec5SDimitry Andric               uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
19860b57cec5SDimitry Andric               unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
19870b57cec5SDimitry Andric {
19880b57cec5SDimitry Andric     frm_nxt = frm;
19890b57cec5SDimitry Andric     to_nxt = to;
19900b57cec5SDimitry Andric     if (mode & consume_header)
19910b57cec5SDimitry Andric     {
19920b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
19930b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
19940b57cec5SDimitry Andric             frm_nxt += 3;
19950b57cec5SDimitry Andric     }
19960b57cec5SDimitry Andric     for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
19970b57cec5SDimitry Andric     {
19980b57cec5SDimitry Andric         uint8_t c1 = *frm_nxt;
19990b57cec5SDimitry Andric         if (c1 > Maxcode)
20000b57cec5SDimitry Andric             return codecvt_base::error;
20010b57cec5SDimitry Andric         if (c1 < 0x80)
20020b57cec5SDimitry Andric         {
20030b57cec5SDimitry Andric             *to_nxt = static_cast<uint16_t>(c1);
20040b57cec5SDimitry Andric             ++frm_nxt;
20050b57cec5SDimitry Andric         }
20060b57cec5SDimitry Andric         else if (c1 < 0xC2)
20070b57cec5SDimitry Andric         {
20080b57cec5SDimitry Andric             return codecvt_base::error;
20090b57cec5SDimitry Andric         }
20100b57cec5SDimitry Andric         else if (c1 < 0xE0)
20110b57cec5SDimitry Andric         {
20120b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
20130b57cec5SDimitry Andric                 return codecvt_base::partial;
20140b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
20150b57cec5SDimitry Andric             if ((c2 & 0xC0) != 0x80)
20160b57cec5SDimitry Andric                 return codecvt_base::error;
20170b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
20180b57cec5SDimitry Andric             if (t > Maxcode)
20190b57cec5SDimitry Andric                 return codecvt_base::error;
20200b57cec5SDimitry Andric             *to_nxt = t;
20210b57cec5SDimitry Andric             frm_nxt += 2;
20220b57cec5SDimitry Andric         }
20230b57cec5SDimitry Andric         else if (c1 < 0xF0)
20240b57cec5SDimitry Andric         {
20250b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
20260b57cec5SDimitry Andric                 return codecvt_base::partial;
20270b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
20280b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
20290b57cec5SDimitry Andric             switch (c1)
20300b57cec5SDimitry Andric             {
20310b57cec5SDimitry Andric             case 0xE0:
20320b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
20330b57cec5SDimitry Andric                     return codecvt_base::error;
20340b57cec5SDimitry Andric                  break;
20350b57cec5SDimitry Andric             case 0xED:
20360b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
20370b57cec5SDimitry Andric                     return codecvt_base::error;
20380b57cec5SDimitry Andric                  break;
20390b57cec5SDimitry Andric             default:
20400b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
20410b57cec5SDimitry Andric                     return codecvt_base::error;
20420b57cec5SDimitry Andric                  break;
20430b57cec5SDimitry Andric             }
20440b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
20450b57cec5SDimitry Andric                 return codecvt_base::error;
20460b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
20470b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 6)
20480b57cec5SDimitry Andric                                              |  (c3 & 0x3F));
20490b57cec5SDimitry Andric             if (t > Maxcode)
20500b57cec5SDimitry Andric                 return codecvt_base::error;
20510b57cec5SDimitry Andric             *to_nxt = t;
20520b57cec5SDimitry Andric             frm_nxt += 3;
20530b57cec5SDimitry Andric         }
20540b57cec5SDimitry Andric         else if (c1 < 0xF5)
20550b57cec5SDimitry Andric         {
20560b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
20570b57cec5SDimitry Andric                 return codecvt_base::partial;
20580b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
20590b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
20600b57cec5SDimitry Andric             uint8_t c4 = frm_nxt[3];
20610b57cec5SDimitry Andric             switch (c1)
20620b57cec5SDimitry Andric             {
20630b57cec5SDimitry Andric             case 0xF0:
20640b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
20650b57cec5SDimitry Andric                     return codecvt_base::error;
20660b57cec5SDimitry Andric                  break;
20670b57cec5SDimitry Andric             case 0xF4:
20680b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
20690b57cec5SDimitry Andric                     return codecvt_base::error;
20700b57cec5SDimitry Andric                  break;
20710b57cec5SDimitry Andric             default:
20720b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
20730b57cec5SDimitry Andric                     return codecvt_base::error;
20740b57cec5SDimitry Andric                  break;
20750b57cec5SDimitry Andric             }
20760b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
20770b57cec5SDimitry Andric                 return codecvt_base::error;
20780b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
20790b57cec5SDimitry Andric                 return codecvt_base::partial;
20800b57cec5SDimitry Andric             if ((((c1 & 7UL) << 18) +
20810b57cec5SDimitry Andric                 ((c2 & 0x3FUL) << 12) +
20820b57cec5SDimitry Andric                 ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
20830b57cec5SDimitry Andric                 return codecvt_base::error;
20840b57cec5SDimitry Andric             *to_nxt = static_cast<uint16_t>(
20850b57cec5SDimitry Andric                     0xD800
20860b57cec5SDimitry Andric                   | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6)
20870b57cec5SDimitry Andric                   | ((c2 & 0x0F) << 2)
20880b57cec5SDimitry Andric                   | ((c3 & 0x30) >> 4));
20890b57cec5SDimitry Andric             *++to_nxt = static_cast<uint16_t>(
20900b57cec5SDimitry Andric                     0xDC00
20910b57cec5SDimitry Andric                   | ((c3 & 0x0F) << 6)
20920b57cec5SDimitry Andric                   |  (c4 & 0x3F));
20930b57cec5SDimitry Andric             frm_nxt += 4;
20940b57cec5SDimitry Andric         }
20950b57cec5SDimitry Andric         else
20960b57cec5SDimitry Andric         {
20970b57cec5SDimitry Andric             return codecvt_base::error;
20980b57cec5SDimitry Andric         }
20990b57cec5SDimitry Andric     }
21000b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
21010b57cec5SDimitry Andric }
21020b57cec5SDimitry Andric 
21030b57cec5SDimitry Andric static
21040b57cec5SDimitry Andric codecvt_base::result
21050b57cec5SDimitry Andric utf8_to_utf16(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
21060b57cec5SDimitry Andric               uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
21070b57cec5SDimitry Andric               unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
21080b57cec5SDimitry Andric {
21090b57cec5SDimitry Andric     frm_nxt = frm;
21100b57cec5SDimitry Andric     to_nxt = to;
21110b57cec5SDimitry Andric     if (mode & consume_header)
21120b57cec5SDimitry Andric     {
21130b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
21140b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
21150b57cec5SDimitry Andric             frm_nxt += 3;
21160b57cec5SDimitry Andric     }
21170b57cec5SDimitry Andric     for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
21180b57cec5SDimitry Andric     {
21190b57cec5SDimitry Andric         uint8_t c1 = *frm_nxt;
21200b57cec5SDimitry Andric         if (c1 > Maxcode)
21210b57cec5SDimitry Andric             return codecvt_base::error;
21220b57cec5SDimitry Andric         if (c1 < 0x80)
21230b57cec5SDimitry Andric         {
21240b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(c1);
21250b57cec5SDimitry Andric             ++frm_nxt;
21260b57cec5SDimitry Andric         }
21270b57cec5SDimitry Andric         else if (c1 < 0xC2)
21280b57cec5SDimitry Andric         {
21290b57cec5SDimitry Andric             return codecvt_base::error;
21300b57cec5SDimitry Andric         }
21310b57cec5SDimitry Andric         else if (c1 < 0xE0)
21320b57cec5SDimitry Andric         {
21330b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
21340b57cec5SDimitry Andric                 return codecvt_base::partial;
21350b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
21360b57cec5SDimitry Andric             if ((c2 & 0xC0) != 0x80)
21370b57cec5SDimitry Andric                 return codecvt_base::error;
21380b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
21390b57cec5SDimitry Andric             if (t > Maxcode)
21400b57cec5SDimitry Andric                 return codecvt_base::error;
21410b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(t);
21420b57cec5SDimitry Andric             frm_nxt += 2;
21430b57cec5SDimitry Andric         }
21440b57cec5SDimitry Andric         else if (c1 < 0xF0)
21450b57cec5SDimitry Andric         {
21460b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
21470b57cec5SDimitry Andric                 return codecvt_base::partial;
21480b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
21490b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
21500b57cec5SDimitry Andric             switch (c1)
21510b57cec5SDimitry Andric             {
21520b57cec5SDimitry Andric             case 0xE0:
21530b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
21540b57cec5SDimitry Andric                     return codecvt_base::error;
21550b57cec5SDimitry Andric                  break;
21560b57cec5SDimitry Andric             case 0xED:
21570b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
21580b57cec5SDimitry Andric                     return codecvt_base::error;
21590b57cec5SDimitry Andric                  break;
21600b57cec5SDimitry Andric             default:
21610b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
21620b57cec5SDimitry Andric                     return codecvt_base::error;
21630b57cec5SDimitry Andric                  break;
21640b57cec5SDimitry Andric             }
21650b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
21660b57cec5SDimitry Andric                 return codecvt_base::error;
21670b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
21680b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 6)
21690b57cec5SDimitry Andric                                              |  (c3 & 0x3F));
21700b57cec5SDimitry Andric             if (t > Maxcode)
21710b57cec5SDimitry Andric                 return codecvt_base::error;
21720b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(t);
21730b57cec5SDimitry Andric             frm_nxt += 3;
21740b57cec5SDimitry Andric         }
21750b57cec5SDimitry Andric         else if (c1 < 0xF5)
21760b57cec5SDimitry Andric         {
21770b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
21780b57cec5SDimitry Andric                 return codecvt_base::partial;
21790b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
21800b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
21810b57cec5SDimitry Andric             uint8_t c4 = frm_nxt[3];
21820b57cec5SDimitry Andric             switch (c1)
21830b57cec5SDimitry Andric             {
21840b57cec5SDimitry Andric             case 0xF0:
21850b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
21860b57cec5SDimitry Andric                     return codecvt_base::error;
21870b57cec5SDimitry Andric                  break;
21880b57cec5SDimitry Andric             case 0xF4:
21890b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
21900b57cec5SDimitry Andric                     return codecvt_base::error;
21910b57cec5SDimitry Andric                  break;
21920b57cec5SDimitry Andric             default:
21930b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
21940b57cec5SDimitry Andric                     return codecvt_base::error;
21950b57cec5SDimitry Andric                  break;
21960b57cec5SDimitry Andric             }
21970b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
21980b57cec5SDimitry Andric                 return codecvt_base::error;
21990b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
22000b57cec5SDimitry Andric                 return codecvt_base::partial;
22010b57cec5SDimitry Andric             if ((((c1 & 7UL) << 18) +
22020b57cec5SDimitry Andric                 ((c2 & 0x3FUL) << 12) +
22030b57cec5SDimitry Andric                 ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
22040b57cec5SDimitry Andric                 return codecvt_base::error;
22050b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(
22060b57cec5SDimitry Andric                     0xD800
22070b57cec5SDimitry Andric                   | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6)
22080b57cec5SDimitry Andric                   | ((c2 & 0x0F) << 2)
22090b57cec5SDimitry Andric                   | ((c3 & 0x30) >> 4));
22100b57cec5SDimitry Andric             *++to_nxt = static_cast<uint32_t>(
22110b57cec5SDimitry Andric                     0xDC00
22120b57cec5SDimitry Andric                   | ((c3 & 0x0F) << 6)
22130b57cec5SDimitry Andric                   |  (c4 & 0x3F));
22140b57cec5SDimitry Andric             frm_nxt += 4;
22150b57cec5SDimitry Andric         }
22160b57cec5SDimitry Andric         else
22170b57cec5SDimitry Andric         {
22180b57cec5SDimitry Andric             return codecvt_base::error;
22190b57cec5SDimitry Andric         }
22200b57cec5SDimitry Andric     }
22210b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
22220b57cec5SDimitry Andric }
22230b57cec5SDimitry Andric 
22240b57cec5SDimitry Andric static
22250b57cec5SDimitry Andric int
22260b57cec5SDimitry Andric utf8_to_utf16_length(const uint8_t* frm, const uint8_t* frm_end,
22270b57cec5SDimitry Andric                      size_t mx, unsigned long Maxcode = 0x10FFFF,
22280b57cec5SDimitry Andric                      codecvt_mode mode = codecvt_mode(0))
22290b57cec5SDimitry Andric {
22300b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
22310b57cec5SDimitry Andric     if (mode & consume_header)
22320b57cec5SDimitry Andric     {
22330b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
22340b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
22350b57cec5SDimitry Andric             frm_nxt += 3;
22360b57cec5SDimitry Andric     }
22370b57cec5SDimitry Andric     for (size_t nchar16_t = 0; frm_nxt < frm_end && nchar16_t < mx; ++nchar16_t)
22380b57cec5SDimitry Andric     {
22390b57cec5SDimitry Andric         uint8_t c1 = *frm_nxt;
22400b57cec5SDimitry Andric         if (c1 > Maxcode)
22410b57cec5SDimitry Andric             break;
22420b57cec5SDimitry Andric         if (c1 < 0x80)
22430b57cec5SDimitry Andric         {
22440b57cec5SDimitry Andric             ++frm_nxt;
22450b57cec5SDimitry Andric         }
22460b57cec5SDimitry Andric         else if (c1 < 0xC2)
22470b57cec5SDimitry Andric         {
22480b57cec5SDimitry Andric             break;
22490b57cec5SDimitry Andric         }
22500b57cec5SDimitry Andric         else if (c1 < 0xE0)
22510b57cec5SDimitry Andric         {
22520b57cec5SDimitry Andric             if ((frm_end-frm_nxt < 2) || (frm_nxt[1] & 0xC0) != 0x80)
22530b57cec5SDimitry Andric                 break;
22540b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (frm_nxt[1] & 0x3F));
22550b57cec5SDimitry Andric             if (t > Maxcode)
22560b57cec5SDimitry Andric                 break;
22570b57cec5SDimitry Andric             frm_nxt += 2;
22580b57cec5SDimitry Andric         }
22590b57cec5SDimitry Andric         else if (c1 < 0xF0)
22600b57cec5SDimitry Andric         {
22610b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
22620b57cec5SDimitry Andric                 break;
22630b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
22640b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
22650b57cec5SDimitry Andric             switch (c1)
22660b57cec5SDimitry Andric             {
22670b57cec5SDimitry Andric             case 0xE0:
22680b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
22690b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
22700b57cec5SDimitry Andric                 break;
22710b57cec5SDimitry Andric             case 0xED:
22720b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
22730b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
22740b57cec5SDimitry Andric                  break;
22750b57cec5SDimitry Andric             default:
22760b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
22770b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
22780b57cec5SDimitry Andric                  break;
22790b57cec5SDimitry Andric             }
22800b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
22810b57cec5SDimitry Andric                 break;
22820b57cec5SDimitry Andric             if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
22830b57cec5SDimitry Andric                 break;
22840b57cec5SDimitry Andric             frm_nxt += 3;
22850b57cec5SDimitry Andric         }
22860b57cec5SDimitry Andric         else if (c1 < 0xF5)
22870b57cec5SDimitry Andric         {
22880b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4 || mx-nchar16_t < 2)
22890b57cec5SDimitry Andric                 break;
22900b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
22910b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
22920b57cec5SDimitry Andric             uint8_t c4 = frm_nxt[3];
22930b57cec5SDimitry Andric             switch (c1)
22940b57cec5SDimitry Andric             {
22950b57cec5SDimitry Andric             case 0xF0:
22960b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
22970b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
22980b57cec5SDimitry Andric                  break;
22990b57cec5SDimitry Andric             case 0xF4:
23000b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
23010b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
23020b57cec5SDimitry Andric                  break;
23030b57cec5SDimitry Andric             default:
23040b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
23050b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
23060b57cec5SDimitry Andric                  break;
23070b57cec5SDimitry Andric             }
23080b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
23090b57cec5SDimitry Andric                 break;
23100b57cec5SDimitry Andric             if ((((c1 & 7UL) << 18) +
23110b57cec5SDimitry Andric                 ((c2 & 0x3FUL) << 12) +
23120b57cec5SDimitry Andric                 ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
23130b57cec5SDimitry Andric                 break;
23140b57cec5SDimitry Andric             ++nchar16_t;
23150b57cec5SDimitry Andric             frm_nxt += 4;
23160b57cec5SDimitry Andric         }
23170b57cec5SDimitry Andric         else
23180b57cec5SDimitry Andric         {
23190b57cec5SDimitry Andric             break;
23200b57cec5SDimitry Andric         }
23210b57cec5SDimitry Andric     }
23220b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
23230b57cec5SDimitry Andric }
23240b57cec5SDimitry Andric 
23250b57cec5SDimitry Andric static
23260b57cec5SDimitry Andric codecvt_base::result
23270b57cec5SDimitry Andric ucs4_to_utf8(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
23280b57cec5SDimitry Andric              uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
23290b57cec5SDimitry Andric              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
23300b57cec5SDimitry Andric {
23310b57cec5SDimitry Andric     frm_nxt = frm;
23320b57cec5SDimitry Andric     to_nxt = to;
23330b57cec5SDimitry Andric     if (mode & generate_header)
23340b57cec5SDimitry Andric     {
23350b57cec5SDimitry Andric         if (to_end-to_nxt < 3)
23360b57cec5SDimitry Andric             return codecvt_base::partial;
23370b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xEF);
23380b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBB);
23390b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBF);
23400b57cec5SDimitry Andric     }
23410b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
23420b57cec5SDimitry Andric     {
23430b57cec5SDimitry Andric         uint32_t wc = *frm_nxt;
23440b57cec5SDimitry Andric         if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
23450b57cec5SDimitry Andric             return codecvt_base::error;
23460b57cec5SDimitry Andric         if (wc < 0x000080)
23470b57cec5SDimitry Andric         {
23480b57cec5SDimitry Andric             if (to_end-to_nxt < 1)
23490b57cec5SDimitry Andric                 return codecvt_base::partial;
23500b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc);
23510b57cec5SDimitry Andric         }
23520b57cec5SDimitry Andric         else if (wc < 0x000800)
23530b57cec5SDimitry Andric         {
23540b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
23550b57cec5SDimitry Andric                 return codecvt_base::partial;
23560b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc >> 6));
23570b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x03F));
23580b57cec5SDimitry Andric         }
23590b57cec5SDimitry Andric         else if (wc < 0x010000)
23600b57cec5SDimitry Andric         {
23610b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
23620b57cec5SDimitry Andric                 return codecvt_base::partial;
23630b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc >> 12));
23640b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6));
23650b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc & 0x003F));
23660b57cec5SDimitry Andric         }
23670b57cec5SDimitry Andric         else // if (wc < 0x110000)
23680b57cec5SDimitry Andric         {
23690b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
23700b57cec5SDimitry Andric                 return codecvt_base::partial;
23710b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xF0 |  (wc >> 18));
23720b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x03F000) >> 12));
23730b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x000FC0) >> 6));
23740b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc & 0x00003F));
23750b57cec5SDimitry Andric         }
23760b57cec5SDimitry Andric     }
23770b57cec5SDimitry Andric     return codecvt_base::ok;
23780b57cec5SDimitry Andric }
23790b57cec5SDimitry Andric 
23800b57cec5SDimitry Andric static
23810b57cec5SDimitry Andric codecvt_base::result
23820b57cec5SDimitry Andric utf8_to_ucs4(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
23830b57cec5SDimitry Andric              uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
23840b57cec5SDimitry Andric              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
23850b57cec5SDimitry Andric {
23860b57cec5SDimitry Andric     frm_nxt = frm;
23870b57cec5SDimitry Andric     to_nxt = to;
23880b57cec5SDimitry Andric     if (mode & consume_header)
23890b57cec5SDimitry Andric     {
23900b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
23910b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
23920b57cec5SDimitry Andric             frm_nxt += 3;
23930b57cec5SDimitry Andric     }
23940b57cec5SDimitry Andric     for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
23950b57cec5SDimitry Andric     {
23960b57cec5SDimitry Andric         uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
23970b57cec5SDimitry Andric         if (c1 < 0x80)
23980b57cec5SDimitry Andric         {
23990b57cec5SDimitry Andric             if (c1 > Maxcode)
24000b57cec5SDimitry Andric                 return codecvt_base::error;
24010b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(c1);
24020b57cec5SDimitry Andric             ++frm_nxt;
24030b57cec5SDimitry Andric         }
24040b57cec5SDimitry Andric         else if (c1 < 0xC2)
24050b57cec5SDimitry Andric         {
24060b57cec5SDimitry Andric             return codecvt_base::error;
24070b57cec5SDimitry Andric         }
24080b57cec5SDimitry Andric         else if (c1 < 0xE0)
24090b57cec5SDimitry Andric         {
24100b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
24110b57cec5SDimitry Andric                 return codecvt_base::partial;
24120b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
24130b57cec5SDimitry Andric             if ((c2 & 0xC0) != 0x80)
24140b57cec5SDimitry Andric                 return codecvt_base::error;
24150b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(((c1 & 0x1F) << 6)
24160b57cec5SDimitry Andric                                               | (c2 & 0x3F));
24170b57cec5SDimitry Andric             if (t > Maxcode)
24180b57cec5SDimitry Andric                 return codecvt_base::error;
24190b57cec5SDimitry Andric             *to_nxt = t;
24200b57cec5SDimitry Andric             frm_nxt += 2;
24210b57cec5SDimitry Andric         }
24220b57cec5SDimitry Andric         else if (c1 < 0xF0)
24230b57cec5SDimitry Andric         {
24240b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
24250b57cec5SDimitry Andric                 return codecvt_base::partial;
24260b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
24270b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
24280b57cec5SDimitry Andric             switch (c1)
24290b57cec5SDimitry Andric             {
24300b57cec5SDimitry Andric             case 0xE0:
24310b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
24320b57cec5SDimitry Andric                     return codecvt_base::error;
24330b57cec5SDimitry Andric                  break;
24340b57cec5SDimitry Andric             case 0xED:
24350b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
24360b57cec5SDimitry Andric                     return codecvt_base::error;
24370b57cec5SDimitry Andric                  break;
24380b57cec5SDimitry Andric             default:
24390b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
24400b57cec5SDimitry Andric                     return codecvt_base::error;
24410b57cec5SDimitry Andric                  break;
24420b57cec5SDimitry Andric             }
24430b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
24440b57cec5SDimitry Andric                 return codecvt_base::error;
24450b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(((c1 & 0x0F) << 12)
24460b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 6)
24470b57cec5SDimitry Andric                                              |  (c3 & 0x3F));
24480b57cec5SDimitry Andric             if (t > Maxcode)
24490b57cec5SDimitry Andric                 return codecvt_base::error;
24500b57cec5SDimitry Andric             *to_nxt = t;
24510b57cec5SDimitry Andric             frm_nxt += 3;
24520b57cec5SDimitry Andric         }
24530b57cec5SDimitry Andric         else if (c1 < 0xF5)
24540b57cec5SDimitry Andric         {
24550b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
24560b57cec5SDimitry Andric                 return codecvt_base::partial;
24570b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
24580b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
24590b57cec5SDimitry Andric             uint8_t c4 = frm_nxt[3];
24600b57cec5SDimitry Andric             switch (c1)
24610b57cec5SDimitry Andric             {
24620b57cec5SDimitry Andric             case 0xF0:
24630b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
24640b57cec5SDimitry Andric                     return codecvt_base::error;
24650b57cec5SDimitry Andric                  break;
24660b57cec5SDimitry Andric             case 0xF4:
24670b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
24680b57cec5SDimitry Andric                     return codecvt_base::error;
24690b57cec5SDimitry Andric                  break;
24700b57cec5SDimitry Andric             default:
24710b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
24720b57cec5SDimitry Andric                     return codecvt_base::error;
24730b57cec5SDimitry Andric                  break;
24740b57cec5SDimitry Andric             }
24750b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
24760b57cec5SDimitry Andric                 return codecvt_base::error;
24770b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(((c1 & 0x07) << 18)
24780b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 12)
24790b57cec5SDimitry Andric                                              | ((c3 & 0x3F) << 6)
24800b57cec5SDimitry Andric                                              |  (c4 & 0x3F));
24810b57cec5SDimitry Andric             if (t > Maxcode)
24820b57cec5SDimitry Andric                 return codecvt_base::error;
24830b57cec5SDimitry Andric             *to_nxt = t;
24840b57cec5SDimitry Andric             frm_nxt += 4;
24850b57cec5SDimitry Andric         }
24860b57cec5SDimitry Andric         else
24870b57cec5SDimitry Andric         {
24880b57cec5SDimitry Andric             return codecvt_base::error;
24890b57cec5SDimitry Andric         }
24900b57cec5SDimitry Andric     }
24910b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
24920b57cec5SDimitry Andric }
24930b57cec5SDimitry Andric 
24940b57cec5SDimitry Andric static
24950b57cec5SDimitry Andric int
24960b57cec5SDimitry Andric utf8_to_ucs4_length(const uint8_t* frm, const uint8_t* frm_end,
24970b57cec5SDimitry Andric                     size_t mx, unsigned long Maxcode = 0x10FFFF,
24980b57cec5SDimitry Andric                     codecvt_mode mode = codecvt_mode(0))
24990b57cec5SDimitry Andric {
25000b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
25010b57cec5SDimitry Andric     if (mode & consume_header)
25020b57cec5SDimitry Andric     {
25030b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
25040b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
25050b57cec5SDimitry Andric             frm_nxt += 3;
25060b57cec5SDimitry Andric     }
25070b57cec5SDimitry Andric     for (size_t nchar32_t = 0; frm_nxt < frm_end && nchar32_t < mx; ++nchar32_t)
25080b57cec5SDimitry Andric     {
25090b57cec5SDimitry Andric         uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
25100b57cec5SDimitry Andric         if (c1 < 0x80)
25110b57cec5SDimitry Andric         {
25120b57cec5SDimitry Andric             if (c1 > Maxcode)
25130b57cec5SDimitry Andric                 break;
25140b57cec5SDimitry Andric             ++frm_nxt;
25150b57cec5SDimitry Andric         }
25160b57cec5SDimitry Andric         else if (c1 < 0xC2)
25170b57cec5SDimitry Andric         {
25180b57cec5SDimitry Andric             break;
25190b57cec5SDimitry Andric         }
25200b57cec5SDimitry Andric         else if (c1 < 0xE0)
25210b57cec5SDimitry Andric         {
25220b57cec5SDimitry Andric             if ((frm_end-frm_nxt < 2) || ((frm_nxt[1] & 0xC0) != 0x80))
25230b57cec5SDimitry Andric                 break;
25240b57cec5SDimitry Andric             if ((((c1 & 0x1Fu) << 6) | (frm_nxt[1] & 0x3Fu)) > Maxcode)
25250b57cec5SDimitry Andric                 break;
25260b57cec5SDimitry Andric             frm_nxt += 2;
25270b57cec5SDimitry Andric         }
25280b57cec5SDimitry Andric         else if (c1 < 0xF0)
25290b57cec5SDimitry Andric         {
25300b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
25310b57cec5SDimitry Andric                 break;
25320b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
25330b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
25340b57cec5SDimitry Andric             switch (c1)
25350b57cec5SDimitry Andric             {
25360b57cec5SDimitry Andric             case 0xE0:
25370b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
25380b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25390b57cec5SDimitry Andric                 break;
25400b57cec5SDimitry Andric             case 0xED:
25410b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
25420b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25430b57cec5SDimitry Andric                  break;
25440b57cec5SDimitry Andric             default:
25450b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
25460b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25470b57cec5SDimitry Andric                  break;
25480b57cec5SDimitry Andric             }
25490b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
25500b57cec5SDimitry Andric                 break;
25510b57cec5SDimitry Andric             if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
25520b57cec5SDimitry Andric                 break;
25530b57cec5SDimitry Andric             frm_nxt += 3;
25540b57cec5SDimitry Andric         }
25550b57cec5SDimitry Andric         else if (c1 < 0xF5)
25560b57cec5SDimitry Andric         {
25570b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
25580b57cec5SDimitry Andric                 break;
25590b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
25600b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
25610b57cec5SDimitry Andric             uint8_t c4 = frm_nxt[3];
25620b57cec5SDimitry Andric             switch (c1)
25630b57cec5SDimitry Andric             {
25640b57cec5SDimitry Andric             case 0xF0:
25650b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
25660b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25670b57cec5SDimitry Andric                  break;
25680b57cec5SDimitry Andric             case 0xF4:
25690b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
25700b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25710b57cec5SDimitry Andric                  break;
25720b57cec5SDimitry Andric             default:
25730b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
25740b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25750b57cec5SDimitry Andric                  break;
25760b57cec5SDimitry Andric             }
25770b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
25780b57cec5SDimitry Andric                 break;
25790b57cec5SDimitry Andric             if ((((c1 & 0x07u) << 18) | ((c2 & 0x3Fu) << 12) |
25800b57cec5SDimitry Andric                  ((c3 & 0x3Fu) << 6)  |  (c4 & 0x3Fu)) > Maxcode)
25810b57cec5SDimitry Andric                 break;
25820b57cec5SDimitry Andric             frm_nxt += 4;
25830b57cec5SDimitry Andric         }
25840b57cec5SDimitry Andric         else
25850b57cec5SDimitry Andric         {
25860b57cec5SDimitry Andric             break;
25870b57cec5SDimitry Andric         }
25880b57cec5SDimitry Andric     }
25890b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
25900b57cec5SDimitry Andric }
25910b57cec5SDimitry Andric 
25920b57cec5SDimitry Andric static
25930b57cec5SDimitry Andric codecvt_base::result
25940b57cec5SDimitry Andric ucs2_to_utf8(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
25950b57cec5SDimitry Andric              uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
25960b57cec5SDimitry Andric              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
25970b57cec5SDimitry Andric {
25980b57cec5SDimitry Andric     frm_nxt = frm;
25990b57cec5SDimitry Andric     to_nxt = to;
26000b57cec5SDimitry Andric     if (mode & generate_header)
26010b57cec5SDimitry Andric     {
26020b57cec5SDimitry Andric         if (to_end-to_nxt < 3)
26030b57cec5SDimitry Andric             return codecvt_base::partial;
26040b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xEF);
26050b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBB);
26060b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBF);
26070b57cec5SDimitry Andric     }
26080b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
26090b57cec5SDimitry Andric     {
26100b57cec5SDimitry Andric         uint16_t wc = *frm_nxt;
26110b57cec5SDimitry Andric         if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
26120b57cec5SDimitry Andric             return codecvt_base::error;
26130b57cec5SDimitry Andric         if (wc < 0x0080)
26140b57cec5SDimitry Andric         {
26150b57cec5SDimitry Andric             if (to_end-to_nxt < 1)
26160b57cec5SDimitry Andric                 return codecvt_base::partial;
26170b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc);
26180b57cec5SDimitry Andric         }
26190b57cec5SDimitry Andric         else if (wc < 0x0800)
26200b57cec5SDimitry Andric         {
26210b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
26220b57cec5SDimitry Andric                 return codecvt_base::partial;
26230b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc >> 6));
26240b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x03F));
26250b57cec5SDimitry Andric         }
26260b57cec5SDimitry Andric         else // if (wc <= 0xFFFF)
26270b57cec5SDimitry Andric         {
26280b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
26290b57cec5SDimitry Andric                 return codecvt_base::partial;
26300b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc >> 12));
26310b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6));
26320b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc & 0x003F));
26330b57cec5SDimitry Andric         }
26340b57cec5SDimitry Andric     }
26350b57cec5SDimitry Andric     return codecvt_base::ok;
26360b57cec5SDimitry Andric }
26370b57cec5SDimitry Andric 
26380b57cec5SDimitry Andric static
26390b57cec5SDimitry Andric codecvt_base::result
26400b57cec5SDimitry Andric utf8_to_ucs2(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
26410b57cec5SDimitry Andric              uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
26420b57cec5SDimitry Andric              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
26430b57cec5SDimitry Andric {
26440b57cec5SDimitry Andric     frm_nxt = frm;
26450b57cec5SDimitry Andric     to_nxt = to;
26460b57cec5SDimitry Andric     if (mode & consume_header)
26470b57cec5SDimitry Andric     {
26480b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
26490b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
26500b57cec5SDimitry Andric             frm_nxt += 3;
26510b57cec5SDimitry Andric     }
26520b57cec5SDimitry Andric     for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
26530b57cec5SDimitry Andric     {
26540b57cec5SDimitry Andric         uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
26550b57cec5SDimitry Andric         if (c1 < 0x80)
26560b57cec5SDimitry Andric         {
26570b57cec5SDimitry Andric             if (c1 > Maxcode)
26580b57cec5SDimitry Andric                 return codecvt_base::error;
26590b57cec5SDimitry Andric             *to_nxt = static_cast<uint16_t>(c1);
26600b57cec5SDimitry Andric             ++frm_nxt;
26610b57cec5SDimitry Andric         }
26620b57cec5SDimitry Andric         else if (c1 < 0xC2)
26630b57cec5SDimitry Andric         {
26640b57cec5SDimitry Andric             return codecvt_base::error;
26650b57cec5SDimitry Andric         }
26660b57cec5SDimitry Andric         else if (c1 < 0xE0)
26670b57cec5SDimitry Andric         {
26680b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
26690b57cec5SDimitry Andric                 return codecvt_base::partial;
26700b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
26710b57cec5SDimitry Andric             if ((c2 & 0xC0) != 0x80)
26720b57cec5SDimitry Andric                 return codecvt_base::error;
26730b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6)
26740b57cec5SDimitry Andric                                               | (c2 & 0x3F));
26750b57cec5SDimitry Andric             if (t > Maxcode)
26760b57cec5SDimitry Andric                 return codecvt_base::error;
26770b57cec5SDimitry Andric             *to_nxt = t;
26780b57cec5SDimitry Andric             frm_nxt += 2;
26790b57cec5SDimitry Andric         }
26800b57cec5SDimitry Andric         else if (c1 < 0xF0)
26810b57cec5SDimitry Andric         {
26820b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
26830b57cec5SDimitry Andric                 return codecvt_base::partial;
26840b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
26850b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
26860b57cec5SDimitry Andric             switch (c1)
26870b57cec5SDimitry Andric             {
26880b57cec5SDimitry Andric             case 0xE0:
26890b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
26900b57cec5SDimitry Andric                     return codecvt_base::error;
26910b57cec5SDimitry Andric                  break;
26920b57cec5SDimitry Andric             case 0xED:
26930b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
26940b57cec5SDimitry Andric                     return codecvt_base::error;
26950b57cec5SDimitry Andric                  break;
26960b57cec5SDimitry Andric             default:
26970b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
26980b57cec5SDimitry Andric                     return codecvt_base::error;
26990b57cec5SDimitry Andric                  break;
27000b57cec5SDimitry Andric             }
27010b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
27020b57cec5SDimitry Andric                 return codecvt_base::error;
27030b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
27040b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 6)
27050b57cec5SDimitry Andric                                              |  (c3 & 0x3F));
27060b57cec5SDimitry Andric             if (t > Maxcode)
27070b57cec5SDimitry Andric                 return codecvt_base::error;
27080b57cec5SDimitry Andric             *to_nxt = t;
27090b57cec5SDimitry Andric             frm_nxt += 3;
27100b57cec5SDimitry Andric         }
27110b57cec5SDimitry Andric         else
27120b57cec5SDimitry Andric         {
27130b57cec5SDimitry Andric             return codecvt_base::error;
27140b57cec5SDimitry Andric         }
27150b57cec5SDimitry Andric     }
27160b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
27170b57cec5SDimitry Andric }
27180b57cec5SDimitry Andric 
27190b57cec5SDimitry Andric static
27200b57cec5SDimitry Andric int
27210b57cec5SDimitry Andric utf8_to_ucs2_length(const uint8_t* frm, const uint8_t* frm_end,
27220b57cec5SDimitry Andric                     size_t mx, unsigned long Maxcode = 0x10FFFF,
27230b57cec5SDimitry Andric                     codecvt_mode mode = codecvt_mode(0))
27240b57cec5SDimitry Andric {
27250b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
27260b57cec5SDimitry Andric     if (mode & consume_header)
27270b57cec5SDimitry Andric     {
27280b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
27290b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
27300b57cec5SDimitry Andric             frm_nxt += 3;
27310b57cec5SDimitry Andric     }
27320b57cec5SDimitry Andric     for (size_t nchar32_t = 0; frm_nxt < frm_end && nchar32_t < mx; ++nchar32_t)
27330b57cec5SDimitry Andric     {
27340b57cec5SDimitry Andric         uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
27350b57cec5SDimitry Andric         if (c1 < 0x80)
27360b57cec5SDimitry Andric         {
27370b57cec5SDimitry Andric             if (c1 > Maxcode)
27380b57cec5SDimitry Andric                 break;
27390b57cec5SDimitry Andric             ++frm_nxt;
27400b57cec5SDimitry Andric         }
27410b57cec5SDimitry Andric         else if (c1 < 0xC2)
27420b57cec5SDimitry Andric         {
27430b57cec5SDimitry Andric             break;
27440b57cec5SDimitry Andric         }
27450b57cec5SDimitry Andric         else if (c1 < 0xE0)
27460b57cec5SDimitry Andric         {
27470b57cec5SDimitry Andric             if ((frm_end-frm_nxt < 2) || ((frm_nxt[1] & 0xC0) != 0x80))
27480b57cec5SDimitry Andric                 break;
27490b57cec5SDimitry Andric             if ((((c1 & 0x1Fu) << 6) | (frm_nxt[1] & 0x3Fu)) > Maxcode)
27500b57cec5SDimitry Andric                 break;
27510b57cec5SDimitry Andric             frm_nxt += 2;
27520b57cec5SDimitry Andric         }
27530b57cec5SDimitry Andric         else if (c1 < 0xF0)
27540b57cec5SDimitry Andric         {
27550b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
27560b57cec5SDimitry Andric                 break;
27570b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
27580b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
27590b57cec5SDimitry Andric             switch (c1)
27600b57cec5SDimitry Andric             {
27610b57cec5SDimitry Andric             case 0xE0:
27620b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
27630b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
27640b57cec5SDimitry Andric                 break;
27650b57cec5SDimitry Andric             case 0xED:
27660b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
27670b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
27680b57cec5SDimitry Andric                  break;
27690b57cec5SDimitry Andric             default:
27700b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
27710b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
27720b57cec5SDimitry Andric                  break;
27730b57cec5SDimitry Andric             }
27740b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
27750b57cec5SDimitry Andric                 break;
27760b57cec5SDimitry Andric             if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
27770b57cec5SDimitry Andric                 break;
27780b57cec5SDimitry Andric             frm_nxt += 3;
27790b57cec5SDimitry Andric         }
27800b57cec5SDimitry Andric         else
27810b57cec5SDimitry Andric         {
27820b57cec5SDimitry Andric             break;
27830b57cec5SDimitry Andric         }
27840b57cec5SDimitry Andric     }
27850b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
27860b57cec5SDimitry Andric }
27870b57cec5SDimitry Andric 
27880b57cec5SDimitry Andric static
27890b57cec5SDimitry Andric codecvt_base::result
27900b57cec5SDimitry Andric ucs4_to_utf16be(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
27910b57cec5SDimitry Andric                 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
27920b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
27930b57cec5SDimitry Andric {
27940b57cec5SDimitry Andric     frm_nxt = frm;
27950b57cec5SDimitry Andric     to_nxt = to;
27960b57cec5SDimitry Andric     if (mode & generate_header)
27970b57cec5SDimitry Andric     {
27980b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
27990b57cec5SDimitry Andric             return codecvt_base::partial;
28000b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFE);
28010b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFF);
28020b57cec5SDimitry Andric     }
28030b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
28040b57cec5SDimitry Andric     {
28050b57cec5SDimitry Andric         uint32_t wc = *frm_nxt;
28060b57cec5SDimitry Andric         if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
28070b57cec5SDimitry Andric             return codecvt_base::error;
28080b57cec5SDimitry Andric         if (wc < 0x010000)
28090b57cec5SDimitry Andric         {
28100b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
28110b57cec5SDimitry Andric                 return codecvt_base::partial;
28120b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc >> 8);
28130b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc);
28140b57cec5SDimitry Andric         }
28150b57cec5SDimitry Andric         else
28160b57cec5SDimitry Andric         {
28170b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
28180b57cec5SDimitry Andric                 return codecvt_base::partial;
28190b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(
28200b57cec5SDimitry Andric                     0xD800
28210b57cec5SDimitry Andric                   | ((((wc & 0x1F0000) >> 16) - 1) << 6)
28220b57cec5SDimitry Andric                   |   ((wc & 0x00FC00) >> 10));
28230b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t >> 8);
28240b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t);
28250b57cec5SDimitry Andric             t = static_cast<uint16_t>(0xDC00 | (wc & 0x03FF));
28260b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t >> 8);
28270b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t);
28280b57cec5SDimitry Andric         }
28290b57cec5SDimitry Andric     }
28300b57cec5SDimitry Andric     return codecvt_base::ok;
28310b57cec5SDimitry Andric }
28320b57cec5SDimitry Andric 
28330b57cec5SDimitry Andric static
28340b57cec5SDimitry Andric codecvt_base::result
28350b57cec5SDimitry Andric utf16be_to_ucs4(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
28360b57cec5SDimitry Andric                 uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
28370b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
28380b57cec5SDimitry Andric {
28390b57cec5SDimitry Andric     frm_nxt = frm;
28400b57cec5SDimitry Andric     to_nxt = to;
28410b57cec5SDimitry Andric     if (mode & consume_header)
28420b57cec5SDimitry Andric     {
28430b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
28440b57cec5SDimitry Andric             frm_nxt += 2;
28450b57cec5SDimitry Andric     }
28460b57cec5SDimitry Andric     for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
28470b57cec5SDimitry Andric     {
28480b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
28490b57cec5SDimitry Andric         if ((c1 & 0xFC00) == 0xDC00)
28500b57cec5SDimitry Andric             return codecvt_base::error;
28510b57cec5SDimitry Andric         if ((c1 & 0xFC00) != 0xD800)
28520b57cec5SDimitry Andric         {
28530b57cec5SDimitry Andric             if (c1 > Maxcode)
28540b57cec5SDimitry Andric                 return codecvt_base::error;
28550b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(c1);
28560b57cec5SDimitry Andric             frm_nxt += 2;
28570b57cec5SDimitry Andric         }
28580b57cec5SDimitry Andric         else
28590b57cec5SDimitry Andric         {
28600b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
28610b57cec5SDimitry Andric                 return codecvt_base::partial;
28620b57cec5SDimitry Andric             uint16_t c2 = static_cast<uint16_t>(frm_nxt[2] << 8 | frm_nxt[3]);
28630b57cec5SDimitry Andric             if ((c2 & 0xFC00) != 0xDC00)
28640b57cec5SDimitry Andric                 return codecvt_base::error;
28650b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(
28660b57cec5SDimitry Andric                     ((((c1 & 0x03C0) >> 6) + 1) << 16)
28670b57cec5SDimitry Andric                   |   ((c1 & 0x003F) << 10)
28680b57cec5SDimitry Andric                   |    (c2 & 0x03FF));
28690b57cec5SDimitry Andric             if (t > Maxcode)
28700b57cec5SDimitry Andric                 return codecvt_base::error;
28710b57cec5SDimitry Andric             *to_nxt = t;
28720b57cec5SDimitry Andric             frm_nxt += 4;
28730b57cec5SDimitry Andric         }
28740b57cec5SDimitry Andric     }
28750b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
28760b57cec5SDimitry Andric }
28770b57cec5SDimitry Andric 
28780b57cec5SDimitry Andric static
28790b57cec5SDimitry Andric int
28800b57cec5SDimitry Andric utf16be_to_ucs4_length(const uint8_t* frm, const uint8_t* frm_end,
28810b57cec5SDimitry Andric                        size_t mx, unsigned long Maxcode = 0x10FFFF,
28820b57cec5SDimitry Andric                        codecvt_mode mode = codecvt_mode(0))
28830b57cec5SDimitry Andric {
28840b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
28850b57cec5SDimitry Andric     if (mode & consume_header)
28860b57cec5SDimitry Andric     {
28870b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
28880b57cec5SDimitry Andric             frm_nxt += 2;
28890b57cec5SDimitry Andric     }
28900b57cec5SDimitry Andric     for (size_t nchar32_t = 0; frm_nxt < frm_end - 1 && nchar32_t < mx; ++nchar32_t)
28910b57cec5SDimitry Andric     {
28920b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
28930b57cec5SDimitry Andric         if ((c1 & 0xFC00) == 0xDC00)
28940b57cec5SDimitry Andric             break;
28950b57cec5SDimitry Andric         if ((c1 & 0xFC00) != 0xD800)
28960b57cec5SDimitry Andric         {
28970b57cec5SDimitry Andric             if (c1 > Maxcode)
28980b57cec5SDimitry Andric                 break;
28990b57cec5SDimitry Andric             frm_nxt += 2;
29000b57cec5SDimitry Andric         }
29010b57cec5SDimitry Andric         else
29020b57cec5SDimitry Andric         {
29030b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
29040b57cec5SDimitry Andric                 break;
29050b57cec5SDimitry Andric             uint16_t c2 = static_cast<uint16_t>(frm_nxt[2] << 8 | frm_nxt[3]);
29060b57cec5SDimitry Andric             if ((c2 & 0xFC00) != 0xDC00)
29070b57cec5SDimitry Andric                 break;
29080b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(
29090b57cec5SDimitry Andric                     ((((c1 & 0x03C0) >> 6) + 1) << 16)
29100b57cec5SDimitry Andric                   |   ((c1 & 0x003F) << 10)
29110b57cec5SDimitry Andric                   |    (c2 & 0x03FF));
29120b57cec5SDimitry Andric             if (t > Maxcode)
29130b57cec5SDimitry Andric                 break;
29140b57cec5SDimitry Andric             frm_nxt += 4;
29150b57cec5SDimitry Andric         }
29160b57cec5SDimitry Andric     }
29170b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
29180b57cec5SDimitry Andric }
29190b57cec5SDimitry Andric 
29200b57cec5SDimitry Andric static
29210b57cec5SDimitry Andric codecvt_base::result
29220b57cec5SDimitry Andric ucs4_to_utf16le(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
29230b57cec5SDimitry Andric                 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
29240b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
29250b57cec5SDimitry Andric {
29260b57cec5SDimitry Andric     frm_nxt = frm;
29270b57cec5SDimitry Andric     to_nxt = to;
29280b57cec5SDimitry Andric     if (mode & generate_header)
29290b57cec5SDimitry Andric     {
29300b57cec5SDimitry Andric         if (to_end - to_nxt < 2)
29310b57cec5SDimitry Andric             return codecvt_base::partial;
29320b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFF);
29330b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFE);
29340b57cec5SDimitry Andric     }
29350b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
29360b57cec5SDimitry Andric     {
29370b57cec5SDimitry Andric         uint32_t wc = *frm_nxt;
29380b57cec5SDimitry Andric         if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
29390b57cec5SDimitry Andric             return codecvt_base::error;
29400b57cec5SDimitry Andric         if (wc < 0x010000)
29410b57cec5SDimitry Andric         {
29420b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
29430b57cec5SDimitry Andric                 return codecvt_base::partial;
29440b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc);
29450b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc >> 8);
29460b57cec5SDimitry Andric         }
29470b57cec5SDimitry Andric         else
29480b57cec5SDimitry Andric         {
29490b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
29500b57cec5SDimitry Andric                 return codecvt_base::partial;
29510b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(
29520b57cec5SDimitry Andric                     0xD800
29530b57cec5SDimitry Andric                   | ((((wc & 0x1F0000) >> 16) - 1) << 6)
29540b57cec5SDimitry Andric                   |   ((wc & 0x00FC00) >> 10));
29550b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t);
29560b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t >> 8);
29570b57cec5SDimitry Andric             t = static_cast<uint16_t>(0xDC00 | (wc & 0x03FF));
29580b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t);
29590b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t >> 8);
29600b57cec5SDimitry Andric         }
29610b57cec5SDimitry Andric     }
29620b57cec5SDimitry Andric     return codecvt_base::ok;
29630b57cec5SDimitry Andric }
29640b57cec5SDimitry Andric 
29650b57cec5SDimitry Andric static
29660b57cec5SDimitry Andric codecvt_base::result
29670b57cec5SDimitry Andric utf16le_to_ucs4(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
29680b57cec5SDimitry Andric                 uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
29690b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
29700b57cec5SDimitry Andric {
29710b57cec5SDimitry Andric     frm_nxt = frm;
29720b57cec5SDimitry Andric     to_nxt = to;
29730b57cec5SDimitry Andric     if (mode & consume_header)
29740b57cec5SDimitry Andric     {
29750b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
29760b57cec5SDimitry Andric             frm_nxt += 2;
29770b57cec5SDimitry Andric     }
29780b57cec5SDimitry Andric     for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
29790b57cec5SDimitry Andric     {
29800b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
29810b57cec5SDimitry Andric         if ((c1 & 0xFC00) == 0xDC00)
29820b57cec5SDimitry Andric             return codecvt_base::error;
29830b57cec5SDimitry Andric         if ((c1 & 0xFC00) != 0xD800)
29840b57cec5SDimitry Andric         {
29850b57cec5SDimitry Andric             if (c1 > Maxcode)
29860b57cec5SDimitry Andric                 return codecvt_base::error;
29870b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(c1);
29880b57cec5SDimitry Andric             frm_nxt += 2;
29890b57cec5SDimitry Andric         }
29900b57cec5SDimitry Andric         else
29910b57cec5SDimitry Andric         {
29920b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
29930b57cec5SDimitry Andric                 return codecvt_base::partial;
29940b57cec5SDimitry Andric             uint16_t c2 = static_cast<uint16_t>(frm_nxt[3] << 8 | frm_nxt[2]);
29950b57cec5SDimitry Andric             if ((c2 & 0xFC00) != 0xDC00)
29960b57cec5SDimitry Andric                 return codecvt_base::error;
29970b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(
29980b57cec5SDimitry Andric                     ((((c1 & 0x03C0) >> 6) + 1) << 16)
29990b57cec5SDimitry Andric                   |   ((c1 & 0x003F) << 10)
30000b57cec5SDimitry Andric                   |    (c2 & 0x03FF));
30010b57cec5SDimitry Andric             if (t > Maxcode)
30020b57cec5SDimitry Andric                 return codecvt_base::error;
30030b57cec5SDimitry Andric             *to_nxt = t;
30040b57cec5SDimitry Andric             frm_nxt += 4;
30050b57cec5SDimitry Andric         }
30060b57cec5SDimitry Andric     }
30070b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
30080b57cec5SDimitry Andric }
30090b57cec5SDimitry Andric 
30100b57cec5SDimitry Andric static
30110b57cec5SDimitry Andric int
30120b57cec5SDimitry Andric utf16le_to_ucs4_length(const uint8_t* frm, const uint8_t* frm_end,
30130b57cec5SDimitry Andric                        size_t mx, unsigned long Maxcode = 0x10FFFF,
30140b57cec5SDimitry Andric                        codecvt_mode mode = codecvt_mode(0))
30150b57cec5SDimitry Andric {
30160b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
30170b57cec5SDimitry Andric     if (mode & consume_header)
30180b57cec5SDimitry Andric     {
30190b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
30200b57cec5SDimitry Andric             frm_nxt += 2;
30210b57cec5SDimitry Andric     }
30220b57cec5SDimitry Andric     for (size_t nchar32_t = 0; frm_nxt < frm_end - 1 && nchar32_t < mx; ++nchar32_t)
30230b57cec5SDimitry Andric     {
30240b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
30250b57cec5SDimitry Andric         if ((c1 & 0xFC00) == 0xDC00)
30260b57cec5SDimitry Andric             break;
30270b57cec5SDimitry Andric         if ((c1 & 0xFC00) != 0xD800)
30280b57cec5SDimitry Andric         {
30290b57cec5SDimitry Andric             if (c1 > Maxcode)
30300b57cec5SDimitry Andric                 break;
30310b57cec5SDimitry Andric             frm_nxt += 2;
30320b57cec5SDimitry Andric         }
30330b57cec5SDimitry Andric         else
30340b57cec5SDimitry Andric         {
30350b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
30360b57cec5SDimitry Andric                 break;
30370b57cec5SDimitry Andric             uint16_t c2 = static_cast<uint16_t>(frm_nxt[3] << 8 | frm_nxt[2]);
30380b57cec5SDimitry Andric             if ((c2 & 0xFC00) != 0xDC00)
30390b57cec5SDimitry Andric                 break;
30400b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(
30410b57cec5SDimitry Andric                     ((((c1 & 0x03C0) >> 6) + 1) << 16)
30420b57cec5SDimitry Andric                   |   ((c1 & 0x003F) << 10)
30430b57cec5SDimitry Andric                   |    (c2 & 0x03FF));
30440b57cec5SDimitry Andric             if (t > Maxcode)
30450b57cec5SDimitry Andric                 break;
30460b57cec5SDimitry Andric             frm_nxt += 4;
30470b57cec5SDimitry Andric         }
30480b57cec5SDimitry Andric     }
30490b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
30500b57cec5SDimitry Andric }
30510b57cec5SDimitry Andric 
30520b57cec5SDimitry Andric static
30530b57cec5SDimitry Andric codecvt_base::result
30540b57cec5SDimitry Andric ucs2_to_utf16be(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
30550b57cec5SDimitry Andric                 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
30560b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
30570b57cec5SDimitry Andric {
30580b57cec5SDimitry Andric     frm_nxt = frm;
30590b57cec5SDimitry Andric     to_nxt = to;
30600b57cec5SDimitry Andric     if (mode & generate_header)
30610b57cec5SDimitry Andric     {
30620b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
30630b57cec5SDimitry Andric             return codecvt_base::partial;
30640b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFE);
30650b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFF);
30660b57cec5SDimitry Andric     }
30670b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
30680b57cec5SDimitry Andric     {
30690b57cec5SDimitry Andric         uint16_t wc = *frm_nxt;
30700b57cec5SDimitry Andric         if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
30710b57cec5SDimitry Andric             return codecvt_base::error;
30720b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
30730b57cec5SDimitry Andric             return codecvt_base::partial;
30740b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(wc >> 8);
30750b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(wc);
30760b57cec5SDimitry Andric     }
30770b57cec5SDimitry Andric     return codecvt_base::ok;
30780b57cec5SDimitry Andric }
30790b57cec5SDimitry Andric 
30800b57cec5SDimitry Andric static
30810b57cec5SDimitry Andric codecvt_base::result
30820b57cec5SDimitry Andric utf16be_to_ucs2(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
30830b57cec5SDimitry Andric                 uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
30840b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
30850b57cec5SDimitry Andric {
30860b57cec5SDimitry Andric     frm_nxt = frm;
30870b57cec5SDimitry Andric     to_nxt = to;
30880b57cec5SDimitry Andric     if (mode & consume_header)
30890b57cec5SDimitry Andric     {
30900b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
30910b57cec5SDimitry Andric             frm_nxt += 2;
30920b57cec5SDimitry Andric     }
30930b57cec5SDimitry Andric     for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
30940b57cec5SDimitry Andric     {
30950b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
30960b57cec5SDimitry Andric         if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
30970b57cec5SDimitry Andric             return codecvt_base::error;
30980b57cec5SDimitry Andric         *to_nxt = c1;
30990b57cec5SDimitry Andric         frm_nxt += 2;
31000b57cec5SDimitry Andric     }
31010b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
31020b57cec5SDimitry Andric }
31030b57cec5SDimitry Andric 
31040b57cec5SDimitry Andric static
31050b57cec5SDimitry Andric int
31060b57cec5SDimitry Andric utf16be_to_ucs2_length(const uint8_t* frm, const uint8_t* frm_end,
31070b57cec5SDimitry Andric                        size_t mx, unsigned long Maxcode = 0x10FFFF,
31080b57cec5SDimitry Andric                        codecvt_mode mode = codecvt_mode(0))
31090b57cec5SDimitry Andric {
31100b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
31110b57cec5SDimitry Andric     if (mode & consume_header)
31120b57cec5SDimitry Andric     {
31130b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
31140b57cec5SDimitry Andric             frm_nxt += 2;
31150b57cec5SDimitry Andric     }
31160b57cec5SDimitry Andric     for (size_t nchar16_t = 0; frm_nxt < frm_end - 1 && nchar16_t < mx; ++nchar16_t)
31170b57cec5SDimitry Andric     {
31180b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
31190b57cec5SDimitry Andric         if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
31200b57cec5SDimitry Andric             break;
31210b57cec5SDimitry Andric         frm_nxt += 2;
31220b57cec5SDimitry Andric     }
31230b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
31240b57cec5SDimitry Andric }
31250b57cec5SDimitry Andric 
31260b57cec5SDimitry Andric static
31270b57cec5SDimitry Andric codecvt_base::result
31280b57cec5SDimitry Andric ucs2_to_utf16le(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
31290b57cec5SDimitry Andric                 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
31300b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
31310b57cec5SDimitry Andric {
31320b57cec5SDimitry Andric     frm_nxt = frm;
31330b57cec5SDimitry Andric     to_nxt = to;
31340b57cec5SDimitry Andric     if (mode & generate_header)
31350b57cec5SDimitry Andric     {
31360b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
31370b57cec5SDimitry Andric             return codecvt_base::partial;
31380b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFF);
31390b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFE);
31400b57cec5SDimitry Andric     }
31410b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
31420b57cec5SDimitry Andric     {
31430b57cec5SDimitry Andric         uint16_t wc = *frm_nxt;
31440b57cec5SDimitry Andric         if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
31450b57cec5SDimitry Andric             return codecvt_base::error;
31460b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
31470b57cec5SDimitry Andric             return codecvt_base::partial;
31480b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(wc);
31490b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(wc >> 8);
31500b57cec5SDimitry Andric     }
31510b57cec5SDimitry Andric     return codecvt_base::ok;
31520b57cec5SDimitry Andric }
31530b57cec5SDimitry Andric 
31540b57cec5SDimitry Andric static
31550b57cec5SDimitry Andric codecvt_base::result
31560b57cec5SDimitry Andric utf16le_to_ucs2(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
31570b57cec5SDimitry Andric                 uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
31580b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
31590b57cec5SDimitry Andric {
31600b57cec5SDimitry Andric     frm_nxt = frm;
31610b57cec5SDimitry Andric     to_nxt = to;
31620b57cec5SDimitry Andric     if (mode & consume_header)
31630b57cec5SDimitry Andric     {
31640b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
31650b57cec5SDimitry Andric             frm_nxt += 2;
31660b57cec5SDimitry Andric     }
31670b57cec5SDimitry Andric     for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
31680b57cec5SDimitry Andric     {
31690b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
31700b57cec5SDimitry Andric         if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
31710b57cec5SDimitry Andric             return codecvt_base::error;
31720b57cec5SDimitry Andric         *to_nxt = c1;
31730b57cec5SDimitry Andric         frm_nxt += 2;
31740b57cec5SDimitry Andric     }
31750b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
31760b57cec5SDimitry Andric }
31770b57cec5SDimitry Andric 
31780b57cec5SDimitry Andric static
31790b57cec5SDimitry Andric int
31800b57cec5SDimitry Andric utf16le_to_ucs2_length(const uint8_t* frm, const uint8_t* frm_end,
31810b57cec5SDimitry Andric                        size_t mx, unsigned long Maxcode = 0x10FFFF,
31820b57cec5SDimitry Andric                        codecvt_mode mode = codecvt_mode(0))
31830b57cec5SDimitry Andric {
31840b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
31850b57cec5SDimitry Andric     frm_nxt = frm;
31860b57cec5SDimitry Andric     if (mode & consume_header)
31870b57cec5SDimitry Andric     {
31880b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
31890b57cec5SDimitry Andric             frm_nxt += 2;
31900b57cec5SDimitry Andric     }
31910b57cec5SDimitry Andric     for (size_t nchar16_t = 0; frm_nxt < frm_end - 1 && nchar16_t < mx; ++nchar16_t)
31920b57cec5SDimitry Andric     {
31930b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
31940b57cec5SDimitry Andric         if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
31950b57cec5SDimitry Andric             break;
31960b57cec5SDimitry Andric         frm_nxt += 2;
31970b57cec5SDimitry Andric     }
31980b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
31990b57cec5SDimitry Andric }
32000b57cec5SDimitry Andric 
320181ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
320281ad6265SDimitry Andric 
32030b57cec5SDimitry Andric // template <> class codecvt<char16_t, char, mbstate_t>
32040b57cec5SDimitry Andric 
32050b57cec5SDimitry Andric locale::id codecvt<char16_t, char, mbstate_t>::id;
32060b57cec5SDimitry Andric 
32070b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::~codecvt()
32080b57cec5SDimitry Andric {
32090b57cec5SDimitry Andric }
32100b57cec5SDimitry Andric 
32110b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::result
32120b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_out(state_type&,
32130b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
32140b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
32150b57cec5SDimitry Andric {
32160b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
32170b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
32180b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
32190b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
32200b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
32210b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
32220b57cec5SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
32230b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
32240b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
32250b57cec5SDimitry Andric     return r;
32260b57cec5SDimitry Andric }
32270b57cec5SDimitry Andric 
32280b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::result
32290b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_in(state_type&,
32300b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
32310b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
32320b57cec5SDimitry Andric {
32330b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
32340b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
32350b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
32360b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
32370b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
32380b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
32390b57cec5SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
32400b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
32410b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
32420b57cec5SDimitry Andric     return r;
32430b57cec5SDimitry Andric }
32440b57cec5SDimitry Andric 
32450b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::result
32460b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_unshift(state_type&,
32470b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
32480b57cec5SDimitry Andric {
32490b57cec5SDimitry Andric     to_nxt = to;
32500b57cec5SDimitry Andric     return noconv;
32510b57cec5SDimitry Andric }
32520b57cec5SDimitry Andric 
32530b57cec5SDimitry Andric int
3254fe6060f1SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_encoding() const noexcept
32550b57cec5SDimitry Andric {
32560b57cec5SDimitry Andric     return 0;
32570b57cec5SDimitry Andric }
32580b57cec5SDimitry Andric 
32590b57cec5SDimitry Andric bool
3260fe6060f1SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_always_noconv() const noexcept
32610b57cec5SDimitry Andric {
32620b57cec5SDimitry Andric     return false;
32630b57cec5SDimitry Andric }
32640b57cec5SDimitry Andric 
32650b57cec5SDimitry Andric int
32660b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_length(state_type&,
32670b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
32680b57cec5SDimitry Andric {
32690b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
32700b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
32710b57cec5SDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx);
32720b57cec5SDimitry Andric }
32730b57cec5SDimitry Andric 
32740b57cec5SDimitry Andric int
3275fe6060f1SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_max_length() const noexcept
32760b57cec5SDimitry Andric {
32770b57cec5SDimitry Andric     return 4;
32780b57cec5SDimitry Andric }
32790b57cec5SDimitry Andric 
3280fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
3281e8d8bef9SDimitry Andric 
3282e8d8bef9SDimitry Andric // template <> class codecvt<char16_t, char8_t, mbstate_t>
3283e8d8bef9SDimitry Andric 
3284e8d8bef9SDimitry Andric locale::id codecvt<char16_t, char8_t, mbstate_t>::id;
3285e8d8bef9SDimitry Andric 
3286e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::~codecvt()
3287e8d8bef9SDimitry Andric {
3288e8d8bef9SDimitry Andric }
3289e8d8bef9SDimitry Andric 
3290e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::result
3291e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_out(state_type&,
3292e8d8bef9SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3293e8d8bef9SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3294e8d8bef9SDimitry Andric {
3295e8d8bef9SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3296e8d8bef9SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3297e8d8bef9SDimitry Andric     const uint16_t* _frm_nxt = _frm;
3298e8d8bef9SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3299e8d8bef9SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3300e8d8bef9SDimitry Andric     uint8_t* _to_nxt = _to;
3301e8d8bef9SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3302e8d8bef9SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
3303e8d8bef9SDimitry Andric     to_nxt = to + (_to_nxt - _to);
3304e8d8bef9SDimitry Andric     return r;
3305e8d8bef9SDimitry Andric }
3306e8d8bef9SDimitry Andric 
3307e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::result
3308e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_in(state_type&,
3309e8d8bef9SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3310e8d8bef9SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3311e8d8bef9SDimitry Andric {
3312e8d8bef9SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3313e8d8bef9SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3314e8d8bef9SDimitry Andric     const uint8_t* _frm_nxt = _frm;
3315e8d8bef9SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3316e8d8bef9SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3317e8d8bef9SDimitry Andric     uint16_t* _to_nxt = _to;
3318e8d8bef9SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3319e8d8bef9SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
3320e8d8bef9SDimitry Andric     to_nxt = to + (_to_nxt - _to);
3321e8d8bef9SDimitry Andric     return r;
3322e8d8bef9SDimitry Andric }
3323e8d8bef9SDimitry Andric 
3324e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::result
3325e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_unshift(state_type&,
3326e8d8bef9SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
3327e8d8bef9SDimitry Andric {
3328e8d8bef9SDimitry Andric     to_nxt = to;
3329e8d8bef9SDimitry Andric     return noconv;
3330e8d8bef9SDimitry Andric }
3331e8d8bef9SDimitry Andric 
3332e8d8bef9SDimitry Andric int
3333fe6060f1SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_encoding() const noexcept
3334e8d8bef9SDimitry Andric {
3335e8d8bef9SDimitry Andric     return 0;
3336e8d8bef9SDimitry Andric }
3337e8d8bef9SDimitry Andric 
3338e8d8bef9SDimitry Andric bool
3339fe6060f1SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_always_noconv() const noexcept
3340e8d8bef9SDimitry Andric {
3341e8d8bef9SDimitry Andric     return false;
3342e8d8bef9SDimitry Andric }
3343e8d8bef9SDimitry Andric 
3344e8d8bef9SDimitry Andric int
3345e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_length(state_type&,
3346e8d8bef9SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
3347e8d8bef9SDimitry Andric {
3348e8d8bef9SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3349e8d8bef9SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3350e8d8bef9SDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx);
3351e8d8bef9SDimitry Andric }
3352e8d8bef9SDimitry Andric 
3353e8d8bef9SDimitry Andric int
3354fe6060f1SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_max_length() const noexcept
3355e8d8bef9SDimitry Andric {
3356e8d8bef9SDimitry Andric     return 4;
3357e8d8bef9SDimitry Andric }
3358e8d8bef9SDimitry Andric 
3359e8d8bef9SDimitry Andric #endif
3360e8d8bef9SDimitry Andric 
33610b57cec5SDimitry Andric // template <> class codecvt<char32_t, char, mbstate_t>
33620b57cec5SDimitry Andric 
33630b57cec5SDimitry Andric locale::id codecvt<char32_t, char, mbstate_t>::id;
33640b57cec5SDimitry Andric 
33650b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::~codecvt()
33660b57cec5SDimitry Andric {
33670b57cec5SDimitry Andric }
33680b57cec5SDimitry Andric 
33690b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::result
33700b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_out(state_type&,
33710b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
33720b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
33730b57cec5SDimitry Andric {
33740b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
33750b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
33760b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
33770b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
33780b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
33790b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
33800b57cec5SDimitry Andric     result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
33810b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
33820b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
33830b57cec5SDimitry Andric     return r;
33840b57cec5SDimitry Andric }
33850b57cec5SDimitry Andric 
33860b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::result
33870b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_in(state_type&,
33880b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
33890b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
33900b57cec5SDimitry Andric {
33910b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
33920b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
33930b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
33940b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
33950b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
33960b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
33970b57cec5SDimitry Andric     result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
33980b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
33990b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
34000b57cec5SDimitry Andric     return r;
34010b57cec5SDimitry Andric }
34020b57cec5SDimitry Andric 
34030b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::result
34040b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_unshift(state_type&,
34050b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
34060b57cec5SDimitry Andric {
34070b57cec5SDimitry Andric     to_nxt = to;
34080b57cec5SDimitry Andric     return noconv;
34090b57cec5SDimitry Andric }
34100b57cec5SDimitry Andric 
34110b57cec5SDimitry Andric int
3412fe6060f1SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_encoding() const noexcept
34130b57cec5SDimitry Andric {
34140b57cec5SDimitry Andric     return 0;
34150b57cec5SDimitry Andric }
34160b57cec5SDimitry Andric 
34170b57cec5SDimitry Andric bool
3418fe6060f1SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_always_noconv() const noexcept
34190b57cec5SDimitry Andric {
34200b57cec5SDimitry Andric     return false;
34210b57cec5SDimitry Andric }
34220b57cec5SDimitry Andric 
34230b57cec5SDimitry Andric int
34240b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_length(state_type&,
34250b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
34260b57cec5SDimitry Andric {
34270b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
34280b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
34290b57cec5SDimitry Andric     return utf8_to_ucs4_length(_frm, _frm_end, mx);
34300b57cec5SDimitry Andric }
34310b57cec5SDimitry Andric 
34320b57cec5SDimitry Andric int
3433fe6060f1SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_max_length() const noexcept
34340b57cec5SDimitry Andric {
34350b57cec5SDimitry Andric     return 4;
34360b57cec5SDimitry Andric }
34370b57cec5SDimitry Andric 
3438fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
3439e8d8bef9SDimitry Andric 
3440e8d8bef9SDimitry Andric // template <> class codecvt<char32_t, char8_t, mbstate_t>
3441e8d8bef9SDimitry Andric 
3442e8d8bef9SDimitry Andric locale::id codecvt<char32_t, char8_t, mbstate_t>::id;
3443e8d8bef9SDimitry Andric 
3444e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::~codecvt()
3445e8d8bef9SDimitry Andric {
3446e8d8bef9SDimitry Andric }
3447e8d8bef9SDimitry Andric 
3448e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::result
3449e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_out(state_type&,
3450e8d8bef9SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3451e8d8bef9SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3452e8d8bef9SDimitry Andric {
3453e8d8bef9SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
3454e8d8bef9SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
3455e8d8bef9SDimitry Andric     const uint32_t* _frm_nxt = _frm;
3456e8d8bef9SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3457e8d8bef9SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3458e8d8bef9SDimitry Andric     uint8_t* _to_nxt = _to;
3459e8d8bef9SDimitry Andric     result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3460e8d8bef9SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
3461e8d8bef9SDimitry Andric     to_nxt = to + (_to_nxt - _to);
3462e8d8bef9SDimitry Andric     return r;
3463e8d8bef9SDimitry Andric }
3464e8d8bef9SDimitry Andric 
3465e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::result
3466e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_in(state_type&,
3467e8d8bef9SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3468e8d8bef9SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3469e8d8bef9SDimitry Andric {
3470e8d8bef9SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3471e8d8bef9SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3472e8d8bef9SDimitry Andric     const uint8_t* _frm_nxt = _frm;
3473e8d8bef9SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
3474e8d8bef9SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
3475e8d8bef9SDimitry Andric     uint32_t* _to_nxt = _to;
3476e8d8bef9SDimitry Andric     result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3477e8d8bef9SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
3478e8d8bef9SDimitry Andric     to_nxt = to + (_to_nxt - _to);
3479e8d8bef9SDimitry Andric     return r;
3480e8d8bef9SDimitry Andric }
3481e8d8bef9SDimitry Andric 
3482e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::result
3483e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_unshift(state_type&,
3484e8d8bef9SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
3485e8d8bef9SDimitry Andric {
3486e8d8bef9SDimitry Andric     to_nxt = to;
3487e8d8bef9SDimitry Andric     return noconv;
3488e8d8bef9SDimitry Andric }
3489e8d8bef9SDimitry Andric 
3490e8d8bef9SDimitry Andric int
3491fe6060f1SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_encoding() const noexcept
3492e8d8bef9SDimitry Andric {
3493e8d8bef9SDimitry Andric     return 0;
3494e8d8bef9SDimitry Andric }
3495e8d8bef9SDimitry Andric 
3496e8d8bef9SDimitry Andric bool
3497fe6060f1SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_always_noconv() const noexcept
3498e8d8bef9SDimitry Andric {
3499e8d8bef9SDimitry Andric     return false;
3500e8d8bef9SDimitry Andric }
3501e8d8bef9SDimitry Andric 
3502e8d8bef9SDimitry Andric int
3503e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_length(state_type&,
3504e8d8bef9SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
3505e8d8bef9SDimitry Andric {
3506e8d8bef9SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3507e8d8bef9SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3508e8d8bef9SDimitry Andric     return utf8_to_ucs4_length(_frm, _frm_end, mx);
3509e8d8bef9SDimitry Andric }
3510e8d8bef9SDimitry Andric 
3511e8d8bef9SDimitry Andric int
3512fe6060f1SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_max_length() const noexcept
3513e8d8bef9SDimitry Andric {
3514e8d8bef9SDimitry Andric     return 4;
3515e8d8bef9SDimitry Andric }
3516e8d8bef9SDimitry Andric 
3517e8d8bef9SDimitry Andric #endif
3518e8d8bef9SDimitry Andric 
35190b57cec5SDimitry Andric // __codecvt_utf8<wchar_t>
35200b57cec5SDimitry Andric 
3521349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
35220b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::result
35230b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::do_out(state_type&,
35240b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
35250b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
35260b57cec5SDimitry Andric {
35270b57cec5SDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
35280b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
35290b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
35300b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
35310b57cec5SDimitry Andric #else
35320b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
35330b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
35340b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
35350b57cec5SDimitry Andric #endif
35360b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
35370b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
35380b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
35390b57cec5SDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
35400b57cec5SDimitry Andric     result r = ucs2_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3541*bdd1243dSDimitry Andric                             __maxcode_, __mode_);
35420b57cec5SDimitry Andric #else
35430b57cec5SDimitry Andric     result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3544*bdd1243dSDimitry Andric                             __maxcode_, __mode_);
35450b57cec5SDimitry Andric #endif
35460b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
35470b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
35480b57cec5SDimitry Andric     return r;
35490b57cec5SDimitry Andric }
35500b57cec5SDimitry Andric 
35510b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::result
35520b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::do_in(state_type&,
35530b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
35540b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
35550b57cec5SDimitry Andric {
35560b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
35570b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
35580b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
35590b57cec5SDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
35600b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
35610b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
35620b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
35630b57cec5SDimitry Andric     result r = utf8_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3564*bdd1243dSDimitry Andric                             __maxcode_, __mode_);
35650b57cec5SDimitry Andric #else
35660b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
35670b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
35680b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
35690b57cec5SDimitry Andric     result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3570*bdd1243dSDimitry Andric                             __maxcode_, __mode_);
35710b57cec5SDimitry Andric #endif
35720b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
35730b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
35740b57cec5SDimitry Andric     return r;
35750b57cec5SDimitry Andric }
35760b57cec5SDimitry Andric 
35770b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::result
35780b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::do_unshift(state_type&,
35790b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
35800b57cec5SDimitry Andric {
35810b57cec5SDimitry Andric     to_nxt = to;
35820b57cec5SDimitry Andric     return noconv;
35830b57cec5SDimitry Andric }
35840b57cec5SDimitry Andric 
35850b57cec5SDimitry Andric int
3586fe6060f1SDimitry Andric __codecvt_utf8<wchar_t>::do_encoding() const noexcept
35870b57cec5SDimitry Andric {
35880b57cec5SDimitry Andric     return 0;
35890b57cec5SDimitry Andric }
35900b57cec5SDimitry Andric 
35910b57cec5SDimitry Andric bool
3592fe6060f1SDimitry Andric __codecvt_utf8<wchar_t>::do_always_noconv() const noexcept
35930b57cec5SDimitry Andric {
35940b57cec5SDimitry Andric     return false;
35950b57cec5SDimitry Andric }
35960b57cec5SDimitry Andric 
35970b57cec5SDimitry Andric int
35980b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::do_length(state_type&,
35990b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
36000b57cec5SDimitry Andric {
36010b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
36020b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3603349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3604*bdd1243dSDimitry Andric     return utf8_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3605349cc55cSDimitry Andric #else
3606*bdd1243dSDimitry Andric     return utf8_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3607349cc55cSDimitry Andric #endif
36080b57cec5SDimitry Andric }
36090b57cec5SDimitry Andric 
361081ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
36110b57cec5SDimitry Andric int
3612fe6060f1SDimitry Andric __codecvt_utf8<wchar_t>::do_max_length() const noexcept
36130b57cec5SDimitry Andric {
3614349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3615*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
3616349cc55cSDimitry Andric         return 6;
3617349cc55cSDimitry Andric     return 3;
3618349cc55cSDimitry Andric #else
3619*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
36200b57cec5SDimitry Andric         return 7;
36210b57cec5SDimitry Andric     return 4;
3622349cc55cSDimitry Andric #endif
36230b57cec5SDimitry Andric }
3624349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
36250b57cec5SDimitry Andric 
36260b57cec5SDimitry Andric // __codecvt_utf8<char16_t>
36270b57cec5SDimitry Andric 
36280b57cec5SDimitry Andric __codecvt_utf8<char16_t>::result
36290b57cec5SDimitry Andric __codecvt_utf8<char16_t>::do_out(state_type&,
36300b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
36310b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
36320b57cec5SDimitry Andric {
36330b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
36340b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
36350b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
36360b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
36370b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
36380b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
36390b57cec5SDimitry Andric     result r = ucs2_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3640*bdd1243dSDimitry Andric                             __maxcode_, __mode_);
36410b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
36420b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
36430b57cec5SDimitry Andric     return r;
36440b57cec5SDimitry Andric }
36450b57cec5SDimitry Andric 
36460b57cec5SDimitry Andric __codecvt_utf8<char16_t>::result
36470b57cec5SDimitry Andric __codecvt_utf8<char16_t>::do_in(state_type&,
36480b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
36490b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
36500b57cec5SDimitry Andric {
36510b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
36520b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
36530b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
36540b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
36550b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
36560b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
36570b57cec5SDimitry Andric     result r = utf8_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3658*bdd1243dSDimitry Andric                             __maxcode_, __mode_);
36590b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
36600b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
36610b57cec5SDimitry Andric     return r;
36620b57cec5SDimitry Andric }
36630b57cec5SDimitry Andric 
36640b57cec5SDimitry Andric __codecvt_utf8<char16_t>::result
36650b57cec5SDimitry Andric __codecvt_utf8<char16_t>::do_unshift(state_type&,
36660b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
36670b57cec5SDimitry Andric {
36680b57cec5SDimitry Andric     to_nxt = to;
36690b57cec5SDimitry Andric     return noconv;
36700b57cec5SDimitry Andric }
36710b57cec5SDimitry Andric 
36720b57cec5SDimitry Andric int
3673fe6060f1SDimitry Andric __codecvt_utf8<char16_t>::do_encoding() const noexcept
36740b57cec5SDimitry Andric {
36750b57cec5SDimitry Andric     return 0;
36760b57cec5SDimitry Andric }
36770b57cec5SDimitry Andric 
36780b57cec5SDimitry Andric bool
3679fe6060f1SDimitry Andric __codecvt_utf8<char16_t>::do_always_noconv() const noexcept
36800b57cec5SDimitry Andric {
36810b57cec5SDimitry Andric     return false;
36820b57cec5SDimitry Andric }
36830b57cec5SDimitry Andric 
36840b57cec5SDimitry Andric int
36850b57cec5SDimitry Andric __codecvt_utf8<char16_t>::do_length(state_type&,
36860b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
36870b57cec5SDimitry Andric {
36880b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
36890b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3690*bdd1243dSDimitry Andric     return utf8_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
36910b57cec5SDimitry Andric }
36920b57cec5SDimitry Andric 
369381ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
36940b57cec5SDimitry Andric int
3695fe6060f1SDimitry Andric __codecvt_utf8<char16_t>::do_max_length() const noexcept
36960b57cec5SDimitry Andric {
3697*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
36980b57cec5SDimitry Andric         return 6;
36990b57cec5SDimitry Andric     return 3;
37000b57cec5SDimitry Andric }
370181ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
37020b57cec5SDimitry Andric 
37030b57cec5SDimitry Andric // __codecvt_utf8<char32_t>
37040b57cec5SDimitry Andric 
37050b57cec5SDimitry Andric __codecvt_utf8<char32_t>::result
37060b57cec5SDimitry Andric __codecvt_utf8<char32_t>::do_out(state_type&,
37070b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
37080b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
37090b57cec5SDimitry Andric {
37100b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
37110b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
37120b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
37130b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
37140b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
37150b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
37160b57cec5SDimitry Andric     result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3717*bdd1243dSDimitry Andric                             __maxcode_, __mode_);
37180b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
37190b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
37200b57cec5SDimitry Andric     return r;
37210b57cec5SDimitry Andric }
37220b57cec5SDimitry Andric 
37230b57cec5SDimitry Andric __codecvt_utf8<char32_t>::result
37240b57cec5SDimitry Andric __codecvt_utf8<char32_t>::do_in(state_type&,
37250b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
37260b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
37270b57cec5SDimitry Andric {
37280b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
37290b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
37300b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
37310b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
37320b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
37330b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
37340b57cec5SDimitry Andric     result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3735*bdd1243dSDimitry Andric                             __maxcode_, __mode_);
37360b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
37370b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
37380b57cec5SDimitry Andric     return r;
37390b57cec5SDimitry Andric }
37400b57cec5SDimitry Andric 
37410b57cec5SDimitry Andric __codecvt_utf8<char32_t>::result
37420b57cec5SDimitry Andric __codecvt_utf8<char32_t>::do_unshift(state_type&,
37430b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
37440b57cec5SDimitry Andric {
37450b57cec5SDimitry Andric     to_nxt = to;
37460b57cec5SDimitry Andric     return noconv;
37470b57cec5SDimitry Andric }
37480b57cec5SDimitry Andric 
37490b57cec5SDimitry Andric int
3750fe6060f1SDimitry Andric __codecvt_utf8<char32_t>::do_encoding() const noexcept
37510b57cec5SDimitry Andric {
37520b57cec5SDimitry Andric     return 0;
37530b57cec5SDimitry Andric }
37540b57cec5SDimitry Andric 
37550b57cec5SDimitry Andric bool
3756fe6060f1SDimitry Andric __codecvt_utf8<char32_t>::do_always_noconv() const noexcept
37570b57cec5SDimitry Andric {
37580b57cec5SDimitry Andric     return false;
37590b57cec5SDimitry Andric }
37600b57cec5SDimitry Andric 
37610b57cec5SDimitry Andric int
37620b57cec5SDimitry Andric __codecvt_utf8<char32_t>::do_length(state_type&,
37630b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
37640b57cec5SDimitry Andric {
37650b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
37660b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3767*bdd1243dSDimitry Andric     return utf8_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
37680b57cec5SDimitry Andric }
37690b57cec5SDimitry Andric 
377081ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
37710b57cec5SDimitry Andric int
3772fe6060f1SDimitry Andric __codecvt_utf8<char32_t>::do_max_length() const noexcept
37730b57cec5SDimitry Andric {
3774*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
37750b57cec5SDimitry Andric         return 7;
37760b57cec5SDimitry Andric     return 4;
37770b57cec5SDimitry Andric }
377881ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
37790b57cec5SDimitry Andric 
37800b57cec5SDimitry Andric // __codecvt_utf16<wchar_t, false>
37810b57cec5SDimitry Andric 
3782349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
37830b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::result
37840b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::do_out(state_type&,
37850b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
37860b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
37870b57cec5SDimitry Andric {
3788349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3789349cc55cSDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3790349cc55cSDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3791349cc55cSDimitry Andric     const uint16_t* _frm_nxt = _frm;
3792349cc55cSDimitry Andric #else
37930b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
37940b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
37950b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
3796349cc55cSDimitry Andric #endif
37970b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
37980b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
37990b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
3800349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3801349cc55cSDimitry Andric     result r = ucs2_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3802*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3803349cc55cSDimitry Andric #else
38040b57cec5SDimitry Andric     result r = ucs4_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3805*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3806349cc55cSDimitry Andric #endif
38070b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
38080b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
38090b57cec5SDimitry Andric     return r;
38100b57cec5SDimitry Andric }
38110b57cec5SDimitry Andric 
38120b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::result
38130b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::do_in(state_type&,
38140b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
38150b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
38160b57cec5SDimitry Andric {
38170b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
38180b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
38190b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
3820349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3821349cc55cSDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3822349cc55cSDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3823349cc55cSDimitry Andric     uint16_t* _to_nxt = _to;
3824349cc55cSDimitry Andric     result r = utf16be_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3825*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3826349cc55cSDimitry Andric #else
38270b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
38280b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
38290b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
38300b57cec5SDimitry Andric     result r = utf16be_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3831*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3832349cc55cSDimitry Andric #endif
38330b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
38340b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
38350b57cec5SDimitry Andric     return r;
38360b57cec5SDimitry Andric }
38370b57cec5SDimitry Andric 
38380b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::result
38390b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::do_unshift(state_type&,
38400b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
38410b57cec5SDimitry Andric {
38420b57cec5SDimitry Andric     to_nxt = to;
38430b57cec5SDimitry Andric     return noconv;
38440b57cec5SDimitry Andric }
38450b57cec5SDimitry Andric 
38460b57cec5SDimitry Andric int
3847fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, false>::do_encoding() const noexcept
38480b57cec5SDimitry Andric {
38490b57cec5SDimitry Andric     return 0;
38500b57cec5SDimitry Andric }
38510b57cec5SDimitry Andric 
38520b57cec5SDimitry Andric bool
3853fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, false>::do_always_noconv() const noexcept
38540b57cec5SDimitry Andric {
38550b57cec5SDimitry Andric     return false;
38560b57cec5SDimitry Andric }
38570b57cec5SDimitry Andric 
38580b57cec5SDimitry Andric int
38590b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::do_length(state_type&,
38600b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
38610b57cec5SDimitry Andric {
38620b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
38630b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3864349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3865*bdd1243dSDimitry Andric     return utf16be_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3866349cc55cSDimitry Andric #else
3867*bdd1243dSDimitry Andric     return utf16be_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3868349cc55cSDimitry Andric #endif
38690b57cec5SDimitry Andric }
38700b57cec5SDimitry Andric 
38710b57cec5SDimitry Andric int
3872fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, false>::do_max_length() const noexcept
38730b57cec5SDimitry Andric {
3874349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3875*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
3876349cc55cSDimitry Andric         return 4;
3877349cc55cSDimitry Andric     return 2;
3878349cc55cSDimitry Andric #else
3879*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
38800b57cec5SDimitry Andric         return 6;
38810b57cec5SDimitry Andric     return 4;
3882349cc55cSDimitry Andric #endif
38830b57cec5SDimitry Andric }
38840b57cec5SDimitry Andric 
38850b57cec5SDimitry Andric // __codecvt_utf16<wchar_t, true>
38860b57cec5SDimitry Andric 
38870b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::result
38880b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::do_out(state_type&,
38890b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
38900b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
38910b57cec5SDimitry Andric {
3892349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3893349cc55cSDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3894349cc55cSDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3895349cc55cSDimitry Andric     const uint16_t* _frm_nxt = _frm;
3896349cc55cSDimitry Andric #else
38970b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
38980b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
38990b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
3900349cc55cSDimitry Andric #endif
39010b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
39020b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
39030b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
3904349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3905349cc55cSDimitry Andric     result r = ucs2_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3906*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3907349cc55cSDimitry Andric #else
39080b57cec5SDimitry Andric     result r = ucs4_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3909*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3910349cc55cSDimitry Andric #endif
39110b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
39120b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
39130b57cec5SDimitry Andric     return r;
39140b57cec5SDimitry Andric }
39150b57cec5SDimitry Andric 
39160b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::result
39170b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::do_in(state_type&,
39180b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
39190b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
39200b57cec5SDimitry Andric {
39210b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
39220b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
39230b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
3924349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3925349cc55cSDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3926349cc55cSDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3927349cc55cSDimitry Andric     uint16_t* _to_nxt = _to;
3928349cc55cSDimitry Andric     result r = utf16le_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3929*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3930349cc55cSDimitry Andric #else
39310b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
39320b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
39330b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
39340b57cec5SDimitry Andric     result r = utf16le_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3935*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
3936349cc55cSDimitry Andric #endif
39370b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
39380b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
39390b57cec5SDimitry Andric     return r;
39400b57cec5SDimitry Andric }
39410b57cec5SDimitry Andric 
39420b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::result
39430b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::do_unshift(state_type&,
39440b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
39450b57cec5SDimitry Andric {
39460b57cec5SDimitry Andric     to_nxt = to;
39470b57cec5SDimitry Andric     return noconv;
39480b57cec5SDimitry Andric }
39490b57cec5SDimitry Andric 
39500b57cec5SDimitry Andric int
3951fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, true>::do_encoding() const noexcept
39520b57cec5SDimitry Andric {
39530b57cec5SDimitry Andric     return 0;
39540b57cec5SDimitry Andric }
39550b57cec5SDimitry Andric 
39560b57cec5SDimitry Andric bool
3957fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, true>::do_always_noconv() const noexcept
39580b57cec5SDimitry Andric {
39590b57cec5SDimitry Andric     return false;
39600b57cec5SDimitry Andric }
39610b57cec5SDimitry Andric 
39620b57cec5SDimitry Andric int
39630b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::do_length(state_type&,
39640b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
39650b57cec5SDimitry Andric {
39660b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
39670b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3968349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3969*bdd1243dSDimitry Andric     return utf16le_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3970349cc55cSDimitry Andric #else
3971*bdd1243dSDimitry Andric     return utf16le_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
3972349cc55cSDimitry Andric #endif
39730b57cec5SDimitry Andric }
39740b57cec5SDimitry Andric 
39750b57cec5SDimitry Andric int
3976fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, true>::do_max_length() const noexcept
39770b57cec5SDimitry Andric {
3978349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3979*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
3980349cc55cSDimitry Andric         return 4;
3981349cc55cSDimitry Andric     return 2;
3982349cc55cSDimitry Andric #else
3983*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
39840b57cec5SDimitry Andric         return 6;
39850b57cec5SDimitry Andric     return 4;
3986349cc55cSDimitry Andric #endif
39870b57cec5SDimitry Andric }
3988349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
39890b57cec5SDimitry Andric 
39900b57cec5SDimitry Andric // __codecvt_utf16<char16_t, false>
39910b57cec5SDimitry Andric 
39920b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::result
39930b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::do_out(state_type&,
39940b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
39950b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
39960b57cec5SDimitry Andric {
39970b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
39980b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
39990b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
40000b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
40010b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
40020b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
40030b57cec5SDimitry Andric     result r = ucs2_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4004*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
40050b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
40060b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
40070b57cec5SDimitry Andric     return r;
40080b57cec5SDimitry Andric }
40090b57cec5SDimitry Andric 
40100b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::result
40110b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::do_in(state_type&,
40120b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
40130b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
40140b57cec5SDimitry Andric {
40150b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
40160b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
40170b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
40180b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
40190b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
40200b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
40210b57cec5SDimitry Andric     result r = utf16be_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4022*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
40230b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
40240b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
40250b57cec5SDimitry Andric     return r;
40260b57cec5SDimitry Andric }
40270b57cec5SDimitry Andric 
40280b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::result
40290b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::do_unshift(state_type&,
40300b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
40310b57cec5SDimitry Andric {
40320b57cec5SDimitry Andric     to_nxt = to;
40330b57cec5SDimitry Andric     return noconv;
40340b57cec5SDimitry Andric }
40350b57cec5SDimitry Andric 
40360b57cec5SDimitry Andric int
4037fe6060f1SDimitry Andric __codecvt_utf16<char16_t, false>::do_encoding() const noexcept
40380b57cec5SDimitry Andric {
40390b57cec5SDimitry Andric     return 0;
40400b57cec5SDimitry Andric }
40410b57cec5SDimitry Andric 
40420b57cec5SDimitry Andric bool
4043fe6060f1SDimitry Andric __codecvt_utf16<char16_t, false>::do_always_noconv() const noexcept
40440b57cec5SDimitry Andric {
40450b57cec5SDimitry Andric     return false;
40460b57cec5SDimitry Andric }
40470b57cec5SDimitry Andric 
40480b57cec5SDimitry Andric int
40490b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::do_length(state_type&,
40500b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
40510b57cec5SDimitry Andric {
40520b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
40530b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4054*bdd1243dSDimitry Andric     return utf16be_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
40550b57cec5SDimitry Andric }
40560b57cec5SDimitry Andric 
405781ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
40580b57cec5SDimitry Andric int
4059fe6060f1SDimitry Andric __codecvt_utf16<char16_t, false>::do_max_length() const noexcept
40600b57cec5SDimitry Andric {
4061*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
40620b57cec5SDimitry Andric         return 4;
40630b57cec5SDimitry Andric     return 2;
40640b57cec5SDimitry Andric }
406581ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
40660b57cec5SDimitry Andric 
40670b57cec5SDimitry Andric // __codecvt_utf16<char16_t, true>
40680b57cec5SDimitry Andric 
40690b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::result
40700b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::do_out(state_type&,
40710b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
40720b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
40730b57cec5SDimitry Andric {
40740b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
40750b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
40760b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
40770b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
40780b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
40790b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
40800b57cec5SDimitry Andric     result r = ucs2_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4081*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
40820b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
40830b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
40840b57cec5SDimitry Andric     return r;
40850b57cec5SDimitry Andric }
40860b57cec5SDimitry Andric 
40870b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::result
40880b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::do_in(state_type&,
40890b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
40900b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
40910b57cec5SDimitry Andric {
40920b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
40930b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
40940b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
40950b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
40960b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
40970b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
40980b57cec5SDimitry Andric     result r = utf16le_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4099*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
41000b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
41010b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
41020b57cec5SDimitry Andric     return r;
41030b57cec5SDimitry Andric }
41040b57cec5SDimitry Andric 
41050b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::result
41060b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::do_unshift(state_type&,
41070b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
41080b57cec5SDimitry Andric {
41090b57cec5SDimitry Andric     to_nxt = to;
41100b57cec5SDimitry Andric     return noconv;
41110b57cec5SDimitry Andric }
41120b57cec5SDimitry Andric 
41130b57cec5SDimitry Andric int
4114fe6060f1SDimitry Andric __codecvt_utf16<char16_t, true>::do_encoding() const noexcept
41150b57cec5SDimitry Andric {
41160b57cec5SDimitry Andric     return 0;
41170b57cec5SDimitry Andric }
41180b57cec5SDimitry Andric 
41190b57cec5SDimitry Andric bool
4120fe6060f1SDimitry Andric __codecvt_utf16<char16_t, true>::do_always_noconv() const noexcept
41210b57cec5SDimitry Andric {
41220b57cec5SDimitry Andric     return false;
41230b57cec5SDimitry Andric }
41240b57cec5SDimitry Andric 
41250b57cec5SDimitry Andric int
41260b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::do_length(state_type&,
41270b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
41280b57cec5SDimitry Andric {
41290b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
41300b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4131*bdd1243dSDimitry Andric     return utf16le_to_ucs2_length(_frm, _frm_end, mx, __maxcode_, __mode_);
41320b57cec5SDimitry Andric }
41330b57cec5SDimitry Andric 
413481ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
41350b57cec5SDimitry Andric int
4136fe6060f1SDimitry Andric __codecvt_utf16<char16_t, true>::do_max_length() const noexcept
41370b57cec5SDimitry Andric {
4138*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
41390b57cec5SDimitry Andric         return 4;
41400b57cec5SDimitry Andric     return 2;
41410b57cec5SDimitry Andric }
414281ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
41430b57cec5SDimitry Andric 
41440b57cec5SDimitry Andric // __codecvt_utf16<char32_t, false>
41450b57cec5SDimitry Andric 
41460b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::result
41470b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::do_out(state_type&,
41480b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
41490b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
41500b57cec5SDimitry Andric {
41510b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
41520b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
41530b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
41540b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
41550b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
41560b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
41570b57cec5SDimitry Andric     result r = ucs4_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4158*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
41590b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
41600b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
41610b57cec5SDimitry Andric     return r;
41620b57cec5SDimitry Andric }
41630b57cec5SDimitry Andric 
41640b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::result
41650b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::do_in(state_type&,
41660b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
41670b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
41680b57cec5SDimitry Andric {
41690b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
41700b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
41710b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
41720b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
41730b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
41740b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
41750b57cec5SDimitry Andric     result r = utf16be_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4176*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
41770b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
41780b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
41790b57cec5SDimitry Andric     return r;
41800b57cec5SDimitry Andric }
41810b57cec5SDimitry Andric 
41820b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::result
41830b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::do_unshift(state_type&,
41840b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
41850b57cec5SDimitry Andric {
41860b57cec5SDimitry Andric     to_nxt = to;
41870b57cec5SDimitry Andric     return noconv;
41880b57cec5SDimitry Andric }
41890b57cec5SDimitry Andric 
41900b57cec5SDimitry Andric int
4191fe6060f1SDimitry Andric __codecvt_utf16<char32_t, false>::do_encoding() const noexcept
41920b57cec5SDimitry Andric {
41930b57cec5SDimitry Andric     return 0;
41940b57cec5SDimitry Andric }
41950b57cec5SDimitry Andric 
41960b57cec5SDimitry Andric bool
4197fe6060f1SDimitry Andric __codecvt_utf16<char32_t, false>::do_always_noconv() const noexcept
41980b57cec5SDimitry Andric {
41990b57cec5SDimitry Andric     return false;
42000b57cec5SDimitry Andric }
42010b57cec5SDimitry Andric 
42020b57cec5SDimitry Andric int
42030b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::do_length(state_type&,
42040b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
42050b57cec5SDimitry Andric {
42060b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
42070b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4208*bdd1243dSDimitry Andric     return utf16be_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
42090b57cec5SDimitry Andric }
42100b57cec5SDimitry Andric 
421181ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
42120b57cec5SDimitry Andric int
4213fe6060f1SDimitry Andric __codecvt_utf16<char32_t, false>::do_max_length() const noexcept
42140b57cec5SDimitry Andric {
4215*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
42160b57cec5SDimitry Andric         return 6;
42170b57cec5SDimitry Andric     return 4;
42180b57cec5SDimitry Andric }
421981ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
42200b57cec5SDimitry Andric 
42210b57cec5SDimitry Andric // __codecvt_utf16<char32_t, true>
42220b57cec5SDimitry Andric 
42230b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::result
42240b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::do_out(state_type&,
42250b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
42260b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
42270b57cec5SDimitry Andric {
42280b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
42290b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
42300b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
42310b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
42320b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
42330b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
42340b57cec5SDimitry Andric     result r = ucs4_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4235*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
42360b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
42370b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
42380b57cec5SDimitry Andric     return r;
42390b57cec5SDimitry Andric }
42400b57cec5SDimitry Andric 
42410b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::result
42420b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::do_in(state_type&,
42430b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
42440b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
42450b57cec5SDimitry Andric {
42460b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
42470b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
42480b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
42490b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
42500b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
42510b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
42520b57cec5SDimitry Andric     result r = utf16le_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4253*bdd1243dSDimitry Andric                                __maxcode_, __mode_);
42540b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
42550b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
42560b57cec5SDimitry Andric     return r;
42570b57cec5SDimitry Andric }
42580b57cec5SDimitry Andric 
42590b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::result
42600b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::do_unshift(state_type&,
42610b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
42620b57cec5SDimitry Andric {
42630b57cec5SDimitry Andric     to_nxt = to;
42640b57cec5SDimitry Andric     return noconv;
42650b57cec5SDimitry Andric }
42660b57cec5SDimitry Andric 
42670b57cec5SDimitry Andric int
4268fe6060f1SDimitry Andric __codecvt_utf16<char32_t, true>::do_encoding() const noexcept
42690b57cec5SDimitry Andric {
42700b57cec5SDimitry Andric     return 0;
42710b57cec5SDimitry Andric }
42720b57cec5SDimitry Andric 
42730b57cec5SDimitry Andric bool
4274fe6060f1SDimitry Andric __codecvt_utf16<char32_t, true>::do_always_noconv() const noexcept
42750b57cec5SDimitry Andric {
42760b57cec5SDimitry Andric     return false;
42770b57cec5SDimitry Andric }
42780b57cec5SDimitry Andric 
42790b57cec5SDimitry Andric int
42800b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::do_length(state_type&,
42810b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
42820b57cec5SDimitry Andric {
42830b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
42840b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4285*bdd1243dSDimitry Andric     return utf16le_to_ucs4_length(_frm, _frm_end, mx, __maxcode_, __mode_);
42860b57cec5SDimitry Andric }
42870b57cec5SDimitry Andric 
428881ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
42890b57cec5SDimitry Andric int
4290fe6060f1SDimitry Andric __codecvt_utf16<char32_t, true>::do_max_length() const noexcept
42910b57cec5SDimitry Andric {
4292*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
42930b57cec5SDimitry Andric         return 6;
42940b57cec5SDimitry Andric     return 4;
42950b57cec5SDimitry Andric }
429681ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
42970b57cec5SDimitry Andric 
42980b57cec5SDimitry Andric // __codecvt_utf8_utf16<wchar_t>
42990b57cec5SDimitry Andric 
4300349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
43010b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::result
43020b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_out(state_type&,
43030b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
43040b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
43050b57cec5SDimitry Andric {
4306349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
4307349cc55cSDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
4308349cc55cSDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
4309349cc55cSDimitry Andric     const uint16_t* _frm_nxt = _frm;
4310349cc55cSDimitry Andric #else
43110b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
43120b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
43130b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
4314349cc55cSDimitry Andric #endif
43150b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
43160b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
43170b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
43180b57cec5SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4319*bdd1243dSDimitry Andric                              __maxcode_, __mode_);
43200b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
43210b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
43220b57cec5SDimitry Andric     return r;
43230b57cec5SDimitry Andric }
43240b57cec5SDimitry Andric 
43250b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::result
43260b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_in(state_type&,
43270b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
43280b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
43290b57cec5SDimitry Andric {
43300b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
43310b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
43320b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
4333349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
4334349cc55cSDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
4335349cc55cSDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
4336349cc55cSDimitry Andric     uint16_t* _to_nxt = _to;
4337349cc55cSDimitry Andric #else
43380b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
43390b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
43400b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
4341349cc55cSDimitry Andric #endif
43420b57cec5SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4343*bdd1243dSDimitry Andric                              __maxcode_, __mode_);
43440b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
43450b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
43460b57cec5SDimitry Andric     return r;
43470b57cec5SDimitry Andric }
43480b57cec5SDimitry Andric 
43490b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::result
43500b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_unshift(state_type&,
43510b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
43520b57cec5SDimitry Andric {
43530b57cec5SDimitry Andric     to_nxt = to;
43540b57cec5SDimitry Andric     return noconv;
43550b57cec5SDimitry Andric }
43560b57cec5SDimitry Andric 
43570b57cec5SDimitry Andric int
4358fe6060f1SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_encoding() const noexcept
43590b57cec5SDimitry Andric {
43600b57cec5SDimitry Andric     return 0;
43610b57cec5SDimitry Andric }
43620b57cec5SDimitry Andric 
43630b57cec5SDimitry Andric bool
4364fe6060f1SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_always_noconv() const noexcept
43650b57cec5SDimitry Andric {
43660b57cec5SDimitry Andric     return false;
43670b57cec5SDimitry Andric }
43680b57cec5SDimitry Andric 
43690b57cec5SDimitry Andric int
43700b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_length(state_type&,
43710b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
43720b57cec5SDimitry Andric {
43730b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
43740b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4375*bdd1243dSDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx, __maxcode_, __mode_);
43760b57cec5SDimitry Andric }
43770b57cec5SDimitry Andric 
43780b57cec5SDimitry Andric int
4379fe6060f1SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_max_length() const noexcept
43800b57cec5SDimitry Andric {
4381*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
43820b57cec5SDimitry Andric         return 7;
43830b57cec5SDimitry Andric     return 4;
43840b57cec5SDimitry Andric }
4385349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
43860b57cec5SDimitry Andric 
43870b57cec5SDimitry Andric // __codecvt_utf8_utf16<char16_t>
43880b57cec5SDimitry Andric 
43890b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::result
43900b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_out(state_type&,
43910b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
43920b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
43930b57cec5SDimitry Andric {
43940b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
43950b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
43960b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
43970b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
43980b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
43990b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
44000b57cec5SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4401*bdd1243dSDimitry Andric                              __maxcode_, __mode_);
44020b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
44030b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
44040b57cec5SDimitry Andric     return r;
44050b57cec5SDimitry Andric }
44060b57cec5SDimitry Andric 
44070b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::result
44080b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_in(state_type&,
44090b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
44100b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
44110b57cec5SDimitry Andric {
44120b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
44130b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
44140b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
44150b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
44160b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
44170b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
44180b57cec5SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4419*bdd1243dSDimitry Andric                              __maxcode_, __mode_);
44200b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
44210b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
44220b57cec5SDimitry Andric     return r;
44230b57cec5SDimitry Andric }
44240b57cec5SDimitry Andric 
44250b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::result
44260b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_unshift(state_type&,
44270b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
44280b57cec5SDimitry Andric {
44290b57cec5SDimitry Andric     to_nxt = to;
44300b57cec5SDimitry Andric     return noconv;
44310b57cec5SDimitry Andric }
44320b57cec5SDimitry Andric 
44330b57cec5SDimitry Andric int
4434fe6060f1SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_encoding() const noexcept
44350b57cec5SDimitry Andric {
44360b57cec5SDimitry Andric     return 0;
44370b57cec5SDimitry Andric }
44380b57cec5SDimitry Andric 
44390b57cec5SDimitry Andric bool
4440fe6060f1SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_always_noconv() const noexcept
44410b57cec5SDimitry Andric {
44420b57cec5SDimitry Andric     return false;
44430b57cec5SDimitry Andric }
44440b57cec5SDimitry Andric 
44450b57cec5SDimitry Andric int
44460b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_length(state_type&,
44470b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
44480b57cec5SDimitry Andric {
44490b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
44500b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4451*bdd1243dSDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx, __maxcode_, __mode_);
44520b57cec5SDimitry Andric }
44530b57cec5SDimitry Andric 
445481ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
44550b57cec5SDimitry Andric int
4456fe6060f1SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_max_length() const noexcept
44570b57cec5SDimitry Andric {
4458*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
44590b57cec5SDimitry Andric         return 7;
44600b57cec5SDimitry Andric     return 4;
44610b57cec5SDimitry Andric }
446281ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
44630b57cec5SDimitry Andric 
44640b57cec5SDimitry Andric // __codecvt_utf8_utf16<char32_t>
44650b57cec5SDimitry Andric 
44660b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::result
44670b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_out(state_type&,
44680b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
44690b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
44700b57cec5SDimitry Andric {
44710b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
44720b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
44730b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
44740b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
44750b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
44760b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
44770b57cec5SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4478*bdd1243dSDimitry Andric                              __maxcode_, __mode_);
44790b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
44800b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
44810b57cec5SDimitry Andric     return r;
44820b57cec5SDimitry Andric }
44830b57cec5SDimitry Andric 
44840b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::result
44850b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_in(state_type&,
44860b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
44870b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
44880b57cec5SDimitry Andric {
44890b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
44900b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
44910b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
44920b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
44930b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
44940b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
44950b57cec5SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
4496*bdd1243dSDimitry Andric                              __maxcode_, __mode_);
44970b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
44980b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
44990b57cec5SDimitry Andric     return r;
45000b57cec5SDimitry Andric }
45010b57cec5SDimitry Andric 
45020b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::result
45030b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_unshift(state_type&,
45040b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
45050b57cec5SDimitry Andric {
45060b57cec5SDimitry Andric     to_nxt = to;
45070b57cec5SDimitry Andric     return noconv;
45080b57cec5SDimitry Andric }
45090b57cec5SDimitry Andric 
45100b57cec5SDimitry Andric int
4511fe6060f1SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_encoding() const noexcept
45120b57cec5SDimitry Andric {
45130b57cec5SDimitry Andric     return 0;
45140b57cec5SDimitry Andric }
45150b57cec5SDimitry Andric 
45160b57cec5SDimitry Andric bool
4517fe6060f1SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_always_noconv() const noexcept
45180b57cec5SDimitry Andric {
45190b57cec5SDimitry Andric     return false;
45200b57cec5SDimitry Andric }
45210b57cec5SDimitry Andric 
45220b57cec5SDimitry Andric int
45230b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_length(state_type&,
45240b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
45250b57cec5SDimitry Andric {
45260b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
45270b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
4528*bdd1243dSDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx, __maxcode_, __mode_);
45290b57cec5SDimitry Andric }
45300b57cec5SDimitry Andric 
453181ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
45320b57cec5SDimitry Andric int
4533fe6060f1SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_max_length() const noexcept
45340b57cec5SDimitry Andric {
4535*bdd1243dSDimitry Andric     if (__mode_ & consume_header)
45360b57cec5SDimitry Andric         return 7;
45370b57cec5SDimitry Andric     return 4;
45380b57cec5SDimitry Andric }
453981ad6265SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
45400b57cec5SDimitry Andric 
45410b57cec5SDimitry Andric // __narrow_to_utf8<16>
45420b57cec5SDimitry Andric 
45430b57cec5SDimitry Andric __narrow_to_utf8<16>::~__narrow_to_utf8()
45440b57cec5SDimitry Andric {
45450b57cec5SDimitry Andric }
45460b57cec5SDimitry Andric 
45470b57cec5SDimitry Andric // __narrow_to_utf8<32>
45480b57cec5SDimitry Andric 
45490b57cec5SDimitry Andric __narrow_to_utf8<32>::~__narrow_to_utf8()
45500b57cec5SDimitry Andric {
45510b57cec5SDimitry Andric }
45520b57cec5SDimitry Andric 
45530b57cec5SDimitry Andric // __widen_from_utf8<16>
45540b57cec5SDimitry Andric 
45550b57cec5SDimitry Andric __widen_from_utf8<16>::~__widen_from_utf8()
45560b57cec5SDimitry Andric {
45570b57cec5SDimitry Andric }
45580b57cec5SDimitry Andric 
45590b57cec5SDimitry Andric // __widen_from_utf8<32>
45600b57cec5SDimitry Andric 
45610b57cec5SDimitry Andric __widen_from_utf8<32>::~__widen_from_utf8()
45620b57cec5SDimitry Andric {
45630b57cec5SDimitry Andric }
45640b57cec5SDimitry Andric 
4565349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
45660b57cec5SDimitry Andric static bool checked_string_to_wchar_convert(wchar_t& dest,
45670b57cec5SDimitry Andric                                             const char* ptr,
45680b57cec5SDimitry Andric                                             locale_t loc) {
45690b57cec5SDimitry Andric   if (*ptr == '\0')
45700b57cec5SDimitry Andric     return false;
45710b57cec5SDimitry Andric   mbstate_t mb = {};
45720b57cec5SDimitry Andric   wchar_t out;
45730b57cec5SDimitry Andric   size_t ret = __libcpp_mbrtowc_l(&out, ptr, strlen(ptr), &mb, loc);
45740b57cec5SDimitry Andric   if (ret == static_cast<size_t>(-1) || ret == static_cast<size_t>(-2)) {
45750b57cec5SDimitry Andric     return false;
45760b57cec5SDimitry Andric   }
45770b57cec5SDimitry Andric   dest = out;
45780b57cec5SDimitry Andric   return true;
45790b57cec5SDimitry Andric }
4580349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
4581349cc55cSDimitry Andric 
4582349cc55cSDimitry Andric #ifdef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4583349cc55cSDimitry Andric static bool is_narrow_non_breaking_space(const char* ptr) {
4584349cc55cSDimitry Andric   // https://www.fileformat.info/info/unicode/char/202f/index.htm
4585349cc55cSDimitry Andric   return ptr[0] == '\xe2' && ptr[1] == '\x80' && ptr[2] == '\xaf';
4586349cc55cSDimitry Andric }
4587349cc55cSDimitry Andric 
4588349cc55cSDimitry Andric static bool is_non_breaking_space(const char* ptr) {
4589349cc55cSDimitry Andric   // https://www.fileformat.info/info/unicode/char/0a/index.htm
4590349cc55cSDimitry Andric   return ptr[0] == '\xc2' && ptr[1] == '\xa0';
4591349cc55cSDimitry Andric }
4592349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
45930b57cec5SDimitry Andric 
45940b57cec5SDimitry Andric static bool checked_string_to_char_convert(char& dest,
45950b57cec5SDimitry Andric                                            const char* ptr,
45960b57cec5SDimitry Andric                                            locale_t __loc) {
45970b57cec5SDimitry Andric   if (*ptr == '\0')
45980b57cec5SDimitry Andric     return false;
45990b57cec5SDimitry Andric   if (!ptr[1]) {
46000b57cec5SDimitry Andric     dest = *ptr;
46010b57cec5SDimitry Andric     return true;
46020b57cec5SDimitry Andric   }
4603349cc55cSDimitry Andric 
4604349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46050b57cec5SDimitry Andric   // First convert the MBS into a wide char then attempt to narrow it using
46060b57cec5SDimitry Andric   // wctob_l.
46070b57cec5SDimitry Andric   wchar_t wout;
46080b57cec5SDimitry Andric   if (!checked_string_to_wchar_convert(wout, ptr, __loc))
46090b57cec5SDimitry Andric     return false;
46100b57cec5SDimitry Andric   int res;
46110b57cec5SDimitry Andric   if ((res = __libcpp_wctob_l(wout, __loc)) != char_traits<char>::eof()) {
46120b57cec5SDimitry Andric     dest = res;
46130b57cec5SDimitry Andric     return true;
46140b57cec5SDimitry Andric   }
4615349cc55cSDimitry Andric   // FIXME: Work around specific multibyte sequences that we can reasonably
46160b57cec5SDimitry Andric   // translate into a different single byte.
46170b57cec5SDimitry Andric   switch (wout) {
46180b57cec5SDimitry Andric   case L'\u202F': // narrow non-breaking space
46190b57cec5SDimitry Andric   case L'\u00A0': // non-breaking space
46200b57cec5SDimitry Andric     dest = ' ';
46210b57cec5SDimitry Andric     return true;
46220b57cec5SDimitry Andric   default:
46230b57cec5SDimitry Andric     return false;
46240b57cec5SDimitry Andric   }
4625349cc55cSDimitry Andric #else // _LIBCPP_HAS_NO_WIDE_CHARACTERS
4626349cc55cSDimitry Andric   // FIXME: Work around specific multibyte sequences that we can reasonably
4627349cc55cSDimitry Andric   // translate into a different single byte.
4628349cc55cSDimitry Andric   if (is_narrow_non_breaking_space(ptr) || is_non_breaking_space(ptr)) {
4629349cc55cSDimitry Andric     dest = ' ';
4630349cc55cSDimitry Andric     return true;
4631349cc55cSDimitry Andric   }
4632349cc55cSDimitry Andric 
4633349cc55cSDimitry Andric   return false;
4634349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
463581ad6265SDimitry Andric   __libcpp_unreachable();
46360b57cec5SDimitry Andric }
46370b57cec5SDimitry Andric 
46380b57cec5SDimitry Andric 
46390b57cec5SDimitry Andric // numpunct<char> && numpunct<wchar_t>
46400b57cec5SDimitry Andric 
46410b57cec5SDimitry Andric locale::id numpunct< char  >::id;
4642349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46430b57cec5SDimitry Andric locale::id numpunct<wchar_t>::id;
4644349cc55cSDimitry Andric #endif
46450b57cec5SDimitry Andric 
46460b57cec5SDimitry Andric numpunct<char>::numpunct(size_t refs)
46470b57cec5SDimitry Andric     : locale::facet(refs),
46480b57cec5SDimitry Andric       __decimal_point_('.'),
46490b57cec5SDimitry Andric       __thousands_sep_(',')
46500b57cec5SDimitry Andric {
46510b57cec5SDimitry Andric }
46520b57cec5SDimitry Andric 
4653349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46540b57cec5SDimitry Andric numpunct<wchar_t>::numpunct(size_t refs)
46550b57cec5SDimitry Andric     : locale::facet(refs),
46560b57cec5SDimitry Andric       __decimal_point_(L'.'),
46570b57cec5SDimitry Andric       __thousands_sep_(L',')
46580b57cec5SDimitry Andric {
46590b57cec5SDimitry Andric }
4660349cc55cSDimitry Andric #endif
46610b57cec5SDimitry Andric 
46620b57cec5SDimitry Andric numpunct<char>::~numpunct()
46630b57cec5SDimitry Andric {
46640b57cec5SDimitry Andric }
46650b57cec5SDimitry Andric 
4666349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46670b57cec5SDimitry Andric numpunct<wchar_t>::~numpunct()
46680b57cec5SDimitry Andric {
46690b57cec5SDimitry Andric }
4670349cc55cSDimitry Andric #endif
46710b57cec5SDimitry Andric 
46720b57cec5SDimitry Andric  char   numpunct< char  >::do_decimal_point() const {return __decimal_point_;}
4673349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46740b57cec5SDimitry Andric wchar_t numpunct<wchar_t>::do_decimal_point() const {return __decimal_point_;}
4675349cc55cSDimitry Andric #endif
46760b57cec5SDimitry Andric 
46770b57cec5SDimitry Andric  char   numpunct< char  >::do_thousands_sep() const {return __thousands_sep_;}
4678349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46790b57cec5SDimitry Andric wchar_t numpunct<wchar_t>::do_thousands_sep() const {return __thousands_sep_;}
4680349cc55cSDimitry Andric #endif
46810b57cec5SDimitry Andric 
46820b57cec5SDimitry Andric string numpunct< char  >::do_grouping() const {return __grouping_;}
4683349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46840b57cec5SDimitry Andric string numpunct<wchar_t>::do_grouping() const {return __grouping_;}
4685349cc55cSDimitry Andric #endif
46860b57cec5SDimitry Andric 
46870b57cec5SDimitry Andric  string numpunct< char  >::do_truename() const {return "true";}
4688349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46890b57cec5SDimitry Andric wstring numpunct<wchar_t>::do_truename() const {return L"true";}
4690349cc55cSDimitry Andric #endif
46910b57cec5SDimitry Andric 
46920b57cec5SDimitry Andric  string numpunct< char  >::do_falsename() const {return "false";}
4693349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46940b57cec5SDimitry Andric wstring numpunct<wchar_t>::do_falsename() const {return L"false";}
4695349cc55cSDimitry Andric #endif
46960b57cec5SDimitry Andric 
46970b57cec5SDimitry Andric // numpunct_byname<char>
46980b57cec5SDimitry Andric 
46990b57cec5SDimitry Andric numpunct_byname<char>::numpunct_byname(const char* nm, size_t refs)
47000b57cec5SDimitry Andric     : numpunct<char>(refs)
47010b57cec5SDimitry Andric {
47020b57cec5SDimitry Andric     __init(nm);
47030b57cec5SDimitry Andric }
47040b57cec5SDimitry Andric 
47050b57cec5SDimitry Andric numpunct_byname<char>::numpunct_byname(const string& nm, size_t refs)
47060b57cec5SDimitry Andric     : numpunct<char>(refs)
47070b57cec5SDimitry Andric {
47080b57cec5SDimitry Andric     __init(nm.c_str());
47090b57cec5SDimitry Andric }
47100b57cec5SDimitry Andric 
47110b57cec5SDimitry Andric numpunct_byname<char>::~numpunct_byname()
47120b57cec5SDimitry Andric {
47130b57cec5SDimitry Andric }
47140b57cec5SDimitry Andric 
47150b57cec5SDimitry Andric void
47160b57cec5SDimitry Andric numpunct_byname<char>::__init(const char* nm)
47170b57cec5SDimitry Andric {
4718349cc55cSDimitry Andric     typedef numpunct<char> base;
47190b57cec5SDimitry Andric     if (strcmp(nm, "C") != 0)
47200b57cec5SDimitry Andric     {
47210b57cec5SDimitry Andric         __libcpp_unique_locale loc(nm);
47220b57cec5SDimitry Andric         if (!loc)
47230b57cec5SDimitry Andric             __throw_runtime_error("numpunct_byname<char>::numpunct_byname"
47240b57cec5SDimitry Andric                                 " failed to construct for " + string(nm));
47250b57cec5SDimitry Andric 
47260b57cec5SDimitry Andric         lconv* lc = __libcpp_localeconv_l(loc.get());
4727349cc55cSDimitry Andric         if (!checked_string_to_char_convert(__decimal_point_, lc->decimal_point,
4728349cc55cSDimitry Andric                                             loc.get()))
4729349cc55cSDimitry Andric             __decimal_point_ = base::do_decimal_point();
4730349cc55cSDimitry Andric         if (!checked_string_to_char_convert(__thousands_sep_, lc->thousands_sep,
4731349cc55cSDimitry Andric                                             loc.get()))
4732349cc55cSDimitry Andric             __thousands_sep_ = base::do_thousands_sep();
47330b57cec5SDimitry Andric         __grouping_ = lc->grouping;
47340b57cec5SDimitry Andric         // localization for truename and falsename is not available
47350b57cec5SDimitry Andric     }
47360b57cec5SDimitry Andric }
47370b57cec5SDimitry Andric 
47380b57cec5SDimitry Andric // numpunct_byname<wchar_t>
47390b57cec5SDimitry Andric 
4740349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
47410b57cec5SDimitry Andric numpunct_byname<wchar_t>::numpunct_byname(const char* nm, size_t refs)
47420b57cec5SDimitry Andric     : numpunct<wchar_t>(refs)
47430b57cec5SDimitry Andric {
47440b57cec5SDimitry Andric     __init(nm);
47450b57cec5SDimitry Andric }
47460b57cec5SDimitry Andric 
47470b57cec5SDimitry Andric numpunct_byname<wchar_t>::numpunct_byname(const string& nm, size_t refs)
47480b57cec5SDimitry Andric     : numpunct<wchar_t>(refs)
47490b57cec5SDimitry Andric {
47500b57cec5SDimitry Andric     __init(nm.c_str());
47510b57cec5SDimitry Andric }
47520b57cec5SDimitry Andric 
47530b57cec5SDimitry Andric numpunct_byname<wchar_t>::~numpunct_byname()
47540b57cec5SDimitry Andric {
47550b57cec5SDimitry Andric }
47560b57cec5SDimitry Andric 
47570b57cec5SDimitry Andric void
47580b57cec5SDimitry Andric numpunct_byname<wchar_t>::__init(const char* nm)
47590b57cec5SDimitry Andric {
47600b57cec5SDimitry Andric     if (strcmp(nm, "C") != 0)
47610b57cec5SDimitry Andric     {
47620b57cec5SDimitry Andric         __libcpp_unique_locale loc(nm);
47630b57cec5SDimitry Andric         if (!loc)
47640b57cec5SDimitry Andric             __throw_runtime_error("numpunct_byname<wchar_t>::numpunct_byname"
47650b57cec5SDimitry Andric                                 " failed to construct for " + string(nm));
47660b57cec5SDimitry Andric 
47670b57cec5SDimitry Andric         lconv* lc = __libcpp_localeconv_l(loc.get());
47680b57cec5SDimitry Andric         checked_string_to_wchar_convert(__decimal_point_, lc->decimal_point,
47690b57cec5SDimitry Andric                                         loc.get());
47700b57cec5SDimitry Andric         checked_string_to_wchar_convert(__thousands_sep_, lc->thousands_sep,
47710b57cec5SDimitry Andric                                         loc.get());
47720b57cec5SDimitry Andric         __grouping_ = lc->grouping;
47730b57cec5SDimitry Andric         // localization for truename and falsename is not available
47740b57cec5SDimitry Andric     }
47750b57cec5SDimitry Andric }
4776349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
47770b57cec5SDimitry Andric 
47780b57cec5SDimitry Andric // num_get helpers
47790b57cec5SDimitry Andric 
47800b57cec5SDimitry Andric int
47810b57cec5SDimitry Andric __num_get_base::__get_base(ios_base& iob)
47820b57cec5SDimitry Andric {
47830b57cec5SDimitry Andric     ios_base::fmtflags __basefield = iob.flags() & ios_base::basefield;
47840b57cec5SDimitry Andric     if (__basefield == ios_base::oct)
47850b57cec5SDimitry Andric         return 8;
47860b57cec5SDimitry Andric     else if (__basefield == ios_base::hex)
47870b57cec5SDimitry Andric         return 16;
47880b57cec5SDimitry Andric     else if (__basefield == 0)
47890b57cec5SDimitry Andric         return 0;
47900b57cec5SDimitry Andric     return 10;
47910b57cec5SDimitry Andric }
47920b57cec5SDimitry Andric 
47930b57cec5SDimitry Andric const char __num_get_base::__src[33] = "0123456789abcdefABCDEFxX+-pPiInN";
47940b57cec5SDimitry Andric 
47950b57cec5SDimitry Andric void
47960b57cec5SDimitry Andric __check_grouping(const string& __grouping, unsigned* __g, unsigned* __g_end,
47970b57cec5SDimitry Andric                  ios_base::iostate& __err)
47980b57cec5SDimitry Andric {
47990b57cec5SDimitry Andric //  if the grouping pattern is empty _or_ there are no grouping bits, then do nothing
48000b57cec5SDimitry Andric //  we always have at least a single entry in [__g, __g_end); the end of the input sequence
48010b57cec5SDimitry Andric     if (__grouping.size() != 0 && __g_end - __g > 1)
48020b57cec5SDimitry Andric     {
48030b57cec5SDimitry Andric         reverse(__g, __g_end);
48040b57cec5SDimitry Andric         const char* __ig = __grouping.data();
48050b57cec5SDimitry Andric         const char* __eg = __ig + __grouping.size();
48060b57cec5SDimitry Andric         for (unsigned* __r = __g; __r < __g_end-1; ++__r)
48070b57cec5SDimitry Andric         {
48080b57cec5SDimitry Andric             if (0 < *__ig && *__ig < numeric_limits<char>::max())
48090b57cec5SDimitry Andric             {
48100b57cec5SDimitry Andric                 if (static_cast<unsigned>(*__ig) != *__r)
48110b57cec5SDimitry Andric                 {
48120b57cec5SDimitry Andric                     __err = ios_base::failbit;
48130b57cec5SDimitry Andric                     return;
48140b57cec5SDimitry Andric                 }
48150b57cec5SDimitry Andric             }
48160b57cec5SDimitry Andric             if (__eg - __ig > 1)
48170b57cec5SDimitry Andric                 ++__ig;
48180b57cec5SDimitry Andric         }
48190b57cec5SDimitry Andric         if (0 < *__ig && *__ig < numeric_limits<char>::max())
48200b57cec5SDimitry Andric         {
48210b57cec5SDimitry Andric             if (static_cast<unsigned>(*__ig) < __g_end[-1] || __g_end[-1] == 0)
48220b57cec5SDimitry Andric                 __err = ios_base::failbit;
48230b57cec5SDimitry Andric         }
48240b57cec5SDimitry Andric     }
48250b57cec5SDimitry Andric }
48260b57cec5SDimitry Andric 
48270b57cec5SDimitry Andric void
48280b57cec5SDimitry Andric __num_put_base::__format_int(char* __fmtp, const char* __len, bool __signd,
48290b57cec5SDimitry Andric                              ios_base::fmtflags __flags)
48300b57cec5SDimitry Andric {
4831fe6060f1SDimitry Andric     if ((__flags & ios_base::showpos) &&
4832fe6060f1SDimitry Andric         (__flags & ios_base::basefield) != ios_base::oct &&
4833fe6060f1SDimitry Andric         (__flags & ios_base::basefield) != ios_base::hex &&
4834fe6060f1SDimitry Andric         __signd)
48350b57cec5SDimitry Andric         *__fmtp++ = '+';
48360b57cec5SDimitry Andric     if (__flags & ios_base::showbase)
48370b57cec5SDimitry Andric         *__fmtp++ = '#';
48380b57cec5SDimitry Andric     while(*__len)
48390b57cec5SDimitry Andric         *__fmtp++ = *__len++;
48400b57cec5SDimitry Andric     if ((__flags & ios_base::basefield) == ios_base::oct)
48410b57cec5SDimitry Andric         *__fmtp = 'o';
48420b57cec5SDimitry Andric     else if ((__flags & ios_base::basefield) == ios_base::hex)
48430b57cec5SDimitry Andric     {
48440b57cec5SDimitry Andric         if (__flags & ios_base::uppercase)
48450b57cec5SDimitry Andric             *__fmtp = 'X';
48460b57cec5SDimitry Andric         else
48470b57cec5SDimitry Andric             *__fmtp = 'x';
48480b57cec5SDimitry Andric     }
48490b57cec5SDimitry Andric     else if (__signd)
48500b57cec5SDimitry Andric         *__fmtp = 'd';
48510b57cec5SDimitry Andric     else
48520b57cec5SDimitry Andric         *__fmtp = 'u';
48530b57cec5SDimitry Andric }
48540b57cec5SDimitry Andric 
48550b57cec5SDimitry Andric bool
48560b57cec5SDimitry Andric __num_put_base::__format_float(char* __fmtp, const char* __len,
48570b57cec5SDimitry Andric                                ios_base::fmtflags __flags)
48580b57cec5SDimitry Andric {
48590b57cec5SDimitry Andric     bool specify_precision = true;
48600b57cec5SDimitry Andric     if (__flags & ios_base::showpos)
48610b57cec5SDimitry Andric         *__fmtp++ = '+';
48620b57cec5SDimitry Andric     if (__flags & ios_base::showpoint)
48630b57cec5SDimitry Andric         *__fmtp++ = '#';
48640b57cec5SDimitry Andric     ios_base::fmtflags floatfield = __flags & ios_base::floatfield;
48650b57cec5SDimitry Andric     bool uppercase = (__flags & ios_base::uppercase) != 0;
48660b57cec5SDimitry Andric     if (floatfield == (ios_base::fixed | ios_base::scientific))
48670b57cec5SDimitry Andric         specify_precision = false;
48680b57cec5SDimitry Andric     else
48690b57cec5SDimitry Andric     {
48700b57cec5SDimitry Andric         *__fmtp++ = '.';
48710b57cec5SDimitry Andric         *__fmtp++ = '*';
48720b57cec5SDimitry Andric     }
48730b57cec5SDimitry Andric     while(*__len)
48740b57cec5SDimitry Andric         *__fmtp++ = *__len++;
48750b57cec5SDimitry Andric     if (floatfield == ios_base::fixed)
48760b57cec5SDimitry Andric     {
48770b57cec5SDimitry Andric         if (uppercase)
48780b57cec5SDimitry Andric             *__fmtp = 'F';
48790b57cec5SDimitry Andric         else
48800b57cec5SDimitry Andric             *__fmtp = 'f';
48810b57cec5SDimitry Andric     }
48820b57cec5SDimitry Andric     else if (floatfield == ios_base::scientific)
48830b57cec5SDimitry Andric     {
48840b57cec5SDimitry Andric         if (uppercase)
48850b57cec5SDimitry Andric             *__fmtp = 'E';
48860b57cec5SDimitry Andric         else
48870b57cec5SDimitry Andric             *__fmtp = 'e';
48880b57cec5SDimitry Andric     }
48890b57cec5SDimitry Andric     else if (floatfield == (ios_base::fixed | ios_base::scientific))
48900b57cec5SDimitry Andric     {
48910b57cec5SDimitry Andric         if (uppercase)
48920b57cec5SDimitry Andric             *__fmtp = 'A';
48930b57cec5SDimitry Andric         else
48940b57cec5SDimitry Andric             *__fmtp = 'a';
48950b57cec5SDimitry Andric     }
48960b57cec5SDimitry Andric     else
48970b57cec5SDimitry Andric     {
48980b57cec5SDimitry Andric         if (uppercase)
48990b57cec5SDimitry Andric             *__fmtp = 'G';
49000b57cec5SDimitry Andric         else
49010b57cec5SDimitry Andric             *__fmtp = 'g';
49020b57cec5SDimitry Andric     }
49030b57cec5SDimitry Andric     return specify_precision;
49040b57cec5SDimitry Andric }
49050b57cec5SDimitry Andric 
49060b57cec5SDimitry Andric char*
49070b57cec5SDimitry Andric __num_put_base::__identify_padding(char* __nb, char* __ne,
49080b57cec5SDimitry Andric                                    const ios_base& __iob)
49090b57cec5SDimitry Andric {
49100b57cec5SDimitry Andric     switch (__iob.flags() & ios_base::adjustfield)
49110b57cec5SDimitry Andric     {
49120b57cec5SDimitry Andric     case ios_base::internal:
49130b57cec5SDimitry Andric         if (__nb[0] == '-' || __nb[0] == '+')
49140b57cec5SDimitry Andric             return __nb+1;
49150b57cec5SDimitry Andric         if (__ne - __nb >= 2 && __nb[0] == '0'
49160b57cec5SDimitry Andric                             && (__nb[1] == 'x' || __nb[1] == 'X'))
49170b57cec5SDimitry Andric             return __nb+2;
49180b57cec5SDimitry Andric         break;
49190b57cec5SDimitry Andric     case ios_base::left:
49200b57cec5SDimitry Andric         return __ne;
49210b57cec5SDimitry Andric     case ios_base::right:
49220b57cec5SDimitry Andric     default:
49230b57cec5SDimitry Andric         break;
49240b57cec5SDimitry Andric     }
49250b57cec5SDimitry Andric     return __nb;
49260b57cec5SDimitry Andric }
49270b57cec5SDimitry Andric 
49280b57cec5SDimitry Andric // time_get
49290b57cec5SDimitry Andric 
49300b57cec5SDimitry Andric static
49310b57cec5SDimitry Andric string*
49320b57cec5SDimitry Andric init_weeks()
49330b57cec5SDimitry Andric {
49340b57cec5SDimitry Andric     static string weeks[14];
49350b57cec5SDimitry Andric     weeks[0]  = "Sunday";
49360b57cec5SDimitry Andric     weeks[1]  = "Monday";
49370b57cec5SDimitry Andric     weeks[2]  = "Tuesday";
49380b57cec5SDimitry Andric     weeks[3]  = "Wednesday";
49390b57cec5SDimitry Andric     weeks[4]  = "Thursday";
49400b57cec5SDimitry Andric     weeks[5]  = "Friday";
49410b57cec5SDimitry Andric     weeks[6]  = "Saturday";
49420b57cec5SDimitry Andric     weeks[7]  = "Sun";
49430b57cec5SDimitry Andric     weeks[8]  = "Mon";
49440b57cec5SDimitry Andric     weeks[9]  = "Tue";
49450b57cec5SDimitry Andric     weeks[10] = "Wed";
49460b57cec5SDimitry Andric     weeks[11] = "Thu";
49470b57cec5SDimitry Andric     weeks[12] = "Fri";
49480b57cec5SDimitry Andric     weeks[13] = "Sat";
49490b57cec5SDimitry Andric     return weeks;
49500b57cec5SDimitry Andric }
49510b57cec5SDimitry Andric 
4952349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
49530b57cec5SDimitry Andric static
49540b57cec5SDimitry Andric wstring*
49550b57cec5SDimitry Andric init_wweeks()
49560b57cec5SDimitry Andric {
49570b57cec5SDimitry Andric     static wstring weeks[14];
49580b57cec5SDimitry Andric     weeks[0]  = L"Sunday";
49590b57cec5SDimitry Andric     weeks[1]  = L"Monday";
49600b57cec5SDimitry Andric     weeks[2]  = L"Tuesday";
49610b57cec5SDimitry Andric     weeks[3]  = L"Wednesday";
49620b57cec5SDimitry Andric     weeks[4]  = L"Thursday";
49630b57cec5SDimitry Andric     weeks[5]  = L"Friday";
49640b57cec5SDimitry Andric     weeks[6]  = L"Saturday";
49650b57cec5SDimitry Andric     weeks[7]  = L"Sun";
49660b57cec5SDimitry Andric     weeks[8]  = L"Mon";
49670b57cec5SDimitry Andric     weeks[9]  = L"Tue";
49680b57cec5SDimitry Andric     weeks[10] = L"Wed";
49690b57cec5SDimitry Andric     weeks[11] = L"Thu";
49700b57cec5SDimitry Andric     weeks[12] = L"Fri";
49710b57cec5SDimitry Andric     weeks[13] = L"Sat";
49720b57cec5SDimitry Andric     return weeks;
49730b57cec5SDimitry Andric }
4974349cc55cSDimitry Andric #endif
49750b57cec5SDimitry Andric 
49760b57cec5SDimitry Andric template <>
49770b57cec5SDimitry Andric const string*
49780b57cec5SDimitry Andric __time_get_c_storage<char>::__weeks() const
49790b57cec5SDimitry Andric {
49800b57cec5SDimitry Andric     static const string* weeks = init_weeks();
49810b57cec5SDimitry Andric     return weeks;
49820b57cec5SDimitry Andric }
49830b57cec5SDimitry Andric 
4984349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
49850b57cec5SDimitry Andric template <>
49860b57cec5SDimitry Andric const wstring*
49870b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__weeks() const
49880b57cec5SDimitry Andric {
49890b57cec5SDimitry Andric     static const wstring* weeks = init_wweeks();
49900b57cec5SDimitry Andric     return weeks;
49910b57cec5SDimitry Andric }
4992349cc55cSDimitry Andric #endif
49930b57cec5SDimitry Andric 
49940b57cec5SDimitry Andric static
49950b57cec5SDimitry Andric string*
49960b57cec5SDimitry Andric init_months()
49970b57cec5SDimitry Andric {
49980b57cec5SDimitry Andric     static string months[24];
49990b57cec5SDimitry Andric     months[0]  = "January";
50000b57cec5SDimitry Andric     months[1]  = "February";
50010b57cec5SDimitry Andric     months[2]  = "March";
50020b57cec5SDimitry Andric     months[3]  = "April";
50030b57cec5SDimitry Andric     months[4]  = "May";
50040b57cec5SDimitry Andric     months[5]  = "June";
50050b57cec5SDimitry Andric     months[6]  = "July";
50060b57cec5SDimitry Andric     months[7]  = "August";
50070b57cec5SDimitry Andric     months[8]  = "September";
50080b57cec5SDimitry Andric     months[9]  = "October";
50090b57cec5SDimitry Andric     months[10] = "November";
50100b57cec5SDimitry Andric     months[11] = "December";
50110b57cec5SDimitry Andric     months[12] = "Jan";
50120b57cec5SDimitry Andric     months[13] = "Feb";
50130b57cec5SDimitry Andric     months[14] = "Mar";
50140b57cec5SDimitry Andric     months[15] = "Apr";
50150b57cec5SDimitry Andric     months[16] = "May";
50160b57cec5SDimitry Andric     months[17] = "Jun";
50170b57cec5SDimitry Andric     months[18] = "Jul";
50180b57cec5SDimitry Andric     months[19] = "Aug";
50190b57cec5SDimitry Andric     months[20] = "Sep";
50200b57cec5SDimitry Andric     months[21] = "Oct";
50210b57cec5SDimitry Andric     months[22] = "Nov";
50220b57cec5SDimitry Andric     months[23] = "Dec";
50230b57cec5SDimitry Andric     return months;
50240b57cec5SDimitry Andric }
50250b57cec5SDimitry Andric 
5026349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
50270b57cec5SDimitry Andric static
50280b57cec5SDimitry Andric wstring*
50290b57cec5SDimitry Andric init_wmonths()
50300b57cec5SDimitry Andric {
50310b57cec5SDimitry Andric     static wstring months[24];
50320b57cec5SDimitry Andric     months[0]  = L"January";
50330b57cec5SDimitry Andric     months[1]  = L"February";
50340b57cec5SDimitry Andric     months[2]  = L"March";
50350b57cec5SDimitry Andric     months[3]  = L"April";
50360b57cec5SDimitry Andric     months[4]  = L"May";
50370b57cec5SDimitry Andric     months[5]  = L"June";
50380b57cec5SDimitry Andric     months[6]  = L"July";
50390b57cec5SDimitry Andric     months[7]  = L"August";
50400b57cec5SDimitry Andric     months[8]  = L"September";
50410b57cec5SDimitry Andric     months[9]  = L"October";
50420b57cec5SDimitry Andric     months[10] = L"November";
50430b57cec5SDimitry Andric     months[11] = L"December";
50440b57cec5SDimitry Andric     months[12] = L"Jan";
50450b57cec5SDimitry Andric     months[13] = L"Feb";
50460b57cec5SDimitry Andric     months[14] = L"Mar";
50470b57cec5SDimitry Andric     months[15] = L"Apr";
50480b57cec5SDimitry Andric     months[16] = L"May";
50490b57cec5SDimitry Andric     months[17] = L"Jun";
50500b57cec5SDimitry Andric     months[18] = L"Jul";
50510b57cec5SDimitry Andric     months[19] = L"Aug";
50520b57cec5SDimitry Andric     months[20] = L"Sep";
50530b57cec5SDimitry Andric     months[21] = L"Oct";
50540b57cec5SDimitry Andric     months[22] = L"Nov";
50550b57cec5SDimitry Andric     months[23] = L"Dec";
50560b57cec5SDimitry Andric     return months;
50570b57cec5SDimitry Andric }
5058349cc55cSDimitry Andric #endif
50590b57cec5SDimitry Andric 
50600b57cec5SDimitry Andric template <>
50610b57cec5SDimitry Andric const string*
50620b57cec5SDimitry Andric __time_get_c_storage<char>::__months() const
50630b57cec5SDimitry Andric {
50640b57cec5SDimitry Andric     static const string* months = init_months();
50650b57cec5SDimitry Andric     return months;
50660b57cec5SDimitry Andric }
50670b57cec5SDimitry Andric 
5068349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
50690b57cec5SDimitry Andric template <>
50700b57cec5SDimitry Andric const wstring*
50710b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__months() const
50720b57cec5SDimitry Andric {
50730b57cec5SDimitry Andric     static const wstring* months = init_wmonths();
50740b57cec5SDimitry Andric     return months;
50750b57cec5SDimitry Andric }
5076349cc55cSDimitry Andric #endif
50770b57cec5SDimitry Andric 
50780b57cec5SDimitry Andric static
50790b57cec5SDimitry Andric string*
50800b57cec5SDimitry Andric init_am_pm()
50810b57cec5SDimitry Andric {
50820b57cec5SDimitry Andric     static string am_pm[2];
50830b57cec5SDimitry Andric     am_pm[0]  = "AM";
50840b57cec5SDimitry Andric     am_pm[1]  = "PM";
50850b57cec5SDimitry Andric     return am_pm;
50860b57cec5SDimitry Andric }
50870b57cec5SDimitry Andric 
5088349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
50890b57cec5SDimitry Andric static
50900b57cec5SDimitry Andric wstring*
50910b57cec5SDimitry Andric init_wam_pm()
50920b57cec5SDimitry Andric {
50930b57cec5SDimitry Andric     static wstring am_pm[2];
50940b57cec5SDimitry Andric     am_pm[0]  = L"AM";
50950b57cec5SDimitry Andric     am_pm[1]  = L"PM";
50960b57cec5SDimitry Andric     return am_pm;
50970b57cec5SDimitry Andric }
5098349cc55cSDimitry Andric #endif
50990b57cec5SDimitry Andric 
51000b57cec5SDimitry Andric template <>
51010b57cec5SDimitry Andric const string*
51020b57cec5SDimitry Andric __time_get_c_storage<char>::__am_pm() const
51030b57cec5SDimitry Andric {
51040b57cec5SDimitry Andric     static const string* am_pm = init_am_pm();
51050b57cec5SDimitry Andric     return am_pm;
51060b57cec5SDimitry Andric }
51070b57cec5SDimitry Andric 
5108349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51090b57cec5SDimitry Andric template <>
51100b57cec5SDimitry Andric const wstring*
51110b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__am_pm() const
51120b57cec5SDimitry Andric {
51130b57cec5SDimitry Andric     static const wstring* am_pm = init_wam_pm();
51140b57cec5SDimitry Andric     return am_pm;
51150b57cec5SDimitry Andric }
5116349cc55cSDimitry Andric #endif
51170b57cec5SDimitry Andric 
51180b57cec5SDimitry Andric template <>
51190b57cec5SDimitry Andric const string&
51200b57cec5SDimitry Andric __time_get_c_storage<char>::__x() const
51210b57cec5SDimitry Andric {
51220b57cec5SDimitry Andric     static string s("%m/%d/%y");
51230b57cec5SDimitry Andric     return s;
51240b57cec5SDimitry Andric }
51250b57cec5SDimitry Andric 
5126349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51270b57cec5SDimitry Andric template <>
51280b57cec5SDimitry Andric const wstring&
51290b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__x() const
51300b57cec5SDimitry Andric {
51310b57cec5SDimitry Andric     static wstring s(L"%m/%d/%y");
51320b57cec5SDimitry Andric     return s;
51330b57cec5SDimitry Andric }
5134349cc55cSDimitry Andric #endif
51350b57cec5SDimitry Andric 
51360b57cec5SDimitry Andric template <>
51370b57cec5SDimitry Andric const string&
51380b57cec5SDimitry Andric __time_get_c_storage<char>::__X() const
51390b57cec5SDimitry Andric {
51400b57cec5SDimitry Andric     static string s("%H:%M:%S");
51410b57cec5SDimitry Andric     return s;
51420b57cec5SDimitry Andric }
51430b57cec5SDimitry Andric 
5144349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51450b57cec5SDimitry Andric template <>
51460b57cec5SDimitry Andric const wstring&
51470b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__X() const
51480b57cec5SDimitry Andric {
51490b57cec5SDimitry Andric     static wstring s(L"%H:%M:%S");
51500b57cec5SDimitry Andric     return s;
51510b57cec5SDimitry Andric }
5152349cc55cSDimitry Andric #endif
51530b57cec5SDimitry Andric 
51540b57cec5SDimitry Andric template <>
51550b57cec5SDimitry Andric const string&
51560b57cec5SDimitry Andric __time_get_c_storage<char>::__c() const
51570b57cec5SDimitry Andric {
51580b57cec5SDimitry Andric     static string s("%a %b %d %H:%M:%S %Y");
51590b57cec5SDimitry Andric     return s;
51600b57cec5SDimitry Andric }
51610b57cec5SDimitry Andric 
5162349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51630b57cec5SDimitry Andric template <>
51640b57cec5SDimitry Andric const wstring&
51650b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__c() const
51660b57cec5SDimitry Andric {
51670b57cec5SDimitry Andric     static wstring s(L"%a %b %d %H:%M:%S %Y");
51680b57cec5SDimitry Andric     return s;
51690b57cec5SDimitry Andric }
5170349cc55cSDimitry Andric #endif
51710b57cec5SDimitry Andric 
51720b57cec5SDimitry Andric template <>
51730b57cec5SDimitry Andric const string&
51740b57cec5SDimitry Andric __time_get_c_storage<char>::__r() const
51750b57cec5SDimitry Andric {
51760b57cec5SDimitry Andric     static string s("%I:%M:%S %p");
51770b57cec5SDimitry Andric     return s;
51780b57cec5SDimitry Andric }
51790b57cec5SDimitry Andric 
5180349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51810b57cec5SDimitry Andric template <>
51820b57cec5SDimitry Andric const wstring&
51830b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__r() const
51840b57cec5SDimitry Andric {
51850b57cec5SDimitry Andric     static wstring s(L"%I:%M:%S %p");
51860b57cec5SDimitry Andric     return s;
51870b57cec5SDimitry Andric }
5188349cc55cSDimitry Andric #endif
51890b57cec5SDimitry Andric 
51900b57cec5SDimitry Andric // time_get_byname
51910b57cec5SDimitry Andric 
51920b57cec5SDimitry Andric __time_get::__time_get(const char* nm)
51930b57cec5SDimitry Andric     : __loc_(newlocale(LC_ALL_MASK, nm, 0))
51940b57cec5SDimitry Andric {
51950b57cec5SDimitry Andric     if (__loc_ == 0)
51960b57cec5SDimitry Andric         __throw_runtime_error("time_get_byname"
51970b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
51980b57cec5SDimitry Andric }
51990b57cec5SDimitry Andric 
52000b57cec5SDimitry Andric __time_get::__time_get(const string& nm)
52010b57cec5SDimitry Andric     : __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0))
52020b57cec5SDimitry Andric {
52030b57cec5SDimitry Andric     if (__loc_ == 0)
52040b57cec5SDimitry Andric         __throw_runtime_error("time_get_byname"
52050b57cec5SDimitry Andric                             " failed to construct for " + nm);
52060b57cec5SDimitry Andric }
52070b57cec5SDimitry Andric 
52080b57cec5SDimitry Andric __time_get::~__time_get()
52090b57cec5SDimitry Andric {
52100b57cec5SDimitry Andric     freelocale(__loc_);
52110b57cec5SDimitry Andric }
521281ad6265SDimitry Andric 
521381ad6265SDimitry Andric _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-field-initializers")
52140b57cec5SDimitry Andric 
52150b57cec5SDimitry Andric template <>
52160b57cec5SDimitry Andric string
52170b57cec5SDimitry Andric __time_get_storage<char>::__analyze(char fmt, const ctype<char>& ct)
52180b57cec5SDimitry Andric {
52190b57cec5SDimitry Andric     tm t = {0};
52200b57cec5SDimitry Andric     t.tm_sec = 59;
52210b57cec5SDimitry Andric     t.tm_min = 55;
52220b57cec5SDimitry Andric     t.tm_hour = 23;
52230b57cec5SDimitry Andric     t.tm_mday = 31;
52240b57cec5SDimitry Andric     t.tm_mon = 11;
52250b57cec5SDimitry Andric     t.tm_year = 161;
52260b57cec5SDimitry Andric     t.tm_wday = 6;
52270b57cec5SDimitry Andric     t.tm_yday = 364;
52280b57cec5SDimitry Andric     t.tm_isdst = -1;
52290b57cec5SDimitry Andric     char buf[100];
52300b57cec5SDimitry Andric     char f[3] = {0};
52310b57cec5SDimitry Andric     f[0] = '%';
52320b57cec5SDimitry Andric     f[1] = fmt;
52330b57cec5SDimitry Andric     size_t n = strftime_l(buf, countof(buf), f, &t, __loc_);
52340b57cec5SDimitry Andric     char* bb = buf;
52350b57cec5SDimitry Andric     char* be = buf + n;
52360b57cec5SDimitry Andric     string result;
52370b57cec5SDimitry Andric     while (bb != be)
52380b57cec5SDimitry Andric     {
52390b57cec5SDimitry Andric         if (ct.is(ctype_base::space, *bb))
52400b57cec5SDimitry Andric         {
52410b57cec5SDimitry Andric             result.push_back(' ');
52420b57cec5SDimitry Andric             for (++bb; bb != be && ct.is(ctype_base::space, *bb); ++bb)
52430b57cec5SDimitry Andric                 ;
52440b57cec5SDimitry Andric             continue;
52450b57cec5SDimitry Andric         }
52460b57cec5SDimitry Andric         char* w = bb;
52470b57cec5SDimitry Andric         ios_base::iostate err = ios_base::goodbit;
52480b57cec5SDimitry Andric         ptrdiff_t i = __scan_keyword(w, be, this->__weeks_, this->__weeks_+14,
52490b57cec5SDimitry Andric                                ct, err, false)
52500b57cec5SDimitry Andric                                - this->__weeks_;
52510b57cec5SDimitry Andric         if (i < 14)
52520b57cec5SDimitry Andric         {
52530b57cec5SDimitry Andric             result.push_back('%');
52540b57cec5SDimitry Andric             if (i < 7)
52550b57cec5SDimitry Andric                 result.push_back('A');
52560b57cec5SDimitry Andric             else
52570b57cec5SDimitry Andric                 result.push_back('a');
52580b57cec5SDimitry Andric             bb = w;
52590b57cec5SDimitry Andric             continue;
52600b57cec5SDimitry Andric         }
52610b57cec5SDimitry Andric         w = bb;
52620b57cec5SDimitry Andric         i = __scan_keyword(w, be, this->__months_, this->__months_+24,
52630b57cec5SDimitry Andric                            ct, err, false)
52640b57cec5SDimitry Andric                            - this->__months_;
52650b57cec5SDimitry Andric         if (i < 24)
52660b57cec5SDimitry Andric         {
52670b57cec5SDimitry Andric             result.push_back('%');
52680b57cec5SDimitry Andric             if (i < 12)
52690b57cec5SDimitry Andric                 result.push_back('B');
52700b57cec5SDimitry Andric             else
52710b57cec5SDimitry Andric                 result.push_back('b');
52720b57cec5SDimitry Andric             if (fmt == 'x' && ct.is(ctype_base::digit, this->__months_[i][0]))
52730b57cec5SDimitry Andric                 result.back() = 'm';
52740b57cec5SDimitry Andric             bb = w;
52750b57cec5SDimitry Andric             continue;
52760b57cec5SDimitry Andric         }
52770b57cec5SDimitry Andric         if (this->__am_pm_[0].size() + this->__am_pm_[1].size() > 0)
52780b57cec5SDimitry Andric         {
52790b57cec5SDimitry Andric             w = bb;
52800b57cec5SDimitry Andric             i = __scan_keyword(w, be, this->__am_pm_, this->__am_pm_+2,
52810b57cec5SDimitry Andric                                ct, err, false) - this->__am_pm_;
52820b57cec5SDimitry Andric             if (i < 2)
52830b57cec5SDimitry Andric             {
52840b57cec5SDimitry Andric                 result.push_back('%');
52850b57cec5SDimitry Andric                 result.push_back('p');
52860b57cec5SDimitry Andric                 bb = w;
52870b57cec5SDimitry Andric                 continue;
52880b57cec5SDimitry Andric             }
52890b57cec5SDimitry Andric         }
52900b57cec5SDimitry Andric         w = bb;
52910b57cec5SDimitry Andric         if (ct.is(ctype_base::digit, *bb))
52920b57cec5SDimitry Andric         {
52930b57cec5SDimitry Andric             switch(__get_up_to_n_digits(bb, be, err, ct, 4))
52940b57cec5SDimitry Andric             {
52950b57cec5SDimitry Andric             case 6:
52960b57cec5SDimitry Andric                 result.push_back('%');
52970b57cec5SDimitry Andric                 result.push_back('w');
52980b57cec5SDimitry Andric                 break;
52990b57cec5SDimitry Andric             case 7:
53000b57cec5SDimitry Andric                 result.push_back('%');
53010b57cec5SDimitry Andric                 result.push_back('u');
53020b57cec5SDimitry Andric                 break;
53030b57cec5SDimitry Andric             case 11:
53040b57cec5SDimitry Andric                 result.push_back('%');
53050b57cec5SDimitry Andric                 result.push_back('I');
53060b57cec5SDimitry Andric                 break;
53070b57cec5SDimitry Andric             case 12:
53080b57cec5SDimitry Andric                 result.push_back('%');
53090b57cec5SDimitry Andric                 result.push_back('m');
53100b57cec5SDimitry Andric                 break;
53110b57cec5SDimitry Andric             case 23:
53120b57cec5SDimitry Andric                 result.push_back('%');
53130b57cec5SDimitry Andric                 result.push_back('H');
53140b57cec5SDimitry Andric                 break;
53150b57cec5SDimitry Andric             case 31:
53160b57cec5SDimitry Andric                 result.push_back('%');
53170b57cec5SDimitry Andric                 result.push_back('d');
53180b57cec5SDimitry Andric                 break;
53190b57cec5SDimitry Andric             case 55:
53200b57cec5SDimitry Andric                 result.push_back('%');
53210b57cec5SDimitry Andric                 result.push_back('M');
53220b57cec5SDimitry Andric                 break;
53230b57cec5SDimitry Andric             case 59:
53240b57cec5SDimitry Andric                 result.push_back('%');
53250b57cec5SDimitry Andric                 result.push_back('S');
53260b57cec5SDimitry Andric                 break;
53270b57cec5SDimitry Andric             case 61:
53280b57cec5SDimitry Andric                 result.push_back('%');
53290b57cec5SDimitry Andric                 result.push_back('y');
53300b57cec5SDimitry Andric                 break;
53310b57cec5SDimitry Andric             case 364:
53320b57cec5SDimitry Andric                 result.push_back('%');
53330b57cec5SDimitry Andric                 result.push_back('j');
53340b57cec5SDimitry Andric                 break;
53350b57cec5SDimitry Andric             case 2061:
53360b57cec5SDimitry Andric                 result.push_back('%');
53370b57cec5SDimitry Andric                 result.push_back('Y');
53380b57cec5SDimitry Andric                 break;
53390b57cec5SDimitry Andric             default:
53400b57cec5SDimitry Andric                 for (; w != bb; ++w)
53410b57cec5SDimitry Andric                     result.push_back(*w);
53420b57cec5SDimitry Andric                 break;
53430b57cec5SDimitry Andric             }
53440b57cec5SDimitry Andric             continue;
53450b57cec5SDimitry Andric         }
53460b57cec5SDimitry Andric         if (*bb == '%')
53470b57cec5SDimitry Andric         {
53480b57cec5SDimitry Andric             result.push_back('%');
53490b57cec5SDimitry Andric             result.push_back('%');
53500b57cec5SDimitry Andric             ++bb;
53510b57cec5SDimitry Andric             continue;
53520b57cec5SDimitry Andric         }
53530b57cec5SDimitry Andric         result.push_back(*bb);
53540b57cec5SDimitry Andric         ++bb;
53550b57cec5SDimitry Andric     }
53560b57cec5SDimitry Andric     return result;
53570b57cec5SDimitry Andric }
53580b57cec5SDimitry Andric 
535981ad6265SDimitry Andric _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-braces")
53600b57cec5SDimitry Andric 
5361349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
53620b57cec5SDimitry Andric template <>
53630b57cec5SDimitry Andric wstring
53640b57cec5SDimitry Andric __time_get_storage<wchar_t>::__analyze(char fmt, const ctype<wchar_t>& ct)
53650b57cec5SDimitry Andric {
53660b57cec5SDimitry Andric     tm t = {0};
53670b57cec5SDimitry Andric     t.tm_sec = 59;
53680b57cec5SDimitry Andric     t.tm_min = 55;
53690b57cec5SDimitry Andric     t.tm_hour = 23;
53700b57cec5SDimitry Andric     t.tm_mday = 31;
53710b57cec5SDimitry Andric     t.tm_mon = 11;
53720b57cec5SDimitry Andric     t.tm_year = 161;
53730b57cec5SDimitry Andric     t.tm_wday = 6;
53740b57cec5SDimitry Andric     t.tm_yday = 364;
53750b57cec5SDimitry Andric     t.tm_isdst = -1;
53760b57cec5SDimitry Andric     char buf[100];
53770b57cec5SDimitry Andric     char f[3] = {0};
53780b57cec5SDimitry Andric     f[0] = '%';
53790b57cec5SDimitry Andric     f[1] = fmt;
53800b57cec5SDimitry Andric     strftime_l(buf, countof(buf), f, &t, __loc_);
53810b57cec5SDimitry Andric     wchar_t wbuf[100];
53820b57cec5SDimitry Andric     wchar_t* wbb = wbuf;
53830b57cec5SDimitry Andric     mbstate_t mb = {0};
53840b57cec5SDimitry Andric     const char* bb = buf;
53850b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l( wbb, &bb, countof(wbuf), &mb, __loc_);
53860b57cec5SDimitry Andric     if (j == size_t(-1))
53870b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
53880b57cec5SDimitry Andric     wchar_t* wbe = wbb + j;
53890b57cec5SDimitry Andric     wstring result;
53900b57cec5SDimitry Andric     while (wbb != wbe)
53910b57cec5SDimitry Andric     {
53920b57cec5SDimitry Andric         if (ct.is(ctype_base::space, *wbb))
53930b57cec5SDimitry Andric         {
53940b57cec5SDimitry Andric             result.push_back(L' ');
53950b57cec5SDimitry Andric             for (++wbb; wbb != wbe && ct.is(ctype_base::space, *wbb); ++wbb)
53960b57cec5SDimitry Andric                 ;
53970b57cec5SDimitry Andric             continue;
53980b57cec5SDimitry Andric         }
53990b57cec5SDimitry Andric         wchar_t* w = wbb;
54000b57cec5SDimitry Andric         ios_base::iostate err = ios_base::goodbit;
54010b57cec5SDimitry Andric         ptrdiff_t i = __scan_keyword(w, wbe, this->__weeks_, this->__weeks_+14,
54020b57cec5SDimitry Andric                                ct, err, false)
54030b57cec5SDimitry Andric                                - this->__weeks_;
54040b57cec5SDimitry Andric         if (i < 14)
54050b57cec5SDimitry Andric         {
54060b57cec5SDimitry Andric             result.push_back(L'%');
54070b57cec5SDimitry Andric             if (i < 7)
54080b57cec5SDimitry Andric                 result.push_back(L'A');
54090b57cec5SDimitry Andric             else
54100b57cec5SDimitry Andric                 result.push_back(L'a');
54110b57cec5SDimitry Andric             wbb = w;
54120b57cec5SDimitry Andric             continue;
54130b57cec5SDimitry Andric         }
54140b57cec5SDimitry Andric         w = wbb;
54150b57cec5SDimitry Andric         i = __scan_keyword(w, wbe, this->__months_, this->__months_+24,
54160b57cec5SDimitry Andric                            ct, err, false)
54170b57cec5SDimitry Andric                            - this->__months_;
54180b57cec5SDimitry Andric         if (i < 24)
54190b57cec5SDimitry Andric         {
54200b57cec5SDimitry Andric             result.push_back(L'%');
54210b57cec5SDimitry Andric             if (i < 12)
54220b57cec5SDimitry Andric                 result.push_back(L'B');
54230b57cec5SDimitry Andric             else
54240b57cec5SDimitry Andric                 result.push_back(L'b');
54250b57cec5SDimitry Andric             if (fmt == 'x' && ct.is(ctype_base::digit, this->__months_[i][0]))
54260b57cec5SDimitry Andric                 result.back() = L'm';
54270b57cec5SDimitry Andric             wbb = w;
54280b57cec5SDimitry Andric             continue;
54290b57cec5SDimitry Andric         }
54300b57cec5SDimitry Andric         if (this->__am_pm_[0].size() + this->__am_pm_[1].size() > 0)
54310b57cec5SDimitry Andric         {
54320b57cec5SDimitry Andric             w = wbb;
54330b57cec5SDimitry Andric             i = __scan_keyword(w, wbe, this->__am_pm_, this->__am_pm_+2,
54340b57cec5SDimitry Andric                                ct, err, false) - this->__am_pm_;
54350b57cec5SDimitry Andric             if (i < 2)
54360b57cec5SDimitry Andric             {
54370b57cec5SDimitry Andric                 result.push_back(L'%');
54380b57cec5SDimitry Andric                 result.push_back(L'p');
54390b57cec5SDimitry Andric                 wbb = w;
54400b57cec5SDimitry Andric                 continue;
54410b57cec5SDimitry Andric             }
54420b57cec5SDimitry Andric         }
54430b57cec5SDimitry Andric         w = wbb;
54440b57cec5SDimitry Andric         if (ct.is(ctype_base::digit, *wbb))
54450b57cec5SDimitry Andric         {
54460b57cec5SDimitry Andric             switch(__get_up_to_n_digits(wbb, wbe, err, ct, 4))
54470b57cec5SDimitry Andric             {
54480b57cec5SDimitry Andric             case 6:
54490b57cec5SDimitry Andric                 result.push_back(L'%');
54500b57cec5SDimitry Andric                 result.push_back(L'w');
54510b57cec5SDimitry Andric                 break;
54520b57cec5SDimitry Andric             case 7:
54530b57cec5SDimitry Andric                 result.push_back(L'%');
54540b57cec5SDimitry Andric                 result.push_back(L'u');
54550b57cec5SDimitry Andric                 break;
54560b57cec5SDimitry Andric             case 11:
54570b57cec5SDimitry Andric                 result.push_back(L'%');
54580b57cec5SDimitry Andric                 result.push_back(L'I');
54590b57cec5SDimitry Andric                 break;
54600b57cec5SDimitry Andric             case 12:
54610b57cec5SDimitry Andric                 result.push_back(L'%');
54620b57cec5SDimitry Andric                 result.push_back(L'm');
54630b57cec5SDimitry Andric                 break;
54640b57cec5SDimitry Andric             case 23:
54650b57cec5SDimitry Andric                 result.push_back(L'%');
54660b57cec5SDimitry Andric                 result.push_back(L'H');
54670b57cec5SDimitry Andric                 break;
54680b57cec5SDimitry Andric             case 31:
54690b57cec5SDimitry Andric                 result.push_back(L'%');
54700b57cec5SDimitry Andric                 result.push_back(L'd');
54710b57cec5SDimitry Andric                 break;
54720b57cec5SDimitry Andric             case 55:
54730b57cec5SDimitry Andric                 result.push_back(L'%');
54740b57cec5SDimitry Andric                 result.push_back(L'M');
54750b57cec5SDimitry Andric                 break;
54760b57cec5SDimitry Andric             case 59:
54770b57cec5SDimitry Andric                 result.push_back(L'%');
54780b57cec5SDimitry Andric                 result.push_back(L'S');
54790b57cec5SDimitry Andric                 break;
54800b57cec5SDimitry Andric             case 61:
54810b57cec5SDimitry Andric                 result.push_back(L'%');
54820b57cec5SDimitry Andric                 result.push_back(L'y');
54830b57cec5SDimitry Andric                 break;
54840b57cec5SDimitry Andric             case 364:
54850b57cec5SDimitry Andric                 result.push_back(L'%');
54860b57cec5SDimitry Andric                 result.push_back(L'j');
54870b57cec5SDimitry Andric                 break;
54880b57cec5SDimitry Andric             case 2061:
54890b57cec5SDimitry Andric                 result.push_back(L'%');
54900b57cec5SDimitry Andric                 result.push_back(L'Y');
54910b57cec5SDimitry Andric                 break;
54920b57cec5SDimitry Andric             default:
54930b57cec5SDimitry Andric                 for (; w != wbb; ++w)
54940b57cec5SDimitry Andric                     result.push_back(*w);
54950b57cec5SDimitry Andric                 break;
54960b57cec5SDimitry Andric             }
54970b57cec5SDimitry Andric             continue;
54980b57cec5SDimitry Andric         }
54990b57cec5SDimitry Andric         if (ct.narrow(*wbb, 0) == '%')
55000b57cec5SDimitry Andric         {
55010b57cec5SDimitry Andric             result.push_back(L'%');
55020b57cec5SDimitry Andric             result.push_back(L'%');
55030b57cec5SDimitry Andric             ++wbb;
55040b57cec5SDimitry Andric             continue;
55050b57cec5SDimitry Andric         }
55060b57cec5SDimitry Andric         result.push_back(*wbb);
55070b57cec5SDimitry Andric         ++wbb;
55080b57cec5SDimitry Andric     }
55090b57cec5SDimitry Andric     return result;
55100b57cec5SDimitry Andric }
5511349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
55120b57cec5SDimitry Andric 
55130b57cec5SDimitry Andric template <>
55140b57cec5SDimitry Andric void
55150b57cec5SDimitry Andric __time_get_storage<char>::init(const ctype<char>& ct)
55160b57cec5SDimitry Andric {
55170b57cec5SDimitry Andric     tm t = {0};
55180b57cec5SDimitry Andric     char buf[100];
55190b57cec5SDimitry Andric     // __weeks_
55200b57cec5SDimitry Andric     for (int i = 0; i < 7; ++i)
55210b57cec5SDimitry Andric     {
55220b57cec5SDimitry Andric         t.tm_wday = i;
55230b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%A", &t, __loc_);
55240b57cec5SDimitry Andric         __weeks_[i] = buf;
55250b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%a", &t, __loc_);
55260b57cec5SDimitry Andric         __weeks_[i+7] = buf;
55270b57cec5SDimitry Andric     }
55280b57cec5SDimitry Andric     // __months_
55290b57cec5SDimitry Andric     for (int i = 0; i < 12; ++i)
55300b57cec5SDimitry Andric     {
55310b57cec5SDimitry Andric         t.tm_mon = i;
55320b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%B", &t, __loc_);
55330b57cec5SDimitry Andric         __months_[i] = buf;
55340b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%b", &t, __loc_);
55350b57cec5SDimitry Andric         __months_[i+12] = buf;
55360b57cec5SDimitry Andric     }
55370b57cec5SDimitry Andric     // __am_pm_
55380b57cec5SDimitry Andric     t.tm_hour = 1;
55390b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%p", &t, __loc_);
55400b57cec5SDimitry Andric     __am_pm_[0] = buf;
55410b57cec5SDimitry Andric     t.tm_hour = 13;
55420b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%p", &t, __loc_);
55430b57cec5SDimitry Andric     __am_pm_[1] = buf;
55440b57cec5SDimitry Andric     __c_ = __analyze('c', ct);
55450b57cec5SDimitry Andric     __r_ = __analyze('r', ct);
55460b57cec5SDimitry Andric     __x_ = __analyze('x', ct);
55470b57cec5SDimitry Andric     __X_ = __analyze('X', ct);
55480b57cec5SDimitry Andric }
55490b57cec5SDimitry Andric 
5550349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
55510b57cec5SDimitry Andric template <>
55520b57cec5SDimitry Andric void
55530b57cec5SDimitry Andric __time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct)
55540b57cec5SDimitry Andric {
55550b57cec5SDimitry Andric     tm t = {0};
55560b57cec5SDimitry Andric     char buf[100];
55570b57cec5SDimitry Andric     wchar_t wbuf[100];
55580b57cec5SDimitry Andric     wchar_t* wbe;
55590b57cec5SDimitry Andric     mbstate_t mb = {0};
55600b57cec5SDimitry Andric     // __weeks_
55610b57cec5SDimitry Andric     for (int i = 0; i < 7; ++i)
55620b57cec5SDimitry Andric     {
55630b57cec5SDimitry Andric         t.tm_wday = i;
55640b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%A", &t, __loc_);
55650b57cec5SDimitry Andric         mb = mbstate_t();
55660b57cec5SDimitry Andric         const char* bb = buf;
55670b57cec5SDimitry Andric         size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5568e8d8bef9SDimitry Andric         if (j == size_t(-1) || j == 0)
55690b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
55700b57cec5SDimitry Andric         wbe = wbuf + j;
55710b57cec5SDimitry Andric         __weeks_[i].assign(wbuf, wbe);
55720b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%a", &t, __loc_);
55730b57cec5SDimitry Andric         mb = mbstate_t();
55740b57cec5SDimitry Andric         bb = buf;
55750b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5576e8d8bef9SDimitry Andric         if (j == size_t(-1) || j == 0)
55770b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
55780b57cec5SDimitry Andric         wbe = wbuf + j;
55790b57cec5SDimitry Andric         __weeks_[i+7].assign(wbuf, wbe);
55800b57cec5SDimitry Andric     }
55810b57cec5SDimitry Andric     // __months_
55820b57cec5SDimitry Andric     for (int i = 0; i < 12; ++i)
55830b57cec5SDimitry Andric     {
55840b57cec5SDimitry Andric         t.tm_mon = i;
55850b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%B", &t, __loc_);
55860b57cec5SDimitry Andric         mb = mbstate_t();
55870b57cec5SDimitry Andric         const char* bb = buf;
55880b57cec5SDimitry Andric         size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5589e8d8bef9SDimitry Andric         if (j == size_t(-1) || j == 0)
55900b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
55910b57cec5SDimitry Andric         wbe = wbuf + j;
55920b57cec5SDimitry Andric         __months_[i].assign(wbuf, wbe);
55930b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%b", &t, __loc_);
55940b57cec5SDimitry Andric         mb = mbstate_t();
55950b57cec5SDimitry Andric         bb = buf;
55960b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5597e8d8bef9SDimitry Andric         if (j == size_t(-1) || j == 0)
55980b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
55990b57cec5SDimitry Andric         wbe = wbuf + j;
56000b57cec5SDimitry Andric         __months_[i+12].assign(wbuf, wbe);
56010b57cec5SDimitry Andric     }
56020b57cec5SDimitry Andric     // __am_pm_
56030b57cec5SDimitry Andric     t.tm_hour = 1;
56040b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%p", &t, __loc_);
56050b57cec5SDimitry Andric     mb = mbstate_t();
56060b57cec5SDimitry Andric     const char* bb = buf;
56070b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
56080b57cec5SDimitry Andric     if (j == size_t(-1))
56090b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
56100b57cec5SDimitry Andric     wbe = wbuf + j;
56110b57cec5SDimitry Andric     __am_pm_[0].assign(wbuf, wbe);
56120b57cec5SDimitry Andric     t.tm_hour = 13;
56130b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%p", &t, __loc_);
56140b57cec5SDimitry Andric     mb = mbstate_t();
56150b57cec5SDimitry Andric     bb = buf;
56160b57cec5SDimitry Andric     j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
56170b57cec5SDimitry Andric     if (j == size_t(-1))
56180b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
56190b57cec5SDimitry Andric     wbe = wbuf + j;
56200b57cec5SDimitry Andric     __am_pm_[1].assign(wbuf, wbe);
56210b57cec5SDimitry Andric     __c_ = __analyze('c', ct);
56220b57cec5SDimitry Andric     __r_ = __analyze('r', ct);
56230b57cec5SDimitry Andric     __x_ = __analyze('x', ct);
56240b57cec5SDimitry Andric     __X_ = __analyze('X', ct);
56250b57cec5SDimitry Andric }
5626349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
56270b57cec5SDimitry Andric 
56280b57cec5SDimitry Andric template <class CharT>
56290b57cec5SDimitry Andric struct _LIBCPP_HIDDEN __time_get_temp
56300b57cec5SDimitry Andric     : public ctype_byname<CharT>
56310b57cec5SDimitry Andric {
56320b57cec5SDimitry Andric     explicit __time_get_temp(const char* nm)
56330b57cec5SDimitry Andric         : ctype_byname<CharT>(nm, 1) {}
56340b57cec5SDimitry Andric     explicit __time_get_temp(const string& nm)
56350b57cec5SDimitry Andric         : ctype_byname<CharT>(nm, 1) {}
56360b57cec5SDimitry Andric };
56370b57cec5SDimitry Andric 
56380b57cec5SDimitry Andric template <>
56390b57cec5SDimitry Andric __time_get_storage<char>::__time_get_storage(const char* __nm)
56400b57cec5SDimitry Andric     : __time_get(__nm)
56410b57cec5SDimitry Andric {
56420b57cec5SDimitry Andric     const __time_get_temp<char> ct(__nm);
56430b57cec5SDimitry Andric     init(ct);
56440b57cec5SDimitry Andric }
56450b57cec5SDimitry Andric 
56460b57cec5SDimitry Andric template <>
56470b57cec5SDimitry Andric __time_get_storage<char>::__time_get_storage(const string& __nm)
56480b57cec5SDimitry Andric     : __time_get(__nm)
56490b57cec5SDimitry Andric {
56500b57cec5SDimitry Andric     const __time_get_temp<char> ct(__nm);
56510b57cec5SDimitry Andric     init(ct);
56520b57cec5SDimitry Andric }
56530b57cec5SDimitry Andric 
5654349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
56550b57cec5SDimitry Andric template <>
56560b57cec5SDimitry Andric __time_get_storage<wchar_t>::__time_get_storage(const char* __nm)
56570b57cec5SDimitry Andric     : __time_get(__nm)
56580b57cec5SDimitry Andric {
56590b57cec5SDimitry Andric     const __time_get_temp<wchar_t> ct(__nm);
56600b57cec5SDimitry Andric     init(ct);
56610b57cec5SDimitry Andric }
56620b57cec5SDimitry Andric 
56630b57cec5SDimitry Andric template <>
56640b57cec5SDimitry Andric __time_get_storage<wchar_t>::__time_get_storage(const string& __nm)
56650b57cec5SDimitry Andric     : __time_get(__nm)
56660b57cec5SDimitry Andric {
56670b57cec5SDimitry Andric     const __time_get_temp<wchar_t> ct(__nm);
56680b57cec5SDimitry Andric     init(ct);
56690b57cec5SDimitry Andric }
5670349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
56710b57cec5SDimitry Andric 
56720b57cec5SDimitry Andric template <>
56730b57cec5SDimitry Andric time_base::dateorder
56740b57cec5SDimitry Andric __time_get_storage<char>::__do_date_order() const
56750b57cec5SDimitry Andric {
56760b57cec5SDimitry Andric     unsigned i;
56770b57cec5SDimitry Andric     for (i = 0; i < __x_.size(); ++i)
56780b57cec5SDimitry Andric         if (__x_[i] == '%')
56790b57cec5SDimitry Andric             break;
56800b57cec5SDimitry Andric     ++i;
56810b57cec5SDimitry Andric     switch (__x_[i])
56820b57cec5SDimitry Andric     {
56830b57cec5SDimitry Andric     case 'y':
56840b57cec5SDimitry Andric     case 'Y':
56850b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
56860b57cec5SDimitry Andric             if (__x_[i] == '%')
56870b57cec5SDimitry Andric                 break;
56880b57cec5SDimitry Andric         if (i == __x_.size())
56890b57cec5SDimitry Andric             break;
56900b57cec5SDimitry Andric         ++i;
56910b57cec5SDimitry Andric         switch (__x_[i])
56920b57cec5SDimitry Andric         {
56930b57cec5SDimitry Andric         case 'm':
56940b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
56950b57cec5SDimitry Andric                 if (__x_[i] == '%')
56960b57cec5SDimitry Andric                     break;
56970b57cec5SDimitry Andric             if (i == __x_.size())
56980b57cec5SDimitry Andric                 break;
56990b57cec5SDimitry Andric             ++i;
57000b57cec5SDimitry Andric             if (__x_[i] == 'd')
57010b57cec5SDimitry Andric                 return time_base::ymd;
57020b57cec5SDimitry Andric             break;
57030b57cec5SDimitry Andric         case 'd':
57040b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57050b57cec5SDimitry Andric                 if (__x_[i] == '%')
57060b57cec5SDimitry Andric                     break;
57070b57cec5SDimitry Andric             if (i == __x_.size())
57080b57cec5SDimitry Andric                 break;
57090b57cec5SDimitry Andric             ++i;
57100b57cec5SDimitry Andric             if (__x_[i] == 'm')
57110b57cec5SDimitry Andric                 return time_base::ydm;
57120b57cec5SDimitry Andric             break;
57130b57cec5SDimitry Andric         }
57140b57cec5SDimitry Andric         break;
57150b57cec5SDimitry Andric     case 'm':
57160b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
57170b57cec5SDimitry Andric             if (__x_[i] == '%')
57180b57cec5SDimitry Andric                 break;
57190b57cec5SDimitry Andric         if (i == __x_.size())
57200b57cec5SDimitry Andric             break;
57210b57cec5SDimitry Andric         ++i;
57220b57cec5SDimitry Andric         if (__x_[i] == 'd')
57230b57cec5SDimitry Andric         {
57240b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57250b57cec5SDimitry Andric                 if (__x_[i] == '%')
57260b57cec5SDimitry Andric                     break;
57270b57cec5SDimitry Andric             if (i == __x_.size())
57280b57cec5SDimitry Andric                 break;
57290b57cec5SDimitry Andric             ++i;
57300b57cec5SDimitry Andric             if (__x_[i] == 'y' || __x_[i] == 'Y')
57310b57cec5SDimitry Andric                 return time_base::mdy;
57320b57cec5SDimitry Andric             break;
57330b57cec5SDimitry Andric         }
57340b57cec5SDimitry Andric         break;
57350b57cec5SDimitry Andric     case 'd':
57360b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
57370b57cec5SDimitry Andric             if (__x_[i] == '%')
57380b57cec5SDimitry Andric                 break;
57390b57cec5SDimitry Andric         if (i == __x_.size())
57400b57cec5SDimitry Andric             break;
57410b57cec5SDimitry Andric         ++i;
57420b57cec5SDimitry Andric         if (__x_[i] == 'm')
57430b57cec5SDimitry Andric         {
57440b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57450b57cec5SDimitry Andric                 if (__x_[i] == '%')
57460b57cec5SDimitry Andric                     break;
57470b57cec5SDimitry Andric             if (i == __x_.size())
57480b57cec5SDimitry Andric                 break;
57490b57cec5SDimitry Andric             ++i;
57500b57cec5SDimitry Andric             if (__x_[i] == 'y' || __x_[i] == 'Y')
57510b57cec5SDimitry Andric                 return time_base::dmy;
57520b57cec5SDimitry Andric             break;
57530b57cec5SDimitry Andric         }
57540b57cec5SDimitry Andric         break;
57550b57cec5SDimitry Andric     }
57560b57cec5SDimitry Andric     return time_base::no_order;
57570b57cec5SDimitry Andric }
57580b57cec5SDimitry Andric 
5759349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
57600b57cec5SDimitry Andric template <>
57610b57cec5SDimitry Andric time_base::dateorder
57620b57cec5SDimitry Andric __time_get_storage<wchar_t>::__do_date_order() const
57630b57cec5SDimitry Andric {
57640b57cec5SDimitry Andric     unsigned i;
57650b57cec5SDimitry Andric     for (i = 0; i < __x_.size(); ++i)
57660b57cec5SDimitry Andric         if (__x_[i] == L'%')
57670b57cec5SDimitry Andric             break;
57680b57cec5SDimitry Andric     ++i;
57690b57cec5SDimitry Andric     switch (__x_[i])
57700b57cec5SDimitry Andric     {
57710b57cec5SDimitry Andric     case L'y':
57720b57cec5SDimitry Andric     case L'Y':
57730b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
57740b57cec5SDimitry Andric             if (__x_[i] == L'%')
57750b57cec5SDimitry Andric                 break;
57760b57cec5SDimitry Andric         if (i == __x_.size())
57770b57cec5SDimitry Andric             break;
57780b57cec5SDimitry Andric         ++i;
57790b57cec5SDimitry Andric         switch (__x_[i])
57800b57cec5SDimitry Andric         {
57810b57cec5SDimitry Andric         case L'm':
57820b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57830b57cec5SDimitry Andric                 if (__x_[i] == L'%')
57840b57cec5SDimitry Andric                     break;
57850b57cec5SDimitry Andric             if (i == __x_.size())
57860b57cec5SDimitry Andric                 break;
57870b57cec5SDimitry Andric             ++i;
57880b57cec5SDimitry Andric             if (__x_[i] == L'd')
57890b57cec5SDimitry Andric                 return time_base::ymd;
57900b57cec5SDimitry Andric             break;
57910b57cec5SDimitry Andric         case L'd':
57920b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57930b57cec5SDimitry Andric                 if (__x_[i] == L'%')
57940b57cec5SDimitry Andric                     break;
57950b57cec5SDimitry Andric             if (i == __x_.size())
57960b57cec5SDimitry Andric                 break;
57970b57cec5SDimitry Andric             ++i;
57980b57cec5SDimitry Andric             if (__x_[i] == L'm')
57990b57cec5SDimitry Andric                 return time_base::ydm;
58000b57cec5SDimitry Andric             break;
58010b57cec5SDimitry Andric         }
58020b57cec5SDimitry Andric         break;
58030b57cec5SDimitry Andric     case L'm':
58040b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
58050b57cec5SDimitry Andric             if (__x_[i] == L'%')
58060b57cec5SDimitry Andric                 break;
58070b57cec5SDimitry Andric         if (i == __x_.size())
58080b57cec5SDimitry Andric             break;
58090b57cec5SDimitry Andric         ++i;
58100b57cec5SDimitry Andric         if (__x_[i] == L'd')
58110b57cec5SDimitry Andric         {
58120b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
58130b57cec5SDimitry Andric                 if (__x_[i] == L'%')
58140b57cec5SDimitry Andric                     break;
58150b57cec5SDimitry Andric             if (i == __x_.size())
58160b57cec5SDimitry Andric                 break;
58170b57cec5SDimitry Andric             ++i;
58180b57cec5SDimitry Andric             if (__x_[i] == L'y' || __x_[i] == L'Y')
58190b57cec5SDimitry Andric                 return time_base::mdy;
58200b57cec5SDimitry Andric             break;
58210b57cec5SDimitry Andric         }
58220b57cec5SDimitry Andric         break;
58230b57cec5SDimitry Andric     case L'd':
58240b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
58250b57cec5SDimitry Andric             if (__x_[i] == L'%')
58260b57cec5SDimitry Andric                 break;
58270b57cec5SDimitry Andric         if (i == __x_.size())
58280b57cec5SDimitry Andric             break;
58290b57cec5SDimitry Andric         ++i;
58300b57cec5SDimitry Andric         if (__x_[i] == L'm')
58310b57cec5SDimitry Andric         {
58320b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
58330b57cec5SDimitry Andric                 if (__x_[i] == L'%')
58340b57cec5SDimitry Andric                     break;
58350b57cec5SDimitry Andric             if (i == __x_.size())
58360b57cec5SDimitry Andric                 break;
58370b57cec5SDimitry Andric             ++i;
58380b57cec5SDimitry Andric             if (__x_[i] == L'y' || __x_[i] == L'Y')
58390b57cec5SDimitry Andric                 return time_base::dmy;
58400b57cec5SDimitry Andric             break;
58410b57cec5SDimitry Andric         }
58420b57cec5SDimitry Andric         break;
58430b57cec5SDimitry Andric     }
58440b57cec5SDimitry Andric     return time_base::no_order;
58450b57cec5SDimitry Andric }
5846349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
58470b57cec5SDimitry Andric 
58480b57cec5SDimitry Andric // time_put
58490b57cec5SDimitry Andric 
58500b57cec5SDimitry Andric __time_put::__time_put(const char* nm)
58510b57cec5SDimitry Andric     : __loc_(newlocale(LC_ALL_MASK, nm, 0))
58520b57cec5SDimitry Andric {
58530b57cec5SDimitry Andric     if (__loc_ == 0)
58540b57cec5SDimitry Andric         __throw_runtime_error("time_put_byname"
58550b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
58560b57cec5SDimitry Andric }
58570b57cec5SDimitry Andric 
58580b57cec5SDimitry Andric __time_put::__time_put(const string& nm)
58590b57cec5SDimitry Andric     : __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0))
58600b57cec5SDimitry Andric {
58610b57cec5SDimitry Andric     if (__loc_ == 0)
58620b57cec5SDimitry Andric         __throw_runtime_error("time_put_byname"
58630b57cec5SDimitry Andric                             " failed to construct for " + nm);
58640b57cec5SDimitry Andric }
58650b57cec5SDimitry Andric 
58660b57cec5SDimitry Andric __time_put::~__time_put()
58670b57cec5SDimitry Andric {
58680b57cec5SDimitry Andric     if (__loc_ != _LIBCPP_GET_C_LOCALE)
58690b57cec5SDimitry Andric         freelocale(__loc_);
58700b57cec5SDimitry Andric }
58710b57cec5SDimitry Andric 
58720b57cec5SDimitry Andric void
58730b57cec5SDimitry Andric __time_put::__do_put(char* __nb, char*& __ne, const tm* __tm,
58740b57cec5SDimitry Andric                      char __fmt, char __mod) const
58750b57cec5SDimitry Andric {
58760b57cec5SDimitry Andric     char fmt[] = {'%', __fmt, __mod, 0};
58770b57cec5SDimitry Andric     if (__mod != 0)
58780b57cec5SDimitry Andric         swap(fmt[1], fmt[2]);
58790b57cec5SDimitry Andric     size_t n = strftime_l(__nb, countof(__nb, __ne), fmt, __tm, __loc_);
58800b57cec5SDimitry Andric     __ne = __nb + n;
58810b57cec5SDimitry Andric }
58820b57cec5SDimitry Andric 
5883349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
58840b57cec5SDimitry Andric void
58850b57cec5SDimitry Andric __time_put::__do_put(wchar_t* __wb, wchar_t*& __we, const tm* __tm,
58860b57cec5SDimitry Andric                      char __fmt, char __mod) const
58870b57cec5SDimitry Andric {
58880b57cec5SDimitry Andric     char __nar[100];
58890b57cec5SDimitry Andric     char* __ne = __nar + 100;
58900b57cec5SDimitry Andric     __do_put(__nar, __ne, __tm, __fmt, __mod);
58910b57cec5SDimitry Andric     mbstate_t mb = {0};
58920b57cec5SDimitry Andric     const char* __nb = __nar;
58930b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l(__wb, &__nb, countof(__wb, __we), &mb, __loc_);
58940b57cec5SDimitry Andric     if (j == size_t(-1))
58950b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
58960b57cec5SDimitry Andric     __we = __wb + j;
58970b57cec5SDimitry Andric }
5898349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
58990b57cec5SDimitry Andric 
59000b57cec5SDimitry Andric // moneypunct_byname
59010b57cec5SDimitry Andric 
59020b57cec5SDimitry Andric template <class charT>
59030b57cec5SDimitry Andric static
59040b57cec5SDimitry Andric void
59050b57cec5SDimitry Andric __init_pat(money_base::pattern& pat, basic_string<charT>& __curr_symbol_,
59060b57cec5SDimitry Andric            bool intl, char cs_precedes, char sep_by_space, char sign_posn,
59070b57cec5SDimitry Andric            charT space_char)
59080b57cec5SDimitry Andric {
59090b57cec5SDimitry Andric     const char sign = static_cast<char>(money_base::sign);
59100b57cec5SDimitry Andric     const char space = static_cast<char>(money_base::space);
59110b57cec5SDimitry Andric     const char none = static_cast<char>(money_base::none);
59120b57cec5SDimitry Andric     const char symbol = static_cast<char>(money_base::symbol);
59130b57cec5SDimitry Andric     const char value = static_cast<char>(money_base::value);
59140b57cec5SDimitry Andric     const bool symbol_contains_sep = intl && __curr_symbol_.size() == 4;
59150b57cec5SDimitry Andric 
59160b57cec5SDimitry Andric     // Comments on case branches reflect 'C11 7.11.2.1 The localeconv
59170b57cec5SDimitry Andric     // function'. "Space between sign and symbol or value" means that
59180b57cec5SDimitry Andric     // if the sign is adjacent to the symbol, there's a space between
59190b57cec5SDimitry Andric     // them, and otherwise there's a space between the sign and value.
59200b57cec5SDimitry Andric     //
59210b57cec5SDimitry Andric     // C11's localeconv specifies that the fourth character of an
59220b57cec5SDimitry Andric     // international curr_symbol is used to separate the sign and
59230b57cec5SDimitry Andric     // value when sep_by_space says to do so. C++ can't represent
59240b57cec5SDimitry Andric     // that, so we just use a space.  When sep_by_space says to
59250b57cec5SDimitry Andric     // separate the symbol and value-or-sign with a space, we rearrange the
59260b57cec5SDimitry Andric     // curr_symbol to put its spacing character on the correct side of
59270b57cec5SDimitry Andric     // the symbol.
59280b57cec5SDimitry Andric     //
59290b57cec5SDimitry Andric     // We also need to avoid adding an extra space between the sign
59300b57cec5SDimitry Andric     // and value when the currency symbol is suppressed (by not
59310b57cec5SDimitry Andric     // setting showbase).  We match glibc's strfmon by interpreting
59320b57cec5SDimitry Andric     // sep_by_space==1 as "omit the space when the currency symbol is
59330b57cec5SDimitry Andric     // absent".
59340b57cec5SDimitry Andric     //
59350b57cec5SDimitry Andric     // Users who want to get this right should use ICU instead.
59360b57cec5SDimitry Andric 
59370b57cec5SDimitry Andric     switch (cs_precedes)
59380b57cec5SDimitry Andric     {
59390b57cec5SDimitry Andric     case 0:  // value before curr_symbol
59400b57cec5SDimitry Andric         if (symbol_contains_sep) {
59410b57cec5SDimitry Andric             // Move the separator to before the symbol, to place it
59420b57cec5SDimitry Andric             // between the value and symbol.
59430b57cec5SDimitry Andric             rotate(__curr_symbol_.begin(), __curr_symbol_.begin() + 3,
59440b57cec5SDimitry Andric                    __curr_symbol_.end());
59450b57cec5SDimitry Andric         }
59460b57cec5SDimitry Andric         switch (sign_posn)
59470b57cec5SDimitry Andric         {
59480b57cec5SDimitry Andric         case 0:  // Parentheses surround the quantity and currency symbol.
59490b57cec5SDimitry Andric             pat.field[0] = sign;
59500b57cec5SDimitry Andric             pat.field[1] = value;
59510b57cec5SDimitry Andric             pat.field[2] = none;  // Any space appears in the symbol.
59520b57cec5SDimitry Andric             pat.field[3] = symbol;
59530b57cec5SDimitry Andric             switch (sep_by_space)
59540b57cec5SDimitry Andric             {
59550b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
59560b57cec5SDimitry Andric                 // This case may have changed between C99 and C11;
59570b57cec5SDimitry Andric                 // assume the currency symbol matches the intention.
59580b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
59590b57cec5SDimitry Andric                 // The "sign" is two parentheses, so no space here either.
59600b57cec5SDimitry Andric                 return;
59610b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
59620b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
59630b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
59640b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
59650b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
59660b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
59670b57cec5SDimitry Andric                 }
59680b57cec5SDimitry Andric                 return;
59690b57cec5SDimitry Andric             default:
59700b57cec5SDimitry Andric                 break;
59710b57cec5SDimitry Andric             }
59720b57cec5SDimitry Andric             break;
59730b57cec5SDimitry Andric         case 1:  // The sign string precedes the quantity and currency symbol.
59740b57cec5SDimitry Andric             pat.field[0] = sign;
59750b57cec5SDimitry Andric             pat.field[3] = symbol;
59760b57cec5SDimitry Andric             switch (sep_by_space)
59770b57cec5SDimitry Andric             {
59780b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
59790b57cec5SDimitry Andric                 pat.field[1] = value;
59800b57cec5SDimitry Andric                 pat.field[2] = none;
59810b57cec5SDimitry Andric                 return;
59820b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
59830b57cec5SDimitry Andric                 pat.field[1] = value;
59840b57cec5SDimitry Andric                 pat.field[2] = none;
59850b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
59860b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
59870b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
59880b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
59890b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
59900b57cec5SDimitry Andric                 }
59910b57cec5SDimitry Andric                 return;
59920b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
59930b57cec5SDimitry Andric                 pat.field[1] = space;
59940b57cec5SDimitry Andric                 pat.field[2] = value;
59950b57cec5SDimitry Andric                 if (symbol_contains_sep) {
59960b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
59970b57cec5SDimitry Andric                     // has already appeared after the sign.
59980b57cec5SDimitry Andric                     __curr_symbol_.erase(__curr_symbol_.begin());
59990b57cec5SDimitry Andric                 }
60000b57cec5SDimitry Andric                 return;
60010b57cec5SDimitry Andric             default:
60020b57cec5SDimitry Andric                 break;
60030b57cec5SDimitry Andric             }
60040b57cec5SDimitry Andric             break;
60050b57cec5SDimitry Andric         case 2:  // The sign string succeeds the quantity and currency symbol.
60060b57cec5SDimitry Andric             pat.field[0] = value;
60070b57cec5SDimitry Andric             pat.field[3] = sign;
60080b57cec5SDimitry Andric             switch (sep_by_space)
60090b57cec5SDimitry Andric             {
60100b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
60110b57cec5SDimitry Andric                 pat.field[1] = none;
60120b57cec5SDimitry Andric                 pat.field[2] = symbol;
60130b57cec5SDimitry Andric                 return;
60140b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
60150b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
60160b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
60170b57cec5SDimitry Andric                     // setting pat.field[1]=space so that when
60180b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
60190b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
60200b57cec5SDimitry Andric                 }
60210b57cec5SDimitry Andric                 pat.field[1] = none;
60220b57cec5SDimitry Andric                 pat.field[2] = symbol;
60230b57cec5SDimitry Andric                 return;
60240b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
60250b57cec5SDimitry Andric                 pat.field[1] = symbol;
60260b57cec5SDimitry Andric                 pat.field[2] = space;
60270b57cec5SDimitry Andric                 if (symbol_contains_sep) {
60280b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
60290b57cec5SDimitry Andric                     // should not be removed if showbase is absent.
60300b57cec5SDimitry Andric                     __curr_symbol_.erase(__curr_symbol_.begin());
60310b57cec5SDimitry Andric                 }
60320b57cec5SDimitry Andric                 return;
60330b57cec5SDimitry Andric             default:
60340b57cec5SDimitry Andric                 break;
60350b57cec5SDimitry Andric             }
60360b57cec5SDimitry Andric             break;
60370b57cec5SDimitry Andric         case 3:  // The sign string immediately precedes the currency symbol.
60380b57cec5SDimitry Andric             pat.field[0] = value;
60390b57cec5SDimitry Andric             pat.field[3] = symbol;
60400b57cec5SDimitry Andric             switch (sep_by_space)
60410b57cec5SDimitry Andric             {
60420b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
60430b57cec5SDimitry Andric                 pat.field[1] = none;
60440b57cec5SDimitry Andric                 pat.field[2] = sign;
60450b57cec5SDimitry Andric                 return;
60460b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
60470b57cec5SDimitry Andric                 pat.field[1] = space;
60480b57cec5SDimitry Andric                 pat.field[2] = sign;
60490b57cec5SDimitry Andric                 if (symbol_contains_sep) {
60500b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
60510b57cec5SDimitry Andric                     // has already appeared before the sign.
60520b57cec5SDimitry Andric                     __curr_symbol_.erase(__curr_symbol_.begin());
60530b57cec5SDimitry Andric                 }
60540b57cec5SDimitry Andric                 return;
60550b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
60560b57cec5SDimitry Andric                 pat.field[1] = sign;
60570b57cec5SDimitry Andric                 pat.field[2] = none;
60580b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
60590b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
60600b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
60610b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
60620b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
60630b57cec5SDimitry Andric                 }
60640b57cec5SDimitry Andric                 return;
60650b57cec5SDimitry Andric             default:
60660b57cec5SDimitry Andric                 break;
60670b57cec5SDimitry Andric             }
60680b57cec5SDimitry Andric             break;
60690b57cec5SDimitry Andric         case 4:  // The sign string immediately succeeds the currency symbol.
60700b57cec5SDimitry Andric             pat.field[0] = value;
60710b57cec5SDimitry Andric             pat.field[3] = sign;
60720b57cec5SDimitry Andric             switch (sep_by_space)
60730b57cec5SDimitry Andric             {
60740b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
60750b57cec5SDimitry Andric                 pat.field[1] = none;
60760b57cec5SDimitry Andric                 pat.field[2] = symbol;
60770b57cec5SDimitry Andric                 return;
60780b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
60790b57cec5SDimitry Andric                 pat.field[1] = none;
60800b57cec5SDimitry Andric                 pat.field[2] = symbol;
60810b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
60820b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
60830b57cec5SDimitry Andric                     // setting pat.field[1]=space so that when
60840b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
60850b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
60860b57cec5SDimitry Andric                 }
60870b57cec5SDimitry Andric                 return;
60880b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
60890b57cec5SDimitry Andric                 pat.field[1] = symbol;
60900b57cec5SDimitry Andric                 pat.field[2] = space;
60910b57cec5SDimitry Andric                 if (symbol_contains_sep) {
60920b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
60930b57cec5SDimitry Andric                     // should not disappear when showbase is absent.
60940b57cec5SDimitry Andric                     __curr_symbol_.erase(__curr_symbol_.begin());
60950b57cec5SDimitry Andric                 }
60960b57cec5SDimitry Andric                 return;
60970b57cec5SDimitry Andric             default:
60980b57cec5SDimitry Andric                 break;
60990b57cec5SDimitry Andric             }
61000b57cec5SDimitry Andric             break;
61010b57cec5SDimitry Andric         default:
61020b57cec5SDimitry Andric             break;
61030b57cec5SDimitry Andric         }
61040b57cec5SDimitry Andric         break;
61050b57cec5SDimitry Andric     case 1:  // curr_symbol before value
61060b57cec5SDimitry Andric         switch (sign_posn)
61070b57cec5SDimitry Andric         {
61080b57cec5SDimitry Andric         case 0:  // Parentheses surround the quantity and currency symbol.
61090b57cec5SDimitry Andric             pat.field[0] = sign;
61100b57cec5SDimitry Andric             pat.field[1] = symbol;
61110b57cec5SDimitry Andric             pat.field[2] = none;  // Any space appears in the symbol.
61120b57cec5SDimitry Andric             pat.field[3] = value;
61130b57cec5SDimitry Andric             switch (sep_by_space)
61140b57cec5SDimitry Andric             {
61150b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
61160b57cec5SDimitry Andric                 // This case may have changed between C99 and C11;
61170b57cec5SDimitry Andric                 // assume the currency symbol matches the intention.
61180b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
61190b57cec5SDimitry Andric                 // The "sign" is two parentheses, so no space here either.
61200b57cec5SDimitry Andric                 return;
61210b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
61220b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
61230b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
61240b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
61250b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
61260b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
61270b57cec5SDimitry Andric                 }
61280b57cec5SDimitry Andric                 return;
61290b57cec5SDimitry Andric             default:
61300b57cec5SDimitry Andric                 break;
61310b57cec5SDimitry Andric             }
61320b57cec5SDimitry Andric             break;
61330b57cec5SDimitry Andric         case 1:  // The sign string precedes the quantity and currency symbol.
61340b57cec5SDimitry Andric             pat.field[0] = sign;
61350b57cec5SDimitry Andric             pat.field[3] = value;
61360b57cec5SDimitry Andric             switch (sep_by_space)
61370b57cec5SDimitry Andric             {
61380b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
61390b57cec5SDimitry Andric                 pat.field[1] = symbol;
61400b57cec5SDimitry Andric                 pat.field[2] = none;
61410b57cec5SDimitry Andric                 return;
61420b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
61430b57cec5SDimitry Andric                 pat.field[1] = symbol;
61440b57cec5SDimitry Andric                 pat.field[2] = none;
61450b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
61460b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
61470b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
61480b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
61490b57cec5SDimitry Andric                     __curr_symbol_.push_back(space_char);
61500b57cec5SDimitry Andric                 }
61510b57cec5SDimitry Andric                 return;
61520b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
61530b57cec5SDimitry Andric                 pat.field[1] = space;
61540b57cec5SDimitry Andric                 pat.field[2] = symbol;
61550b57cec5SDimitry Andric                 if (symbol_contains_sep) {
61560b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
61570b57cec5SDimitry Andric                     // has already appeared after the sign.
61580b57cec5SDimitry Andric                     __curr_symbol_.pop_back();
61590b57cec5SDimitry Andric                 }
61600b57cec5SDimitry Andric                 return;
61610b57cec5SDimitry Andric             default:
61620b57cec5SDimitry Andric                 break;
61630b57cec5SDimitry Andric             }
61640b57cec5SDimitry Andric             break;
61650b57cec5SDimitry Andric         case 2:  // The sign string succeeds the quantity and currency symbol.
61660b57cec5SDimitry Andric             pat.field[0] = symbol;
61670b57cec5SDimitry Andric             pat.field[3] = sign;
61680b57cec5SDimitry Andric             switch (sep_by_space)
61690b57cec5SDimitry Andric             {
61700b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
61710b57cec5SDimitry Andric                 pat.field[1] = none;
61720b57cec5SDimitry Andric                 pat.field[2] = value;
61730b57cec5SDimitry Andric                 return;
61740b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
61750b57cec5SDimitry Andric                 pat.field[1] = none;
61760b57cec5SDimitry Andric                 pat.field[2] = value;
61770b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
61780b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
61790b57cec5SDimitry Andric                     // setting pat.field[1]=space so that when
61800b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
61810b57cec5SDimitry Andric                     __curr_symbol_.push_back(space_char);
61820b57cec5SDimitry Andric                 }
61830b57cec5SDimitry Andric                 return;
61840b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
61850b57cec5SDimitry Andric                 pat.field[1] = value;
61860b57cec5SDimitry Andric                 pat.field[2] = space;
61870b57cec5SDimitry Andric                 if (symbol_contains_sep) {
61880b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
61890b57cec5SDimitry Andric                     // will appear before the sign.
61900b57cec5SDimitry Andric                     __curr_symbol_.pop_back();
61910b57cec5SDimitry Andric                 }
61920b57cec5SDimitry Andric                 return;
61930b57cec5SDimitry Andric             default:
61940b57cec5SDimitry Andric                 break;
61950b57cec5SDimitry Andric             }
61960b57cec5SDimitry Andric             break;
61970b57cec5SDimitry Andric         case 3:  // The sign string immediately precedes the currency symbol.
61980b57cec5SDimitry Andric             pat.field[0] = sign;
61990b57cec5SDimitry Andric             pat.field[3] = value;
62000b57cec5SDimitry Andric             switch (sep_by_space)
62010b57cec5SDimitry Andric             {
62020b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
62030b57cec5SDimitry Andric                 pat.field[1] = symbol;
62040b57cec5SDimitry Andric                 pat.field[2] = none;
62050b57cec5SDimitry Andric                 return;
62060b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
62070b57cec5SDimitry Andric                 pat.field[1] = symbol;
62080b57cec5SDimitry Andric                 pat.field[2] = none;
62090b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
62100b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
62110b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
62120b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
62130b57cec5SDimitry Andric                     __curr_symbol_.push_back(space_char);
62140b57cec5SDimitry Andric                 }
62150b57cec5SDimitry Andric                 return;
62160b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
62170b57cec5SDimitry Andric                 pat.field[1] = space;
62180b57cec5SDimitry Andric                 pat.field[2] = symbol;
62190b57cec5SDimitry Andric                 if (symbol_contains_sep) {
62200b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
62210b57cec5SDimitry Andric                     // has already appeared after the sign.
62220b57cec5SDimitry Andric                     __curr_symbol_.pop_back();
62230b57cec5SDimitry Andric                 }
62240b57cec5SDimitry Andric                 return;
62250b57cec5SDimitry Andric             default:
62260b57cec5SDimitry Andric                 break;
62270b57cec5SDimitry Andric             }
62280b57cec5SDimitry Andric             break;
62290b57cec5SDimitry Andric         case 4:  // The sign string immediately succeeds the currency symbol.
62300b57cec5SDimitry Andric             pat.field[0] = symbol;
62310b57cec5SDimitry Andric             pat.field[3] = value;
62320b57cec5SDimitry Andric             switch (sep_by_space)
62330b57cec5SDimitry Andric             {
62340b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
62350b57cec5SDimitry Andric                 pat.field[1] = sign;
62360b57cec5SDimitry Andric                 pat.field[2] = none;
62370b57cec5SDimitry Andric                 return;
62380b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
62390b57cec5SDimitry Andric                 pat.field[1] = sign;
62400b57cec5SDimitry Andric                 pat.field[2] = space;
62410b57cec5SDimitry Andric                 if (symbol_contains_sep) {
62420b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
62430b57cec5SDimitry Andric                     // should not disappear when showbase is absent.
62440b57cec5SDimitry Andric                     __curr_symbol_.pop_back();
62450b57cec5SDimitry Andric                 }
62460b57cec5SDimitry Andric                 return;
62470b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
62480b57cec5SDimitry Andric                 pat.field[1] = none;
62490b57cec5SDimitry Andric                 pat.field[2] = sign;
62500b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
62510b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
62520b57cec5SDimitry Andric                     // setting pat.field[1]=space so that when
62530b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
62540b57cec5SDimitry Andric                     __curr_symbol_.push_back(space_char);
62550b57cec5SDimitry Andric                 }
62560b57cec5SDimitry Andric                 return;
62570b57cec5SDimitry Andric            default:
62580b57cec5SDimitry Andric                 break;
62590b57cec5SDimitry Andric             }
62600b57cec5SDimitry Andric             break;
62610b57cec5SDimitry Andric         default:
62620b57cec5SDimitry Andric             break;
62630b57cec5SDimitry Andric         }
62640b57cec5SDimitry Andric         break;
62650b57cec5SDimitry Andric     default:
62660b57cec5SDimitry Andric         break;
62670b57cec5SDimitry Andric     }
62680b57cec5SDimitry Andric     pat.field[0] = symbol;
62690b57cec5SDimitry Andric     pat.field[1] = sign;
62700b57cec5SDimitry Andric     pat.field[2] = none;
62710b57cec5SDimitry Andric     pat.field[3] = value;
62720b57cec5SDimitry Andric }
62730b57cec5SDimitry Andric 
62740b57cec5SDimitry Andric template<>
62750b57cec5SDimitry Andric void
62760b57cec5SDimitry Andric moneypunct_byname<char, false>::init(const char* nm)
62770b57cec5SDimitry Andric {
62780b57cec5SDimitry Andric     typedef moneypunct<char, false> base;
62790b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
62800b57cec5SDimitry Andric     if (!loc)
62810b57cec5SDimitry Andric         __throw_runtime_error("moneypunct_byname"
62820b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
62830b57cec5SDimitry Andric 
62840b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
62850b57cec5SDimitry Andric     if (!checked_string_to_char_convert(__decimal_point_,
62860b57cec5SDimitry Andric                                         lc->mon_decimal_point,
62870b57cec5SDimitry Andric                                         loc.get()))
62880b57cec5SDimitry Andric       __decimal_point_ = base::do_decimal_point();
62890b57cec5SDimitry Andric     if (!checked_string_to_char_convert(__thousands_sep_,
62900b57cec5SDimitry Andric                                         lc->mon_thousands_sep,
62910b57cec5SDimitry Andric                                         loc.get()))
62920b57cec5SDimitry Andric       __thousands_sep_ = base::do_thousands_sep();
62930b57cec5SDimitry Andric 
62940b57cec5SDimitry Andric     __grouping_ = lc->mon_grouping;
62950b57cec5SDimitry Andric     __curr_symbol_ = lc->currency_symbol;
62960b57cec5SDimitry Andric     if (lc->frac_digits != CHAR_MAX)
62970b57cec5SDimitry Andric         __frac_digits_ = lc->frac_digits;
62980b57cec5SDimitry Andric     else
62990b57cec5SDimitry Andric         __frac_digits_ = base::do_frac_digits();
63000b57cec5SDimitry Andric     if (lc->p_sign_posn == 0)
63010b57cec5SDimitry Andric         __positive_sign_ = "()";
63020b57cec5SDimitry Andric     else
63030b57cec5SDimitry Andric         __positive_sign_ = lc->positive_sign;
63040b57cec5SDimitry Andric     if (lc->n_sign_posn == 0)
63050b57cec5SDimitry Andric         __negative_sign_ = "()";
63060b57cec5SDimitry Andric     else
63070b57cec5SDimitry Andric         __negative_sign_ = lc->negative_sign;
63080b57cec5SDimitry Andric     // Assume the positive and negative formats will want spaces in
63090b57cec5SDimitry Andric     // the same places in curr_symbol since there's no way to
63100b57cec5SDimitry Andric     // represent anything else.
63110b57cec5SDimitry Andric     string_type __dummy_curr_symbol = __curr_symbol_;
63120b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, false,
63130b57cec5SDimitry Andric                lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, ' ');
63140b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, false,
63150b57cec5SDimitry Andric                lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, ' ');
63160b57cec5SDimitry Andric }
63170b57cec5SDimitry Andric 
63180b57cec5SDimitry Andric template<>
63190b57cec5SDimitry Andric void
63200b57cec5SDimitry Andric moneypunct_byname<char, true>::init(const char* nm)
63210b57cec5SDimitry Andric {
63220b57cec5SDimitry Andric     typedef moneypunct<char, true> base;
63230b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
63240b57cec5SDimitry Andric     if (!loc)
63250b57cec5SDimitry Andric         __throw_runtime_error("moneypunct_byname"
63260b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
63270b57cec5SDimitry Andric 
63280b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
63290b57cec5SDimitry Andric     if (!checked_string_to_char_convert(__decimal_point_,
63300b57cec5SDimitry Andric                                         lc->mon_decimal_point,
63310b57cec5SDimitry Andric                                         loc.get()))
63320b57cec5SDimitry Andric       __decimal_point_ = base::do_decimal_point();
63330b57cec5SDimitry Andric     if (!checked_string_to_char_convert(__thousands_sep_,
63340b57cec5SDimitry Andric                                         lc->mon_thousands_sep,
63350b57cec5SDimitry Andric                                         loc.get()))
63360b57cec5SDimitry Andric       __thousands_sep_ = base::do_thousands_sep();
63370b57cec5SDimitry Andric     __grouping_ = lc->mon_grouping;
63380b57cec5SDimitry Andric     __curr_symbol_ = lc->int_curr_symbol;
63390b57cec5SDimitry Andric     if (lc->int_frac_digits != CHAR_MAX)
63400b57cec5SDimitry Andric         __frac_digits_ = lc->int_frac_digits;
63410b57cec5SDimitry Andric     else
63420b57cec5SDimitry Andric         __frac_digits_ = base::do_frac_digits();
63430b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
63440b57cec5SDimitry Andric     if (lc->p_sign_posn == 0)
63450b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
63460b57cec5SDimitry Andric     if (lc->int_p_sign_posn == 0)
63470b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
63480b57cec5SDimitry Andric         __positive_sign_ = "()";
63490b57cec5SDimitry Andric     else
63500b57cec5SDimitry Andric         __positive_sign_ = lc->positive_sign;
63510b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
63520b57cec5SDimitry Andric     if(lc->n_sign_posn == 0)
63530b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
63540b57cec5SDimitry Andric     if (lc->int_n_sign_posn == 0)
63550b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
63560b57cec5SDimitry Andric         __negative_sign_ = "()";
63570b57cec5SDimitry Andric     else
63580b57cec5SDimitry Andric         __negative_sign_ = lc->negative_sign;
63590b57cec5SDimitry Andric     // Assume the positive and negative formats will want spaces in
63600b57cec5SDimitry Andric     // the same places in curr_symbol since there's no way to
63610b57cec5SDimitry Andric     // represent anything else.
63620b57cec5SDimitry Andric     string_type __dummy_curr_symbol = __curr_symbol_;
63630b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
63640b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, true,
63650b57cec5SDimitry Andric                lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, ' ');
63660b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, true,
63670b57cec5SDimitry Andric                lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, ' ');
63680b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
63690b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, true,
63700b57cec5SDimitry Andric                lc->int_p_cs_precedes, lc->int_p_sep_by_space,
63710b57cec5SDimitry Andric                lc->int_p_sign_posn, ' ');
63720b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, true,
63730b57cec5SDimitry Andric                lc->int_n_cs_precedes, lc->int_n_sep_by_space,
63740b57cec5SDimitry Andric                lc->int_n_sign_posn, ' ');
63750b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
63760b57cec5SDimitry Andric }
63770b57cec5SDimitry Andric 
6378349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
63790b57cec5SDimitry Andric template<>
63800b57cec5SDimitry Andric void
63810b57cec5SDimitry Andric moneypunct_byname<wchar_t, false>::init(const char* nm)
63820b57cec5SDimitry Andric {
63830b57cec5SDimitry Andric     typedef moneypunct<wchar_t, false> base;
63840b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
63850b57cec5SDimitry Andric     if (!loc)
63860b57cec5SDimitry Andric         __throw_runtime_error("moneypunct_byname"
63870b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
63880b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
63890b57cec5SDimitry Andric     if (!checked_string_to_wchar_convert(__decimal_point_,
63900b57cec5SDimitry Andric                                          lc->mon_decimal_point,
63910b57cec5SDimitry Andric                                          loc.get()))
63920b57cec5SDimitry Andric       __decimal_point_ = base::do_decimal_point();
63930b57cec5SDimitry Andric     if (!checked_string_to_wchar_convert(__thousands_sep_,
63940b57cec5SDimitry Andric                                          lc->mon_thousands_sep,
63950b57cec5SDimitry Andric                                          loc.get()))
63960b57cec5SDimitry Andric       __thousands_sep_ = base::do_thousands_sep();
63970b57cec5SDimitry Andric     __grouping_ = lc->mon_grouping;
63980b57cec5SDimitry Andric     wchar_t wbuf[100];
63990b57cec5SDimitry Andric     mbstate_t mb = {0};
64000b57cec5SDimitry Andric     const char* bb = lc->currency_symbol;
64010b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
64020b57cec5SDimitry Andric     if (j == size_t(-1))
64030b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
64040b57cec5SDimitry Andric     wchar_t* wbe = wbuf + j;
64050b57cec5SDimitry Andric     __curr_symbol_.assign(wbuf, wbe);
64060b57cec5SDimitry Andric     if (lc->frac_digits != CHAR_MAX)
64070b57cec5SDimitry Andric         __frac_digits_ = lc->frac_digits;
64080b57cec5SDimitry Andric     else
64090b57cec5SDimitry Andric         __frac_digits_ = base::do_frac_digits();
64100b57cec5SDimitry Andric     if (lc->p_sign_posn == 0)
64110b57cec5SDimitry Andric         __positive_sign_ = L"()";
64120b57cec5SDimitry Andric     else
64130b57cec5SDimitry Andric     {
64140b57cec5SDimitry Andric         mb = mbstate_t();
64150b57cec5SDimitry Andric         bb = lc->positive_sign;
64160b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
64170b57cec5SDimitry Andric         if (j == size_t(-1))
64180b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
64190b57cec5SDimitry Andric         wbe = wbuf + j;
64200b57cec5SDimitry Andric         __positive_sign_.assign(wbuf, wbe);
64210b57cec5SDimitry Andric     }
64220b57cec5SDimitry Andric     if (lc->n_sign_posn == 0)
64230b57cec5SDimitry Andric         __negative_sign_ = L"()";
64240b57cec5SDimitry Andric     else
64250b57cec5SDimitry Andric     {
64260b57cec5SDimitry Andric         mb = mbstate_t();
64270b57cec5SDimitry Andric         bb = lc->negative_sign;
64280b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
64290b57cec5SDimitry Andric         if (j == size_t(-1))
64300b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
64310b57cec5SDimitry Andric         wbe = wbuf + j;
64320b57cec5SDimitry Andric         __negative_sign_.assign(wbuf, wbe);
64330b57cec5SDimitry Andric     }
64340b57cec5SDimitry Andric     // Assume the positive and negative formats will want spaces in
64350b57cec5SDimitry Andric     // the same places in curr_symbol since there's no way to
64360b57cec5SDimitry Andric     // represent anything else.
64370b57cec5SDimitry Andric     string_type __dummy_curr_symbol = __curr_symbol_;
64380b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, false,
64390b57cec5SDimitry Andric                lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, L' ');
64400b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, false,
64410b57cec5SDimitry Andric                lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, L' ');
64420b57cec5SDimitry Andric }
64430b57cec5SDimitry Andric 
64440b57cec5SDimitry Andric template<>
64450b57cec5SDimitry Andric void
64460b57cec5SDimitry Andric moneypunct_byname<wchar_t, true>::init(const char* nm)
64470b57cec5SDimitry Andric {
64480b57cec5SDimitry Andric     typedef moneypunct<wchar_t, true> base;
64490b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
64500b57cec5SDimitry Andric     if (!loc)
64510b57cec5SDimitry Andric         __throw_runtime_error("moneypunct_byname"
64520b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
64530b57cec5SDimitry Andric 
64540b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
64550b57cec5SDimitry Andric     if (!checked_string_to_wchar_convert(__decimal_point_,
64560b57cec5SDimitry Andric                                          lc->mon_decimal_point,
64570b57cec5SDimitry Andric                                          loc.get()))
64580b57cec5SDimitry Andric       __decimal_point_ = base::do_decimal_point();
64590b57cec5SDimitry Andric     if (!checked_string_to_wchar_convert(__thousands_sep_,
64600b57cec5SDimitry Andric                                          lc->mon_thousands_sep,
64610b57cec5SDimitry Andric                                          loc.get()))
64620b57cec5SDimitry Andric       __thousands_sep_ = base::do_thousands_sep();
64630b57cec5SDimitry Andric     __grouping_ = lc->mon_grouping;
64640b57cec5SDimitry Andric     wchar_t wbuf[100];
64650b57cec5SDimitry Andric     mbstate_t mb = {0};
64660b57cec5SDimitry Andric     const char* bb = lc->int_curr_symbol;
64670b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
64680b57cec5SDimitry Andric     if (j == size_t(-1))
64690b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
64700b57cec5SDimitry Andric     wchar_t* wbe = wbuf + j;
64710b57cec5SDimitry Andric     __curr_symbol_.assign(wbuf, wbe);
64720b57cec5SDimitry Andric     if (lc->int_frac_digits != CHAR_MAX)
64730b57cec5SDimitry Andric         __frac_digits_ = lc->int_frac_digits;
64740b57cec5SDimitry Andric     else
64750b57cec5SDimitry Andric         __frac_digits_ = base::do_frac_digits();
64760b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
64770b57cec5SDimitry Andric     if (lc->p_sign_posn == 0)
64780b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
64790b57cec5SDimitry Andric     if (lc->int_p_sign_posn == 0)
64800b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
64810b57cec5SDimitry Andric         __positive_sign_ = L"()";
64820b57cec5SDimitry Andric     else
64830b57cec5SDimitry Andric     {
64840b57cec5SDimitry Andric         mb = mbstate_t();
64850b57cec5SDimitry Andric         bb = lc->positive_sign;
64860b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
64870b57cec5SDimitry Andric         if (j == size_t(-1))
64880b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
64890b57cec5SDimitry Andric         wbe = wbuf + j;
64900b57cec5SDimitry Andric         __positive_sign_.assign(wbuf, wbe);
64910b57cec5SDimitry Andric     }
64920b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
64930b57cec5SDimitry Andric     if (lc->n_sign_posn == 0)
64940b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
64950b57cec5SDimitry Andric     if (lc->int_n_sign_posn == 0)
64960b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
64970b57cec5SDimitry Andric         __negative_sign_ = L"()";
64980b57cec5SDimitry Andric     else
64990b57cec5SDimitry Andric     {
65000b57cec5SDimitry Andric         mb = mbstate_t();
65010b57cec5SDimitry Andric         bb = lc->negative_sign;
65020b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
65030b57cec5SDimitry Andric         if (j == size_t(-1))
65040b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
65050b57cec5SDimitry Andric         wbe = wbuf + j;
65060b57cec5SDimitry Andric         __negative_sign_.assign(wbuf, wbe);
65070b57cec5SDimitry Andric     }
65080b57cec5SDimitry Andric     // Assume the positive and negative formats will want spaces in
65090b57cec5SDimitry Andric     // the same places in curr_symbol since there's no way to
65100b57cec5SDimitry Andric     // represent anything else.
65110b57cec5SDimitry Andric     string_type __dummy_curr_symbol = __curr_symbol_;
65120b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
65130b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, true,
65140b57cec5SDimitry Andric                lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, L' ');
65150b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, true,
65160b57cec5SDimitry Andric                lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, L' ');
65170b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
65180b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, true,
65190b57cec5SDimitry Andric                lc->int_p_cs_precedes, lc->int_p_sep_by_space,
65200b57cec5SDimitry Andric                lc->int_p_sign_posn, L' ');
65210b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, true,
65220b57cec5SDimitry Andric                lc->int_n_cs_precedes, lc->int_n_sep_by_space,
65230b57cec5SDimitry Andric                lc->int_n_sign_posn, L' ');
65240b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
65250b57cec5SDimitry Andric }
6526349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
65270b57cec5SDimitry Andric 
65280b57cec5SDimitry Andric void __do_nothing(void*) {}
65290b57cec5SDimitry Andric 
65300b57cec5SDimitry Andric void __throw_runtime_error(const char* msg)
65310b57cec5SDimitry Andric {
65320b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
65330b57cec5SDimitry Andric     throw runtime_error(msg);
65340b57cec5SDimitry Andric #else
65350b57cec5SDimitry Andric     (void)msg;
65360b57cec5SDimitry Andric     _VSTD::abort();
65370b57cec5SDimitry Andric #endif
65380b57cec5SDimitry Andric }
65390b57cec5SDimitry Andric 
65400b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<char>;
6541349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<wchar_t>;)
65420b57cec5SDimitry Andric 
65430b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<char>;
6544349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<wchar_t>;)
65450b57cec5SDimitry Andric 
65460b57cec5SDimitry Andric                            template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<char>;
6547349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<wchar_t>;)
65480b57cec5SDimitry Andric 
65490b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<char>;
6550349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<wchar_t>;)
65510b57cec5SDimitry Andric 
65520b57cec5SDimitry Andric                            template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<char>;
6553349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<wchar_t>;)
65540b57cec5SDimitry Andric 
65550b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<char>;
6556349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<wchar_t>;)
65570b57cec5SDimitry Andric 
65580b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<char>;
6559349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<wchar_t>;)
65600b57cec5SDimitry Andric 
65610b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<char>;
6562349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<wchar_t>;)
65630b57cec5SDimitry Andric 
65640b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<char>;
6565349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<wchar_t>;)
65660b57cec5SDimitry Andric 
65670b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, false>;
65680b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, true>;
6569349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, false>;)
6570349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, true>;)
65710b57cec5SDimitry Andric 
65720b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, false>;
65730b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, true>;
6574349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, false>;)
6575349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, true>;)
65760b57cec5SDimitry Andric 
65770b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<char>;
6578349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<wchar_t>;)
65790b57cec5SDimitry Andric 
65800b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<char>;
6581349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_get<wchar_t>;)
65820b57cec5SDimitry Andric 
65830b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<char>;
6584349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<wchar_t>;)
65850b57cec5SDimitry Andric 
65860b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<char>;
6587349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __money_put<wchar_t>;)
65880b57cec5SDimitry Andric 
65890b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<char>;
6590349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<wchar_t>;)
65910b57cec5SDimitry Andric 
65920b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<char>;
6593349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<wchar_t>;)
65940b57cec5SDimitry Andric 
65950b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char, char, mbstate_t>;
6596349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<wchar_t, char, mbstate_t>;)
6597e8d8bef9SDimitry Andric template class _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char16_t, char, mbstate_t>;
6598e8d8bef9SDimitry Andric template class _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char32_t, char, mbstate_t>;
6599fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
6600e8d8bef9SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char16_t, char8_t, mbstate_t>;
6601e8d8bef9SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char32_t, char8_t, mbstate_t>;
6602e8d8bef9SDimitry Andric #endif
66030b57cec5SDimitry Andric 
66040b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
660581ad6265SDimitry Andric 
660681ad6265SDimitry Andric _LIBCPP_POP_MACROS
6607