xref: /freebsd/contrib/llvm-project/libcxx/src/locale.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
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 
150b57cec5SDimitry Andric #include "algorithm"
160b57cec5SDimitry Andric #include "clocale"
17349cc55cSDimitry Andric #include "codecvt"
18349cc55cSDimitry Andric #include "cstdio"
19349cc55cSDimitry Andric #include "cstdlib"
200b57cec5SDimitry Andric #include "cstring"
21349cc55cSDimitry Andric #include "locale"
22349cc55cSDimitry Andric #include "string"
23349cc55cSDimitry Andric #include "type_traits"
24349cc55cSDimitry Andric #include "typeinfo"
25349cc55cSDimitry Andric #include "vector"
26349cc55cSDimitry Andric 
27349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
28349cc55cSDimitry Andric #   include "cwctype"
29349cc55cSDimitry Andric #endif
30349cc55cSDimitry Andric 
31349cc55cSDimitry Andric #if defined(_AIX)
32349cc55cSDimitry Andric #   include <sys/localedef.h> // for __lc_ctype_ptr
33349cc55cSDimitry Andric #endif
34349cc55cSDimitry Andric 
350b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT)
360b57cec5SDimitry Andric #   define _CTYPE_DISABLE_MACROS
370b57cec5SDimitry Andric #endif
38349cc55cSDimitry Andric 
390b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
40d409305fSDimitry Andric #   include "__support/win32/locale_win32.h"
41e8d8bef9SDimitry Andric #elif !defined(__BIONIC__) && !defined(__NuttX__)
420b57cec5SDimitry Andric #   include <langinfo.h>
430b57cec5SDimitry Andric #endif
44349cc55cSDimitry Andric 
450b57cec5SDimitry Andric #include "include/atomic_support.h"
46fe6060f1SDimitry Andric #include "include/sso_allocator.h"
470b57cec5SDimitry Andric #include "__undef_macros"
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.
510b57cec5SDimitry Andric #if defined(__clang__)
520b57cec5SDimitry Andric #pragma clang diagnostic ignored "-Wsign-conversion"
530b57cec5SDimitry Andric #endif
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric struct __libcpp_unique_locale {
580b57cec5SDimitry Andric   __libcpp_unique_locale(const char* nm) : __loc_(newlocale(LC_ALL_MASK, nm, 0)) {}
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   ~__libcpp_unique_locale() {
610b57cec5SDimitry Andric     if (__loc_)
620b57cec5SDimitry Andric       freelocale(__loc_);
630b57cec5SDimitry Andric   }
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric   explicit operator bool() const { return __loc_; }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   locale_t& get() { return __loc_; }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   locale_t __loc_;
700b57cec5SDimitry Andric private:
710b57cec5SDimitry Andric   __libcpp_unique_locale(__libcpp_unique_locale const&);
720b57cec5SDimitry Andric   __libcpp_unique_locale& operator=(__libcpp_unique_locale const&);
730b57cec5SDimitry Andric };
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric #ifdef __cloc_defined
760b57cec5SDimitry Andric locale_t __cloc() {
770b57cec5SDimitry Andric   // In theory this could create a race condition. In practice
780b57cec5SDimitry Andric   // the race condition is non-fatal since it will just create
790b57cec5SDimitry Andric   // a little resource leak. Better approach would be appreciated.
800b57cec5SDimitry Andric   static locale_t result = newlocale(LC_ALL_MASK, "C", 0);
810b57cec5SDimitry Andric   return result;
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric #endif // __cloc_defined
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric namespace {
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric struct release
880b57cec5SDimitry Andric {
890b57cec5SDimitry Andric     void operator()(locale::facet* p) {p->__release_shared();}
900b57cec5SDimitry Andric };
910b57cec5SDimitry Andric 
92349cc55cSDimitry Andric template <class T, class ...Args>
93349cc55cSDimitry Andric T& make(Args ...args)
940b57cec5SDimitry Andric {
950b57cec5SDimitry Andric     static typename aligned_storage<sizeof(T)>::type buf;
96349cc55cSDimitry Andric     auto *obj = ::new (&buf) T(args...);
970b57cec5SDimitry Andric     return *obj;
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric template <typename T, size_t N>
1010b57cec5SDimitry Andric inline
1020b57cec5SDimitry Andric _LIBCPP_CONSTEXPR
1030b57cec5SDimitry Andric size_t
1040b57cec5SDimitry Andric countof(const T (&)[N])
1050b57cec5SDimitry Andric {
1060b57cec5SDimitry Andric     return N;
1070b57cec5SDimitry Andric }
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric template <typename T>
1100b57cec5SDimitry Andric inline
1110b57cec5SDimitry Andric _LIBCPP_CONSTEXPR
1120b57cec5SDimitry Andric size_t
1130b57cec5SDimitry Andric countof(const T * const begin, const T * const end)
1140b57cec5SDimitry Andric {
1150b57cec5SDimitry Andric     return static_cast<size_t>(end - begin);
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric _LIBCPP_NORETURN static void __throw_runtime_error(const string &msg)
1190b57cec5SDimitry Andric {
1200b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
1210b57cec5SDimitry Andric     throw runtime_error(msg);
1220b57cec5SDimitry Andric #else
1230b57cec5SDimitry Andric     (void)msg;
1240b57cec5SDimitry Andric     _VSTD::abort();
1250b57cec5SDimitry Andric #endif
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric #if defined(_AIX)
1310b57cec5SDimitry Andric // Set priority to INT_MIN + 256 + 150
1320b57cec5SDimitry Andric # pragma priority ( -2147483242 )
1330b57cec5SDimitry Andric #endif
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric const locale::category locale::none;
1360b57cec5SDimitry Andric const locale::category locale::collate;
1370b57cec5SDimitry Andric const locale::category locale::ctype;
1380b57cec5SDimitry Andric const locale::category locale::monetary;
1390b57cec5SDimitry Andric const locale::category locale::numeric;
1400b57cec5SDimitry Andric const locale::category locale::time;
1410b57cec5SDimitry Andric const locale::category locale::messages;
1420b57cec5SDimitry Andric const locale::category locale::all;
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric class _LIBCPP_HIDDEN locale::__imp
1450b57cec5SDimitry Andric     : public facet
1460b57cec5SDimitry Andric {
147e8d8bef9SDimitry Andric     enum {N = 30};
1480b57cec5SDimitry Andric #if defined(_LIBCPP_COMPILER_MSVC)
1490b57cec5SDimitry Andric // FIXME: MSVC doesn't support aligned parameters by value.
1500b57cec5SDimitry Andric // I can't get the __sso_allocator to work here
1510b57cec5SDimitry Andric // for MSVC I think for this reason.
1520b57cec5SDimitry Andric     vector<facet*> facets_;
1530b57cec5SDimitry Andric #else
1540b57cec5SDimitry Andric     vector<facet*, __sso_allocator<facet*, N> > facets_;
1550b57cec5SDimitry Andric #endif
1560b57cec5SDimitry Andric     string         name_;
1570b57cec5SDimitry Andric public:
1580b57cec5SDimitry Andric     explicit __imp(size_t refs = 0);
1590b57cec5SDimitry Andric     explicit __imp(const string& name, size_t refs = 0);
1600b57cec5SDimitry Andric     __imp(const __imp&);
1610b57cec5SDimitry Andric     __imp(const __imp&, const string&, locale::category c);
1620b57cec5SDimitry Andric     __imp(const __imp& other, const __imp& one, locale::category c);
1630b57cec5SDimitry Andric     __imp(const __imp&, facet* f, long id);
1640b57cec5SDimitry Andric     ~__imp();
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric     const string& name() const {return name_;}
1670b57cec5SDimitry Andric     bool has_facet(long id) const
1680b57cec5SDimitry Andric         {return static_cast<size_t>(id) < facets_.size() && facets_[static_cast<size_t>(id)];}
1690b57cec5SDimitry Andric     const locale::facet* use_facet(long id) const;
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric     static const locale& make_classic();
1720b57cec5SDimitry Andric     static       locale& make_global();
1730b57cec5SDimitry Andric private:
1740b57cec5SDimitry Andric     void install(facet* f, long id);
1750b57cec5SDimitry Andric     template <class F> void install(F* f) {install(f, f->id.__get());}
1760b57cec5SDimitry Andric     template <class F> void install_from(const __imp& other);
1770b57cec5SDimitry Andric };
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric locale::__imp::__imp(size_t refs)
1800b57cec5SDimitry Andric     : facet(refs),
1810b57cec5SDimitry Andric       facets_(N),
1820b57cec5SDimitry Andric       name_("C")
1830b57cec5SDimitry Andric {
1840b57cec5SDimitry Andric     facets_.clear();
1850b57cec5SDimitry Andric     install(&make<_VSTD::collate<char> >(1u));
186349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1870b57cec5SDimitry Andric     install(&make<_VSTD::collate<wchar_t> >(1u));
188349cc55cSDimitry Andric #endif
1890b57cec5SDimitry Andric     install(&make<_VSTD::ctype<char> >(nullptr, false, 1u));
190349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1910b57cec5SDimitry Andric     install(&make<_VSTD::ctype<wchar_t> >(1u));
192349cc55cSDimitry Andric #endif
1930b57cec5SDimitry Andric     install(&make<codecvt<char, char, mbstate_t> >(1u));
194349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1950b57cec5SDimitry Andric     install(&make<codecvt<wchar_t, char, mbstate_t> >(1u));
196349cc55cSDimitry Andric #endif
197e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
1980b57cec5SDimitry Andric     install(&make<codecvt<char16_t, char, mbstate_t> >(1u));
1990b57cec5SDimitry Andric     install(&make<codecvt<char32_t, char, mbstate_t> >(1u));
200e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
201fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
202e8d8bef9SDimitry Andric     install(&make<codecvt<char16_t, char8_t, mbstate_t> >(1u));
203e8d8bef9SDimitry Andric     install(&make<codecvt<char32_t, char8_t, mbstate_t> >(1u));
204e8d8bef9SDimitry Andric #endif
2050b57cec5SDimitry Andric     install(&make<numpunct<char> >(1u));
206349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2070b57cec5SDimitry Andric     install(&make<numpunct<wchar_t> >(1u));
208349cc55cSDimitry Andric #endif
2090b57cec5SDimitry Andric     install(&make<num_get<char> >(1u));
210349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2110b57cec5SDimitry Andric     install(&make<num_get<wchar_t> >(1u));
212349cc55cSDimitry Andric #endif
2130b57cec5SDimitry Andric     install(&make<num_put<char> >(1u));
214349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2150b57cec5SDimitry Andric     install(&make<num_put<wchar_t> >(1u));
216349cc55cSDimitry Andric #endif
2170b57cec5SDimitry Andric     install(&make<moneypunct<char, false> >(1u));
2180b57cec5SDimitry Andric     install(&make<moneypunct<char, true> >(1u));
219349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2200b57cec5SDimitry Andric     install(&make<moneypunct<wchar_t, false> >(1u));
2210b57cec5SDimitry Andric     install(&make<moneypunct<wchar_t, true> >(1u));
222349cc55cSDimitry Andric #endif
2230b57cec5SDimitry Andric     install(&make<money_get<char> >(1u));
224349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2250b57cec5SDimitry Andric     install(&make<money_get<wchar_t> >(1u));
226349cc55cSDimitry Andric #endif
2270b57cec5SDimitry Andric     install(&make<money_put<char> >(1u));
228349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2290b57cec5SDimitry Andric     install(&make<money_put<wchar_t> >(1u));
230349cc55cSDimitry Andric #endif
2310b57cec5SDimitry Andric     install(&make<time_get<char> >(1u));
232349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2330b57cec5SDimitry Andric     install(&make<time_get<wchar_t> >(1u));
234349cc55cSDimitry Andric #endif
2350b57cec5SDimitry Andric     install(&make<time_put<char> >(1u));
236349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2370b57cec5SDimitry Andric     install(&make<time_put<wchar_t> >(1u));
238349cc55cSDimitry Andric #endif
2390b57cec5SDimitry Andric     install(&make<_VSTD::messages<char> >(1u));
240349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2410b57cec5SDimitry Andric     install(&make<_VSTD::messages<wchar_t> >(1u));
242349cc55cSDimitry Andric #endif
2430b57cec5SDimitry Andric }
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric locale::__imp::__imp(const string& name, size_t refs)
2460b57cec5SDimitry Andric     : facet(refs),
2470b57cec5SDimitry Andric       facets_(N),
2480b57cec5SDimitry Andric       name_(name)
2490b57cec5SDimitry Andric {
2500b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
2510b57cec5SDimitry Andric     try
2520b57cec5SDimitry Andric     {
2530b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS
2540b57cec5SDimitry Andric         facets_ = locale::classic().__locale_->facets_;
2550b57cec5SDimitry Andric         for (unsigned i = 0; i < facets_.size(); ++i)
2560b57cec5SDimitry Andric             if (facets_[i])
2570b57cec5SDimitry Andric                 facets_[i]->__add_shared();
2580b57cec5SDimitry Andric         install(new collate_byname<char>(name_));
259349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2600b57cec5SDimitry Andric         install(new collate_byname<wchar_t>(name_));
261349cc55cSDimitry Andric #endif
2620b57cec5SDimitry Andric         install(new ctype_byname<char>(name_));
263349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2640b57cec5SDimitry Andric         install(new ctype_byname<wchar_t>(name_));
265349cc55cSDimitry Andric #endif
2660b57cec5SDimitry Andric         install(new codecvt_byname<char, char, mbstate_t>(name_));
267349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2680b57cec5SDimitry Andric         install(new codecvt_byname<wchar_t, char, mbstate_t>(name_));
269349cc55cSDimitry Andric #endif
270e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
2710b57cec5SDimitry Andric         install(new codecvt_byname<char16_t, char, mbstate_t>(name_));
2720b57cec5SDimitry Andric         install(new codecvt_byname<char32_t, char, mbstate_t>(name_));
273e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
274fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
275e8d8bef9SDimitry Andric         install(new codecvt_byname<char16_t, char8_t, mbstate_t>(name_));
276e8d8bef9SDimitry Andric         install(new codecvt_byname<char32_t, char8_t, mbstate_t>(name_));
277e8d8bef9SDimitry Andric #endif
2780b57cec5SDimitry Andric         install(new numpunct_byname<char>(name_));
279349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2800b57cec5SDimitry Andric         install(new numpunct_byname<wchar_t>(name_));
281349cc55cSDimitry Andric #endif
2820b57cec5SDimitry Andric         install(new moneypunct_byname<char, false>(name_));
2830b57cec5SDimitry Andric         install(new moneypunct_byname<char, true>(name_));
284349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2850b57cec5SDimitry Andric         install(new moneypunct_byname<wchar_t, false>(name_));
2860b57cec5SDimitry Andric         install(new moneypunct_byname<wchar_t, true>(name_));
287349cc55cSDimitry Andric #endif
2880b57cec5SDimitry Andric         install(new time_get_byname<char>(name_));
289349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2900b57cec5SDimitry Andric         install(new time_get_byname<wchar_t>(name_));
291349cc55cSDimitry Andric #endif
2920b57cec5SDimitry Andric         install(new time_put_byname<char>(name_));
293349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2940b57cec5SDimitry Andric         install(new time_put_byname<wchar_t>(name_));
295349cc55cSDimitry Andric #endif
2960b57cec5SDimitry Andric         install(new messages_byname<char>(name_));
297349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2980b57cec5SDimitry Andric         install(new messages_byname<wchar_t>(name_));
299349cc55cSDimitry Andric #endif
3000b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
3010b57cec5SDimitry Andric     }
3020b57cec5SDimitry Andric     catch (...)
3030b57cec5SDimitry Andric     {
3040b57cec5SDimitry Andric         for (unsigned i = 0; i < facets_.size(); ++i)
3050b57cec5SDimitry Andric             if (facets_[i])
3060b57cec5SDimitry Andric                 facets_[i]->__release_shared();
3070b57cec5SDimitry Andric         throw;
3080b57cec5SDimitry Andric     }
3090b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS
3100b57cec5SDimitry Andric }
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric locale::__imp::__imp(const __imp& other)
3130b57cec5SDimitry Andric     : facets_(max<size_t>(N, other.facets_.size())),
3140b57cec5SDimitry Andric       name_(other.name_)
3150b57cec5SDimitry Andric {
3160b57cec5SDimitry Andric     facets_ = other.facets_;
3170b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
3180b57cec5SDimitry Andric         if (facets_[i])
3190b57cec5SDimitry Andric             facets_[i]->__add_shared();
3200b57cec5SDimitry Andric }
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric locale::__imp::__imp(const __imp& other, const string& name, locale::category c)
3230b57cec5SDimitry Andric     : facets_(N),
3240b57cec5SDimitry Andric       name_("*")
3250b57cec5SDimitry Andric {
3260b57cec5SDimitry Andric     facets_ = other.facets_;
3270b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
3280b57cec5SDimitry Andric         if (facets_[i])
3290b57cec5SDimitry Andric             facets_[i]->__add_shared();
3300b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
3310b57cec5SDimitry Andric     try
3320b57cec5SDimitry Andric     {
3330b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS
3340b57cec5SDimitry Andric         if (c & locale::collate)
3350b57cec5SDimitry Andric         {
3360b57cec5SDimitry Andric             install(new collate_byname<char>(name));
337349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3380b57cec5SDimitry Andric             install(new collate_byname<wchar_t>(name));
339349cc55cSDimitry Andric #endif
3400b57cec5SDimitry Andric         }
3410b57cec5SDimitry Andric         if (c & locale::ctype)
3420b57cec5SDimitry Andric         {
3430b57cec5SDimitry Andric             install(new ctype_byname<char>(name));
344349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3450b57cec5SDimitry Andric             install(new ctype_byname<wchar_t>(name));
346349cc55cSDimitry Andric #endif
3470b57cec5SDimitry Andric             install(new codecvt_byname<char, char, mbstate_t>(name));
348349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3490b57cec5SDimitry Andric             install(new codecvt_byname<wchar_t, char, mbstate_t>(name));
350349cc55cSDimitry Andric #endif
351e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
3520b57cec5SDimitry Andric             install(new codecvt_byname<char16_t, char, mbstate_t>(name));
3530b57cec5SDimitry Andric             install(new codecvt_byname<char32_t, char, mbstate_t>(name));
354e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
355fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
356e8d8bef9SDimitry Andric             install(new codecvt_byname<char16_t, char8_t, mbstate_t>(name));
357e8d8bef9SDimitry Andric             install(new codecvt_byname<char32_t, char8_t, mbstate_t>(name));
358e8d8bef9SDimitry Andric #endif
3590b57cec5SDimitry Andric         }
3600b57cec5SDimitry Andric         if (c & locale::monetary)
3610b57cec5SDimitry Andric         {
3620b57cec5SDimitry Andric             install(new moneypunct_byname<char, false>(name));
3630b57cec5SDimitry Andric             install(new moneypunct_byname<char, true>(name));
364349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3650b57cec5SDimitry Andric             install(new moneypunct_byname<wchar_t, false>(name));
3660b57cec5SDimitry Andric             install(new moneypunct_byname<wchar_t, true>(name));
367349cc55cSDimitry Andric #endif
3680b57cec5SDimitry Andric         }
3690b57cec5SDimitry Andric         if (c & locale::numeric)
3700b57cec5SDimitry Andric         {
3710b57cec5SDimitry Andric             install(new numpunct_byname<char>(name));
372349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3730b57cec5SDimitry Andric             install(new numpunct_byname<wchar_t>(name));
374349cc55cSDimitry Andric #endif
3750b57cec5SDimitry Andric         }
3760b57cec5SDimitry Andric         if (c & locale::time)
3770b57cec5SDimitry Andric         {
3780b57cec5SDimitry Andric             install(new time_get_byname<char>(name));
379349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3800b57cec5SDimitry Andric             install(new time_get_byname<wchar_t>(name));
381349cc55cSDimitry Andric #endif
3820b57cec5SDimitry Andric             install(new time_put_byname<char>(name));
383349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3840b57cec5SDimitry Andric             install(new time_put_byname<wchar_t>(name));
385349cc55cSDimitry Andric #endif
3860b57cec5SDimitry Andric         }
3870b57cec5SDimitry Andric         if (c & locale::messages)
3880b57cec5SDimitry Andric         {
3890b57cec5SDimitry Andric             install(new messages_byname<char>(name));
390349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3910b57cec5SDimitry Andric             install(new messages_byname<wchar_t>(name));
392349cc55cSDimitry Andric #endif
3930b57cec5SDimitry Andric         }
3940b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
3950b57cec5SDimitry Andric     }
3960b57cec5SDimitry Andric     catch (...)
3970b57cec5SDimitry Andric     {
3980b57cec5SDimitry Andric         for (unsigned i = 0; i < facets_.size(); ++i)
3990b57cec5SDimitry Andric             if (facets_[i])
4000b57cec5SDimitry Andric                 facets_[i]->__release_shared();
4010b57cec5SDimitry Andric         throw;
4020b57cec5SDimitry Andric     }
4030b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS
4040b57cec5SDimitry Andric }
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric template<class F>
4070b57cec5SDimitry Andric inline
4080b57cec5SDimitry Andric void
4090b57cec5SDimitry Andric locale::__imp::install_from(const locale::__imp& one)
4100b57cec5SDimitry Andric {
4110b57cec5SDimitry Andric     long id = F::id.__get();
4120b57cec5SDimitry Andric     install(const_cast<F*>(static_cast<const F*>(one.use_facet(id))), id);
4130b57cec5SDimitry Andric }
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric locale::__imp::__imp(const __imp& other, const __imp& one, locale::category c)
4160b57cec5SDimitry Andric     : facets_(N),
4170b57cec5SDimitry Andric       name_("*")
4180b57cec5SDimitry Andric {
4190b57cec5SDimitry Andric     facets_ = other.facets_;
4200b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
4210b57cec5SDimitry Andric         if (facets_[i])
4220b57cec5SDimitry Andric             facets_[i]->__add_shared();
4230b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
4240b57cec5SDimitry Andric     try
4250b57cec5SDimitry Andric     {
4260b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS
4270b57cec5SDimitry Andric         if (c & locale::collate)
4280b57cec5SDimitry Andric         {
4290b57cec5SDimitry Andric             install_from<_VSTD::collate<char> >(one);
430349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4310b57cec5SDimitry Andric             install_from<_VSTD::collate<wchar_t> >(one);
432349cc55cSDimitry Andric #endif
4330b57cec5SDimitry Andric         }
4340b57cec5SDimitry Andric         if (c & locale::ctype)
4350b57cec5SDimitry Andric         {
4360b57cec5SDimitry Andric             install_from<_VSTD::ctype<char> >(one);
437349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4380b57cec5SDimitry Andric             install_from<_VSTD::ctype<wchar_t> >(one);
439349cc55cSDimitry Andric #endif
4400b57cec5SDimitry Andric             install_from<_VSTD::codecvt<char, char, mbstate_t> >(one);
441e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_PUSH
4420b57cec5SDimitry Andric             install_from<_VSTD::codecvt<char16_t, char, mbstate_t> >(one);
4430b57cec5SDimitry Andric             install_from<_VSTD::codecvt<char32_t, char, mbstate_t> >(one);
444e8d8bef9SDimitry Andric _LIBCPP_SUPPRESS_DEPRECATED_POP
445fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
446e8d8bef9SDimitry Andric             install_from<_VSTD::codecvt<char16_t, char8_t, mbstate_t> >(one);
447e8d8bef9SDimitry Andric             install_from<_VSTD::codecvt<char32_t, char8_t, mbstate_t> >(one);
448e8d8bef9SDimitry Andric #endif
449349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4500b57cec5SDimitry Andric             install_from<_VSTD::codecvt<wchar_t, char, mbstate_t> >(one);
451349cc55cSDimitry Andric #endif
4520b57cec5SDimitry Andric         }
4530b57cec5SDimitry Andric         if (c & locale::monetary)
4540b57cec5SDimitry Andric         {
4550b57cec5SDimitry Andric             install_from<moneypunct<char, false> >(one);
4560b57cec5SDimitry Andric             install_from<moneypunct<char, true> >(one);
457349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4580b57cec5SDimitry Andric             install_from<moneypunct<wchar_t, false> >(one);
4590b57cec5SDimitry Andric             install_from<moneypunct<wchar_t, true> >(one);
460349cc55cSDimitry Andric #endif
4610b57cec5SDimitry Andric             install_from<money_get<char> >(one);
462349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4630b57cec5SDimitry Andric             install_from<money_get<wchar_t> >(one);
464349cc55cSDimitry Andric #endif
4650b57cec5SDimitry Andric             install_from<money_put<char> >(one);
466349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4670b57cec5SDimitry Andric             install_from<money_put<wchar_t> >(one);
468349cc55cSDimitry Andric #endif
4690b57cec5SDimitry Andric         }
4700b57cec5SDimitry Andric         if (c & locale::numeric)
4710b57cec5SDimitry Andric         {
4720b57cec5SDimitry Andric             install_from<numpunct<char> >(one);
473349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4740b57cec5SDimitry Andric             install_from<numpunct<wchar_t> >(one);
475349cc55cSDimitry Andric #endif
4760b57cec5SDimitry Andric             install_from<num_get<char> >(one);
477349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4780b57cec5SDimitry Andric             install_from<num_get<wchar_t> >(one);
479349cc55cSDimitry Andric #endif
4800b57cec5SDimitry Andric             install_from<num_put<char> >(one);
481349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4820b57cec5SDimitry Andric             install_from<num_put<wchar_t> >(one);
483349cc55cSDimitry Andric #endif
4840b57cec5SDimitry Andric         }
4850b57cec5SDimitry Andric         if (c & locale::time)
4860b57cec5SDimitry Andric         {
4870b57cec5SDimitry Andric             install_from<time_get<char> >(one);
488349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4890b57cec5SDimitry Andric             install_from<time_get<wchar_t> >(one);
490349cc55cSDimitry Andric #endif
4910b57cec5SDimitry Andric             install_from<time_put<char> >(one);
492349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4930b57cec5SDimitry Andric             install_from<time_put<wchar_t> >(one);
494349cc55cSDimitry Andric #endif
4950b57cec5SDimitry Andric         }
4960b57cec5SDimitry Andric         if (c & locale::messages)
4970b57cec5SDimitry Andric         {
4980b57cec5SDimitry Andric             install_from<_VSTD::messages<char> >(one);
499349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
5000b57cec5SDimitry Andric             install_from<_VSTD::messages<wchar_t> >(one);
501349cc55cSDimitry Andric #endif
5020b57cec5SDimitry Andric         }
5030b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
5040b57cec5SDimitry Andric     }
5050b57cec5SDimitry Andric     catch (...)
5060b57cec5SDimitry Andric     {
5070b57cec5SDimitry Andric         for (unsigned i = 0; i < facets_.size(); ++i)
5080b57cec5SDimitry Andric             if (facets_[i])
5090b57cec5SDimitry Andric                 facets_[i]->__release_shared();
5100b57cec5SDimitry Andric         throw;
5110b57cec5SDimitry Andric     }
5120b57cec5SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS
5130b57cec5SDimitry Andric }
5140b57cec5SDimitry Andric 
5150b57cec5SDimitry Andric locale::__imp::__imp(const __imp& other, facet* f, long id)
5160b57cec5SDimitry Andric     : facets_(max<size_t>(N, other.facets_.size()+1)),
5170b57cec5SDimitry Andric       name_("*")
5180b57cec5SDimitry Andric {
5190b57cec5SDimitry Andric     f->__add_shared();
5200b57cec5SDimitry Andric     unique_ptr<facet, release> hold(f);
5210b57cec5SDimitry Andric     facets_ = other.facets_;
5220b57cec5SDimitry Andric     for (unsigned i = 0; i < other.facets_.size(); ++i)
5230b57cec5SDimitry Andric         if (facets_[i])
5240b57cec5SDimitry Andric             facets_[i]->__add_shared();
5250b57cec5SDimitry Andric     install(hold.get(), id);
5260b57cec5SDimitry Andric }
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric locale::__imp::~__imp()
5290b57cec5SDimitry Andric {
5300b57cec5SDimitry Andric     for (unsigned i = 0; i < facets_.size(); ++i)
5310b57cec5SDimitry Andric         if (facets_[i])
5320b57cec5SDimitry Andric             facets_[i]->__release_shared();
5330b57cec5SDimitry Andric }
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric void
5360b57cec5SDimitry Andric locale::__imp::install(facet* f, long id)
5370b57cec5SDimitry Andric {
5380b57cec5SDimitry Andric     f->__add_shared();
5390b57cec5SDimitry Andric     unique_ptr<facet, release> hold(f);
5400b57cec5SDimitry Andric     if (static_cast<size_t>(id) >= facets_.size())
5410b57cec5SDimitry Andric         facets_.resize(static_cast<size_t>(id+1));
5420b57cec5SDimitry Andric     if (facets_[static_cast<size_t>(id)])
5430b57cec5SDimitry Andric         facets_[static_cast<size_t>(id)]->__release_shared();
5440b57cec5SDimitry Andric     facets_[static_cast<size_t>(id)] = hold.release();
5450b57cec5SDimitry Andric }
5460b57cec5SDimitry Andric 
5470b57cec5SDimitry Andric const locale::facet*
5480b57cec5SDimitry Andric locale::__imp::use_facet(long id) const
5490b57cec5SDimitry Andric {
5500b57cec5SDimitry Andric     if (!has_facet(id))
5510b57cec5SDimitry Andric         __throw_bad_cast();
5520b57cec5SDimitry Andric     return facets_[static_cast<size_t>(id)];
5530b57cec5SDimitry Andric }
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric // locale
5560b57cec5SDimitry Andric 
5570b57cec5SDimitry Andric const locale&
5580b57cec5SDimitry Andric locale::__imp::make_classic()
5590b57cec5SDimitry Andric {
5600b57cec5SDimitry Andric     // only one thread can get in here and it only gets in once
5610b57cec5SDimitry Andric     static aligned_storage<sizeof(locale)>::type buf;
5620b57cec5SDimitry Andric     locale* c = reinterpret_cast<locale*>(&buf);
5630b57cec5SDimitry Andric     c->__locale_ = &make<__imp>(1u);
5640b57cec5SDimitry Andric     return *c;
5650b57cec5SDimitry Andric }
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric const locale&
5680b57cec5SDimitry Andric locale::classic()
5690b57cec5SDimitry Andric {
5700b57cec5SDimitry Andric     static const locale& c = __imp::make_classic();
5710b57cec5SDimitry Andric     return c;
5720b57cec5SDimitry Andric }
5730b57cec5SDimitry Andric 
5740b57cec5SDimitry Andric locale&
5750b57cec5SDimitry Andric locale::__imp::make_global()
5760b57cec5SDimitry Andric {
5770b57cec5SDimitry Andric     // only one thread can get in here and it only gets in once
5780b57cec5SDimitry Andric     static aligned_storage<sizeof(locale)>::type buf;
5790b57cec5SDimitry Andric     auto *obj = ::new (&buf) locale(locale::classic());
5800b57cec5SDimitry Andric     return *obj;
5810b57cec5SDimitry Andric }
5820b57cec5SDimitry Andric 
5830b57cec5SDimitry Andric locale&
5840b57cec5SDimitry Andric locale::__global()
5850b57cec5SDimitry Andric {
5860b57cec5SDimitry Andric     static locale& g = __imp::make_global();
5870b57cec5SDimitry Andric     return g;
5880b57cec5SDimitry Andric }
5890b57cec5SDimitry Andric 
590fe6060f1SDimitry Andric locale::locale() noexcept
5910b57cec5SDimitry Andric     : __locale_(__global().__locale_)
5920b57cec5SDimitry Andric {
5930b57cec5SDimitry Andric     __locale_->__add_shared();
5940b57cec5SDimitry Andric }
5950b57cec5SDimitry Andric 
596fe6060f1SDimitry Andric locale::locale(const locale& l) noexcept
5970b57cec5SDimitry Andric     : __locale_(l.__locale_)
5980b57cec5SDimitry Andric {
5990b57cec5SDimitry Andric     __locale_->__add_shared();
6000b57cec5SDimitry Andric }
6010b57cec5SDimitry Andric 
6020b57cec5SDimitry Andric locale::~locale()
6030b57cec5SDimitry Andric {
6040b57cec5SDimitry Andric     __locale_->__release_shared();
6050b57cec5SDimitry Andric }
6060b57cec5SDimitry Andric 
6070b57cec5SDimitry Andric const locale&
608fe6060f1SDimitry Andric locale::operator=(const locale& other) noexcept
6090b57cec5SDimitry Andric {
6100b57cec5SDimitry Andric     other.__locale_->__add_shared();
6110b57cec5SDimitry Andric     __locale_->__release_shared();
6120b57cec5SDimitry Andric     __locale_ = other.__locale_;
6130b57cec5SDimitry Andric     return *this;
6140b57cec5SDimitry Andric }
6150b57cec5SDimitry Andric 
6160b57cec5SDimitry Andric locale::locale(const char* name)
6170b57cec5SDimitry Andric     : __locale_(name ? new __imp(name)
6185ffd83dbSDimitry Andric                      : (__throw_runtime_error("locale constructed with null"), nullptr))
6190b57cec5SDimitry Andric {
6200b57cec5SDimitry Andric     __locale_->__add_shared();
6210b57cec5SDimitry Andric }
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric locale::locale(const string& name)
6240b57cec5SDimitry Andric     : __locale_(new __imp(name))
6250b57cec5SDimitry Andric {
6260b57cec5SDimitry Andric     __locale_->__add_shared();
6270b57cec5SDimitry Andric }
6280b57cec5SDimitry Andric 
6290b57cec5SDimitry Andric locale::locale(const locale& other, const char* name, category c)
6300b57cec5SDimitry Andric     : __locale_(name ? new __imp(*other.__locale_, name, c)
6315ffd83dbSDimitry Andric                      : (__throw_runtime_error("locale constructed with null"), nullptr))
6320b57cec5SDimitry Andric {
6330b57cec5SDimitry Andric     __locale_->__add_shared();
6340b57cec5SDimitry Andric }
6350b57cec5SDimitry Andric 
6360b57cec5SDimitry Andric locale::locale(const locale& other, const string& name, category c)
6370b57cec5SDimitry Andric     : __locale_(new __imp(*other.__locale_, name, c))
6380b57cec5SDimitry Andric {
6390b57cec5SDimitry Andric     __locale_->__add_shared();
6400b57cec5SDimitry Andric }
6410b57cec5SDimitry Andric 
6420b57cec5SDimitry Andric locale::locale(const locale& other, const locale& one, category c)
6430b57cec5SDimitry Andric     : __locale_(new __imp(*other.__locale_, *one.__locale_, c))
6440b57cec5SDimitry Andric {
6450b57cec5SDimitry Andric     __locale_->__add_shared();
6460b57cec5SDimitry Andric }
6470b57cec5SDimitry Andric 
6480b57cec5SDimitry Andric string
6490b57cec5SDimitry Andric locale::name() const
6500b57cec5SDimitry Andric {
6510b57cec5SDimitry Andric     return __locale_->name();
6520b57cec5SDimitry Andric }
6530b57cec5SDimitry Andric 
6540b57cec5SDimitry Andric void
6550b57cec5SDimitry Andric locale::__install_ctor(const locale& other, facet* f, long id)
6560b57cec5SDimitry Andric {
6570b57cec5SDimitry Andric     if (f)
6580b57cec5SDimitry Andric         __locale_ = new __imp(*other.__locale_, f, id);
6590b57cec5SDimitry Andric     else
6600b57cec5SDimitry Andric         __locale_ = other.__locale_;
6610b57cec5SDimitry Andric     __locale_->__add_shared();
6620b57cec5SDimitry Andric }
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric locale
6650b57cec5SDimitry Andric locale::global(const locale& loc)
6660b57cec5SDimitry Andric {
6670b57cec5SDimitry Andric     locale& g = __global();
6680b57cec5SDimitry Andric     locale r = g;
6690b57cec5SDimitry Andric     g = loc;
6700b57cec5SDimitry Andric     if (g.name() != "*")
6710b57cec5SDimitry Andric         setlocale(LC_ALL, g.name().c_str());
6720b57cec5SDimitry Andric     return r;
6730b57cec5SDimitry Andric }
6740b57cec5SDimitry Andric 
6750b57cec5SDimitry Andric bool
6760b57cec5SDimitry Andric locale::has_facet(id& x) const
6770b57cec5SDimitry Andric {
6780b57cec5SDimitry Andric     return __locale_->has_facet(x.__get());
6790b57cec5SDimitry Andric }
6800b57cec5SDimitry Andric 
6810b57cec5SDimitry Andric const locale::facet*
6820b57cec5SDimitry Andric locale::use_facet(id& x) const
6830b57cec5SDimitry Andric {
6840b57cec5SDimitry Andric     return __locale_->use_facet(x.__get());
6850b57cec5SDimitry Andric }
6860b57cec5SDimitry Andric 
6870b57cec5SDimitry Andric bool
6880b57cec5SDimitry Andric locale::operator==(const locale& y) const
6890b57cec5SDimitry Andric {
6900b57cec5SDimitry Andric     return (__locale_ == y.__locale_)
6910b57cec5SDimitry Andric         || (__locale_->name() != "*" && __locale_->name() == y.__locale_->name());
6920b57cec5SDimitry Andric }
6930b57cec5SDimitry Andric 
6940b57cec5SDimitry Andric // locale::facet
6950b57cec5SDimitry Andric 
6960b57cec5SDimitry Andric locale::facet::~facet()
6970b57cec5SDimitry Andric {
6980b57cec5SDimitry Andric }
6990b57cec5SDimitry Andric 
7000b57cec5SDimitry Andric void
701fe6060f1SDimitry Andric locale::facet::__on_zero_shared() noexcept
7020b57cec5SDimitry Andric {
7030b57cec5SDimitry Andric     delete this;
7040b57cec5SDimitry Andric }
7050b57cec5SDimitry Andric 
7060b57cec5SDimitry Andric // locale::id
7070b57cec5SDimitry Andric 
7080b57cec5SDimitry Andric int32_t locale::id::__next_id = 0;
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric namespace
7110b57cec5SDimitry Andric {
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric class __fake_bind
7140b57cec5SDimitry Andric {
7150b57cec5SDimitry Andric     locale::id* id_;
7160b57cec5SDimitry Andric     void (locale::id::* pmf_)();
7170b57cec5SDimitry Andric public:
7180b57cec5SDimitry Andric     __fake_bind(void (locale::id::* pmf)(), locale::id* id)
7190b57cec5SDimitry Andric         : id_(id), pmf_(pmf) {}
7200b57cec5SDimitry Andric 
7210b57cec5SDimitry Andric     void operator()() const
7220b57cec5SDimitry Andric     {
7230b57cec5SDimitry Andric         (id_->*pmf_)();
7240b57cec5SDimitry Andric     }
7250b57cec5SDimitry Andric };
7260b57cec5SDimitry Andric 
7270b57cec5SDimitry Andric }
7280b57cec5SDimitry Andric 
7290b57cec5SDimitry Andric long
7300b57cec5SDimitry Andric locale::id::__get()
7310b57cec5SDimitry Andric {
7320b57cec5SDimitry Andric     call_once(__flag_, __fake_bind(&locale::id::__init, this));
7330b57cec5SDimitry Andric     return __id_ - 1;
7340b57cec5SDimitry Andric }
7350b57cec5SDimitry Andric 
7360b57cec5SDimitry Andric void
7370b57cec5SDimitry Andric locale::id::__init()
7380b57cec5SDimitry Andric {
7390b57cec5SDimitry Andric     __id_ = __libcpp_atomic_add(&__next_id, 1);
7400b57cec5SDimitry Andric }
7410b57cec5SDimitry Andric 
7420b57cec5SDimitry Andric // template <> class collate_byname<char>
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric collate_byname<char>::collate_byname(const char* n, size_t refs)
7450b57cec5SDimitry Andric     : collate<char>(refs),
7460b57cec5SDimitry Andric       __l(newlocale(LC_ALL_MASK, n, 0))
7470b57cec5SDimitry Andric {
7480b57cec5SDimitry Andric     if (__l == 0)
7490b57cec5SDimitry Andric         __throw_runtime_error("collate_byname<char>::collate_byname"
7500b57cec5SDimitry Andric                             " failed to construct for " + string(n));
7510b57cec5SDimitry Andric }
7520b57cec5SDimitry Andric 
7530b57cec5SDimitry Andric collate_byname<char>::collate_byname(const string& name, size_t refs)
7540b57cec5SDimitry Andric     : collate<char>(refs),
7550b57cec5SDimitry Andric       __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
7560b57cec5SDimitry Andric {
7570b57cec5SDimitry Andric     if (__l == 0)
7580b57cec5SDimitry Andric         __throw_runtime_error("collate_byname<char>::collate_byname"
7590b57cec5SDimitry Andric                             " failed to construct for " + name);
7600b57cec5SDimitry Andric }
7610b57cec5SDimitry Andric 
7620b57cec5SDimitry Andric collate_byname<char>::~collate_byname()
7630b57cec5SDimitry Andric {
7640b57cec5SDimitry Andric     freelocale(__l);
7650b57cec5SDimitry Andric }
7660b57cec5SDimitry Andric 
7670b57cec5SDimitry Andric int
7680b57cec5SDimitry Andric collate_byname<char>::do_compare(const char_type* __lo1, const char_type* __hi1,
7690b57cec5SDimitry Andric                                  const char_type* __lo2, const char_type* __hi2) const
7700b57cec5SDimitry Andric {
7710b57cec5SDimitry Andric     string_type lhs(__lo1, __hi1);
7720b57cec5SDimitry Andric     string_type rhs(__lo2, __hi2);
7730b57cec5SDimitry Andric     int r = strcoll_l(lhs.c_str(), rhs.c_str(), __l);
7740b57cec5SDimitry Andric     if (r < 0)
7750b57cec5SDimitry Andric         return -1;
7760b57cec5SDimitry Andric     if (r > 0)
7770b57cec5SDimitry Andric         return 1;
7780b57cec5SDimitry Andric     return r;
7790b57cec5SDimitry Andric }
7800b57cec5SDimitry Andric 
7810b57cec5SDimitry Andric collate_byname<char>::string_type
7820b57cec5SDimitry Andric collate_byname<char>::do_transform(const char_type* lo, const char_type* hi) const
7830b57cec5SDimitry Andric {
7840b57cec5SDimitry Andric     const string_type in(lo, hi);
7850b57cec5SDimitry Andric     string_type out(strxfrm_l(0, in.c_str(), 0, __l), char());
7860b57cec5SDimitry Andric     strxfrm_l(const_cast<char*>(out.c_str()), in.c_str(), out.size()+1, __l);
7870b57cec5SDimitry Andric     return out;
7880b57cec5SDimitry Andric }
7890b57cec5SDimitry Andric 
7900b57cec5SDimitry Andric // template <> class collate_byname<wchar_t>
7910b57cec5SDimitry Andric 
792349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
7930b57cec5SDimitry Andric collate_byname<wchar_t>::collate_byname(const char* n, size_t refs)
7940b57cec5SDimitry Andric     : collate<wchar_t>(refs),
7950b57cec5SDimitry Andric       __l(newlocale(LC_ALL_MASK, n, 0))
7960b57cec5SDimitry Andric {
7970b57cec5SDimitry Andric     if (__l == 0)
7980b57cec5SDimitry Andric         __throw_runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)"
7990b57cec5SDimitry Andric                             " failed to construct for " + string(n));
8000b57cec5SDimitry Andric }
8010b57cec5SDimitry Andric 
8020b57cec5SDimitry Andric collate_byname<wchar_t>::collate_byname(const string& name, size_t refs)
8030b57cec5SDimitry Andric     : collate<wchar_t>(refs),
8040b57cec5SDimitry Andric       __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
8050b57cec5SDimitry Andric {
8060b57cec5SDimitry Andric     if (__l == 0)
8070b57cec5SDimitry Andric         __throw_runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)"
8080b57cec5SDimitry Andric                             " failed to construct for " + name);
8090b57cec5SDimitry Andric }
8100b57cec5SDimitry Andric 
8110b57cec5SDimitry Andric collate_byname<wchar_t>::~collate_byname()
8120b57cec5SDimitry Andric {
8130b57cec5SDimitry Andric     freelocale(__l);
8140b57cec5SDimitry Andric }
8150b57cec5SDimitry Andric 
8160b57cec5SDimitry Andric int
8170b57cec5SDimitry Andric collate_byname<wchar_t>::do_compare(const char_type* __lo1, const char_type* __hi1,
8180b57cec5SDimitry Andric                                  const char_type* __lo2, const char_type* __hi2) const
8190b57cec5SDimitry Andric {
8200b57cec5SDimitry Andric     string_type lhs(__lo1, __hi1);
8210b57cec5SDimitry Andric     string_type rhs(__lo2, __hi2);
8220b57cec5SDimitry Andric     int r = wcscoll_l(lhs.c_str(), rhs.c_str(), __l);
8230b57cec5SDimitry Andric     if (r < 0)
8240b57cec5SDimitry Andric         return -1;
8250b57cec5SDimitry Andric     if (r > 0)
8260b57cec5SDimitry Andric         return 1;
8270b57cec5SDimitry Andric     return r;
8280b57cec5SDimitry Andric }
8290b57cec5SDimitry Andric 
8300b57cec5SDimitry Andric collate_byname<wchar_t>::string_type
8310b57cec5SDimitry Andric collate_byname<wchar_t>::do_transform(const char_type* lo, const char_type* hi) const
8320b57cec5SDimitry Andric {
8330b57cec5SDimitry Andric     const string_type in(lo, hi);
8340b57cec5SDimitry Andric     string_type out(wcsxfrm_l(0, in.c_str(), 0, __l), wchar_t());
8350b57cec5SDimitry Andric     wcsxfrm_l(const_cast<wchar_t*>(out.c_str()), in.c_str(), out.size()+1, __l);
8360b57cec5SDimitry Andric     return out;
8370b57cec5SDimitry Andric }
838349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
8390b57cec5SDimitry Andric 
8400b57cec5SDimitry Andric const ctype_base::mask ctype_base::space;
8410b57cec5SDimitry Andric const ctype_base::mask ctype_base::print;
8420b57cec5SDimitry Andric const ctype_base::mask ctype_base::cntrl;
8430b57cec5SDimitry Andric const ctype_base::mask ctype_base::upper;
8440b57cec5SDimitry Andric const ctype_base::mask ctype_base::lower;
8450b57cec5SDimitry Andric const ctype_base::mask ctype_base::alpha;
8460b57cec5SDimitry Andric const ctype_base::mask ctype_base::digit;
8470b57cec5SDimitry Andric const ctype_base::mask ctype_base::punct;
8480b57cec5SDimitry Andric const ctype_base::mask ctype_base::xdigit;
8490b57cec5SDimitry Andric const ctype_base::mask ctype_base::blank;
8500b57cec5SDimitry Andric const ctype_base::mask ctype_base::alnum;
8510b57cec5SDimitry Andric const ctype_base::mask ctype_base::graph;
8520b57cec5SDimitry Andric 
853349cc55cSDimitry Andric // template <> class ctype<wchar_t>;
854349cc55cSDimitry Andric 
855349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
8560b57cec5SDimitry Andric locale::id ctype<wchar_t>::id;
8570b57cec5SDimitry Andric 
8580b57cec5SDimitry Andric ctype<wchar_t>::~ctype()
8590b57cec5SDimitry Andric {
8600b57cec5SDimitry Andric }
8610b57cec5SDimitry Andric 
8620b57cec5SDimitry Andric bool
8630b57cec5SDimitry Andric ctype<wchar_t>::do_is(mask m, char_type c) const
8640b57cec5SDimitry Andric {
8650b57cec5SDimitry Andric     return isascii(c) ? (ctype<char>::classic_table()[c] & m) != 0 : false;
8660b57cec5SDimitry Andric }
8670b57cec5SDimitry Andric 
8680b57cec5SDimitry Andric const wchar_t*
8690b57cec5SDimitry Andric ctype<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
8700b57cec5SDimitry Andric {
8710b57cec5SDimitry Andric     for (; low != high; ++low, ++vec)
8720b57cec5SDimitry Andric         *vec = static_cast<mask>(isascii(*low) ?
8730b57cec5SDimitry Andric                                    ctype<char>::classic_table()[*low] : 0);
8740b57cec5SDimitry Andric     return low;
8750b57cec5SDimitry Andric }
8760b57cec5SDimitry Andric 
8770b57cec5SDimitry Andric const wchar_t*
8780b57cec5SDimitry Andric ctype<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const
8790b57cec5SDimitry Andric {
8800b57cec5SDimitry Andric     for (; low != high; ++low)
8810b57cec5SDimitry Andric         if (isascii(*low) && (ctype<char>::classic_table()[*low] & m))
8820b57cec5SDimitry Andric             break;
8830b57cec5SDimitry Andric     return low;
8840b57cec5SDimitry Andric }
8850b57cec5SDimitry Andric 
8860b57cec5SDimitry Andric const wchar_t*
8870b57cec5SDimitry Andric ctype<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const
8880b57cec5SDimitry Andric {
8890b57cec5SDimitry Andric     for (; low != high; ++low)
8900b57cec5SDimitry Andric         if (!(isascii(*low) && (ctype<char>::classic_table()[*low] & m)))
8910b57cec5SDimitry Andric             break;
8920b57cec5SDimitry Andric     return low;
8930b57cec5SDimitry Andric }
8940b57cec5SDimitry Andric 
8950b57cec5SDimitry Andric wchar_t
8960b57cec5SDimitry Andric ctype<wchar_t>::do_toupper(char_type c) const
8970b57cec5SDimitry Andric {
8980b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
8990b57cec5SDimitry Andric     return isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c;
9000b57cec5SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
901*04eeddc0SDimitry Andric       defined(__NetBSD__) || defined(__MVS__)
9020b57cec5SDimitry Andric     return isascii(c) ? ctype<char>::__classic_upper_table()[c] : c;
9030b57cec5SDimitry Andric #else
9040b57cec5SDimitry Andric     return (isascii(c) && iswlower_l(c, _LIBCPP_GET_C_LOCALE)) ? c-L'a'+L'A' : c;
9050b57cec5SDimitry Andric #endif
9060b57cec5SDimitry Andric }
9070b57cec5SDimitry Andric 
9080b57cec5SDimitry Andric const wchar_t*
9090b57cec5SDimitry Andric ctype<wchar_t>::do_toupper(char_type* low, const char_type* high) const
9100b57cec5SDimitry Andric {
9110b57cec5SDimitry Andric     for (; low != high; ++low)
9120b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
9130b57cec5SDimitry Andric         *low = isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low;
9140b57cec5SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
915*04eeddc0SDimitry Andric       defined(__NetBSD__) || defined(__MVS__)
9160b57cec5SDimitry Andric         *low = isascii(*low) ? ctype<char>::__classic_upper_table()[*low]
9170b57cec5SDimitry Andric                              : *low;
9180b57cec5SDimitry Andric #else
9190b57cec5SDimitry Andric         *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? (*low-L'a'+L'A') : *low;
9200b57cec5SDimitry Andric #endif
9210b57cec5SDimitry Andric     return low;
9220b57cec5SDimitry Andric }
9230b57cec5SDimitry Andric 
9240b57cec5SDimitry Andric wchar_t
9250b57cec5SDimitry Andric ctype<wchar_t>::do_tolower(char_type c) const
9260b57cec5SDimitry Andric {
9270b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
9280b57cec5SDimitry Andric     return isascii(c) ? _DefaultRuneLocale.__maplower[c] : c;
9290b57cec5SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
930*04eeddc0SDimitry Andric       defined(__NetBSD__) || defined(__MVS__)
9310b57cec5SDimitry Andric     return isascii(c) ? ctype<char>::__classic_lower_table()[c] : c;
9320b57cec5SDimitry Andric #else
9330b57cec5SDimitry Andric     return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c-L'A'+'a' : c;
9340b57cec5SDimitry Andric #endif
9350b57cec5SDimitry Andric }
9360b57cec5SDimitry Andric 
9370b57cec5SDimitry Andric const wchar_t*
9380b57cec5SDimitry Andric ctype<wchar_t>::do_tolower(char_type* low, const char_type* high) const
9390b57cec5SDimitry Andric {
9400b57cec5SDimitry Andric     for (; low != high; ++low)
9410b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
9420b57cec5SDimitry Andric         *low = isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low;
9430b57cec5SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
944*04eeddc0SDimitry Andric       defined(__NetBSD__) || defined(__MVS__)
9450b57cec5SDimitry Andric         *low = isascii(*low) ? ctype<char>::__classic_lower_table()[*low]
9460b57cec5SDimitry Andric                              : *low;
9470b57cec5SDimitry Andric #else
9480b57cec5SDimitry Andric         *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-L'A'+L'a' : *low;
9490b57cec5SDimitry Andric #endif
9500b57cec5SDimitry Andric     return low;
9510b57cec5SDimitry Andric }
9520b57cec5SDimitry Andric 
9530b57cec5SDimitry Andric wchar_t
9540b57cec5SDimitry Andric ctype<wchar_t>::do_widen(char c) const
9550b57cec5SDimitry Andric {
9560b57cec5SDimitry Andric     return c;
9570b57cec5SDimitry Andric }
9580b57cec5SDimitry Andric 
9590b57cec5SDimitry Andric const char*
9600b57cec5SDimitry Andric ctype<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const
9610b57cec5SDimitry Andric {
9620b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
9630b57cec5SDimitry Andric         *dest = *low;
9640b57cec5SDimitry Andric     return low;
9650b57cec5SDimitry Andric }
9660b57cec5SDimitry Andric 
9670b57cec5SDimitry Andric char
9680b57cec5SDimitry Andric ctype<wchar_t>::do_narrow(char_type c, char dfault) const
9690b57cec5SDimitry Andric {
9700b57cec5SDimitry Andric     if (isascii(c))
9710b57cec5SDimitry Andric         return static_cast<char>(c);
9720b57cec5SDimitry Andric     return dfault;
9730b57cec5SDimitry Andric }
9740b57cec5SDimitry Andric 
9750b57cec5SDimitry Andric const wchar_t*
9760b57cec5SDimitry Andric ctype<wchar_t>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
9770b57cec5SDimitry Andric {
9780b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
9790b57cec5SDimitry Andric         if (isascii(*low))
9800b57cec5SDimitry Andric             *dest = static_cast<char>(*low);
9810b57cec5SDimitry Andric         else
9820b57cec5SDimitry Andric             *dest = dfault;
9830b57cec5SDimitry Andric     return low;
9840b57cec5SDimitry Andric }
985349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
9860b57cec5SDimitry Andric 
9870b57cec5SDimitry Andric // template <> class ctype<char>;
9880b57cec5SDimitry Andric 
9890b57cec5SDimitry Andric locale::id ctype<char>::id;
9900b57cec5SDimitry Andric 
991349cc55cSDimitry Andric const size_t ctype<char>::table_size;
992349cc55cSDimitry Andric 
9930b57cec5SDimitry Andric ctype<char>::ctype(const mask* tab, bool del, size_t refs)
9940b57cec5SDimitry Andric     : locale::facet(refs),
9950b57cec5SDimitry Andric       __tab_(tab),
9960b57cec5SDimitry Andric       __del_(del)
9970b57cec5SDimitry Andric {
9980b57cec5SDimitry Andric   if (__tab_ == 0)
9990b57cec5SDimitry Andric       __tab_ = classic_table();
10000b57cec5SDimitry Andric }
10010b57cec5SDimitry Andric 
10020b57cec5SDimitry Andric ctype<char>::~ctype()
10030b57cec5SDimitry Andric {
10040b57cec5SDimitry Andric     if (__tab_ && __del_)
10050b57cec5SDimitry Andric         delete [] __tab_;
10060b57cec5SDimitry Andric }
10070b57cec5SDimitry Andric 
10080b57cec5SDimitry Andric char
10090b57cec5SDimitry Andric ctype<char>::do_toupper(char_type c) const
10100b57cec5SDimitry Andric {
10110b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
10120b57cec5SDimitry Andric     return isascii(c) ?
10130b57cec5SDimitry Andric       static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(c)]) : c;
10140b57cec5SDimitry Andric #elif defined(__NetBSD__)
10150b57cec5SDimitry Andric     return static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]);
1016*04eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
10170b57cec5SDimitry Andric     return isascii(c) ?
10180b57cec5SDimitry Andric       static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]) : c;
10190b57cec5SDimitry Andric #else
10200b57cec5SDimitry Andric     return (isascii(c) && islower_l(c, _LIBCPP_GET_C_LOCALE)) ? c-'a'+'A' : c;
10210b57cec5SDimitry Andric #endif
10220b57cec5SDimitry Andric }
10230b57cec5SDimitry Andric 
10240b57cec5SDimitry Andric const char*
10250b57cec5SDimitry Andric ctype<char>::do_toupper(char_type* low, const char_type* high) const
10260b57cec5SDimitry Andric {
10270b57cec5SDimitry Andric     for (; low != high; ++low)
10280b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
10290b57cec5SDimitry Andric         *low = isascii(*low) ?
10300b57cec5SDimitry Andric           static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(*low)]) : *low;
10310b57cec5SDimitry Andric #elif defined(__NetBSD__)
10320b57cec5SDimitry Andric         *low = static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(*low)]);
1033*04eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
10340b57cec5SDimitry Andric         *low = isascii(*low) ?
10350b57cec5SDimitry Andric           static_cast<char>(__classic_upper_table()[static_cast<size_t>(*low)]) : *low;
10360b57cec5SDimitry Andric #else
10370b57cec5SDimitry Andric         *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-'a'+'A' : *low;
10380b57cec5SDimitry Andric #endif
10390b57cec5SDimitry Andric     return low;
10400b57cec5SDimitry Andric }
10410b57cec5SDimitry Andric 
10420b57cec5SDimitry Andric char
10430b57cec5SDimitry Andric ctype<char>::do_tolower(char_type c) const
10440b57cec5SDimitry Andric {
10450b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
10460b57cec5SDimitry Andric     return isascii(c) ?
10470b57cec5SDimitry Andric       static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(c)]) : c;
10480b57cec5SDimitry Andric #elif defined(__NetBSD__)
10490b57cec5SDimitry Andric     return static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(c)]);
1050*04eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
10510b57cec5SDimitry Andric     return isascii(c) ?
10520b57cec5SDimitry Andric       static_cast<char>(__classic_lower_table()[static_cast<size_t>(c)]) : c;
10530b57cec5SDimitry Andric #else
10540b57cec5SDimitry Andric     return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c-'A'+'a' : c;
10550b57cec5SDimitry Andric #endif
10560b57cec5SDimitry Andric }
10570b57cec5SDimitry Andric 
10580b57cec5SDimitry Andric const char*
10590b57cec5SDimitry Andric ctype<char>::do_tolower(char_type* low, const char_type* high) const
10600b57cec5SDimitry Andric {
10610b57cec5SDimitry Andric     for (; low != high; ++low)
10620b57cec5SDimitry Andric #ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
10630b57cec5SDimitry Andric         *low = isascii(*low) ? static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(*low)]) : *low;
10640b57cec5SDimitry Andric #elif defined(__NetBSD__)
10650b57cec5SDimitry Andric         *low = static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(*low)]);
1066*04eeddc0SDimitry Andric #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || defined(__MVS__)
10670b57cec5SDimitry Andric         *low = isascii(*low) ? static_cast<char>(__classic_lower_table()[static_cast<size_t>(*low)]) : *low;
10680b57cec5SDimitry Andric #else
10690b57cec5SDimitry Andric         *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-'A'+'a' : *low;
10700b57cec5SDimitry Andric #endif
10710b57cec5SDimitry Andric     return low;
10720b57cec5SDimitry Andric }
10730b57cec5SDimitry Andric 
10740b57cec5SDimitry Andric char
10750b57cec5SDimitry Andric ctype<char>::do_widen(char c) const
10760b57cec5SDimitry Andric {
10770b57cec5SDimitry Andric     return c;
10780b57cec5SDimitry Andric }
10790b57cec5SDimitry Andric 
10800b57cec5SDimitry Andric const char*
10810b57cec5SDimitry Andric ctype<char>::do_widen(const char* low, const char* high, char_type* dest) const
10820b57cec5SDimitry Andric {
10830b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
10840b57cec5SDimitry Andric         *dest = *low;
10850b57cec5SDimitry Andric     return low;
10860b57cec5SDimitry Andric }
10870b57cec5SDimitry Andric 
10880b57cec5SDimitry Andric char
10890b57cec5SDimitry Andric ctype<char>::do_narrow(char_type c, char dfault) const
10900b57cec5SDimitry Andric {
10910b57cec5SDimitry Andric     if (isascii(c))
10920b57cec5SDimitry Andric         return static_cast<char>(c);
10930b57cec5SDimitry Andric     return dfault;
10940b57cec5SDimitry Andric }
10950b57cec5SDimitry Andric 
10960b57cec5SDimitry Andric const char*
10970b57cec5SDimitry Andric ctype<char>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
10980b57cec5SDimitry Andric {
10990b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
11000b57cec5SDimitry Andric         if (isascii(*low))
11010b57cec5SDimitry Andric             *dest = *low;
11020b57cec5SDimitry Andric         else
11030b57cec5SDimitry Andric             *dest = dfault;
11040b57cec5SDimitry Andric     return low;
11050b57cec5SDimitry Andric }
11060b57cec5SDimitry Andric 
11070b57cec5SDimitry Andric #if defined(__EMSCRIPTEN__)
11080b57cec5SDimitry Andric extern "C" const unsigned short ** __ctype_b_loc();
11090b57cec5SDimitry Andric extern "C" const int ** __ctype_tolower_loc();
11100b57cec5SDimitry Andric extern "C" const int ** __ctype_toupper_loc();
11110b57cec5SDimitry Andric #endif
11120b57cec5SDimitry Andric 
11130b57cec5SDimitry Andric #ifdef _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE
11140b57cec5SDimitry Andric const ctype<char>::mask*
1115fe6060f1SDimitry Andric ctype<char>::classic_table() noexcept
11160b57cec5SDimitry Andric {
11170b57cec5SDimitry Andric     static _LIBCPP_CONSTEXPR const ctype<char>::mask builtin_table[table_size] = {
11180b57cec5SDimitry Andric         cntrl,                          cntrl,
11190b57cec5SDimitry Andric         cntrl,                          cntrl,
11200b57cec5SDimitry Andric         cntrl,                          cntrl,
11210b57cec5SDimitry Andric         cntrl,                          cntrl,
11220b57cec5SDimitry Andric         cntrl,                          cntrl | space | blank,
11230b57cec5SDimitry Andric         cntrl | space,                  cntrl | space,
11240b57cec5SDimitry Andric         cntrl | space,                  cntrl | space,
11250b57cec5SDimitry Andric         cntrl,                          cntrl,
11260b57cec5SDimitry Andric         cntrl,                          cntrl,
11270b57cec5SDimitry Andric         cntrl,                          cntrl,
11280b57cec5SDimitry Andric         cntrl,                          cntrl,
11290b57cec5SDimitry Andric         cntrl,                          cntrl,
11300b57cec5SDimitry Andric         cntrl,                          cntrl,
11310b57cec5SDimitry Andric         cntrl,                          cntrl,
11320b57cec5SDimitry Andric         cntrl,                          cntrl,
11330b57cec5SDimitry Andric         cntrl,                          cntrl,
11340b57cec5SDimitry Andric         space | blank | print,          punct | print,
11350b57cec5SDimitry Andric         punct | print,                  punct | print,
11360b57cec5SDimitry Andric         punct | print,                  punct | print,
11370b57cec5SDimitry Andric         punct | print,                  punct | print,
11380b57cec5SDimitry Andric         punct | print,                  punct | print,
11390b57cec5SDimitry Andric         punct | print,                  punct | print,
11400b57cec5SDimitry Andric         punct | print,                  punct | print,
11410b57cec5SDimitry Andric         punct | print,                  punct | print,
11420b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
11430b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
11440b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
11450b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
11460b57cec5SDimitry Andric         digit | print | xdigit,         digit | print | xdigit,
11470b57cec5SDimitry Andric         punct | print,                  punct | print,
11480b57cec5SDimitry Andric         punct | print,                  punct | print,
11490b57cec5SDimitry Andric         punct | print,                  punct | print,
11500b57cec5SDimitry Andric         punct | print,                  upper | xdigit | print | alpha,
11510b57cec5SDimitry Andric         upper | xdigit | print | alpha, upper | xdigit | print | alpha,
11520b57cec5SDimitry Andric         upper | xdigit | print | alpha, upper | xdigit | print | alpha,
11530b57cec5SDimitry Andric         upper | xdigit | print | alpha, upper | print | alpha,
11540b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11550b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11560b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11570b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11580b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11590b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11600b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11610b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11620b57cec5SDimitry Andric         upper | print | alpha,          upper | print | alpha,
11630b57cec5SDimitry Andric         upper | print | alpha,          punct | print,
11640b57cec5SDimitry Andric         punct | print,                  punct | print,
11650b57cec5SDimitry Andric         punct | print,                  punct | print,
11660b57cec5SDimitry Andric         punct | print,                  lower | xdigit | print | alpha,
11670b57cec5SDimitry Andric         lower | xdigit | print | alpha, lower | xdigit | print | alpha,
11680b57cec5SDimitry Andric         lower | xdigit | print | alpha, lower | xdigit | print | alpha,
11690b57cec5SDimitry Andric         lower | xdigit | print | alpha, lower | print | alpha,
11700b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11710b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11720b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11730b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11740b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11750b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11760b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11770b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11780b57cec5SDimitry Andric         lower | print | alpha,          lower | print | alpha,
11790b57cec5SDimitry Andric         lower | print | alpha,          punct | print,
11800b57cec5SDimitry Andric         punct | print,                  punct | print,
11810b57cec5SDimitry Andric         punct | print,                  cntrl,
11820b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11830b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11840b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11850b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11860b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11870b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11880b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11890b57cec5SDimitry Andric         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
11900b57cec5SDimitry Andric     };
11910b57cec5SDimitry Andric     return builtin_table;
11920b57cec5SDimitry Andric }
11930b57cec5SDimitry Andric #else
11940b57cec5SDimitry Andric const ctype<char>::mask*
1195fe6060f1SDimitry Andric ctype<char>::classic_table() noexcept
11960b57cec5SDimitry Andric {
11970b57cec5SDimitry Andric #if defined(__APPLE__) || defined(__FreeBSD__)
11980b57cec5SDimitry Andric     return _DefaultRuneLocale.__runetype;
11990b57cec5SDimitry Andric #elif defined(__NetBSD__)
12000b57cec5SDimitry Andric     return _C_ctype_tab_ + 1;
12010b57cec5SDimitry Andric #elif defined(__GLIBC__)
12020b57cec5SDimitry Andric     return _LIBCPP_GET_C_LOCALE->__ctype_b;
1203fe6060f1SDimitry Andric #elif defined(__sun__)
12040b57cec5SDimitry Andric     return __ctype_mask;
12050b57cec5SDimitry Andric #elif defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
12060b57cec5SDimitry Andric     return __pctype_func();
12070b57cec5SDimitry Andric #elif defined(__EMSCRIPTEN__)
12080b57cec5SDimitry Andric     return *__ctype_b_loc();
12090b57cec5SDimitry Andric #elif defined(_NEWLIB_VERSION)
12100b57cec5SDimitry Andric     // Newlib has a 257-entry table in ctype_.c, where (char)0 starts at [1].
12110b57cec5SDimitry Andric     return _ctype_ + 1;
12120b57cec5SDimitry Andric #elif defined(_AIX)
12130b57cec5SDimitry Andric     return (const unsigned int *)__lc_ctype_ptr->obj->mask;
1214*04eeddc0SDimitry Andric #elif defined(__MVS__)
1215*04eeddc0SDimitry Andric # if defined(__NATIVE_ASCII_F)
1216*04eeddc0SDimitry Andric     return const_cast<const ctype<char>::mask*> (__OBJ_DATA(__lc_ctype_a)->mask);
1217*04eeddc0SDimitry Andric # else
1218*04eeddc0SDimitry Andric     return const_cast<const ctype<char>::mask*> (__ctypec);
1219*04eeddc0SDimitry Andric # endif
12200b57cec5SDimitry Andric #else
12210b57cec5SDimitry Andric     // Platform not supported: abort so the person doing the port knows what to
12220b57cec5SDimitry Andric     // fix
12230b57cec5SDimitry Andric # warning  ctype<char>::classic_table() is not implemented
12240b57cec5SDimitry Andric     printf("ctype<char>::classic_table() is not implemented\n");
12250b57cec5SDimitry Andric     abort();
12260b57cec5SDimitry Andric     return NULL;
12270b57cec5SDimitry Andric #endif
12280b57cec5SDimitry Andric }
12290b57cec5SDimitry Andric #endif
12300b57cec5SDimitry Andric 
12310b57cec5SDimitry Andric #if defined(__GLIBC__)
12320b57cec5SDimitry Andric const int*
1233fe6060f1SDimitry Andric ctype<char>::__classic_lower_table() noexcept
12340b57cec5SDimitry Andric {
12350b57cec5SDimitry Andric     return _LIBCPP_GET_C_LOCALE->__ctype_tolower;
12360b57cec5SDimitry Andric }
12370b57cec5SDimitry Andric 
12380b57cec5SDimitry Andric const int*
1239fe6060f1SDimitry Andric ctype<char>::__classic_upper_table() noexcept
12400b57cec5SDimitry Andric {
12410b57cec5SDimitry Andric     return _LIBCPP_GET_C_LOCALE->__ctype_toupper;
12420b57cec5SDimitry Andric }
1243e8d8bef9SDimitry Andric #elif defined(__NetBSD__)
12440b57cec5SDimitry Andric const short*
1245fe6060f1SDimitry Andric ctype<char>::__classic_lower_table() noexcept
12460b57cec5SDimitry Andric {
12470b57cec5SDimitry Andric     return _C_tolower_tab_ + 1;
12480b57cec5SDimitry Andric }
12490b57cec5SDimitry Andric 
12500b57cec5SDimitry Andric const short*
1251fe6060f1SDimitry Andric ctype<char>::__classic_upper_table() noexcept
12520b57cec5SDimitry Andric {
12530b57cec5SDimitry Andric     return _C_toupper_tab_ + 1;
12540b57cec5SDimitry Andric }
12550b57cec5SDimitry Andric 
12560b57cec5SDimitry Andric #elif defined(__EMSCRIPTEN__)
12570b57cec5SDimitry Andric const int*
1258fe6060f1SDimitry Andric ctype<char>::__classic_lower_table() noexcept
12590b57cec5SDimitry Andric {
12600b57cec5SDimitry Andric     return *__ctype_tolower_loc();
12610b57cec5SDimitry Andric }
12620b57cec5SDimitry Andric 
12630b57cec5SDimitry Andric const int*
1264fe6060f1SDimitry Andric ctype<char>::__classic_upper_table() noexcept
12650b57cec5SDimitry Andric {
12660b57cec5SDimitry Andric     return *__ctype_toupper_loc();
12670b57cec5SDimitry Andric }
1268*04eeddc0SDimitry Andric #elif defined(__MVS__)
1269*04eeddc0SDimitry Andric const unsigned short*
1270*04eeddc0SDimitry Andric ctype<char>::__classic_lower_table() _NOEXCEPT
1271*04eeddc0SDimitry Andric {
1272*04eeddc0SDimitry Andric # if defined(__NATIVE_ASCII_F)
1273*04eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__OBJ_DATA(__lc_ctype_a)->lower);
1274*04eeddc0SDimitry Andric # else
1275*04eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__ctype + __TOLOWER_INDEX);
1276*04eeddc0SDimitry Andric # endif
1277*04eeddc0SDimitry Andric }
1278*04eeddc0SDimitry Andric const unsigned short *
1279*04eeddc0SDimitry Andric ctype<char>::__classic_upper_table() _NOEXCEPT
1280*04eeddc0SDimitry Andric {
1281*04eeddc0SDimitry Andric # if defined(__NATIVE_ASCII_F)
1282*04eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__OBJ_DATA(__lc_ctype_a)->upper);
1283*04eeddc0SDimitry Andric # else
1284*04eeddc0SDimitry Andric   return const_cast<const unsigned short*>(__ctype + __TOUPPER_INDEX);
1285*04eeddc0SDimitry Andric # endif
1286*04eeddc0SDimitry Andric }
1287*04eeddc0SDimitry Andric #endif // __GLIBC__ || __NETBSD__ || __EMSCRIPTEN__ || __MVS__
12880b57cec5SDimitry Andric 
12890b57cec5SDimitry Andric // template <> class ctype_byname<char>
12900b57cec5SDimitry Andric 
12910b57cec5SDimitry Andric ctype_byname<char>::ctype_byname(const char* name, size_t refs)
12920b57cec5SDimitry Andric     : ctype<char>(0, false, refs),
12930b57cec5SDimitry Andric       __l(newlocale(LC_ALL_MASK, name, 0))
12940b57cec5SDimitry Andric {
12950b57cec5SDimitry Andric     if (__l == 0)
12960b57cec5SDimitry Andric         __throw_runtime_error("ctype_byname<char>::ctype_byname"
12970b57cec5SDimitry Andric                             " failed to construct for " + string(name));
12980b57cec5SDimitry Andric }
12990b57cec5SDimitry Andric 
13000b57cec5SDimitry Andric ctype_byname<char>::ctype_byname(const string& name, size_t refs)
13010b57cec5SDimitry Andric     : ctype<char>(0, false, refs),
13020b57cec5SDimitry Andric       __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
13030b57cec5SDimitry Andric {
13040b57cec5SDimitry Andric     if (__l == 0)
13050b57cec5SDimitry Andric         __throw_runtime_error("ctype_byname<char>::ctype_byname"
13060b57cec5SDimitry Andric                             " failed to construct for " + name);
13070b57cec5SDimitry Andric }
13080b57cec5SDimitry Andric 
13090b57cec5SDimitry Andric ctype_byname<char>::~ctype_byname()
13100b57cec5SDimitry Andric {
13110b57cec5SDimitry Andric     freelocale(__l);
13120b57cec5SDimitry Andric }
13130b57cec5SDimitry Andric 
13140b57cec5SDimitry Andric char
13150b57cec5SDimitry Andric ctype_byname<char>::do_toupper(char_type c) const
13160b57cec5SDimitry Andric {
13170b57cec5SDimitry Andric     return static_cast<char>(toupper_l(static_cast<unsigned char>(c), __l));
13180b57cec5SDimitry Andric }
13190b57cec5SDimitry Andric 
13200b57cec5SDimitry Andric const char*
13210b57cec5SDimitry Andric ctype_byname<char>::do_toupper(char_type* low, const char_type* high) const
13220b57cec5SDimitry Andric {
13230b57cec5SDimitry Andric     for (; low != high; ++low)
13240b57cec5SDimitry Andric         *low = static_cast<char>(toupper_l(static_cast<unsigned char>(*low), __l));
13250b57cec5SDimitry Andric     return low;
13260b57cec5SDimitry Andric }
13270b57cec5SDimitry Andric 
13280b57cec5SDimitry Andric char
13290b57cec5SDimitry Andric ctype_byname<char>::do_tolower(char_type c) const
13300b57cec5SDimitry Andric {
13310b57cec5SDimitry Andric     return static_cast<char>(tolower_l(static_cast<unsigned char>(c), __l));
13320b57cec5SDimitry Andric }
13330b57cec5SDimitry Andric 
13340b57cec5SDimitry Andric const char*
13350b57cec5SDimitry Andric ctype_byname<char>::do_tolower(char_type* low, const char_type* high) const
13360b57cec5SDimitry Andric {
13370b57cec5SDimitry Andric     for (; low != high; ++low)
13380b57cec5SDimitry Andric         *low = static_cast<char>(tolower_l(static_cast<unsigned char>(*low), __l));
13390b57cec5SDimitry Andric     return low;
13400b57cec5SDimitry Andric }
13410b57cec5SDimitry Andric 
13420b57cec5SDimitry Andric // template <> class ctype_byname<wchar_t>
13430b57cec5SDimitry Andric 
1344349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
13450b57cec5SDimitry Andric ctype_byname<wchar_t>::ctype_byname(const char* name, size_t refs)
13460b57cec5SDimitry Andric     : ctype<wchar_t>(refs),
13470b57cec5SDimitry Andric       __l(newlocale(LC_ALL_MASK, name, 0))
13480b57cec5SDimitry Andric {
13490b57cec5SDimitry Andric     if (__l == 0)
13500b57cec5SDimitry Andric         __throw_runtime_error("ctype_byname<wchar_t>::ctype_byname"
13510b57cec5SDimitry Andric                             " failed to construct for " + string(name));
13520b57cec5SDimitry Andric }
13530b57cec5SDimitry Andric 
13540b57cec5SDimitry Andric ctype_byname<wchar_t>::ctype_byname(const string& name, size_t refs)
13550b57cec5SDimitry Andric     : ctype<wchar_t>(refs),
13560b57cec5SDimitry Andric       __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
13570b57cec5SDimitry Andric {
13580b57cec5SDimitry Andric     if (__l == 0)
13590b57cec5SDimitry Andric         __throw_runtime_error("ctype_byname<wchar_t>::ctype_byname"
13600b57cec5SDimitry Andric                             " failed to construct for " + name);
13610b57cec5SDimitry Andric }
13620b57cec5SDimitry Andric 
13630b57cec5SDimitry Andric ctype_byname<wchar_t>::~ctype_byname()
13640b57cec5SDimitry Andric {
13650b57cec5SDimitry Andric     freelocale(__l);
13660b57cec5SDimitry Andric }
13670b57cec5SDimitry Andric 
13680b57cec5SDimitry Andric bool
13690b57cec5SDimitry Andric ctype_byname<wchar_t>::do_is(mask m, char_type c) const
13700b57cec5SDimitry Andric {
13710b57cec5SDimitry Andric #ifdef _LIBCPP_WCTYPE_IS_MASK
13720b57cec5SDimitry Andric     return static_cast<bool>(iswctype_l(c, m, __l));
13730b57cec5SDimitry Andric #else
13740b57cec5SDimitry Andric     bool result = false;
13750b57cec5SDimitry Andric     wint_t ch = static_cast<wint_t>(c);
13760b57cec5SDimitry Andric     if ((m & space) == space) result |= (iswspace_l(ch, __l) != 0);
13770b57cec5SDimitry Andric     if ((m & print) == print) result |= (iswprint_l(ch, __l) != 0);
13780b57cec5SDimitry Andric     if ((m & cntrl) == cntrl) result |= (iswcntrl_l(ch, __l) != 0);
13790b57cec5SDimitry Andric     if ((m & upper) == upper) result |= (iswupper_l(ch, __l) != 0);
13800b57cec5SDimitry Andric     if ((m & lower) == lower) result |= (iswlower_l(ch, __l) != 0);
13810b57cec5SDimitry Andric     if ((m & alpha) == alpha) result |= (iswalpha_l(ch, __l) != 0);
13820b57cec5SDimitry Andric     if ((m & digit) == digit) result |= (iswdigit_l(ch, __l) != 0);
13830b57cec5SDimitry Andric     if ((m & punct) == punct) result |= (iswpunct_l(ch, __l) != 0);
13840b57cec5SDimitry Andric     if ((m & xdigit) == xdigit) result |= (iswxdigit_l(ch, __l) != 0);
13850b57cec5SDimitry Andric     if ((m & blank) == blank) result |= (iswblank_l(ch, __l) != 0);
13860b57cec5SDimitry Andric     return result;
13870b57cec5SDimitry Andric #endif
13880b57cec5SDimitry Andric }
13890b57cec5SDimitry Andric 
13900b57cec5SDimitry Andric const wchar_t*
13910b57cec5SDimitry Andric ctype_byname<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
13920b57cec5SDimitry Andric {
13930b57cec5SDimitry Andric     for (; low != high; ++low, ++vec)
13940b57cec5SDimitry Andric     {
13950b57cec5SDimitry Andric         if (isascii(*low))
13960b57cec5SDimitry Andric             *vec = static_cast<mask>(ctype<char>::classic_table()[*low]);
13970b57cec5SDimitry Andric         else
13980b57cec5SDimitry Andric         {
13990b57cec5SDimitry Andric             *vec = 0;
14000b57cec5SDimitry Andric             wint_t ch = static_cast<wint_t>(*low);
14010b57cec5SDimitry Andric             if (iswspace_l(ch, __l))
14020b57cec5SDimitry Andric                 *vec |= space;
14030b57cec5SDimitry Andric #ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT
14040b57cec5SDimitry Andric             if (iswprint_l(ch, __l))
14050b57cec5SDimitry Andric                 *vec |= print;
14060b57cec5SDimitry Andric #endif
14070b57cec5SDimitry Andric             if (iswcntrl_l(ch, __l))
14080b57cec5SDimitry Andric                 *vec |= cntrl;
14090b57cec5SDimitry Andric             if (iswupper_l(ch, __l))
14100b57cec5SDimitry Andric                 *vec |= upper;
14110b57cec5SDimitry Andric             if (iswlower_l(ch, __l))
14120b57cec5SDimitry Andric                 *vec |= lower;
14130b57cec5SDimitry Andric #ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA
14140b57cec5SDimitry Andric             if (iswalpha_l(ch, __l))
14150b57cec5SDimitry Andric                 *vec |= alpha;
14160b57cec5SDimitry Andric #endif
14170b57cec5SDimitry Andric             if (iswdigit_l(ch, __l))
14180b57cec5SDimitry Andric                 *vec |= digit;
14190b57cec5SDimitry Andric             if (iswpunct_l(ch, __l))
14200b57cec5SDimitry Andric                 *vec |= punct;
14210b57cec5SDimitry Andric #ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_XDIGIT
14220b57cec5SDimitry Andric             if (iswxdigit_l(ch, __l))
14230b57cec5SDimitry Andric                 *vec |= xdigit;
14240b57cec5SDimitry Andric #endif
14250b57cec5SDimitry Andric #if !defined(__sun__)
14260b57cec5SDimitry Andric             if (iswblank_l(ch, __l))
14270b57cec5SDimitry Andric                 *vec |= blank;
14280b57cec5SDimitry Andric #endif
14290b57cec5SDimitry Andric         }
14300b57cec5SDimitry Andric     }
14310b57cec5SDimitry Andric     return low;
14320b57cec5SDimitry Andric }
14330b57cec5SDimitry Andric 
14340b57cec5SDimitry Andric const wchar_t*
14350b57cec5SDimitry Andric ctype_byname<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const
14360b57cec5SDimitry Andric {
14370b57cec5SDimitry Andric     for (; low != high; ++low)
14380b57cec5SDimitry Andric     {
14390b57cec5SDimitry Andric #ifdef _LIBCPP_WCTYPE_IS_MASK
14400b57cec5SDimitry Andric         if (iswctype_l(*low, m, __l))
14410b57cec5SDimitry Andric             break;
14420b57cec5SDimitry Andric #else
14430b57cec5SDimitry Andric         wint_t ch = static_cast<wint_t>(*low);
14440b57cec5SDimitry Andric         if ((m & space) == space && iswspace_l(ch, __l)) break;
14450b57cec5SDimitry Andric         if ((m & print) == print && iswprint_l(ch, __l)) break;
14460b57cec5SDimitry Andric         if ((m & cntrl) == cntrl && iswcntrl_l(ch, __l)) break;
14470b57cec5SDimitry Andric         if ((m & upper) == upper && iswupper_l(ch, __l)) break;
14480b57cec5SDimitry Andric         if ((m & lower) == lower && iswlower_l(ch, __l)) break;
14490b57cec5SDimitry Andric         if ((m & alpha) == alpha && iswalpha_l(ch, __l)) break;
14500b57cec5SDimitry Andric         if ((m & digit) == digit && iswdigit_l(ch, __l)) break;
14510b57cec5SDimitry Andric         if ((m & punct) == punct && iswpunct_l(ch, __l)) break;
14520b57cec5SDimitry Andric         if ((m & xdigit) == xdigit && iswxdigit_l(ch, __l)) break;
14530b57cec5SDimitry Andric         if ((m & blank) == blank && iswblank_l(ch, __l)) break;
14540b57cec5SDimitry Andric #endif
14550b57cec5SDimitry Andric     }
14560b57cec5SDimitry Andric     return low;
14570b57cec5SDimitry Andric }
14580b57cec5SDimitry Andric 
14590b57cec5SDimitry Andric const wchar_t*
14600b57cec5SDimitry Andric ctype_byname<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const
14610b57cec5SDimitry Andric {
14620b57cec5SDimitry Andric     for (; low != high; ++low)
14630b57cec5SDimitry Andric     {
14640b57cec5SDimitry Andric #ifdef _LIBCPP_WCTYPE_IS_MASK
14650b57cec5SDimitry Andric         if (!iswctype_l(*low, m, __l))
14660b57cec5SDimitry Andric             break;
14670b57cec5SDimitry Andric #else
14680b57cec5SDimitry Andric         wint_t ch = static_cast<wint_t>(*low);
14690b57cec5SDimitry Andric         if ((m & space) == space && iswspace_l(ch, __l)) continue;
14700b57cec5SDimitry Andric         if ((m & print) == print && iswprint_l(ch, __l)) continue;
14710b57cec5SDimitry Andric         if ((m & cntrl) == cntrl && iswcntrl_l(ch, __l)) continue;
14720b57cec5SDimitry Andric         if ((m & upper) == upper && iswupper_l(ch, __l)) continue;
14730b57cec5SDimitry Andric         if ((m & lower) == lower && iswlower_l(ch, __l)) continue;
14740b57cec5SDimitry Andric         if ((m & alpha) == alpha && iswalpha_l(ch, __l)) continue;
14750b57cec5SDimitry Andric         if ((m & digit) == digit && iswdigit_l(ch, __l)) continue;
14760b57cec5SDimitry Andric         if ((m & punct) == punct && iswpunct_l(ch, __l)) continue;
14770b57cec5SDimitry Andric         if ((m & xdigit) == xdigit && iswxdigit_l(ch, __l)) continue;
14780b57cec5SDimitry Andric         if ((m & blank) == blank && iswblank_l(ch, __l)) continue;
14790b57cec5SDimitry Andric         break;
14800b57cec5SDimitry Andric #endif
14810b57cec5SDimitry Andric     }
14820b57cec5SDimitry Andric     return low;
14830b57cec5SDimitry Andric }
14840b57cec5SDimitry Andric 
14850b57cec5SDimitry Andric wchar_t
14860b57cec5SDimitry Andric ctype_byname<wchar_t>::do_toupper(char_type c) const
14870b57cec5SDimitry Andric {
14880b57cec5SDimitry Andric     return towupper_l(c, __l);
14890b57cec5SDimitry Andric }
14900b57cec5SDimitry Andric 
14910b57cec5SDimitry Andric const wchar_t*
14920b57cec5SDimitry Andric ctype_byname<wchar_t>::do_toupper(char_type* low, const char_type* high) const
14930b57cec5SDimitry Andric {
14940b57cec5SDimitry Andric     for (; low != high; ++low)
14950b57cec5SDimitry Andric         *low = towupper_l(*low, __l);
14960b57cec5SDimitry Andric     return low;
14970b57cec5SDimitry Andric }
14980b57cec5SDimitry Andric 
14990b57cec5SDimitry Andric wchar_t
15000b57cec5SDimitry Andric ctype_byname<wchar_t>::do_tolower(char_type c) const
15010b57cec5SDimitry Andric {
15020b57cec5SDimitry Andric     return towlower_l(c, __l);
15030b57cec5SDimitry Andric }
15040b57cec5SDimitry Andric 
15050b57cec5SDimitry Andric const wchar_t*
15060b57cec5SDimitry Andric ctype_byname<wchar_t>::do_tolower(char_type* low, const char_type* high) const
15070b57cec5SDimitry Andric {
15080b57cec5SDimitry Andric     for (; low != high; ++low)
15090b57cec5SDimitry Andric         *low = towlower_l(*low, __l);
15100b57cec5SDimitry Andric     return low;
15110b57cec5SDimitry Andric }
15120b57cec5SDimitry Andric 
15130b57cec5SDimitry Andric wchar_t
15140b57cec5SDimitry Andric ctype_byname<wchar_t>::do_widen(char c) const
15150b57cec5SDimitry Andric {
15160b57cec5SDimitry Andric     return __libcpp_btowc_l(c, __l);
15170b57cec5SDimitry Andric }
15180b57cec5SDimitry Andric 
15190b57cec5SDimitry Andric const char*
15200b57cec5SDimitry Andric ctype_byname<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const
15210b57cec5SDimitry Andric {
15220b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
15230b57cec5SDimitry Andric         *dest = __libcpp_btowc_l(*low, __l);
15240b57cec5SDimitry Andric     return low;
15250b57cec5SDimitry Andric }
15260b57cec5SDimitry Andric 
15270b57cec5SDimitry Andric char
15280b57cec5SDimitry Andric ctype_byname<wchar_t>::do_narrow(char_type c, char dfault) const
15290b57cec5SDimitry Andric {
15300b57cec5SDimitry Andric     int r = __libcpp_wctob_l(c, __l);
15310b57cec5SDimitry Andric     return r != static_cast<int>(WEOF) ? static_cast<char>(r) : dfault;
15320b57cec5SDimitry Andric }
15330b57cec5SDimitry Andric 
15340b57cec5SDimitry Andric const wchar_t*
15350b57cec5SDimitry Andric ctype_byname<wchar_t>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
15360b57cec5SDimitry Andric {
15370b57cec5SDimitry Andric     for (; low != high; ++low, ++dest)
15380b57cec5SDimitry Andric     {
15390b57cec5SDimitry Andric         int r = __libcpp_wctob_l(*low, __l);
15400b57cec5SDimitry Andric         *dest = r != static_cast<int>(WEOF) ? static_cast<char>(r) : dfault;
15410b57cec5SDimitry Andric     }
15420b57cec5SDimitry Andric     return low;
15430b57cec5SDimitry Andric }
1544349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
15450b57cec5SDimitry Andric 
15460b57cec5SDimitry Andric // template <> class codecvt<char, char, mbstate_t>
15470b57cec5SDimitry Andric 
15480b57cec5SDimitry Andric locale::id codecvt<char, char, mbstate_t>::id;
15490b57cec5SDimitry Andric 
15500b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::~codecvt()
15510b57cec5SDimitry Andric {
15520b57cec5SDimitry Andric }
15530b57cec5SDimitry Andric 
15540b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::result
15550b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::do_out(state_type&,
15560b57cec5SDimitry Andric     const intern_type* frm, const intern_type*, const intern_type*& frm_nxt,
15570b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
15580b57cec5SDimitry Andric {
15590b57cec5SDimitry Andric     frm_nxt = frm;
15600b57cec5SDimitry Andric     to_nxt = to;
15610b57cec5SDimitry Andric     return noconv;
15620b57cec5SDimitry Andric }
15630b57cec5SDimitry Andric 
15640b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::result
15650b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::do_in(state_type&,
15660b57cec5SDimitry Andric     const extern_type* frm, const extern_type*, const extern_type*& frm_nxt,
15670b57cec5SDimitry Andric     intern_type* to, intern_type*, intern_type*& to_nxt) const
15680b57cec5SDimitry Andric {
15690b57cec5SDimitry Andric     frm_nxt = frm;
15700b57cec5SDimitry Andric     to_nxt = to;
15710b57cec5SDimitry Andric     return noconv;
15720b57cec5SDimitry Andric }
15730b57cec5SDimitry Andric 
15740b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::result
15750b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::do_unshift(state_type&,
15760b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
15770b57cec5SDimitry Andric {
15780b57cec5SDimitry Andric     to_nxt = to;
15790b57cec5SDimitry Andric     return noconv;
15800b57cec5SDimitry Andric }
15810b57cec5SDimitry Andric 
15820b57cec5SDimitry Andric int
1583fe6060f1SDimitry Andric codecvt<char, char, mbstate_t>::do_encoding() const noexcept
15840b57cec5SDimitry Andric {
15850b57cec5SDimitry Andric     return 1;
15860b57cec5SDimitry Andric }
15870b57cec5SDimitry Andric 
15880b57cec5SDimitry Andric bool
1589fe6060f1SDimitry Andric codecvt<char, char, mbstate_t>::do_always_noconv() const noexcept
15900b57cec5SDimitry Andric {
15910b57cec5SDimitry Andric     return true;
15920b57cec5SDimitry Andric }
15930b57cec5SDimitry Andric 
15940b57cec5SDimitry Andric int
15950b57cec5SDimitry Andric codecvt<char, char, mbstate_t>::do_length(state_type&,
15960b57cec5SDimitry Andric     const extern_type* frm, const extern_type* end, size_t mx) const
15970b57cec5SDimitry Andric {
15980b57cec5SDimitry Andric     return static_cast<int>(min<size_t>(mx, static_cast<size_t>(end-frm)));
15990b57cec5SDimitry Andric }
16000b57cec5SDimitry Andric 
16010b57cec5SDimitry Andric int
1602fe6060f1SDimitry Andric codecvt<char, char, mbstate_t>::do_max_length() const noexcept
16030b57cec5SDimitry Andric {
16040b57cec5SDimitry Andric     return 1;
16050b57cec5SDimitry Andric }
16060b57cec5SDimitry Andric 
16070b57cec5SDimitry Andric // template <> class codecvt<wchar_t, char, mbstate_t>
16080b57cec5SDimitry Andric 
1609349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
16100b57cec5SDimitry Andric locale::id codecvt<wchar_t, char, mbstate_t>::id;
16110b57cec5SDimitry Andric 
16120b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::codecvt(size_t refs)
16130b57cec5SDimitry Andric     : locale::facet(refs),
16140b57cec5SDimitry Andric       __l(_LIBCPP_GET_C_LOCALE)
16150b57cec5SDimitry Andric {
16160b57cec5SDimitry Andric }
16170b57cec5SDimitry Andric 
16180b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::codecvt(const char* nm, size_t refs)
16190b57cec5SDimitry Andric     : locale::facet(refs),
16200b57cec5SDimitry Andric       __l(newlocale(LC_ALL_MASK, nm, 0))
16210b57cec5SDimitry Andric {
16220b57cec5SDimitry Andric     if (__l == 0)
16230b57cec5SDimitry Andric         __throw_runtime_error("codecvt_byname<wchar_t, char, mbstate_t>::codecvt_byname"
16240b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
16250b57cec5SDimitry Andric }
16260b57cec5SDimitry Andric 
16270b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::~codecvt()
16280b57cec5SDimitry Andric {
16290b57cec5SDimitry Andric     if (__l != _LIBCPP_GET_C_LOCALE)
16300b57cec5SDimitry Andric         freelocale(__l);
16310b57cec5SDimitry Andric }
16320b57cec5SDimitry Andric 
16330b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::result
16340b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_out(state_type& st,
16350b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
16360b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
16370b57cec5SDimitry Andric {
16380b57cec5SDimitry Andric     // look for first internal null in frm
16390b57cec5SDimitry Andric     const intern_type* fend = frm;
16400b57cec5SDimitry Andric     for (; fend != frm_end; ++fend)
16410b57cec5SDimitry Andric         if (*fend == 0)
16420b57cec5SDimitry Andric             break;
16430b57cec5SDimitry Andric     // loop over all null-terminated sequences in frm
16440b57cec5SDimitry Andric     to_nxt = to;
16450b57cec5SDimitry Andric     for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt)
16460b57cec5SDimitry Andric     {
16470b57cec5SDimitry Andric         // save state in case it is needed to recover to_nxt on error
16480b57cec5SDimitry Andric         mbstate_t save_state = st;
16490b57cec5SDimitry Andric         size_t n = __libcpp_wcsnrtombs_l(to, &frm_nxt, static_cast<size_t>(fend-frm),
16500b57cec5SDimitry Andric                                      static_cast<size_t>(to_end-to), &st, __l);
16510b57cec5SDimitry Andric         if (n == size_t(-1))
16520b57cec5SDimitry Andric         {
16530b57cec5SDimitry Andric             // need to recover to_nxt
16540b57cec5SDimitry Andric             for (to_nxt = to; frm != frm_nxt; ++frm)
16550b57cec5SDimitry Andric             {
16560b57cec5SDimitry Andric                 n = __libcpp_wcrtomb_l(to_nxt, *frm, &save_state, __l);
16570b57cec5SDimitry Andric                 if (n == size_t(-1))
16580b57cec5SDimitry Andric                     break;
16590b57cec5SDimitry Andric                 to_nxt += n;
16600b57cec5SDimitry Andric             }
16610b57cec5SDimitry Andric             frm_nxt = frm;
16620b57cec5SDimitry Andric             return error;
16630b57cec5SDimitry Andric         }
16640b57cec5SDimitry Andric         if (n == 0)
16650b57cec5SDimitry Andric             return partial;
16660b57cec5SDimitry Andric         to_nxt += n;
16670b57cec5SDimitry Andric         if (to_nxt == to_end)
16680b57cec5SDimitry Andric             break;
16690b57cec5SDimitry Andric         if (fend != frm_end)  // set up next null terminated sequence
16700b57cec5SDimitry Andric         {
16710b57cec5SDimitry Andric             // Try to write the terminating null
16720b57cec5SDimitry Andric             extern_type tmp[MB_LEN_MAX];
16730b57cec5SDimitry Andric             n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l);
16740b57cec5SDimitry Andric             if (n == size_t(-1))  // on error
16750b57cec5SDimitry Andric                 return error;
16760b57cec5SDimitry Andric             if (n > static_cast<size_t>(to_end-to_nxt))  // is there room?
16770b57cec5SDimitry Andric                 return partial;
16780b57cec5SDimitry Andric             for (extern_type* p = tmp; n; --n)  // write it
16790b57cec5SDimitry Andric                 *to_nxt++ = *p++;
16800b57cec5SDimitry Andric             ++frm_nxt;
16810b57cec5SDimitry Andric             // look for next null in frm
16820b57cec5SDimitry Andric             for (fend = frm_nxt; fend != frm_end; ++fend)
16830b57cec5SDimitry Andric                 if (*fend == 0)
16840b57cec5SDimitry Andric                     break;
16850b57cec5SDimitry Andric         }
16860b57cec5SDimitry Andric     }
16870b57cec5SDimitry Andric     return frm_nxt == frm_end ? ok : partial;
16880b57cec5SDimitry Andric }
16890b57cec5SDimitry Andric 
16900b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::result
16910b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_in(state_type& st,
16920b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
16930b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
16940b57cec5SDimitry Andric {
16950b57cec5SDimitry Andric     // look for first internal null in frm
16960b57cec5SDimitry Andric     const extern_type* fend = frm;
16970b57cec5SDimitry Andric     for (; fend != frm_end; ++fend)
16980b57cec5SDimitry Andric         if (*fend == 0)
16990b57cec5SDimitry Andric             break;
17000b57cec5SDimitry Andric     // loop over all null-terminated sequences in frm
17010b57cec5SDimitry Andric     to_nxt = to;
17020b57cec5SDimitry Andric     for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt)
17030b57cec5SDimitry Andric     {
17040b57cec5SDimitry Andric         // save state in case it is needed to recover to_nxt on error
17050b57cec5SDimitry Andric         mbstate_t save_state = st;
17060b57cec5SDimitry Andric         size_t n = __libcpp_mbsnrtowcs_l(to, &frm_nxt, static_cast<size_t>(fend-frm),
17070b57cec5SDimitry Andric                                      static_cast<size_t>(to_end-to), &st, __l);
17080b57cec5SDimitry Andric         if (n == size_t(-1))
17090b57cec5SDimitry Andric         {
17100b57cec5SDimitry Andric             // need to recover to_nxt
17110b57cec5SDimitry Andric             for (to_nxt = to; frm != frm_nxt; ++to_nxt)
17120b57cec5SDimitry Andric             {
17130b57cec5SDimitry Andric                 n = __libcpp_mbrtowc_l(to_nxt, frm, static_cast<size_t>(fend-frm),
17140b57cec5SDimitry Andric                                    &save_state, __l);
17150b57cec5SDimitry Andric                 switch (n)
17160b57cec5SDimitry Andric                 {
17170b57cec5SDimitry Andric                 case 0:
17180b57cec5SDimitry Andric                     ++frm;
17190b57cec5SDimitry Andric                     break;
17200b57cec5SDimitry Andric                 case size_t(-1):
17210b57cec5SDimitry Andric                     frm_nxt = frm;
17220b57cec5SDimitry Andric                     return error;
17230b57cec5SDimitry Andric                 case size_t(-2):
17240b57cec5SDimitry Andric                     frm_nxt = frm;
17250b57cec5SDimitry Andric                     return partial;
17260b57cec5SDimitry Andric                 default:
17270b57cec5SDimitry Andric                     frm += n;
17280b57cec5SDimitry Andric                     break;
17290b57cec5SDimitry Andric                 }
17300b57cec5SDimitry Andric             }
17310b57cec5SDimitry Andric             frm_nxt = frm;
17320b57cec5SDimitry Andric             return frm_nxt == frm_end ? ok : partial;
17330b57cec5SDimitry Andric         }
17340b57cec5SDimitry Andric         if (n == size_t(-1))
17350b57cec5SDimitry Andric             return error;
17360b57cec5SDimitry Andric         to_nxt += n;
17370b57cec5SDimitry Andric         if (to_nxt == to_end)
17380b57cec5SDimitry Andric             break;
17390b57cec5SDimitry Andric         if (fend != frm_end)  // set up next null terminated sequence
17400b57cec5SDimitry Andric         {
17410b57cec5SDimitry Andric             // Try to write the terminating null
17420b57cec5SDimitry Andric             n = __libcpp_mbrtowc_l(to_nxt, frm_nxt, 1, &st, __l);
17430b57cec5SDimitry Andric             if (n != 0)  // on error
17440b57cec5SDimitry Andric                 return error;
17450b57cec5SDimitry Andric             ++to_nxt;
17460b57cec5SDimitry Andric             ++frm_nxt;
17470b57cec5SDimitry Andric             // look for next null in frm
17480b57cec5SDimitry Andric             for (fend = frm_nxt; fend != frm_end; ++fend)
17490b57cec5SDimitry Andric                 if (*fend == 0)
17500b57cec5SDimitry Andric                     break;
17510b57cec5SDimitry Andric         }
17520b57cec5SDimitry Andric     }
17530b57cec5SDimitry Andric     return frm_nxt == frm_end ? ok : partial;
17540b57cec5SDimitry Andric }
17550b57cec5SDimitry Andric 
17560b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::result
17570b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_unshift(state_type& st,
17580b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
17590b57cec5SDimitry Andric {
17600b57cec5SDimitry Andric     to_nxt = to;
17610b57cec5SDimitry Andric     extern_type tmp[MB_LEN_MAX];
17620b57cec5SDimitry Andric     size_t n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l);
17630b57cec5SDimitry Andric     if (n == size_t(-1) || n == 0)  // on error
17640b57cec5SDimitry Andric         return error;
17650b57cec5SDimitry Andric     --n;
17660b57cec5SDimitry Andric     if (n > static_cast<size_t>(to_end-to_nxt))  // is there room?
17670b57cec5SDimitry Andric         return partial;
17680b57cec5SDimitry Andric     for (extern_type* p = tmp; n; --n)  // write it
17690b57cec5SDimitry Andric         *to_nxt++ = *p++;
17700b57cec5SDimitry Andric     return ok;
17710b57cec5SDimitry Andric }
17720b57cec5SDimitry Andric 
17730b57cec5SDimitry Andric int
1774fe6060f1SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_encoding() const noexcept
17750b57cec5SDimitry Andric {
17760b57cec5SDimitry Andric     if (__libcpp_mbtowc_l(nullptr, nullptr, MB_LEN_MAX, __l) != 0)
17770b57cec5SDimitry Andric         return -1;
17780b57cec5SDimitry Andric 
17790b57cec5SDimitry Andric     // stateless encoding
17800b57cec5SDimitry Andric     if (__l == 0 || __libcpp_mb_cur_max_l(__l) == 1)  // there are no known constant length encodings
17810b57cec5SDimitry Andric         return 1;                // which take more than 1 char to form a wchar_t
17820b57cec5SDimitry Andric     return 0;
17830b57cec5SDimitry Andric }
17840b57cec5SDimitry Andric 
17850b57cec5SDimitry Andric bool
1786fe6060f1SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_always_noconv() const noexcept
17870b57cec5SDimitry Andric {
17880b57cec5SDimitry Andric     return false;
17890b57cec5SDimitry Andric }
17900b57cec5SDimitry Andric 
17910b57cec5SDimitry Andric int
17920b57cec5SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_length(state_type& st,
17930b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
17940b57cec5SDimitry Andric {
17950b57cec5SDimitry Andric     int nbytes = 0;
17960b57cec5SDimitry Andric     for (size_t nwchar_t = 0; nwchar_t < mx && frm != frm_end; ++nwchar_t)
17970b57cec5SDimitry Andric     {
17980b57cec5SDimitry Andric         size_t n = __libcpp_mbrlen_l(frm, static_cast<size_t>(frm_end-frm), &st, __l);
17990b57cec5SDimitry Andric         switch (n)
18000b57cec5SDimitry Andric         {
18010b57cec5SDimitry Andric         case 0:
18020b57cec5SDimitry Andric             ++nbytes;
18030b57cec5SDimitry Andric             ++frm;
18040b57cec5SDimitry Andric             break;
18050b57cec5SDimitry Andric         case size_t(-1):
18060b57cec5SDimitry Andric         case size_t(-2):
18070b57cec5SDimitry Andric             return nbytes;
18080b57cec5SDimitry Andric         default:
18090b57cec5SDimitry Andric             nbytes += n;
18100b57cec5SDimitry Andric             frm += n;
18110b57cec5SDimitry Andric             break;
18120b57cec5SDimitry Andric         }
18130b57cec5SDimitry Andric     }
18140b57cec5SDimitry Andric     return nbytes;
18150b57cec5SDimitry Andric }
18160b57cec5SDimitry Andric 
18170b57cec5SDimitry Andric int
1818fe6060f1SDimitry Andric codecvt<wchar_t, char, mbstate_t>::do_max_length() const noexcept
18190b57cec5SDimitry Andric {
18200b57cec5SDimitry Andric     return __l == 0 ? 1 : static_cast<int>(__libcpp_mb_cur_max_l(__l));
18210b57cec5SDimitry Andric }
1822349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
18230b57cec5SDimitry Andric 
18240b57cec5SDimitry Andric //                                     Valid UTF ranges
18250b57cec5SDimitry Andric //     UTF-32               UTF-16                          UTF-8               # of code points
18260b57cec5SDimitry Andric //                     first      second       first   second    third   fourth
18270b57cec5SDimitry Andric // 000000 - 00007F  0000 - 007F               00 - 7F                                 127
18280b57cec5SDimitry Andric // 000080 - 0007FF  0080 - 07FF               C2 - DF, 80 - BF                       1920
18290b57cec5SDimitry Andric // 000800 - 000FFF  0800 - 0FFF               E0 - E0, A0 - BF, 80 - BF              2048
18300b57cec5SDimitry Andric // 001000 - 00CFFF  1000 - CFFF               E1 - EC, 80 - BF, 80 - BF             49152
18310b57cec5SDimitry Andric // 00D000 - 00D7FF  D000 - D7FF               ED - ED, 80 - 9F, 80 - BF              2048
18320b57cec5SDimitry Andric // 00D800 - 00DFFF                invalid
18330b57cec5SDimitry Andric // 00E000 - 00FFFF  E000 - FFFF               EE - EF, 80 - BF, 80 - BF              8192
18340b57cec5SDimitry Andric // 010000 - 03FFFF  D800 - D8BF, DC00 - DFFF  F0 - F0, 90 - BF, 80 - BF, 80 - BF   196608
18350b57cec5SDimitry Andric // 040000 - 0FFFFF  D8C0 - DBBF, DC00 - DFFF  F1 - F3, 80 - BF, 80 - BF, 80 - BF   786432
18360b57cec5SDimitry Andric // 100000 - 10FFFF  DBC0 - DBFF, DC00 - DFFF  F4 - F4, 80 - 8F, 80 - BF, 80 - BF    65536
18370b57cec5SDimitry Andric 
18380b57cec5SDimitry Andric static
18390b57cec5SDimitry Andric codecvt_base::result
18400b57cec5SDimitry Andric utf16_to_utf8(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
18410b57cec5SDimitry Andric               uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
18420b57cec5SDimitry Andric               unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
18430b57cec5SDimitry Andric {
18440b57cec5SDimitry Andric     frm_nxt = frm;
18450b57cec5SDimitry Andric     to_nxt = to;
18460b57cec5SDimitry Andric     if (mode & generate_header)
18470b57cec5SDimitry Andric     {
18480b57cec5SDimitry Andric         if (to_end-to_nxt < 3)
18490b57cec5SDimitry Andric             return codecvt_base::partial;
18500b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xEF);
18510b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBB);
18520b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBF);
18530b57cec5SDimitry Andric     }
18540b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
18550b57cec5SDimitry Andric     {
18560b57cec5SDimitry Andric         uint16_t wc1 = *frm_nxt;
18570b57cec5SDimitry Andric         if (wc1 > Maxcode)
18580b57cec5SDimitry Andric             return codecvt_base::error;
18590b57cec5SDimitry Andric         if (wc1 < 0x0080)
18600b57cec5SDimitry Andric         {
18610b57cec5SDimitry Andric             if (to_end-to_nxt < 1)
18620b57cec5SDimitry Andric                 return codecvt_base::partial;
18630b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc1);
18640b57cec5SDimitry Andric         }
18650b57cec5SDimitry Andric         else if (wc1 < 0x0800)
18660b57cec5SDimitry Andric         {
18670b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
18680b57cec5SDimitry Andric                 return codecvt_base::partial;
18690b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc1 >> 6));
18700b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x03F));
18710b57cec5SDimitry Andric         }
18720b57cec5SDimitry Andric         else if (wc1 < 0xD800)
18730b57cec5SDimitry Andric         {
18740b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
18750b57cec5SDimitry Andric                 return codecvt_base::partial;
18760b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
18770b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
18780b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
18790b57cec5SDimitry Andric         }
18800b57cec5SDimitry Andric         else if (wc1 < 0xDC00)
18810b57cec5SDimitry Andric         {
18820b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
18830b57cec5SDimitry Andric                 return codecvt_base::partial;
18840b57cec5SDimitry Andric             uint16_t wc2 = frm_nxt[1];
18850b57cec5SDimitry Andric             if ((wc2 & 0xFC00) != 0xDC00)
18860b57cec5SDimitry Andric                 return codecvt_base::error;
18870b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
18880b57cec5SDimitry Andric                 return codecvt_base::partial;
18890b57cec5SDimitry Andric             if (((((wc1 & 0x03C0UL) >> 6) + 1) << 16) +
18900b57cec5SDimitry Andric                 ((wc1 & 0x003FUL) << 10) + (wc2 & 0x03FF) > Maxcode)
18910b57cec5SDimitry Andric                 return codecvt_base::error;
18920b57cec5SDimitry Andric             ++frm_nxt;
18930b57cec5SDimitry Andric             uint8_t z = ((wc1 & 0x03C0) >> 6) + 1;
18940b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xF0 | (z >> 2));
18950b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((z & 0x03) << 4)     | ((wc1 & 0x003C) >> 2));
18960b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6));
18970b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc2 & 0x003F));
18980b57cec5SDimitry Andric         }
18990b57cec5SDimitry Andric         else if (wc1 < 0xE000)
19000b57cec5SDimitry Andric         {
19010b57cec5SDimitry Andric             return codecvt_base::error;
19020b57cec5SDimitry Andric         }
19030b57cec5SDimitry Andric         else
19040b57cec5SDimitry Andric         {
19050b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
19060b57cec5SDimitry Andric                 return codecvt_base::partial;
19070b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
19080b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
19090b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
19100b57cec5SDimitry Andric         }
19110b57cec5SDimitry Andric     }
19120b57cec5SDimitry Andric     return codecvt_base::ok;
19130b57cec5SDimitry Andric }
19140b57cec5SDimitry Andric 
19150b57cec5SDimitry Andric static
19160b57cec5SDimitry Andric codecvt_base::result
19170b57cec5SDimitry Andric utf16_to_utf8(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
19180b57cec5SDimitry Andric               uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
19190b57cec5SDimitry Andric               unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
19200b57cec5SDimitry Andric {
19210b57cec5SDimitry Andric     frm_nxt = frm;
19220b57cec5SDimitry Andric     to_nxt = to;
19230b57cec5SDimitry Andric     if (mode & generate_header)
19240b57cec5SDimitry Andric     {
19250b57cec5SDimitry Andric         if (to_end-to_nxt < 3)
19260b57cec5SDimitry Andric             return codecvt_base::partial;
19270b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xEF);
19280b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBB);
19290b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBF);
19300b57cec5SDimitry Andric     }
19310b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
19320b57cec5SDimitry Andric     {
19330b57cec5SDimitry Andric         uint16_t wc1 = static_cast<uint16_t>(*frm_nxt);
19340b57cec5SDimitry Andric         if (wc1 > Maxcode)
19350b57cec5SDimitry Andric             return codecvt_base::error;
19360b57cec5SDimitry Andric         if (wc1 < 0x0080)
19370b57cec5SDimitry Andric         {
19380b57cec5SDimitry Andric             if (to_end-to_nxt < 1)
19390b57cec5SDimitry Andric                 return codecvt_base::partial;
19400b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc1);
19410b57cec5SDimitry Andric         }
19420b57cec5SDimitry Andric         else if (wc1 < 0x0800)
19430b57cec5SDimitry Andric         {
19440b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
19450b57cec5SDimitry Andric                 return codecvt_base::partial;
19460b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc1 >> 6));
19470b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x03F));
19480b57cec5SDimitry Andric         }
19490b57cec5SDimitry Andric         else if (wc1 < 0xD800)
19500b57cec5SDimitry Andric         {
19510b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
19520b57cec5SDimitry Andric                 return codecvt_base::partial;
19530b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
19540b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
19550b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
19560b57cec5SDimitry Andric         }
19570b57cec5SDimitry Andric         else if (wc1 < 0xDC00)
19580b57cec5SDimitry Andric         {
19590b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
19600b57cec5SDimitry Andric                 return codecvt_base::partial;
19610b57cec5SDimitry Andric             uint16_t wc2 = static_cast<uint16_t>(frm_nxt[1]);
19620b57cec5SDimitry Andric             if ((wc2 & 0xFC00) != 0xDC00)
19630b57cec5SDimitry Andric                 return codecvt_base::error;
19640b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
19650b57cec5SDimitry Andric                 return codecvt_base::partial;
19660b57cec5SDimitry Andric             if (((((wc1 & 0x03C0UL) >> 6) + 1) << 16) +
19670b57cec5SDimitry Andric                 ((wc1 & 0x003FUL) << 10) + (wc2 & 0x03FF) > Maxcode)
19680b57cec5SDimitry Andric                 return codecvt_base::error;
19690b57cec5SDimitry Andric             ++frm_nxt;
19700b57cec5SDimitry Andric             uint8_t z = ((wc1 & 0x03C0) >> 6) + 1;
19710b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xF0 | (z >> 2));
19720b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((z & 0x03) << 4)     | ((wc1 & 0x003C) >> 2));
19730b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6));
19740b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc2 & 0x003F));
19750b57cec5SDimitry Andric         }
19760b57cec5SDimitry Andric         else if (wc1 < 0xE000)
19770b57cec5SDimitry Andric         {
19780b57cec5SDimitry Andric             return codecvt_base::error;
19790b57cec5SDimitry Andric         }
19800b57cec5SDimitry Andric         else
19810b57cec5SDimitry Andric         {
19820b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
19830b57cec5SDimitry Andric                 return codecvt_base::partial;
19840b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
19850b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
19860b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
19870b57cec5SDimitry Andric         }
19880b57cec5SDimitry Andric     }
19890b57cec5SDimitry Andric     return codecvt_base::ok;
19900b57cec5SDimitry Andric }
19910b57cec5SDimitry Andric 
19920b57cec5SDimitry Andric static
19930b57cec5SDimitry Andric codecvt_base::result
19940b57cec5SDimitry Andric utf8_to_utf16(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
19950b57cec5SDimitry Andric               uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
19960b57cec5SDimitry Andric               unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
19970b57cec5SDimitry Andric {
19980b57cec5SDimitry Andric     frm_nxt = frm;
19990b57cec5SDimitry Andric     to_nxt = to;
20000b57cec5SDimitry Andric     if (mode & consume_header)
20010b57cec5SDimitry Andric     {
20020b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
20030b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
20040b57cec5SDimitry Andric             frm_nxt += 3;
20050b57cec5SDimitry Andric     }
20060b57cec5SDimitry Andric     for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
20070b57cec5SDimitry Andric     {
20080b57cec5SDimitry Andric         uint8_t c1 = *frm_nxt;
20090b57cec5SDimitry Andric         if (c1 > Maxcode)
20100b57cec5SDimitry Andric             return codecvt_base::error;
20110b57cec5SDimitry Andric         if (c1 < 0x80)
20120b57cec5SDimitry Andric         {
20130b57cec5SDimitry Andric             *to_nxt = static_cast<uint16_t>(c1);
20140b57cec5SDimitry Andric             ++frm_nxt;
20150b57cec5SDimitry Andric         }
20160b57cec5SDimitry Andric         else if (c1 < 0xC2)
20170b57cec5SDimitry Andric         {
20180b57cec5SDimitry Andric             return codecvt_base::error;
20190b57cec5SDimitry Andric         }
20200b57cec5SDimitry Andric         else if (c1 < 0xE0)
20210b57cec5SDimitry Andric         {
20220b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
20230b57cec5SDimitry Andric                 return codecvt_base::partial;
20240b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
20250b57cec5SDimitry Andric             if ((c2 & 0xC0) != 0x80)
20260b57cec5SDimitry Andric                 return codecvt_base::error;
20270b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
20280b57cec5SDimitry Andric             if (t > Maxcode)
20290b57cec5SDimitry Andric                 return codecvt_base::error;
20300b57cec5SDimitry Andric             *to_nxt = t;
20310b57cec5SDimitry Andric             frm_nxt += 2;
20320b57cec5SDimitry Andric         }
20330b57cec5SDimitry Andric         else if (c1 < 0xF0)
20340b57cec5SDimitry Andric         {
20350b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
20360b57cec5SDimitry Andric                 return codecvt_base::partial;
20370b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
20380b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
20390b57cec5SDimitry Andric             switch (c1)
20400b57cec5SDimitry Andric             {
20410b57cec5SDimitry Andric             case 0xE0:
20420b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
20430b57cec5SDimitry Andric                     return codecvt_base::error;
20440b57cec5SDimitry Andric                  break;
20450b57cec5SDimitry Andric             case 0xED:
20460b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
20470b57cec5SDimitry Andric                     return codecvt_base::error;
20480b57cec5SDimitry Andric                  break;
20490b57cec5SDimitry Andric             default:
20500b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
20510b57cec5SDimitry Andric                     return codecvt_base::error;
20520b57cec5SDimitry Andric                  break;
20530b57cec5SDimitry Andric             }
20540b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
20550b57cec5SDimitry Andric                 return codecvt_base::error;
20560b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
20570b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 6)
20580b57cec5SDimitry Andric                                              |  (c3 & 0x3F));
20590b57cec5SDimitry Andric             if (t > Maxcode)
20600b57cec5SDimitry Andric                 return codecvt_base::error;
20610b57cec5SDimitry Andric             *to_nxt = t;
20620b57cec5SDimitry Andric             frm_nxt += 3;
20630b57cec5SDimitry Andric         }
20640b57cec5SDimitry Andric         else if (c1 < 0xF5)
20650b57cec5SDimitry Andric         {
20660b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
20670b57cec5SDimitry Andric                 return codecvt_base::partial;
20680b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
20690b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
20700b57cec5SDimitry Andric             uint8_t c4 = frm_nxt[3];
20710b57cec5SDimitry Andric             switch (c1)
20720b57cec5SDimitry Andric             {
20730b57cec5SDimitry Andric             case 0xF0:
20740b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
20750b57cec5SDimitry Andric                     return codecvt_base::error;
20760b57cec5SDimitry Andric                  break;
20770b57cec5SDimitry Andric             case 0xF4:
20780b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
20790b57cec5SDimitry Andric                     return codecvt_base::error;
20800b57cec5SDimitry Andric                  break;
20810b57cec5SDimitry Andric             default:
20820b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
20830b57cec5SDimitry Andric                     return codecvt_base::error;
20840b57cec5SDimitry Andric                  break;
20850b57cec5SDimitry Andric             }
20860b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
20870b57cec5SDimitry Andric                 return codecvt_base::error;
20880b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
20890b57cec5SDimitry Andric                 return codecvt_base::partial;
20900b57cec5SDimitry Andric             if ((((c1 & 7UL) << 18) +
20910b57cec5SDimitry Andric                 ((c2 & 0x3FUL) << 12) +
20920b57cec5SDimitry Andric                 ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
20930b57cec5SDimitry Andric                 return codecvt_base::error;
20940b57cec5SDimitry Andric             *to_nxt = static_cast<uint16_t>(
20950b57cec5SDimitry Andric                     0xD800
20960b57cec5SDimitry Andric                   | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6)
20970b57cec5SDimitry Andric                   | ((c2 & 0x0F) << 2)
20980b57cec5SDimitry Andric                   | ((c3 & 0x30) >> 4));
20990b57cec5SDimitry Andric             *++to_nxt = static_cast<uint16_t>(
21000b57cec5SDimitry Andric                     0xDC00
21010b57cec5SDimitry Andric                   | ((c3 & 0x0F) << 6)
21020b57cec5SDimitry Andric                   |  (c4 & 0x3F));
21030b57cec5SDimitry Andric             frm_nxt += 4;
21040b57cec5SDimitry Andric         }
21050b57cec5SDimitry Andric         else
21060b57cec5SDimitry Andric         {
21070b57cec5SDimitry Andric             return codecvt_base::error;
21080b57cec5SDimitry Andric         }
21090b57cec5SDimitry Andric     }
21100b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
21110b57cec5SDimitry Andric }
21120b57cec5SDimitry Andric 
21130b57cec5SDimitry Andric static
21140b57cec5SDimitry Andric codecvt_base::result
21150b57cec5SDimitry Andric utf8_to_utf16(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
21160b57cec5SDimitry Andric               uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
21170b57cec5SDimitry Andric               unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
21180b57cec5SDimitry Andric {
21190b57cec5SDimitry Andric     frm_nxt = frm;
21200b57cec5SDimitry Andric     to_nxt = to;
21210b57cec5SDimitry Andric     if (mode & consume_header)
21220b57cec5SDimitry Andric     {
21230b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
21240b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
21250b57cec5SDimitry Andric             frm_nxt += 3;
21260b57cec5SDimitry Andric     }
21270b57cec5SDimitry Andric     for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
21280b57cec5SDimitry Andric     {
21290b57cec5SDimitry Andric         uint8_t c1 = *frm_nxt;
21300b57cec5SDimitry Andric         if (c1 > Maxcode)
21310b57cec5SDimitry Andric             return codecvt_base::error;
21320b57cec5SDimitry Andric         if (c1 < 0x80)
21330b57cec5SDimitry Andric         {
21340b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(c1);
21350b57cec5SDimitry Andric             ++frm_nxt;
21360b57cec5SDimitry Andric         }
21370b57cec5SDimitry Andric         else if (c1 < 0xC2)
21380b57cec5SDimitry Andric         {
21390b57cec5SDimitry Andric             return codecvt_base::error;
21400b57cec5SDimitry Andric         }
21410b57cec5SDimitry Andric         else if (c1 < 0xE0)
21420b57cec5SDimitry Andric         {
21430b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
21440b57cec5SDimitry Andric                 return codecvt_base::partial;
21450b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
21460b57cec5SDimitry Andric             if ((c2 & 0xC0) != 0x80)
21470b57cec5SDimitry Andric                 return codecvt_base::error;
21480b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
21490b57cec5SDimitry Andric             if (t > Maxcode)
21500b57cec5SDimitry Andric                 return codecvt_base::error;
21510b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(t);
21520b57cec5SDimitry Andric             frm_nxt += 2;
21530b57cec5SDimitry Andric         }
21540b57cec5SDimitry Andric         else if (c1 < 0xF0)
21550b57cec5SDimitry Andric         {
21560b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
21570b57cec5SDimitry Andric                 return codecvt_base::partial;
21580b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
21590b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
21600b57cec5SDimitry Andric             switch (c1)
21610b57cec5SDimitry Andric             {
21620b57cec5SDimitry Andric             case 0xE0:
21630b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
21640b57cec5SDimitry Andric                     return codecvt_base::error;
21650b57cec5SDimitry Andric                  break;
21660b57cec5SDimitry Andric             case 0xED:
21670b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
21680b57cec5SDimitry Andric                     return codecvt_base::error;
21690b57cec5SDimitry Andric                  break;
21700b57cec5SDimitry Andric             default:
21710b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
21720b57cec5SDimitry Andric                     return codecvt_base::error;
21730b57cec5SDimitry Andric                  break;
21740b57cec5SDimitry Andric             }
21750b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
21760b57cec5SDimitry Andric                 return codecvt_base::error;
21770b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
21780b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 6)
21790b57cec5SDimitry Andric                                              |  (c3 & 0x3F));
21800b57cec5SDimitry Andric             if (t > Maxcode)
21810b57cec5SDimitry Andric                 return codecvt_base::error;
21820b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(t);
21830b57cec5SDimitry Andric             frm_nxt += 3;
21840b57cec5SDimitry Andric         }
21850b57cec5SDimitry Andric         else if (c1 < 0xF5)
21860b57cec5SDimitry Andric         {
21870b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
21880b57cec5SDimitry Andric                 return codecvt_base::partial;
21890b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
21900b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
21910b57cec5SDimitry Andric             uint8_t c4 = frm_nxt[3];
21920b57cec5SDimitry Andric             switch (c1)
21930b57cec5SDimitry Andric             {
21940b57cec5SDimitry Andric             case 0xF0:
21950b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
21960b57cec5SDimitry Andric                     return codecvt_base::error;
21970b57cec5SDimitry Andric                  break;
21980b57cec5SDimitry Andric             case 0xF4:
21990b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
22000b57cec5SDimitry Andric                     return codecvt_base::error;
22010b57cec5SDimitry Andric                  break;
22020b57cec5SDimitry Andric             default:
22030b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
22040b57cec5SDimitry Andric                     return codecvt_base::error;
22050b57cec5SDimitry Andric                  break;
22060b57cec5SDimitry Andric             }
22070b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
22080b57cec5SDimitry Andric                 return codecvt_base::error;
22090b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
22100b57cec5SDimitry Andric                 return codecvt_base::partial;
22110b57cec5SDimitry Andric             if ((((c1 & 7UL) << 18) +
22120b57cec5SDimitry Andric                 ((c2 & 0x3FUL) << 12) +
22130b57cec5SDimitry Andric                 ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
22140b57cec5SDimitry Andric                 return codecvt_base::error;
22150b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(
22160b57cec5SDimitry Andric                     0xD800
22170b57cec5SDimitry Andric                   | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6)
22180b57cec5SDimitry Andric                   | ((c2 & 0x0F) << 2)
22190b57cec5SDimitry Andric                   | ((c3 & 0x30) >> 4));
22200b57cec5SDimitry Andric             *++to_nxt = static_cast<uint32_t>(
22210b57cec5SDimitry Andric                     0xDC00
22220b57cec5SDimitry Andric                   | ((c3 & 0x0F) << 6)
22230b57cec5SDimitry Andric                   |  (c4 & 0x3F));
22240b57cec5SDimitry Andric             frm_nxt += 4;
22250b57cec5SDimitry Andric         }
22260b57cec5SDimitry Andric         else
22270b57cec5SDimitry Andric         {
22280b57cec5SDimitry Andric             return codecvt_base::error;
22290b57cec5SDimitry Andric         }
22300b57cec5SDimitry Andric     }
22310b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
22320b57cec5SDimitry Andric }
22330b57cec5SDimitry Andric 
22340b57cec5SDimitry Andric static
22350b57cec5SDimitry Andric int
22360b57cec5SDimitry Andric utf8_to_utf16_length(const uint8_t* frm, const uint8_t* frm_end,
22370b57cec5SDimitry Andric                      size_t mx, unsigned long Maxcode = 0x10FFFF,
22380b57cec5SDimitry Andric                      codecvt_mode mode = codecvt_mode(0))
22390b57cec5SDimitry Andric {
22400b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
22410b57cec5SDimitry Andric     if (mode & consume_header)
22420b57cec5SDimitry Andric     {
22430b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
22440b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
22450b57cec5SDimitry Andric             frm_nxt += 3;
22460b57cec5SDimitry Andric     }
22470b57cec5SDimitry Andric     for (size_t nchar16_t = 0; frm_nxt < frm_end && nchar16_t < mx; ++nchar16_t)
22480b57cec5SDimitry Andric     {
22490b57cec5SDimitry Andric         uint8_t c1 = *frm_nxt;
22500b57cec5SDimitry Andric         if (c1 > Maxcode)
22510b57cec5SDimitry Andric             break;
22520b57cec5SDimitry Andric         if (c1 < 0x80)
22530b57cec5SDimitry Andric         {
22540b57cec5SDimitry Andric             ++frm_nxt;
22550b57cec5SDimitry Andric         }
22560b57cec5SDimitry Andric         else if (c1 < 0xC2)
22570b57cec5SDimitry Andric         {
22580b57cec5SDimitry Andric             break;
22590b57cec5SDimitry Andric         }
22600b57cec5SDimitry Andric         else if (c1 < 0xE0)
22610b57cec5SDimitry Andric         {
22620b57cec5SDimitry Andric             if ((frm_end-frm_nxt < 2) || (frm_nxt[1] & 0xC0) != 0x80)
22630b57cec5SDimitry Andric                 break;
22640b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (frm_nxt[1] & 0x3F));
22650b57cec5SDimitry Andric             if (t > Maxcode)
22660b57cec5SDimitry Andric                 break;
22670b57cec5SDimitry Andric             frm_nxt += 2;
22680b57cec5SDimitry Andric         }
22690b57cec5SDimitry Andric         else if (c1 < 0xF0)
22700b57cec5SDimitry Andric         {
22710b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
22720b57cec5SDimitry Andric                 break;
22730b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
22740b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
22750b57cec5SDimitry Andric             switch (c1)
22760b57cec5SDimitry Andric             {
22770b57cec5SDimitry Andric             case 0xE0:
22780b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
22790b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
22800b57cec5SDimitry Andric                 break;
22810b57cec5SDimitry Andric             case 0xED:
22820b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
22830b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
22840b57cec5SDimitry Andric                  break;
22850b57cec5SDimitry Andric             default:
22860b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
22870b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
22880b57cec5SDimitry Andric                  break;
22890b57cec5SDimitry Andric             }
22900b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
22910b57cec5SDimitry Andric                 break;
22920b57cec5SDimitry Andric             if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
22930b57cec5SDimitry Andric                 break;
22940b57cec5SDimitry Andric             frm_nxt += 3;
22950b57cec5SDimitry Andric         }
22960b57cec5SDimitry Andric         else if (c1 < 0xF5)
22970b57cec5SDimitry Andric         {
22980b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4 || mx-nchar16_t < 2)
22990b57cec5SDimitry Andric                 break;
23000b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
23010b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
23020b57cec5SDimitry Andric             uint8_t c4 = frm_nxt[3];
23030b57cec5SDimitry Andric             switch (c1)
23040b57cec5SDimitry Andric             {
23050b57cec5SDimitry Andric             case 0xF0:
23060b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
23070b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
23080b57cec5SDimitry Andric                  break;
23090b57cec5SDimitry Andric             case 0xF4:
23100b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
23110b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
23120b57cec5SDimitry Andric                  break;
23130b57cec5SDimitry Andric             default:
23140b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
23150b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
23160b57cec5SDimitry Andric                  break;
23170b57cec5SDimitry Andric             }
23180b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
23190b57cec5SDimitry Andric                 break;
23200b57cec5SDimitry Andric             if ((((c1 & 7UL) << 18) +
23210b57cec5SDimitry Andric                 ((c2 & 0x3FUL) << 12) +
23220b57cec5SDimitry Andric                 ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
23230b57cec5SDimitry Andric                 break;
23240b57cec5SDimitry Andric             ++nchar16_t;
23250b57cec5SDimitry Andric             frm_nxt += 4;
23260b57cec5SDimitry Andric         }
23270b57cec5SDimitry Andric         else
23280b57cec5SDimitry Andric         {
23290b57cec5SDimitry Andric             break;
23300b57cec5SDimitry Andric         }
23310b57cec5SDimitry Andric     }
23320b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
23330b57cec5SDimitry Andric }
23340b57cec5SDimitry Andric 
23350b57cec5SDimitry Andric static
23360b57cec5SDimitry Andric codecvt_base::result
23370b57cec5SDimitry Andric ucs4_to_utf8(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
23380b57cec5SDimitry Andric              uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
23390b57cec5SDimitry Andric              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
23400b57cec5SDimitry Andric {
23410b57cec5SDimitry Andric     frm_nxt = frm;
23420b57cec5SDimitry Andric     to_nxt = to;
23430b57cec5SDimitry Andric     if (mode & generate_header)
23440b57cec5SDimitry Andric     {
23450b57cec5SDimitry Andric         if (to_end-to_nxt < 3)
23460b57cec5SDimitry Andric             return codecvt_base::partial;
23470b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xEF);
23480b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBB);
23490b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBF);
23500b57cec5SDimitry Andric     }
23510b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
23520b57cec5SDimitry Andric     {
23530b57cec5SDimitry Andric         uint32_t wc = *frm_nxt;
23540b57cec5SDimitry Andric         if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
23550b57cec5SDimitry Andric             return codecvt_base::error;
23560b57cec5SDimitry Andric         if (wc < 0x000080)
23570b57cec5SDimitry Andric         {
23580b57cec5SDimitry Andric             if (to_end-to_nxt < 1)
23590b57cec5SDimitry Andric                 return codecvt_base::partial;
23600b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc);
23610b57cec5SDimitry Andric         }
23620b57cec5SDimitry Andric         else if (wc < 0x000800)
23630b57cec5SDimitry Andric         {
23640b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
23650b57cec5SDimitry Andric                 return codecvt_base::partial;
23660b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc >> 6));
23670b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x03F));
23680b57cec5SDimitry Andric         }
23690b57cec5SDimitry Andric         else if (wc < 0x010000)
23700b57cec5SDimitry Andric         {
23710b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
23720b57cec5SDimitry Andric                 return codecvt_base::partial;
23730b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc >> 12));
23740b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6));
23750b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc & 0x003F));
23760b57cec5SDimitry Andric         }
23770b57cec5SDimitry Andric         else // if (wc < 0x110000)
23780b57cec5SDimitry Andric         {
23790b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
23800b57cec5SDimitry Andric                 return codecvt_base::partial;
23810b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xF0 |  (wc >> 18));
23820b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x03F000) >> 12));
23830b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x000FC0) >> 6));
23840b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc & 0x00003F));
23850b57cec5SDimitry Andric         }
23860b57cec5SDimitry Andric     }
23870b57cec5SDimitry Andric     return codecvt_base::ok;
23880b57cec5SDimitry Andric }
23890b57cec5SDimitry Andric 
23900b57cec5SDimitry Andric static
23910b57cec5SDimitry Andric codecvt_base::result
23920b57cec5SDimitry Andric utf8_to_ucs4(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
23930b57cec5SDimitry Andric              uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
23940b57cec5SDimitry Andric              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
23950b57cec5SDimitry Andric {
23960b57cec5SDimitry Andric     frm_nxt = frm;
23970b57cec5SDimitry Andric     to_nxt = to;
23980b57cec5SDimitry Andric     if (mode & consume_header)
23990b57cec5SDimitry Andric     {
24000b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
24010b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
24020b57cec5SDimitry Andric             frm_nxt += 3;
24030b57cec5SDimitry Andric     }
24040b57cec5SDimitry Andric     for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
24050b57cec5SDimitry Andric     {
24060b57cec5SDimitry Andric         uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
24070b57cec5SDimitry Andric         if (c1 < 0x80)
24080b57cec5SDimitry Andric         {
24090b57cec5SDimitry Andric             if (c1 > Maxcode)
24100b57cec5SDimitry Andric                 return codecvt_base::error;
24110b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(c1);
24120b57cec5SDimitry Andric             ++frm_nxt;
24130b57cec5SDimitry Andric         }
24140b57cec5SDimitry Andric         else if (c1 < 0xC2)
24150b57cec5SDimitry Andric         {
24160b57cec5SDimitry Andric             return codecvt_base::error;
24170b57cec5SDimitry Andric         }
24180b57cec5SDimitry Andric         else if (c1 < 0xE0)
24190b57cec5SDimitry Andric         {
24200b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
24210b57cec5SDimitry Andric                 return codecvt_base::partial;
24220b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
24230b57cec5SDimitry Andric             if ((c2 & 0xC0) != 0x80)
24240b57cec5SDimitry Andric                 return codecvt_base::error;
24250b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(((c1 & 0x1F) << 6)
24260b57cec5SDimitry Andric                                               | (c2 & 0x3F));
24270b57cec5SDimitry Andric             if (t > Maxcode)
24280b57cec5SDimitry Andric                 return codecvt_base::error;
24290b57cec5SDimitry Andric             *to_nxt = t;
24300b57cec5SDimitry Andric             frm_nxt += 2;
24310b57cec5SDimitry Andric         }
24320b57cec5SDimitry Andric         else if (c1 < 0xF0)
24330b57cec5SDimitry Andric         {
24340b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
24350b57cec5SDimitry Andric                 return codecvt_base::partial;
24360b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
24370b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
24380b57cec5SDimitry Andric             switch (c1)
24390b57cec5SDimitry Andric             {
24400b57cec5SDimitry Andric             case 0xE0:
24410b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
24420b57cec5SDimitry Andric                     return codecvt_base::error;
24430b57cec5SDimitry Andric                  break;
24440b57cec5SDimitry Andric             case 0xED:
24450b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
24460b57cec5SDimitry Andric                     return codecvt_base::error;
24470b57cec5SDimitry Andric                  break;
24480b57cec5SDimitry Andric             default:
24490b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
24500b57cec5SDimitry Andric                     return codecvt_base::error;
24510b57cec5SDimitry Andric                  break;
24520b57cec5SDimitry Andric             }
24530b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
24540b57cec5SDimitry Andric                 return codecvt_base::error;
24550b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(((c1 & 0x0F) << 12)
24560b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 6)
24570b57cec5SDimitry Andric                                              |  (c3 & 0x3F));
24580b57cec5SDimitry Andric             if (t > Maxcode)
24590b57cec5SDimitry Andric                 return codecvt_base::error;
24600b57cec5SDimitry Andric             *to_nxt = t;
24610b57cec5SDimitry Andric             frm_nxt += 3;
24620b57cec5SDimitry Andric         }
24630b57cec5SDimitry Andric         else if (c1 < 0xF5)
24640b57cec5SDimitry Andric         {
24650b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
24660b57cec5SDimitry Andric                 return codecvt_base::partial;
24670b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
24680b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
24690b57cec5SDimitry Andric             uint8_t c4 = frm_nxt[3];
24700b57cec5SDimitry Andric             switch (c1)
24710b57cec5SDimitry Andric             {
24720b57cec5SDimitry Andric             case 0xF0:
24730b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
24740b57cec5SDimitry Andric                     return codecvt_base::error;
24750b57cec5SDimitry Andric                  break;
24760b57cec5SDimitry Andric             case 0xF4:
24770b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
24780b57cec5SDimitry Andric                     return codecvt_base::error;
24790b57cec5SDimitry Andric                  break;
24800b57cec5SDimitry Andric             default:
24810b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
24820b57cec5SDimitry Andric                     return codecvt_base::error;
24830b57cec5SDimitry Andric                  break;
24840b57cec5SDimitry Andric             }
24850b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
24860b57cec5SDimitry Andric                 return codecvt_base::error;
24870b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(((c1 & 0x07) << 18)
24880b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 12)
24890b57cec5SDimitry Andric                                              | ((c3 & 0x3F) << 6)
24900b57cec5SDimitry Andric                                              |  (c4 & 0x3F));
24910b57cec5SDimitry Andric             if (t > Maxcode)
24920b57cec5SDimitry Andric                 return codecvt_base::error;
24930b57cec5SDimitry Andric             *to_nxt = t;
24940b57cec5SDimitry Andric             frm_nxt += 4;
24950b57cec5SDimitry Andric         }
24960b57cec5SDimitry Andric         else
24970b57cec5SDimitry Andric         {
24980b57cec5SDimitry Andric             return codecvt_base::error;
24990b57cec5SDimitry Andric         }
25000b57cec5SDimitry Andric     }
25010b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
25020b57cec5SDimitry Andric }
25030b57cec5SDimitry Andric 
25040b57cec5SDimitry Andric static
25050b57cec5SDimitry Andric int
25060b57cec5SDimitry Andric utf8_to_ucs4_length(const uint8_t* frm, const uint8_t* frm_end,
25070b57cec5SDimitry Andric                     size_t mx, unsigned long Maxcode = 0x10FFFF,
25080b57cec5SDimitry Andric                     codecvt_mode mode = codecvt_mode(0))
25090b57cec5SDimitry Andric {
25100b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
25110b57cec5SDimitry Andric     if (mode & consume_header)
25120b57cec5SDimitry Andric     {
25130b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
25140b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
25150b57cec5SDimitry Andric             frm_nxt += 3;
25160b57cec5SDimitry Andric     }
25170b57cec5SDimitry Andric     for (size_t nchar32_t = 0; frm_nxt < frm_end && nchar32_t < mx; ++nchar32_t)
25180b57cec5SDimitry Andric     {
25190b57cec5SDimitry Andric         uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
25200b57cec5SDimitry Andric         if (c1 < 0x80)
25210b57cec5SDimitry Andric         {
25220b57cec5SDimitry Andric             if (c1 > Maxcode)
25230b57cec5SDimitry Andric                 break;
25240b57cec5SDimitry Andric             ++frm_nxt;
25250b57cec5SDimitry Andric         }
25260b57cec5SDimitry Andric         else if (c1 < 0xC2)
25270b57cec5SDimitry Andric         {
25280b57cec5SDimitry Andric             break;
25290b57cec5SDimitry Andric         }
25300b57cec5SDimitry Andric         else if (c1 < 0xE0)
25310b57cec5SDimitry Andric         {
25320b57cec5SDimitry Andric             if ((frm_end-frm_nxt < 2) || ((frm_nxt[1] & 0xC0) != 0x80))
25330b57cec5SDimitry Andric                 break;
25340b57cec5SDimitry Andric             if ((((c1 & 0x1Fu) << 6) | (frm_nxt[1] & 0x3Fu)) > Maxcode)
25350b57cec5SDimitry Andric                 break;
25360b57cec5SDimitry Andric             frm_nxt += 2;
25370b57cec5SDimitry Andric         }
25380b57cec5SDimitry Andric         else if (c1 < 0xF0)
25390b57cec5SDimitry Andric         {
25400b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
25410b57cec5SDimitry Andric                 break;
25420b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
25430b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
25440b57cec5SDimitry Andric             switch (c1)
25450b57cec5SDimitry Andric             {
25460b57cec5SDimitry Andric             case 0xE0:
25470b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
25480b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25490b57cec5SDimitry Andric                 break;
25500b57cec5SDimitry Andric             case 0xED:
25510b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
25520b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25530b57cec5SDimitry Andric                  break;
25540b57cec5SDimitry Andric             default:
25550b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
25560b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25570b57cec5SDimitry Andric                  break;
25580b57cec5SDimitry Andric             }
25590b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
25600b57cec5SDimitry Andric                 break;
25610b57cec5SDimitry Andric             if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
25620b57cec5SDimitry Andric                 break;
25630b57cec5SDimitry Andric             frm_nxt += 3;
25640b57cec5SDimitry Andric         }
25650b57cec5SDimitry Andric         else if (c1 < 0xF5)
25660b57cec5SDimitry Andric         {
25670b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
25680b57cec5SDimitry Andric                 break;
25690b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
25700b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
25710b57cec5SDimitry Andric             uint8_t c4 = frm_nxt[3];
25720b57cec5SDimitry Andric             switch (c1)
25730b57cec5SDimitry Andric             {
25740b57cec5SDimitry Andric             case 0xF0:
25750b57cec5SDimitry Andric                 if (!(0x90 <= c2 && c2 <= 0xBF))
25760b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25770b57cec5SDimitry Andric                  break;
25780b57cec5SDimitry Andric             case 0xF4:
25790b57cec5SDimitry Andric                 if ((c2 & 0xF0) != 0x80)
25800b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25810b57cec5SDimitry Andric                  break;
25820b57cec5SDimitry Andric             default:
25830b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
25840b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
25850b57cec5SDimitry Andric                  break;
25860b57cec5SDimitry Andric             }
25870b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
25880b57cec5SDimitry Andric                 break;
25890b57cec5SDimitry Andric             if ((((c1 & 0x07u) << 18) | ((c2 & 0x3Fu) << 12) |
25900b57cec5SDimitry Andric                  ((c3 & 0x3Fu) << 6)  |  (c4 & 0x3Fu)) > Maxcode)
25910b57cec5SDimitry Andric                 break;
25920b57cec5SDimitry Andric             frm_nxt += 4;
25930b57cec5SDimitry Andric         }
25940b57cec5SDimitry Andric         else
25950b57cec5SDimitry Andric         {
25960b57cec5SDimitry Andric             break;
25970b57cec5SDimitry Andric         }
25980b57cec5SDimitry Andric     }
25990b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
26000b57cec5SDimitry Andric }
26010b57cec5SDimitry Andric 
26020b57cec5SDimitry Andric static
26030b57cec5SDimitry Andric codecvt_base::result
26040b57cec5SDimitry Andric ucs2_to_utf8(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
26050b57cec5SDimitry Andric              uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
26060b57cec5SDimitry Andric              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
26070b57cec5SDimitry Andric {
26080b57cec5SDimitry Andric     frm_nxt = frm;
26090b57cec5SDimitry Andric     to_nxt = to;
26100b57cec5SDimitry Andric     if (mode & generate_header)
26110b57cec5SDimitry Andric     {
26120b57cec5SDimitry Andric         if (to_end-to_nxt < 3)
26130b57cec5SDimitry Andric             return codecvt_base::partial;
26140b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xEF);
26150b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBB);
26160b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xBF);
26170b57cec5SDimitry Andric     }
26180b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
26190b57cec5SDimitry Andric     {
26200b57cec5SDimitry Andric         uint16_t wc = *frm_nxt;
26210b57cec5SDimitry Andric         if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
26220b57cec5SDimitry Andric             return codecvt_base::error;
26230b57cec5SDimitry Andric         if (wc < 0x0080)
26240b57cec5SDimitry Andric         {
26250b57cec5SDimitry Andric             if (to_end-to_nxt < 1)
26260b57cec5SDimitry Andric                 return codecvt_base::partial;
26270b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc);
26280b57cec5SDimitry Andric         }
26290b57cec5SDimitry Andric         else if (wc < 0x0800)
26300b57cec5SDimitry Andric         {
26310b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
26320b57cec5SDimitry Andric                 return codecvt_base::partial;
26330b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc >> 6));
26340b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x03F));
26350b57cec5SDimitry Andric         }
26360b57cec5SDimitry Andric         else // if (wc <= 0xFFFF)
26370b57cec5SDimitry Andric         {
26380b57cec5SDimitry Andric             if (to_end-to_nxt < 3)
26390b57cec5SDimitry Andric                 return codecvt_base::partial;
26400b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc >> 12));
26410b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6));
26420b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc & 0x003F));
26430b57cec5SDimitry Andric         }
26440b57cec5SDimitry Andric     }
26450b57cec5SDimitry Andric     return codecvt_base::ok;
26460b57cec5SDimitry Andric }
26470b57cec5SDimitry Andric 
26480b57cec5SDimitry Andric static
26490b57cec5SDimitry Andric codecvt_base::result
26500b57cec5SDimitry Andric utf8_to_ucs2(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
26510b57cec5SDimitry Andric              uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
26520b57cec5SDimitry Andric              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
26530b57cec5SDimitry Andric {
26540b57cec5SDimitry Andric     frm_nxt = frm;
26550b57cec5SDimitry Andric     to_nxt = to;
26560b57cec5SDimitry Andric     if (mode & consume_header)
26570b57cec5SDimitry Andric     {
26580b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
26590b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
26600b57cec5SDimitry Andric             frm_nxt += 3;
26610b57cec5SDimitry Andric     }
26620b57cec5SDimitry Andric     for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
26630b57cec5SDimitry Andric     {
26640b57cec5SDimitry Andric         uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
26650b57cec5SDimitry Andric         if (c1 < 0x80)
26660b57cec5SDimitry Andric         {
26670b57cec5SDimitry Andric             if (c1 > Maxcode)
26680b57cec5SDimitry Andric                 return codecvt_base::error;
26690b57cec5SDimitry Andric             *to_nxt = static_cast<uint16_t>(c1);
26700b57cec5SDimitry Andric             ++frm_nxt;
26710b57cec5SDimitry Andric         }
26720b57cec5SDimitry Andric         else if (c1 < 0xC2)
26730b57cec5SDimitry Andric         {
26740b57cec5SDimitry Andric             return codecvt_base::error;
26750b57cec5SDimitry Andric         }
26760b57cec5SDimitry Andric         else if (c1 < 0xE0)
26770b57cec5SDimitry Andric         {
26780b57cec5SDimitry Andric             if (frm_end-frm_nxt < 2)
26790b57cec5SDimitry Andric                 return codecvt_base::partial;
26800b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
26810b57cec5SDimitry Andric             if ((c2 & 0xC0) != 0x80)
26820b57cec5SDimitry Andric                 return codecvt_base::error;
26830b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6)
26840b57cec5SDimitry Andric                                               | (c2 & 0x3F));
26850b57cec5SDimitry Andric             if (t > Maxcode)
26860b57cec5SDimitry Andric                 return codecvt_base::error;
26870b57cec5SDimitry Andric             *to_nxt = t;
26880b57cec5SDimitry Andric             frm_nxt += 2;
26890b57cec5SDimitry Andric         }
26900b57cec5SDimitry Andric         else if (c1 < 0xF0)
26910b57cec5SDimitry Andric         {
26920b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
26930b57cec5SDimitry Andric                 return codecvt_base::partial;
26940b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
26950b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
26960b57cec5SDimitry Andric             switch (c1)
26970b57cec5SDimitry Andric             {
26980b57cec5SDimitry Andric             case 0xE0:
26990b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
27000b57cec5SDimitry Andric                     return codecvt_base::error;
27010b57cec5SDimitry Andric                  break;
27020b57cec5SDimitry Andric             case 0xED:
27030b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
27040b57cec5SDimitry Andric                     return codecvt_base::error;
27050b57cec5SDimitry Andric                  break;
27060b57cec5SDimitry Andric             default:
27070b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
27080b57cec5SDimitry Andric                     return codecvt_base::error;
27090b57cec5SDimitry Andric                  break;
27100b57cec5SDimitry Andric             }
27110b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
27120b57cec5SDimitry Andric                 return codecvt_base::error;
27130b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
27140b57cec5SDimitry Andric                                              | ((c2 & 0x3F) << 6)
27150b57cec5SDimitry Andric                                              |  (c3 & 0x3F));
27160b57cec5SDimitry Andric             if (t > Maxcode)
27170b57cec5SDimitry Andric                 return codecvt_base::error;
27180b57cec5SDimitry Andric             *to_nxt = t;
27190b57cec5SDimitry Andric             frm_nxt += 3;
27200b57cec5SDimitry Andric         }
27210b57cec5SDimitry Andric         else
27220b57cec5SDimitry Andric         {
27230b57cec5SDimitry Andric             return codecvt_base::error;
27240b57cec5SDimitry Andric         }
27250b57cec5SDimitry Andric     }
27260b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
27270b57cec5SDimitry Andric }
27280b57cec5SDimitry Andric 
27290b57cec5SDimitry Andric static
27300b57cec5SDimitry Andric int
27310b57cec5SDimitry Andric utf8_to_ucs2_length(const uint8_t* frm, const uint8_t* frm_end,
27320b57cec5SDimitry Andric                     size_t mx, unsigned long Maxcode = 0x10FFFF,
27330b57cec5SDimitry Andric                     codecvt_mode mode = codecvt_mode(0))
27340b57cec5SDimitry Andric {
27350b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
27360b57cec5SDimitry Andric     if (mode & consume_header)
27370b57cec5SDimitry Andric     {
27380b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
27390b57cec5SDimitry Andric                                                           frm_nxt[2] == 0xBF)
27400b57cec5SDimitry Andric             frm_nxt += 3;
27410b57cec5SDimitry Andric     }
27420b57cec5SDimitry Andric     for (size_t nchar32_t = 0; frm_nxt < frm_end && nchar32_t < mx; ++nchar32_t)
27430b57cec5SDimitry Andric     {
27440b57cec5SDimitry Andric         uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
27450b57cec5SDimitry Andric         if (c1 < 0x80)
27460b57cec5SDimitry Andric         {
27470b57cec5SDimitry Andric             if (c1 > Maxcode)
27480b57cec5SDimitry Andric                 break;
27490b57cec5SDimitry Andric             ++frm_nxt;
27500b57cec5SDimitry Andric         }
27510b57cec5SDimitry Andric         else if (c1 < 0xC2)
27520b57cec5SDimitry Andric         {
27530b57cec5SDimitry Andric             break;
27540b57cec5SDimitry Andric         }
27550b57cec5SDimitry Andric         else if (c1 < 0xE0)
27560b57cec5SDimitry Andric         {
27570b57cec5SDimitry Andric             if ((frm_end-frm_nxt < 2) || ((frm_nxt[1] & 0xC0) != 0x80))
27580b57cec5SDimitry Andric                 break;
27590b57cec5SDimitry Andric             if ((((c1 & 0x1Fu) << 6) | (frm_nxt[1] & 0x3Fu)) > Maxcode)
27600b57cec5SDimitry Andric                 break;
27610b57cec5SDimitry Andric             frm_nxt += 2;
27620b57cec5SDimitry Andric         }
27630b57cec5SDimitry Andric         else if (c1 < 0xF0)
27640b57cec5SDimitry Andric         {
27650b57cec5SDimitry Andric             if (frm_end-frm_nxt < 3)
27660b57cec5SDimitry Andric                 break;
27670b57cec5SDimitry Andric             uint8_t c2 = frm_nxt[1];
27680b57cec5SDimitry Andric             uint8_t c3 = frm_nxt[2];
27690b57cec5SDimitry Andric             switch (c1)
27700b57cec5SDimitry Andric             {
27710b57cec5SDimitry Andric             case 0xE0:
27720b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0xA0)
27730b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
27740b57cec5SDimitry Andric                 break;
27750b57cec5SDimitry Andric             case 0xED:
27760b57cec5SDimitry Andric                 if ((c2 & 0xE0) != 0x80)
27770b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
27780b57cec5SDimitry Andric                  break;
27790b57cec5SDimitry Andric             default:
27800b57cec5SDimitry Andric                 if ((c2 & 0xC0) != 0x80)
27810b57cec5SDimitry Andric                     return static_cast<int>(frm_nxt - frm);
27820b57cec5SDimitry Andric                  break;
27830b57cec5SDimitry Andric             }
27840b57cec5SDimitry Andric             if ((c3 & 0xC0) != 0x80)
27850b57cec5SDimitry Andric                 break;
27860b57cec5SDimitry Andric             if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
27870b57cec5SDimitry Andric                 break;
27880b57cec5SDimitry Andric             frm_nxt += 3;
27890b57cec5SDimitry Andric         }
27900b57cec5SDimitry Andric         else
27910b57cec5SDimitry Andric         {
27920b57cec5SDimitry Andric             break;
27930b57cec5SDimitry Andric         }
27940b57cec5SDimitry Andric     }
27950b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
27960b57cec5SDimitry Andric }
27970b57cec5SDimitry Andric 
27980b57cec5SDimitry Andric static
27990b57cec5SDimitry Andric codecvt_base::result
28000b57cec5SDimitry Andric ucs4_to_utf16be(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
28010b57cec5SDimitry Andric                 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
28020b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
28030b57cec5SDimitry Andric {
28040b57cec5SDimitry Andric     frm_nxt = frm;
28050b57cec5SDimitry Andric     to_nxt = to;
28060b57cec5SDimitry Andric     if (mode & generate_header)
28070b57cec5SDimitry Andric     {
28080b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
28090b57cec5SDimitry Andric             return codecvt_base::partial;
28100b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFE);
28110b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFF);
28120b57cec5SDimitry Andric     }
28130b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
28140b57cec5SDimitry Andric     {
28150b57cec5SDimitry Andric         uint32_t wc = *frm_nxt;
28160b57cec5SDimitry Andric         if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
28170b57cec5SDimitry Andric             return codecvt_base::error;
28180b57cec5SDimitry Andric         if (wc < 0x010000)
28190b57cec5SDimitry Andric         {
28200b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
28210b57cec5SDimitry Andric                 return codecvt_base::partial;
28220b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc >> 8);
28230b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc);
28240b57cec5SDimitry Andric         }
28250b57cec5SDimitry Andric         else
28260b57cec5SDimitry Andric         {
28270b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
28280b57cec5SDimitry Andric                 return codecvt_base::partial;
28290b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(
28300b57cec5SDimitry Andric                     0xD800
28310b57cec5SDimitry Andric                   | ((((wc & 0x1F0000) >> 16) - 1) << 6)
28320b57cec5SDimitry Andric                   |   ((wc & 0x00FC00) >> 10));
28330b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t >> 8);
28340b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t);
28350b57cec5SDimitry Andric             t = static_cast<uint16_t>(0xDC00 | (wc & 0x03FF));
28360b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t >> 8);
28370b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t);
28380b57cec5SDimitry Andric         }
28390b57cec5SDimitry Andric     }
28400b57cec5SDimitry Andric     return codecvt_base::ok;
28410b57cec5SDimitry Andric }
28420b57cec5SDimitry Andric 
28430b57cec5SDimitry Andric static
28440b57cec5SDimitry Andric codecvt_base::result
28450b57cec5SDimitry Andric utf16be_to_ucs4(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
28460b57cec5SDimitry Andric                 uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
28470b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
28480b57cec5SDimitry Andric {
28490b57cec5SDimitry Andric     frm_nxt = frm;
28500b57cec5SDimitry Andric     to_nxt = to;
28510b57cec5SDimitry Andric     if (mode & consume_header)
28520b57cec5SDimitry Andric     {
28530b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
28540b57cec5SDimitry Andric             frm_nxt += 2;
28550b57cec5SDimitry Andric     }
28560b57cec5SDimitry Andric     for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
28570b57cec5SDimitry Andric     {
28580b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
28590b57cec5SDimitry Andric         if ((c1 & 0xFC00) == 0xDC00)
28600b57cec5SDimitry Andric             return codecvt_base::error;
28610b57cec5SDimitry Andric         if ((c1 & 0xFC00) != 0xD800)
28620b57cec5SDimitry Andric         {
28630b57cec5SDimitry Andric             if (c1 > Maxcode)
28640b57cec5SDimitry Andric                 return codecvt_base::error;
28650b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(c1);
28660b57cec5SDimitry Andric             frm_nxt += 2;
28670b57cec5SDimitry Andric         }
28680b57cec5SDimitry Andric         else
28690b57cec5SDimitry Andric         {
28700b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
28710b57cec5SDimitry Andric                 return codecvt_base::partial;
28720b57cec5SDimitry Andric             uint16_t c2 = static_cast<uint16_t>(frm_nxt[2] << 8 | frm_nxt[3]);
28730b57cec5SDimitry Andric             if ((c2 & 0xFC00) != 0xDC00)
28740b57cec5SDimitry Andric                 return codecvt_base::error;
28750b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(
28760b57cec5SDimitry Andric                     ((((c1 & 0x03C0) >> 6) + 1) << 16)
28770b57cec5SDimitry Andric                   |   ((c1 & 0x003F) << 10)
28780b57cec5SDimitry Andric                   |    (c2 & 0x03FF));
28790b57cec5SDimitry Andric             if (t > Maxcode)
28800b57cec5SDimitry Andric                 return codecvt_base::error;
28810b57cec5SDimitry Andric             *to_nxt = t;
28820b57cec5SDimitry Andric             frm_nxt += 4;
28830b57cec5SDimitry Andric         }
28840b57cec5SDimitry Andric     }
28850b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
28860b57cec5SDimitry Andric }
28870b57cec5SDimitry Andric 
28880b57cec5SDimitry Andric static
28890b57cec5SDimitry Andric int
28900b57cec5SDimitry Andric utf16be_to_ucs4_length(const uint8_t* frm, const uint8_t* frm_end,
28910b57cec5SDimitry Andric                        size_t mx, unsigned long Maxcode = 0x10FFFF,
28920b57cec5SDimitry Andric                        codecvt_mode mode = codecvt_mode(0))
28930b57cec5SDimitry Andric {
28940b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
28950b57cec5SDimitry Andric     if (mode & consume_header)
28960b57cec5SDimitry Andric     {
28970b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
28980b57cec5SDimitry Andric             frm_nxt += 2;
28990b57cec5SDimitry Andric     }
29000b57cec5SDimitry Andric     for (size_t nchar32_t = 0; frm_nxt < frm_end - 1 && nchar32_t < mx; ++nchar32_t)
29010b57cec5SDimitry Andric     {
29020b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
29030b57cec5SDimitry Andric         if ((c1 & 0xFC00) == 0xDC00)
29040b57cec5SDimitry Andric             break;
29050b57cec5SDimitry Andric         if ((c1 & 0xFC00) != 0xD800)
29060b57cec5SDimitry Andric         {
29070b57cec5SDimitry Andric             if (c1 > Maxcode)
29080b57cec5SDimitry Andric                 break;
29090b57cec5SDimitry Andric             frm_nxt += 2;
29100b57cec5SDimitry Andric         }
29110b57cec5SDimitry Andric         else
29120b57cec5SDimitry Andric         {
29130b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
29140b57cec5SDimitry Andric                 break;
29150b57cec5SDimitry Andric             uint16_t c2 = static_cast<uint16_t>(frm_nxt[2] << 8 | frm_nxt[3]);
29160b57cec5SDimitry Andric             if ((c2 & 0xFC00) != 0xDC00)
29170b57cec5SDimitry Andric                 break;
29180b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(
29190b57cec5SDimitry Andric                     ((((c1 & 0x03C0) >> 6) + 1) << 16)
29200b57cec5SDimitry Andric                   |   ((c1 & 0x003F) << 10)
29210b57cec5SDimitry Andric                   |    (c2 & 0x03FF));
29220b57cec5SDimitry Andric             if (t > Maxcode)
29230b57cec5SDimitry Andric                 break;
29240b57cec5SDimitry Andric             frm_nxt += 4;
29250b57cec5SDimitry Andric         }
29260b57cec5SDimitry Andric     }
29270b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
29280b57cec5SDimitry Andric }
29290b57cec5SDimitry Andric 
29300b57cec5SDimitry Andric static
29310b57cec5SDimitry Andric codecvt_base::result
29320b57cec5SDimitry Andric ucs4_to_utf16le(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
29330b57cec5SDimitry Andric                 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
29340b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
29350b57cec5SDimitry Andric {
29360b57cec5SDimitry Andric     frm_nxt = frm;
29370b57cec5SDimitry Andric     to_nxt = to;
29380b57cec5SDimitry Andric     if (mode & generate_header)
29390b57cec5SDimitry Andric     {
29400b57cec5SDimitry Andric         if (to_end - to_nxt < 2)
29410b57cec5SDimitry Andric             return codecvt_base::partial;
29420b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFF);
29430b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFE);
29440b57cec5SDimitry Andric     }
29450b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
29460b57cec5SDimitry Andric     {
29470b57cec5SDimitry Andric         uint32_t wc = *frm_nxt;
29480b57cec5SDimitry Andric         if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
29490b57cec5SDimitry Andric             return codecvt_base::error;
29500b57cec5SDimitry Andric         if (wc < 0x010000)
29510b57cec5SDimitry Andric         {
29520b57cec5SDimitry Andric             if (to_end-to_nxt < 2)
29530b57cec5SDimitry Andric                 return codecvt_base::partial;
29540b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc);
29550b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(wc >> 8);
29560b57cec5SDimitry Andric         }
29570b57cec5SDimitry Andric         else
29580b57cec5SDimitry Andric         {
29590b57cec5SDimitry Andric             if (to_end-to_nxt < 4)
29600b57cec5SDimitry Andric                 return codecvt_base::partial;
29610b57cec5SDimitry Andric             uint16_t t = static_cast<uint16_t>(
29620b57cec5SDimitry Andric                     0xD800
29630b57cec5SDimitry Andric                   | ((((wc & 0x1F0000) >> 16) - 1) << 6)
29640b57cec5SDimitry Andric                   |   ((wc & 0x00FC00) >> 10));
29650b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t);
29660b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t >> 8);
29670b57cec5SDimitry Andric             t = static_cast<uint16_t>(0xDC00 | (wc & 0x03FF));
29680b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t);
29690b57cec5SDimitry Andric             *to_nxt++ = static_cast<uint8_t>(t >> 8);
29700b57cec5SDimitry Andric         }
29710b57cec5SDimitry Andric     }
29720b57cec5SDimitry Andric     return codecvt_base::ok;
29730b57cec5SDimitry Andric }
29740b57cec5SDimitry Andric 
29750b57cec5SDimitry Andric static
29760b57cec5SDimitry Andric codecvt_base::result
29770b57cec5SDimitry Andric utf16le_to_ucs4(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
29780b57cec5SDimitry Andric                 uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
29790b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
29800b57cec5SDimitry Andric {
29810b57cec5SDimitry Andric     frm_nxt = frm;
29820b57cec5SDimitry Andric     to_nxt = to;
29830b57cec5SDimitry Andric     if (mode & consume_header)
29840b57cec5SDimitry Andric     {
29850b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
29860b57cec5SDimitry Andric             frm_nxt += 2;
29870b57cec5SDimitry Andric     }
29880b57cec5SDimitry Andric     for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
29890b57cec5SDimitry Andric     {
29900b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
29910b57cec5SDimitry Andric         if ((c1 & 0xFC00) == 0xDC00)
29920b57cec5SDimitry Andric             return codecvt_base::error;
29930b57cec5SDimitry Andric         if ((c1 & 0xFC00) != 0xD800)
29940b57cec5SDimitry Andric         {
29950b57cec5SDimitry Andric             if (c1 > Maxcode)
29960b57cec5SDimitry Andric                 return codecvt_base::error;
29970b57cec5SDimitry Andric             *to_nxt = static_cast<uint32_t>(c1);
29980b57cec5SDimitry Andric             frm_nxt += 2;
29990b57cec5SDimitry Andric         }
30000b57cec5SDimitry Andric         else
30010b57cec5SDimitry Andric         {
30020b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
30030b57cec5SDimitry Andric                 return codecvt_base::partial;
30040b57cec5SDimitry Andric             uint16_t c2 = static_cast<uint16_t>(frm_nxt[3] << 8 | frm_nxt[2]);
30050b57cec5SDimitry Andric             if ((c2 & 0xFC00) != 0xDC00)
30060b57cec5SDimitry Andric                 return codecvt_base::error;
30070b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(
30080b57cec5SDimitry Andric                     ((((c1 & 0x03C0) >> 6) + 1) << 16)
30090b57cec5SDimitry Andric                   |   ((c1 & 0x003F) << 10)
30100b57cec5SDimitry Andric                   |    (c2 & 0x03FF));
30110b57cec5SDimitry Andric             if (t > Maxcode)
30120b57cec5SDimitry Andric                 return codecvt_base::error;
30130b57cec5SDimitry Andric             *to_nxt = t;
30140b57cec5SDimitry Andric             frm_nxt += 4;
30150b57cec5SDimitry Andric         }
30160b57cec5SDimitry Andric     }
30170b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
30180b57cec5SDimitry Andric }
30190b57cec5SDimitry Andric 
30200b57cec5SDimitry Andric static
30210b57cec5SDimitry Andric int
30220b57cec5SDimitry Andric utf16le_to_ucs4_length(const uint8_t* frm, const uint8_t* frm_end,
30230b57cec5SDimitry Andric                        size_t mx, unsigned long Maxcode = 0x10FFFF,
30240b57cec5SDimitry Andric                        codecvt_mode mode = codecvt_mode(0))
30250b57cec5SDimitry Andric {
30260b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
30270b57cec5SDimitry Andric     if (mode & consume_header)
30280b57cec5SDimitry Andric     {
30290b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
30300b57cec5SDimitry Andric             frm_nxt += 2;
30310b57cec5SDimitry Andric     }
30320b57cec5SDimitry Andric     for (size_t nchar32_t = 0; frm_nxt < frm_end - 1 && nchar32_t < mx; ++nchar32_t)
30330b57cec5SDimitry Andric     {
30340b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
30350b57cec5SDimitry Andric         if ((c1 & 0xFC00) == 0xDC00)
30360b57cec5SDimitry Andric             break;
30370b57cec5SDimitry Andric         if ((c1 & 0xFC00) != 0xD800)
30380b57cec5SDimitry Andric         {
30390b57cec5SDimitry Andric             if (c1 > Maxcode)
30400b57cec5SDimitry Andric                 break;
30410b57cec5SDimitry Andric             frm_nxt += 2;
30420b57cec5SDimitry Andric         }
30430b57cec5SDimitry Andric         else
30440b57cec5SDimitry Andric         {
30450b57cec5SDimitry Andric             if (frm_end-frm_nxt < 4)
30460b57cec5SDimitry Andric                 break;
30470b57cec5SDimitry Andric             uint16_t c2 = static_cast<uint16_t>(frm_nxt[3] << 8 | frm_nxt[2]);
30480b57cec5SDimitry Andric             if ((c2 & 0xFC00) != 0xDC00)
30490b57cec5SDimitry Andric                 break;
30500b57cec5SDimitry Andric             uint32_t t = static_cast<uint32_t>(
30510b57cec5SDimitry Andric                     ((((c1 & 0x03C0) >> 6) + 1) << 16)
30520b57cec5SDimitry Andric                   |   ((c1 & 0x003F) << 10)
30530b57cec5SDimitry Andric                   |    (c2 & 0x03FF));
30540b57cec5SDimitry Andric             if (t > Maxcode)
30550b57cec5SDimitry Andric                 break;
30560b57cec5SDimitry Andric             frm_nxt += 4;
30570b57cec5SDimitry Andric         }
30580b57cec5SDimitry Andric     }
30590b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
30600b57cec5SDimitry Andric }
30610b57cec5SDimitry Andric 
30620b57cec5SDimitry Andric static
30630b57cec5SDimitry Andric codecvt_base::result
30640b57cec5SDimitry Andric ucs2_to_utf16be(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
30650b57cec5SDimitry Andric                 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
30660b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
30670b57cec5SDimitry Andric {
30680b57cec5SDimitry Andric     frm_nxt = frm;
30690b57cec5SDimitry Andric     to_nxt = to;
30700b57cec5SDimitry Andric     if (mode & generate_header)
30710b57cec5SDimitry Andric     {
30720b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
30730b57cec5SDimitry Andric             return codecvt_base::partial;
30740b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFE);
30750b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFF);
30760b57cec5SDimitry Andric     }
30770b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
30780b57cec5SDimitry Andric     {
30790b57cec5SDimitry Andric         uint16_t wc = *frm_nxt;
30800b57cec5SDimitry Andric         if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
30810b57cec5SDimitry Andric             return codecvt_base::error;
30820b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
30830b57cec5SDimitry Andric             return codecvt_base::partial;
30840b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(wc >> 8);
30850b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(wc);
30860b57cec5SDimitry Andric     }
30870b57cec5SDimitry Andric     return codecvt_base::ok;
30880b57cec5SDimitry Andric }
30890b57cec5SDimitry Andric 
30900b57cec5SDimitry Andric static
30910b57cec5SDimitry Andric codecvt_base::result
30920b57cec5SDimitry Andric utf16be_to_ucs2(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
30930b57cec5SDimitry Andric                 uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
30940b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
30950b57cec5SDimitry Andric {
30960b57cec5SDimitry Andric     frm_nxt = frm;
30970b57cec5SDimitry Andric     to_nxt = to;
30980b57cec5SDimitry Andric     if (mode & consume_header)
30990b57cec5SDimitry Andric     {
31000b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
31010b57cec5SDimitry Andric             frm_nxt += 2;
31020b57cec5SDimitry Andric     }
31030b57cec5SDimitry Andric     for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
31040b57cec5SDimitry Andric     {
31050b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
31060b57cec5SDimitry Andric         if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
31070b57cec5SDimitry Andric             return codecvt_base::error;
31080b57cec5SDimitry Andric         *to_nxt = c1;
31090b57cec5SDimitry Andric         frm_nxt += 2;
31100b57cec5SDimitry Andric     }
31110b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
31120b57cec5SDimitry Andric }
31130b57cec5SDimitry Andric 
31140b57cec5SDimitry Andric static
31150b57cec5SDimitry Andric int
31160b57cec5SDimitry Andric utf16be_to_ucs2_length(const uint8_t* frm, const uint8_t* frm_end,
31170b57cec5SDimitry Andric                        size_t mx, unsigned long Maxcode = 0x10FFFF,
31180b57cec5SDimitry Andric                        codecvt_mode mode = codecvt_mode(0))
31190b57cec5SDimitry Andric {
31200b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
31210b57cec5SDimitry Andric     if (mode & consume_header)
31220b57cec5SDimitry Andric     {
31230b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFE && frm_nxt[1] == 0xFF)
31240b57cec5SDimitry Andric             frm_nxt += 2;
31250b57cec5SDimitry Andric     }
31260b57cec5SDimitry Andric     for (size_t nchar16_t = 0; frm_nxt < frm_end - 1 && nchar16_t < mx; ++nchar16_t)
31270b57cec5SDimitry Andric     {
31280b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[0] << 8 | frm_nxt[1]);
31290b57cec5SDimitry Andric         if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
31300b57cec5SDimitry Andric             break;
31310b57cec5SDimitry Andric         frm_nxt += 2;
31320b57cec5SDimitry Andric     }
31330b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
31340b57cec5SDimitry Andric }
31350b57cec5SDimitry Andric 
31360b57cec5SDimitry Andric static
31370b57cec5SDimitry Andric codecvt_base::result
31380b57cec5SDimitry Andric ucs2_to_utf16le(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
31390b57cec5SDimitry Andric                 uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
31400b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
31410b57cec5SDimitry Andric {
31420b57cec5SDimitry Andric     frm_nxt = frm;
31430b57cec5SDimitry Andric     to_nxt = to;
31440b57cec5SDimitry Andric     if (mode & generate_header)
31450b57cec5SDimitry Andric     {
31460b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
31470b57cec5SDimitry Andric             return codecvt_base::partial;
31480b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFF);
31490b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(0xFE);
31500b57cec5SDimitry Andric     }
31510b57cec5SDimitry Andric     for (; frm_nxt < frm_end; ++frm_nxt)
31520b57cec5SDimitry Andric     {
31530b57cec5SDimitry Andric         uint16_t wc = *frm_nxt;
31540b57cec5SDimitry Andric         if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
31550b57cec5SDimitry Andric             return codecvt_base::error;
31560b57cec5SDimitry Andric         if (to_end-to_nxt < 2)
31570b57cec5SDimitry Andric             return codecvt_base::partial;
31580b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(wc);
31590b57cec5SDimitry Andric         *to_nxt++ = static_cast<uint8_t>(wc >> 8);
31600b57cec5SDimitry Andric     }
31610b57cec5SDimitry Andric     return codecvt_base::ok;
31620b57cec5SDimitry Andric }
31630b57cec5SDimitry Andric 
31640b57cec5SDimitry Andric static
31650b57cec5SDimitry Andric codecvt_base::result
31660b57cec5SDimitry Andric utf16le_to_ucs2(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
31670b57cec5SDimitry Andric                 uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
31680b57cec5SDimitry Andric                 unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
31690b57cec5SDimitry Andric {
31700b57cec5SDimitry Andric     frm_nxt = frm;
31710b57cec5SDimitry Andric     to_nxt = to;
31720b57cec5SDimitry Andric     if (mode & consume_header)
31730b57cec5SDimitry Andric     {
31740b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
31750b57cec5SDimitry Andric             frm_nxt += 2;
31760b57cec5SDimitry Andric     }
31770b57cec5SDimitry Andric     for (; frm_nxt < frm_end - 1 && to_nxt < to_end; ++to_nxt)
31780b57cec5SDimitry Andric     {
31790b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
31800b57cec5SDimitry Andric         if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
31810b57cec5SDimitry Andric             return codecvt_base::error;
31820b57cec5SDimitry Andric         *to_nxt = c1;
31830b57cec5SDimitry Andric         frm_nxt += 2;
31840b57cec5SDimitry Andric     }
31850b57cec5SDimitry Andric     return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
31860b57cec5SDimitry Andric }
31870b57cec5SDimitry Andric 
31880b57cec5SDimitry Andric static
31890b57cec5SDimitry Andric int
31900b57cec5SDimitry Andric utf16le_to_ucs2_length(const uint8_t* frm, const uint8_t* frm_end,
31910b57cec5SDimitry Andric                        size_t mx, unsigned long Maxcode = 0x10FFFF,
31920b57cec5SDimitry Andric                        codecvt_mode mode = codecvt_mode(0))
31930b57cec5SDimitry Andric {
31940b57cec5SDimitry Andric     const uint8_t* frm_nxt = frm;
31950b57cec5SDimitry Andric     frm_nxt = frm;
31960b57cec5SDimitry Andric     if (mode & consume_header)
31970b57cec5SDimitry Andric     {
31980b57cec5SDimitry Andric         if (frm_end-frm_nxt >= 2 && frm_nxt[0] == 0xFF && frm_nxt[1] == 0xFE)
31990b57cec5SDimitry Andric             frm_nxt += 2;
32000b57cec5SDimitry Andric     }
32010b57cec5SDimitry Andric     for (size_t nchar16_t = 0; frm_nxt < frm_end - 1 && nchar16_t < mx; ++nchar16_t)
32020b57cec5SDimitry Andric     {
32030b57cec5SDimitry Andric         uint16_t c1 = static_cast<uint16_t>(frm_nxt[1] << 8 | frm_nxt[0]);
32040b57cec5SDimitry Andric         if ((c1 & 0xF800) == 0xD800 || c1 > Maxcode)
32050b57cec5SDimitry Andric             break;
32060b57cec5SDimitry Andric         frm_nxt += 2;
32070b57cec5SDimitry Andric     }
32080b57cec5SDimitry Andric     return static_cast<int>(frm_nxt - frm);
32090b57cec5SDimitry Andric }
32100b57cec5SDimitry Andric 
32110b57cec5SDimitry Andric // template <> class codecvt<char16_t, char, mbstate_t>
32120b57cec5SDimitry Andric 
32130b57cec5SDimitry Andric locale::id codecvt<char16_t, char, mbstate_t>::id;
32140b57cec5SDimitry Andric 
32150b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::~codecvt()
32160b57cec5SDimitry Andric {
32170b57cec5SDimitry Andric }
32180b57cec5SDimitry Andric 
32190b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::result
32200b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_out(state_type&,
32210b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
32220b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
32230b57cec5SDimitry Andric {
32240b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
32250b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
32260b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
32270b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
32280b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
32290b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
32300b57cec5SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
32310b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
32320b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
32330b57cec5SDimitry Andric     return r;
32340b57cec5SDimitry Andric }
32350b57cec5SDimitry Andric 
32360b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::result
32370b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_in(state_type&,
32380b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
32390b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
32400b57cec5SDimitry Andric {
32410b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
32420b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
32430b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
32440b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
32450b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
32460b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
32470b57cec5SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
32480b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
32490b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
32500b57cec5SDimitry Andric     return r;
32510b57cec5SDimitry Andric }
32520b57cec5SDimitry Andric 
32530b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::result
32540b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_unshift(state_type&,
32550b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
32560b57cec5SDimitry Andric {
32570b57cec5SDimitry Andric     to_nxt = to;
32580b57cec5SDimitry Andric     return noconv;
32590b57cec5SDimitry Andric }
32600b57cec5SDimitry Andric 
32610b57cec5SDimitry Andric int
3262fe6060f1SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_encoding() const noexcept
32630b57cec5SDimitry Andric {
32640b57cec5SDimitry Andric     return 0;
32650b57cec5SDimitry Andric }
32660b57cec5SDimitry Andric 
32670b57cec5SDimitry Andric bool
3268fe6060f1SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_always_noconv() const noexcept
32690b57cec5SDimitry Andric {
32700b57cec5SDimitry Andric     return false;
32710b57cec5SDimitry Andric }
32720b57cec5SDimitry Andric 
32730b57cec5SDimitry Andric int
32740b57cec5SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_length(state_type&,
32750b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
32760b57cec5SDimitry Andric {
32770b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
32780b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
32790b57cec5SDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx);
32800b57cec5SDimitry Andric }
32810b57cec5SDimitry Andric 
32820b57cec5SDimitry Andric int
3283fe6060f1SDimitry Andric codecvt<char16_t, char, mbstate_t>::do_max_length() const noexcept
32840b57cec5SDimitry Andric {
32850b57cec5SDimitry Andric     return 4;
32860b57cec5SDimitry Andric }
32870b57cec5SDimitry Andric 
3288fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
3289e8d8bef9SDimitry Andric 
3290e8d8bef9SDimitry Andric // template <> class codecvt<char16_t, char8_t, mbstate_t>
3291e8d8bef9SDimitry Andric 
3292e8d8bef9SDimitry Andric locale::id codecvt<char16_t, char8_t, mbstate_t>::id;
3293e8d8bef9SDimitry Andric 
3294e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::~codecvt()
3295e8d8bef9SDimitry Andric {
3296e8d8bef9SDimitry Andric }
3297e8d8bef9SDimitry Andric 
3298e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::result
3299e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_out(state_type&,
3300e8d8bef9SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3301e8d8bef9SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3302e8d8bef9SDimitry Andric {
3303e8d8bef9SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3304e8d8bef9SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3305e8d8bef9SDimitry Andric     const uint16_t* _frm_nxt = _frm;
3306e8d8bef9SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3307e8d8bef9SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3308e8d8bef9SDimitry Andric     uint8_t* _to_nxt = _to;
3309e8d8bef9SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3310e8d8bef9SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
3311e8d8bef9SDimitry Andric     to_nxt = to + (_to_nxt - _to);
3312e8d8bef9SDimitry Andric     return r;
3313e8d8bef9SDimitry Andric }
3314e8d8bef9SDimitry Andric 
3315e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::result
3316e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_in(state_type&,
3317e8d8bef9SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3318e8d8bef9SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3319e8d8bef9SDimitry Andric {
3320e8d8bef9SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3321e8d8bef9SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3322e8d8bef9SDimitry Andric     const uint8_t* _frm_nxt = _frm;
3323e8d8bef9SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3324e8d8bef9SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3325e8d8bef9SDimitry Andric     uint16_t* _to_nxt = _to;
3326e8d8bef9SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3327e8d8bef9SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
3328e8d8bef9SDimitry Andric     to_nxt = to + (_to_nxt - _to);
3329e8d8bef9SDimitry Andric     return r;
3330e8d8bef9SDimitry Andric }
3331e8d8bef9SDimitry Andric 
3332e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::result
3333e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_unshift(state_type&,
3334e8d8bef9SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
3335e8d8bef9SDimitry Andric {
3336e8d8bef9SDimitry Andric     to_nxt = to;
3337e8d8bef9SDimitry Andric     return noconv;
3338e8d8bef9SDimitry Andric }
3339e8d8bef9SDimitry Andric 
3340e8d8bef9SDimitry Andric int
3341fe6060f1SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_encoding() const noexcept
3342e8d8bef9SDimitry Andric {
3343e8d8bef9SDimitry Andric     return 0;
3344e8d8bef9SDimitry Andric }
3345e8d8bef9SDimitry Andric 
3346e8d8bef9SDimitry Andric bool
3347fe6060f1SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_always_noconv() const noexcept
3348e8d8bef9SDimitry Andric {
3349e8d8bef9SDimitry Andric     return false;
3350e8d8bef9SDimitry Andric }
3351e8d8bef9SDimitry Andric 
3352e8d8bef9SDimitry Andric int
3353e8d8bef9SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_length(state_type&,
3354e8d8bef9SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
3355e8d8bef9SDimitry Andric {
3356e8d8bef9SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3357e8d8bef9SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3358e8d8bef9SDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx);
3359e8d8bef9SDimitry Andric }
3360e8d8bef9SDimitry Andric 
3361e8d8bef9SDimitry Andric int
3362fe6060f1SDimitry Andric codecvt<char16_t, char8_t, mbstate_t>::do_max_length() const noexcept
3363e8d8bef9SDimitry Andric {
3364e8d8bef9SDimitry Andric     return 4;
3365e8d8bef9SDimitry Andric }
3366e8d8bef9SDimitry Andric 
3367e8d8bef9SDimitry Andric #endif
3368e8d8bef9SDimitry Andric 
33690b57cec5SDimitry Andric // template <> class codecvt<char32_t, char, mbstate_t>
33700b57cec5SDimitry Andric 
33710b57cec5SDimitry Andric locale::id codecvt<char32_t, char, mbstate_t>::id;
33720b57cec5SDimitry Andric 
33730b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::~codecvt()
33740b57cec5SDimitry Andric {
33750b57cec5SDimitry Andric }
33760b57cec5SDimitry Andric 
33770b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::result
33780b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_out(state_type&,
33790b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
33800b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
33810b57cec5SDimitry Andric {
33820b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
33830b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
33840b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
33850b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
33860b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
33870b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
33880b57cec5SDimitry Andric     result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
33890b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
33900b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
33910b57cec5SDimitry Andric     return r;
33920b57cec5SDimitry Andric }
33930b57cec5SDimitry Andric 
33940b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::result
33950b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_in(state_type&,
33960b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
33970b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
33980b57cec5SDimitry Andric {
33990b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
34000b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
34010b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
34020b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
34030b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
34040b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
34050b57cec5SDimitry Andric     result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
34060b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
34070b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
34080b57cec5SDimitry Andric     return r;
34090b57cec5SDimitry Andric }
34100b57cec5SDimitry Andric 
34110b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::result
34120b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_unshift(state_type&,
34130b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
34140b57cec5SDimitry Andric {
34150b57cec5SDimitry Andric     to_nxt = to;
34160b57cec5SDimitry Andric     return noconv;
34170b57cec5SDimitry Andric }
34180b57cec5SDimitry Andric 
34190b57cec5SDimitry Andric int
3420fe6060f1SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_encoding() const noexcept
34210b57cec5SDimitry Andric {
34220b57cec5SDimitry Andric     return 0;
34230b57cec5SDimitry Andric }
34240b57cec5SDimitry Andric 
34250b57cec5SDimitry Andric bool
3426fe6060f1SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_always_noconv() const noexcept
34270b57cec5SDimitry Andric {
34280b57cec5SDimitry Andric     return false;
34290b57cec5SDimitry Andric }
34300b57cec5SDimitry Andric 
34310b57cec5SDimitry Andric int
34320b57cec5SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_length(state_type&,
34330b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
34340b57cec5SDimitry Andric {
34350b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
34360b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
34370b57cec5SDimitry Andric     return utf8_to_ucs4_length(_frm, _frm_end, mx);
34380b57cec5SDimitry Andric }
34390b57cec5SDimitry Andric 
34400b57cec5SDimitry Andric int
3441fe6060f1SDimitry Andric codecvt<char32_t, char, mbstate_t>::do_max_length() const noexcept
34420b57cec5SDimitry Andric {
34430b57cec5SDimitry Andric     return 4;
34440b57cec5SDimitry Andric }
34450b57cec5SDimitry Andric 
3446fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
3447e8d8bef9SDimitry Andric 
3448e8d8bef9SDimitry Andric // template <> class codecvt<char32_t, char8_t, mbstate_t>
3449e8d8bef9SDimitry Andric 
3450e8d8bef9SDimitry Andric locale::id codecvt<char32_t, char8_t, mbstate_t>::id;
3451e8d8bef9SDimitry Andric 
3452e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::~codecvt()
3453e8d8bef9SDimitry Andric {
3454e8d8bef9SDimitry Andric }
3455e8d8bef9SDimitry Andric 
3456e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::result
3457e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_out(state_type&,
3458e8d8bef9SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
3459e8d8bef9SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
3460e8d8bef9SDimitry Andric {
3461e8d8bef9SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
3462e8d8bef9SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
3463e8d8bef9SDimitry Andric     const uint32_t* _frm_nxt = _frm;
3464e8d8bef9SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
3465e8d8bef9SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
3466e8d8bef9SDimitry Andric     uint8_t* _to_nxt = _to;
3467e8d8bef9SDimitry Andric     result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3468e8d8bef9SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
3469e8d8bef9SDimitry Andric     to_nxt = to + (_to_nxt - _to);
3470e8d8bef9SDimitry Andric     return r;
3471e8d8bef9SDimitry Andric }
3472e8d8bef9SDimitry Andric 
3473e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::result
3474e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_in(state_type&,
3475e8d8bef9SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
3476e8d8bef9SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
3477e8d8bef9SDimitry Andric {
3478e8d8bef9SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3479e8d8bef9SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3480e8d8bef9SDimitry Andric     const uint8_t* _frm_nxt = _frm;
3481e8d8bef9SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
3482e8d8bef9SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
3483e8d8bef9SDimitry Andric     uint32_t* _to_nxt = _to;
3484e8d8bef9SDimitry Andric     result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt);
3485e8d8bef9SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
3486e8d8bef9SDimitry Andric     to_nxt = to + (_to_nxt - _to);
3487e8d8bef9SDimitry Andric     return r;
3488e8d8bef9SDimitry Andric }
3489e8d8bef9SDimitry Andric 
3490e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::result
3491e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_unshift(state_type&,
3492e8d8bef9SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
3493e8d8bef9SDimitry Andric {
3494e8d8bef9SDimitry Andric     to_nxt = to;
3495e8d8bef9SDimitry Andric     return noconv;
3496e8d8bef9SDimitry Andric }
3497e8d8bef9SDimitry Andric 
3498e8d8bef9SDimitry Andric int
3499fe6060f1SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_encoding() const noexcept
3500e8d8bef9SDimitry Andric {
3501e8d8bef9SDimitry Andric     return 0;
3502e8d8bef9SDimitry Andric }
3503e8d8bef9SDimitry Andric 
3504e8d8bef9SDimitry Andric bool
3505fe6060f1SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_always_noconv() const noexcept
3506e8d8bef9SDimitry Andric {
3507e8d8bef9SDimitry Andric     return false;
3508e8d8bef9SDimitry Andric }
3509e8d8bef9SDimitry Andric 
3510e8d8bef9SDimitry Andric int
3511e8d8bef9SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_length(state_type&,
3512e8d8bef9SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
3513e8d8bef9SDimitry Andric {
3514e8d8bef9SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
3515e8d8bef9SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3516e8d8bef9SDimitry Andric     return utf8_to_ucs4_length(_frm, _frm_end, mx);
3517e8d8bef9SDimitry Andric }
3518e8d8bef9SDimitry Andric 
3519e8d8bef9SDimitry Andric int
3520fe6060f1SDimitry Andric codecvt<char32_t, char8_t, mbstate_t>::do_max_length() const noexcept
3521e8d8bef9SDimitry Andric {
3522e8d8bef9SDimitry Andric     return 4;
3523e8d8bef9SDimitry Andric }
3524e8d8bef9SDimitry Andric 
3525e8d8bef9SDimitry Andric #endif
3526e8d8bef9SDimitry Andric 
35270b57cec5SDimitry Andric // __codecvt_utf8<wchar_t>
35280b57cec5SDimitry Andric 
3529349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
35300b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::result
35310b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::do_out(state_type&,
35320b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
35330b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
35340b57cec5SDimitry Andric {
35350b57cec5SDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
35360b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
35370b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
35380b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
35390b57cec5SDimitry Andric #else
35400b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
35410b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
35420b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
35430b57cec5SDimitry Andric #endif
35440b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
35450b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
35460b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
35470b57cec5SDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
35480b57cec5SDimitry Andric     result r = ucs2_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
35490b57cec5SDimitry Andric                             _Maxcode_, _Mode_);
35500b57cec5SDimitry Andric #else
35510b57cec5SDimitry Andric     result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
35520b57cec5SDimitry Andric                             _Maxcode_, _Mode_);
35530b57cec5SDimitry Andric #endif
35540b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
35550b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
35560b57cec5SDimitry Andric     return r;
35570b57cec5SDimitry Andric }
35580b57cec5SDimitry Andric 
35590b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::result
35600b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::do_in(state_type&,
35610b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
35620b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
35630b57cec5SDimitry Andric {
35640b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
35650b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
35660b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
35670b57cec5SDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
35680b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
35690b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
35700b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
35710b57cec5SDimitry Andric     result r = utf8_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
35720b57cec5SDimitry Andric                             _Maxcode_, _Mode_);
35730b57cec5SDimitry Andric #else
35740b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
35750b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
35760b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
35770b57cec5SDimitry Andric     result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
35780b57cec5SDimitry Andric                             _Maxcode_, _Mode_);
35790b57cec5SDimitry Andric #endif
35800b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
35810b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
35820b57cec5SDimitry Andric     return r;
35830b57cec5SDimitry Andric }
35840b57cec5SDimitry Andric 
35850b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::result
35860b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::do_unshift(state_type&,
35870b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
35880b57cec5SDimitry Andric {
35890b57cec5SDimitry Andric     to_nxt = to;
35900b57cec5SDimitry Andric     return noconv;
35910b57cec5SDimitry Andric }
35920b57cec5SDimitry Andric 
35930b57cec5SDimitry Andric int
3594fe6060f1SDimitry Andric __codecvt_utf8<wchar_t>::do_encoding() const noexcept
35950b57cec5SDimitry Andric {
35960b57cec5SDimitry Andric     return 0;
35970b57cec5SDimitry Andric }
35980b57cec5SDimitry Andric 
35990b57cec5SDimitry Andric bool
3600fe6060f1SDimitry Andric __codecvt_utf8<wchar_t>::do_always_noconv() const noexcept
36010b57cec5SDimitry Andric {
36020b57cec5SDimitry Andric     return false;
36030b57cec5SDimitry Andric }
36040b57cec5SDimitry Andric 
36050b57cec5SDimitry Andric int
36060b57cec5SDimitry Andric __codecvt_utf8<wchar_t>::do_length(state_type&,
36070b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
36080b57cec5SDimitry Andric {
36090b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
36100b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3611349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3612349cc55cSDimitry Andric     return utf8_to_ucs2_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3613349cc55cSDimitry Andric #else
36140b57cec5SDimitry Andric     return utf8_to_ucs4_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3615349cc55cSDimitry Andric #endif
36160b57cec5SDimitry Andric }
36170b57cec5SDimitry Andric 
36180b57cec5SDimitry Andric int
3619fe6060f1SDimitry Andric __codecvt_utf8<wchar_t>::do_max_length() const noexcept
36200b57cec5SDimitry Andric {
3621349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3622349cc55cSDimitry Andric     if (_Mode_ & consume_header)
3623349cc55cSDimitry Andric         return 6;
3624349cc55cSDimitry Andric     return 3;
3625349cc55cSDimitry Andric #else
36260b57cec5SDimitry Andric     if (_Mode_ & consume_header)
36270b57cec5SDimitry Andric         return 7;
36280b57cec5SDimitry Andric     return 4;
3629349cc55cSDimitry Andric #endif
36300b57cec5SDimitry Andric }
3631349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
36320b57cec5SDimitry Andric 
36330b57cec5SDimitry Andric // __codecvt_utf8<char16_t>
36340b57cec5SDimitry Andric 
36350b57cec5SDimitry Andric __codecvt_utf8<char16_t>::result
36360b57cec5SDimitry Andric __codecvt_utf8<char16_t>::do_out(state_type&,
36370b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
36380b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
36390b57cec5SDimitry Andric {
36400b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
36410b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
36420b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
36430b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
36440b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
36450b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
36460b57cec5SDimitry Andric     result r = ucs2_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
36470b57cec5SDimitry Andric                             _Maxcode_, _Mode_);
36480b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
36490b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
36500b57cec5SDimitry Andric     return r;
36510b57cec5SDimitry Andric }
36520b57cec5SDimitry Andric 
36530b57cec5SDimitry Andric __codecvt_utf8<char16_t>::result
36540b57cec5SDimitry Andric __codecvt_utf8<char16_t>::do_in(state_type&,
36550b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
36560b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
36570b57cec5SDimitry Andric {
36580b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
36590b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
36600b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
36610b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
36620b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
36630b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
36640b57cec5SDimitry Andric     result r = utf8_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
36650b57cec5SDimitry Andric                             _Maxcode_, _Mode_);
36660b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
36670b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
36680b57cec5SDimitry Andric     return r;
36690b57cec5SDimitry Andric }
36700b57cec5SDimitry Andric 
36710b57cec5SDimitry Andric __codecvt_utf8<char16_t>::result
36720b57cec5SDimitry Andric __codecvt_utf8<char16_t>::do_unshift(state_type&,
36730b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
36740b57cec5SDimitry Andric {
36750b57cec5SDimitry Andric     to_nxt = to;
36760b57cec5SDimitry Andric     return noconv;
36770b57cec5SDimitry Andric }
36780b57cec5SDimitry Andric 
36790b57cec5SDimitry Andric int
3680fe6060f1SDimitry Andric __codecvt_utf8<char16_t>::do_encoding() const noexcept
36810b57cec5SDimitry Andric {
36820b57cec5SDimitry Andric     return 0;
36830b57cec5SDimitry Andric }
36840b57cec5SDimitry Andric 
36850b57cec5SDimitry Andric bool
3686fe6060f1SDimitry Andric __codecvt_utf8<char16_t>::do_always_noconv() const noexcept
36870b57cec5SDimitry Andric {
36880b57cec5SDimitry Andric     return false;
36890b57cec5SDimitry Andric }
36900b57cec5SDimitry Andric 
36910b57cec5SDimitry Andric int
36920b57cec5SDimitry Andric __codecvt_utf8<char16_t>::do_length(state_type&,
36930b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
36940b57cec5SDimitry Andric {
36950b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
36960b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
36970b57cec5SDimitry Andric     return utf8_to_ucs2_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
36980b57cec5SDimitry Andric }
36990b57cec5SDimitry Andric 
37000b57cec5SDimitry Andric int
3701fe6060f1SDimitry Andric __codecvt_utf8<char16_t>::do_max_length() const noexcept
37020b57cec5SDimitry Andric {
37030b57cec5SDimitry Andric     if (_Mode_ & consume_header)
37040b57cec5SDimitry Andric         return 6;
37050b57cec5SDimitry Andric     return 3;
37060b57cec5SDimitry Andric }
37070b57cec5SDimitry Andric 
37080b57cec5SDimitry Andric // __codecvt_utf8<char32_t>
37090b57cec5SDimitry Andric 
37100b57cec5SDimitry Andric __codecvt_utf8<char32_t>::result
37110b57cec5SDimitry Andric __codecvt_utf8<char32_t>::do_out(state_type&,
37120b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
37130b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
37140b57cec5SDimitry Andric {
37150b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
37160b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
37170b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
37180b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
37190b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
37200b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
37210b57cec5SDimitry Andric     result r = ucs4_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
37220b57cec5SDimitry Andric                             _Maxcode_, _Mode_);
37230b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
37240b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
37250b57cec5SDimitry Andric     return r;
37260b57cec5SDimitry Andric }
37270b57cec5SDimitry Andric 
37280b57cec5SDimitry Andric __codecvt_utf8<char32_t>::result
37290b57cec5SDimitry Andric __codecvt_utf8<char32_t>::do_in(state_type&,
37300b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
37310b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
37320b57cec5SDimitry Andric {
37330b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
37340b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
37350b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
37360b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
37370b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
37380b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
37390b57cec5SDimitry Andric     result r = utf8_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
37400b57cec5SDimitry Andric                             _Maxcode_, _Mode_);
37410b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
37420b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
37430b57cec5SDimitry Andric     return r;
37440b57cec5SDimitry Andric }
37450b57cec5SDimitry Andric 
37460b57cec5SDimitry Andric __codecvt_utf8<char32_t>::result
37470b57cec5SDimitry Andric __codecvt_utf8<char32_t>::do_unshift(state_type&,
37480b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
37490b57cec5SDimitry Andric {
37500b57cec5SDimitry Andric     to_nxt = to;
37510b57cec5SDimitry Andric     return noconv;
37520b57cec5SDimitry Andric }
37530b57cec5SDimitry Andric 
37540b57cec5SDimitry Andric int
3755fe6060f1SDimitry Andric __codecvt_utf8<char32_t>::do_encoding() const noexcept
37560b57cec5SDimitry Andric {
37570b57cec5SDimitry Andric     return 0;
37580b57cec5SDimitry Andric }
37590b57cec5SDimitry Andric 
37600b57cec5SDimitry Andric bool
3761fe6060f1SDimitry Andric __codecvt_utf8<char32_t>::do_always_noconv() const noexcept
37620b57cec5SDimitry Andric {
37630b57cec5SDimitry Andric     return false;
37640b57cec5SDimitry Andric }
37650b57cec5SDimitry Andric 
37660b57cec5SDimitry Andric int
37670b57cec5SDimitry Andric __codecvt_utf8<char32_t>::do_length(state_type&,
37680b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
37690b57cec5SDimitry Andric {
37700b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
37710b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
37720b57cec5SDimitry Andric     return utf8_to_ucs4_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
37730b57cec5SDimitry Andric }
37740b57cec5SDimitry Andric 
37750b57cec5SDimitry Andric int
3776fe6060f1SDimitry Andric __codecvt_utf8<char32_t>::do_max_length() const noexcept
37770b57cec5SDimitry Andric {
37780b57cec5SDimitry Andric     if (_Mode_ & consume_header)
37790b57cec5SDimitry Andric         return 7;
37800b57cec5SDimitry Andric     return 4;
37810b57cec5SDimitry Andric }
37820b57cec5SDimitry Andric 
37830b57cec5SDimitry Andric // __codecvt_utf16<wchar_t, false>
37840b57cec5SDimitry Andric 
3785349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
37860b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::result
37870b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::do_out(state_type&,
37880b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
37890b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
37900b57cec5SDimitry Andric {
3791349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3792349cc55cSDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3793349cc55cSDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3794349cc55cSDimitry Andric     const uint16_t* _frm_nxt = _frm;
3795349cc55cSDimitry Andric #else
37960b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
37970b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
37980b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
3799349cc55cSDimitry Andric #endif
38000b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
38010b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
38020b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
3803349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3804349cc55cSDimitry Andric     result r = ucs2_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3805349cc55cSDimitry Andric                                _Maxcode_, _Mode_);
3806349cc55cSDimitry Andric #else
38070b57cec5SDimitry Andric     result r = ucs4_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
38080b57cec5SDimitry Andric                                _Maxcode_, _Mode_);
3809349cc55cSDimitry Andric #endif
38100b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
38110b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
38120b57cec5SDimitry Andric     return r;
38130b57cec5SDimitry Andric }
38140b57cec5SDimitry Andric 
38150b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::result
38160b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::do_in(state_type&,
38170b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
38180b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
38190b57cec5SDimitry Andric {
38200b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
38210b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
38220b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
3823349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3824349cc55cSDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3825349cc55cSDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3826349cc55cSDimitry Andric     uint16_t* _to_nxt = _to;
3827349cc55cSDimitry Andric     result r = utf16be_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3828349cc55cSDimitry Andric                                _Maxcode_, _Mode_);
3829349cc55cSDimitry Andric #else
38300b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
38310b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
38320b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
38330b57cec5SDimitry Andric     result r = utf16be_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
38340b57cec5SDimitry Andric                                _Maxcode_, _Mode_);
3835349cc55cSDimitry Andric #endif
38360b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
38370b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
38380b57cec5SDimitry Andric     return r;
38390b57cec5SDimitry Andric }
38400b57cec5SDimitry Andric 
38410b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::result
38420b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::do_unshift(state_type&,
38430b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
38440b57cec5SDimitry Andric {
38450b57cec5SDimitry Andric     to_nxt = to;
38460b57cec5SDimitry Andric     return noconv;
38470b57cec5SDimitry Andric }
38480b57cec5SDimitry Andric 
38490b57cec5SDimitry Andric int
3850fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, false>::do_encoding() const noexcept
38510b57cec5SDimitry Andric {
38520b57cec5SDimitry Andric     return 0;
38530b57cec5SDimitry Andric }
38540b57cec5SDimitry Andric 
38550b57cec5SDimitry Andric bool
3856fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, false>::do_always_noconv() const noexcept
38570b57cec5SDimitry Andric {
38580b57cec5SDimitry Andric     return false;
38590b57cec5SDimitry Andric }
38600b57cec5SDimitry Andric 
38610b57cec5SDimitry Andric int
38620b57cec5SDimitry Andric __codecvt_utf16<wchar_t, false>::do_length(state_type&,
38630b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
38640b57cec5SDimitry Andric {
38650b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
38660b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3867349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3868349cc55cSDimitry Andric     return utf16be_to_ucs2_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3869349cc55cSDimitry Andric #else
38700b57cec5SDimitry Andric     return utf16be_to_ucs4_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3871349cc55cSDimitry Andric #endif
38720b57cec5SDimitry Andric }
38730b57cec5SDimitry Andric 
38740b57cec5SDimitry Andric int
3875fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, false>::do_max_length() const noexcept
38760b57cec5SDimitry Andric {
3877349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3878349cc55cSDimitry Andric     if (_Mode_ & consume_header)
3879349cc55cSDimitry Andric         return 4;
3880349cc55cSDimitry Andric     return 2;
3881349cc55cSDimitry Andric #else
38820b57cec5SDimitry Andric     if (_Mode_ & consume_header)
38830b57cec5SDimitry Andric         return 6;
38840b57cec5SDimitry Andric     return 4;
3885349cc55cSDimitry Andric #endif
38860b57cec5SDimitry Andric }
38870b57cec5SDimitry Andric 
38880b57cec5SDimitry Andric // __codecvt_utf16<wchar_t, true>
38890b57cec5SDimitry Andric 
38900b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::result
38910b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::do_out(state_type&,
38920b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
38930b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
38940b57cec5SDimitry Andric {
3895349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3896349cc55cSDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
3897349cc55cSDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
3898349cc55cSDimitry Andric     const uint16_t* _frm_nxt = _frm;
3899349cc55cSDimitry Andric #else
39000b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
39010b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
39020b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
3903349cc55cSDimitry Andric #endif
39040b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
39050b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
39060b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
3907349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3908349cc55cSDimitry Andric     result r = ucs2_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3909349cc55cSDimitry Andric                                _Maxcode_, _Mode_);
3910349cc55cSDimitry Andric #else
39110b57cec5SDimitry Andric     result r = ucs4_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
39120b57cec5SDimitry Andric                                _Maxcode_, _Mode_);
3913349cc55cSDimitry Andric #endif
39140b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
39150b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
39160b57cec5SDimitry Andric     return r;
39170b57cec5SDimitry Andric }
39180b57cec5SDimitry Andric 
39190b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::result
39200b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::do_in(state_type&,
39210b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
39220b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
39230b57cec5SDimitry Andric {
39240b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
39250b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
39260b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
3927349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3928349cc55cSDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
3929349cc55cSDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
3930349cc55cSDimitry Andric     uint16_t* _to_nxt = _to;
3931349cc55cSDimitry Andric     result r = utf16le_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
3932349cc55cSDimitry Andric                                _Maxcode_, _Mode_);
3933349cc55cSDimitry Andric #else
39340b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
39350b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
39360b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
39370b57cec5SDimitry Andric     result r = utf16le_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
39380b57cec5SDimitry Andric                                _Maxcode_, _Mode_);
3939349cc55cSDimitry Andric #endif
39400b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
39410b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
39420b57cec5SDimitry Andric     return r;
39430b57cec5SDimitry Andric }
39440b57cec5SDimitry Andric 
39450b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::result
39460b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::do_unshift(state_type&,
39470b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
39480b57cec5SDimitry Andric {
39490b57cec5SDimitry Andric     to_nxt = to;
39500b57cec5SDimitry Andric     return noconv;
39510b57cec5SDimitry Andric }
39520b57cec5SDimitry Andric 
39530b57cec5SDimitry Andric int
3954fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, true>::do_encoding() const noexcept
39550b57cec5SDimitry Andric {
39560b57cec5SDimitry Andric     return 0;
39570b57cec5SDimitry Andric }
39580b57cec5SDimitry Andric 
39590b57cec5SDimitry Andric bool
3960fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, true>::do_always_noconv() const noexcept
39610b57cec5SDimitry Andric {
39620b57cec5SDimitry Andric     return false;
39630b57cec5SDimitry Andric }
39640b57cec5SDimitry Andric 
39650b57cec5SDimitry Andric int
39660b57cec5SDimitry Andric __codecvt_utf16<wchar_t, true>::do_length(state_type&,
39670b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
39680b57cec5SDimitry Andric {
39690b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
39700b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
3971349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3972349cc55cSDimitry Andric     return utf16le_to_ucs2_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3973349cc55cSDimitry Andric #else
39740b57cec5SDimitry Andric     return utf16le_to_ucs4_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
3975349cc55cSDimitry Andric #endif
39760b57cec5SDimitry Andric }
39770b57cec5SDimitry Andric 
39780b57cec5SDimitry Andric int
3979fe6060f1SDimitry Andric __codecvt_utf16<wchar_t, true>::do_max_length() const noexcept
39800b57cec5SDimitry Andric {
3981349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
3982349cc55cSDimitry Andric     if (_Mode_ & consume_header)
3983349cc55cSDimitry Andric         return 4;
3984349cc55cSDimitry Andric     return 2;
3985349cc55cSDimitry Andric #else
39860b57cec5SDimitry Andric     if (_Mode_ & consume_header)
39870b57cec5SDimitry Andric         return 6;
39880b57cec5SDimitry Andric     return 4;
3989349cc55cSDimitry Andric #endif
39900b57cec5SDimitry Andric }
3991349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
39920b57cec5SDimitry Andric 
39930b57cec5SDimitry Andric // __codecvt_utf16<char16_t, false>
39940b57cec5SDimitry Andric 
39950b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::result
39960b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::do_out(state_type&,
39970b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
39980b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
39990b57cec5SDimitry Andric {
40000b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
40010b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
40020b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
40030b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
40040b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
40050b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
40060b57cec5SDimitry Andric     result r = ucs2_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
40070b57cec5SDimitry Andric                                _Maxcode_, _Mode_);
40080b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
40090b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
40100b57cec5SDimitry Andric     return r;
40110b57cec5SDimitry Andric }
40120b57cec5SDimitry Andric 
40130b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::result
40140b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::do_in(state_type&,
40150b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
40160b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
40170b57cec5SDimitry Andric {
40180b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
40190b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
40200b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
40210b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
40220b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
40230b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
40240b57cec5SDimitry Andric     result r = utf16be_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
40250b57cec5SDimitry Andric                                _Maxcode_, _Mode_);
40260b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
40270b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
40280b57cec5SDimitry Andric     return r;
40290b57cec5SDimitry Andric }
40300b57cec5SDimitry Andric 
40310b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::result
40320b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::do_unshift(state_type&,
40330b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
40340b57cec5SDimitry Andric {
40350b57cec5SDimitry Andric     to_nxt = to;
40360b57cec5SDimitry Andric     return noconv;
40370b57cec5SDimitry Andric }
40380b57cec5SDimitry Andric 
40390b57cec5SDimitry Andric int
4040fe6060f1SDimitry Andric __codecvt_utf16<char16_t, false>::do_encoding() const noexcept
40410b57cec5SDimitry Andric {
40420b57cec5SDimitry Andric     return 0;
40430b57cec5SDimitry Andric }
40440b57cec5SDimitry Andric 
40450b57cec5SDimitry Andric bool
4046fe6060f1SDimitry Andric __codecvt_utf16<char16_t, false>::do_always_noconv() const noexcept
40470b57cec5SDimitry Andric {
40480b57cec5SDimitry Andric     return false;
40490b57cec5SDimitry Andric }
40500b57cec5SDimitry Andric 
40510b57cec5SDimitry Andric int
40520b57cec5SDimitry Andric __codecvt_utf16<char16_t, false>::do_length(state_type&,
40530b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
40540b57cec5SDimitry Andric {
40550b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
40560b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
40570b57cec5SDimitry Andric     return utf16be_to_ucs2_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
40580b57cec5SDimitry Andric }
40590b57cec5SDimitry Andric 
40600b57cec5SDimitry Andric int
4061fe6060f1SDimitry Andric __codecvt_utf16<char16_t, false>::do_max_length() const noexcept
40620b57cec5SDimitry Andric {
40630b57cec5SDimitry Andric     if (_Mode_ & consume_header)
40640b57cec5SDimitry Andric         return 4;
40650b57cec5SDimitry Andric     return 2;
40660b57cec5SDimitry Andric }
40670b57cec5SDimitry Andric 
40680b57cec5SDimitry Andric // __codecvt_utf16<char16_t, true>
40690b57cec5SDimitry Andric 
40700b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::result
40710b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::do_out(state_type&,
40720b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
40730b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
40740b57cec5SDimitry Andric {
40750b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
40760b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
40770b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
40780b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
40790b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
40800b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
40810b57cec5SDimitry Andric     result r = ucs2_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
40820b57cec5SDimitry Andric                                _Maxcode_, _Mode_);
40830b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
40840b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
40850b57cec5SDimitry Andric     return r;
40860b57cec5SDimitry Andric }
40870b57cec5SDimitry Andric 
40880b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::result
40890b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::do_in(state_type&,
40900b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
40910b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
40920b57cec5SDimitry Andric {
40930b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
40940b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
40950b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
40960b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
40970b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
40980b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
40990b57cec5SDimitry Andric     result r = utf16le_to_ucs2(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
41000b57cec5SDimitry Andric                                _Maxcode_, _Mode_);
41010b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
41020b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
41030b57cec5SDimitry Andric     return r;
41040b57cec5SDimitry Andric }
41050b57cec5SDimitry Andric 
41060b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::result
41070b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::do_unshift(state_type&,
41080b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
41090b57cec5SDimitry Andric {
41100b57cec5SDimitry Andric     to_nxt = to;
41110b57cec5SDimitry Andric     return noconv;
41120b57cec5SDimitry Andric }
41130b57cec5SDimitry Andric 
41140b57cec5SDimitry Andric int
4115fe6060f1SDimitry Andric __codecvt_utf16<char16_t, true>::do_encoding() const noexcept
41160b57cec5SDimitry Andric {
41170b57cec5SDimitry Andric     return 0;
41180b57cec5SDimitry Andric }
41190b57cec5SDimitry Andric 
41200b57cec5SDimitry Andric bool
4121fe6060f1SDimitry Andric __codecvt_utf16<char16_t, true>::do_always_noconv() const noexcept
41220b57cec5SDimitry Andric {
41230b57cec5SDimitry Andric     return false;
41240b57cec5SDimitry Andric }
41250b57cec5SDimitry Andric 
41260b57cec5SDimitry Andric int
41270b57cec5SDimitry Andric __codecvt_utf16<char16_t, true>::do_length(state_type&,
41280b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
41290b57cec5SDimitry Andric {
41300b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
41310b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
41320b57cec5SDimitry Andric     return utf16le_to_ucs2_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
41330b57cec5SDimitry Andric }
41340b57cec5SDimitry Andric 
41350b57cec5SDimitry Andric int
4136fe6060f1SDimitry Andric __codecvt_utf16<char16_t, true>::do_max_length() const noexcept
41370b57cec5SDimitry Andric {
41380b57cec5SDimitry Andric     if (_Mode_ & consume_header)
41390b57cec5SDimitry Andric         return 4;
41400b57cec5SDimitry Andric     return 2;
41410b57cec5SDimitry Andric }
41420b57cec5SDimitry Andric 
41430b57cec5SDimitry Andric // __codecvt_utf16<char32_t, false>
41440b57cec5SDimitry Andric 
41450b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::result
41460b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::do_out(state_type&,
41470b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
41480b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
41490b57cec5SDimitry Andric {
41500b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
41510b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
41520b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
41530b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
41540b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
41550b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
41560b57cec5SDimitry Andric     result r = ucs4_to_utf16be(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
41570b57cec5SDimitry Andric                                _Maxcode_, _Mode_);
41580b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
41590b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
41600b57cec5SDimitry Andric     return r;
41610b57cec5SDimitry Andric }
41620b57cec5SDimitry Andric 
41630b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::result
41640b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::do_in(state_type&,
41650b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
41660b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
41670b57cec5SDimitry Andric {
41680b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
41690b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
41700b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
41710b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
41720b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
41730b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
41740b57cec5SDimitry Andric     result r = utf16be_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
41750b57cec5SDimitry Andric                                _Maxcode_, _Mode_);
41760b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
41770b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
41780b57cec5SDimitry Andric     return r;
41790b57cec5SDimitry Andric }
41800b57cec5SDimitry Andric 
41810b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::result
41820b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::do_unshift(state_type&,
41830b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
41840b57cec5SDimitry Andric {
41850b57cec5SDimitry Andric     to_nxt = to;
41860b57cec5SDimitry Andric     return noconv;
41870b57cec5SDimitry Andric }
41880b57cec5SDimitry Andric 
41890b57cec5SDimitry Andric int
4190fe6060f1SDimitry Andric __codecvt_utf16<char32_t, false>::do_encoding() const noexcept
41910b57cec5SDimitry Andric {
41920b57cec5SDimitry Andric     return 0;
41930b57cec5SDimitry Andric }
41940b57cec5SDimitry Andric 
41950b57cec5SDimitry Andric bool
4196fe6060f1SDimitry Andric __codecvt_utf16<char32_t, false>::do_always_noconv() const noexcept
41970b57cec5SDimitry Andric {
41980b57cec5SDimitry Andric     return false;
41990b57cec5SDimitry Andric }
42000b57cec5SDimitry Andric 
42010b57cec5SDimitry Andric int
42020b57cec5SDimitry Andric __codecvt_utf16<char32_t, false>::do_length(state_type&,
42030b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
42040b57cec5SDimitry Andric {
42050b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
42060b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
42070b57cec5SDimitry Andric     return utf16be_to_ucs4_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
42080b57cec5SDimitry Andric }
42090b57cec5SDimitry Andric 
42100b57cec5SDimitry Andric int
4211fe6060f1SDimitry Andric __codecvt_utf16<char32_t, false>::do_max_length() const noexcept
42120b57cec5SDimitry Andric {
42130b57cec5SDimitry Andric     if (_Mode_ & consume_header)
42140b57cec5SDimitry Andric         return 6;
42150b57cec5SDimitry Andric     return 4;
42160b57cec5SDimitry Andric }
42170b57cec5SDimitry Andric 
42180b57cec5SDimitry Andric // __codecvt_utf16<char32_t, true>
42190b57cec5SDimitry Andric 
42200b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::result
42210b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::do_out(state_type&,
42220b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
42230b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
42240b57cec5SDimitry Andric {
42250b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
42260b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
42270b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
42280b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
42290b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
42300b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
42310b57cec5SDimitry Andric     result r = ucs4_to_utf16le(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
42320b57cec5SDimitry Andric                                _Maxcode_, _Mode_);
42330b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
42340b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
42350b57cec5SDimitry Andric     return r;
42360b57cec5SDimitry Andric }
42370b57cec5SDimitry Andric 
42380b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::result
42390b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::do_in(state_type&,
42400b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
42410b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
42420b57cec5SDimitry Andric {
42430b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
42440b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
42450b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
42460b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
42470b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
42480b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
42490b57cec5SDimitry Andric     result r = utf16le_to_ucs4(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
42500b57cec5SDimitry Andric                                _Maxcode_, _Mode_);
42510b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
42520b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
42530b57cec5SDimitry Andric     return r;
42540b57cec5SDimitry Andric }
42550b57cec5SDimitry Andric 
42560b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::result
42570b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::do_unshift(state_type&,
42580b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
42590b57cec5SDimitry Andric {
42600b57cec5SDimitry Andric     to_nxt = to;
42610b57cec5SDimitry Andric     return noconv;
42620b57cec5SDimitry Andric }
42630b57cec5SDimitry Andric 
42640b57cec5SDimitry Andric int
4265fe6060f1SDimitry Andric __codecvt_utf16<char32_t, true>::do_encoding() const noexcept
42660b57cec5SDimitry Andric {
42670b57cec5SDimitry Andric     return 0;
42680b57cec5SDimitry Andric }
42690b57cec5SDimitry Andric 
42700b57cec5SDimitry Andric bool
4271fe6060f1SDimitry Andric __codecvt_utf16<char32_t, true>::do_always_noconv() const noexcept
42720b57cec5SDimitry Andric {
42730b57cec5SDimitry Andric     return false;
42740b57cec5SDimitry Andric }
42750b57cec5SDimitry Andric 
42760b57cec5SDimitry Andric int
42770b57cec5SDimitry Andric __codecvt_utf16<char32_t, true>::do_length(state_type&,
42780b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
42790b57cec5SDimitry Andric {
42800b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
42810b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
42820b57cec5SDimitry Andric     return utf16le_to_ucs4_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
42830b57cec5SDimitry Andric }
42840b57cec5SDimitry Andric 
42850b57cec5SDimitry Andric int
4286fe6060f1SDimitry Andric __codecvt_utf16<char32_t, true>::do_max_length() const noexcept
42870b57cec5SDimitry Andric {
42880b57cec5SDimitry Andric     if (_Mode_ & consume_header)
42890b57cec5SDimitry Andric         return 6;
42900b57cec5SDimitry Andric     return 4;
42910b57cec5SDimitry Andric }
42920b57cec5SDimitry Andric 
42930b57cec5SDimitry Andric // __codecvt_utf8_utf16<wchar_t>
42940b57cec5SDimitry Andric 
4295349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
42960b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::result
42970b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_out(state_type&,
42980b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
42990b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
43000b57cec5SDimitry Andric {
4301349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
4302349cc55cSDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
4303349cc55cSDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
4304349cc55cSDimitry Andric     const uint16_t* _frm_nxt = _frm;
4305349cc55cSDimitry Andric #else
43060b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
43070b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
43080b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
4309349cc55cSDimitry Andric #endif
43100b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
43110b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
43120b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
43130b57cec5SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
43140b57cec5SDimitry Andric                              _Maxcode_, _Mode_);
43150b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
43160b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
43170b57cec5SDimitry Andric     return r;
43180b57cec5SDimitry Andric }
43190b57cec5SDimitry Andric 
43200b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::result
43210b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_in(state_type&,
43220b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
43230b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
43240b57cec5SDimitry Andric {
43250b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
43260b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
43270b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
4328349cc55cSDimitry Andric #if defined(_LIBCPP_SHORT_WCHAR)
4329349cc55cSDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
4330349cc55cSDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
4331349cc55cSDimitry Andric     uint16_t* _to_nxt = _to;
4332349cc55cSDimitry Andric #else
43330b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
43340b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
43350b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
4336349cc55cSDimitry Andric #endif
43370b57cec5SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
43380b57cec5SDimitry Andric                              _Maxcode_, _Mode_);
43390b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
43400b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
43410b57cec5SDimitry Andric     return r;
43420b57cec5SDimitry Andric }
43430b57cec5SDimitry Andric 
43440b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::result
43450b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_unshift(state_type&,
43460b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
43470b57cec5SDimitry Andric {
43480b57cec5SDimitry Andric     to_nxt = to;
43490b57cec5SDimitry Andric     return noconv;
43500b57cec5SDimitry Andric }
43510b57cec5SDimitry Andric 
43520b57cec5SDimitry Andric int
4353fe6060f1SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_encoding() const noexcept
43540b57cec5SDimitry Andric {
43550b57cec5SDimitry Andric     return 0;
43560b57cec5SDimitry Andric }
43570b57cec5SDimitry Andric 
43580b57cec5SDimitry Andric bool
4359fe6060f1SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_always_noconv() const noexcept
43600b57cec5SDimitry Andric {
43610b57cec5SDimitry Andric     return false;
43620b57cec5SDimitry Andric }
43630b57cec5SDimitry Andric 
43640b57cec5SDimitry Andric int
43650b57cec5SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_length(state_type&,
43660b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
43670b57cec5SDimitry Andric {
43680b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
43690b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
43700b57cec5SDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
43710b57cec5SDimitry Andric }
43720b57cec5SDimitry Andric 
43730b57cec5SDimitry Andric int
4374fe6060f1SDimitry Andric __codecvt_utf8_utf16<wchar_t>::do_max_length() const noexcept
43750b57cec5SDimitry Andric {
43760b57cec5SDimitry Andric     if (_Mode_ & consume_header)
43770b57cec5SDimitry Andric         return 7;
43780b57cec5SDimitry Andric     return 4;
43790b57cec5SDimitry Andric }
4380349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
43810b57cec5SDimitry Andric 
43820b57cec5SDimitry Andric // __codecvt_utf8_utf16<char16_t>
43830b57cec5SDimitry Andric 
43840b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::result
43850b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_out(state_type&,
43860b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
43870b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
43880b57cec5SDimitry Andric {
43890b57cec5SDimitry Andric     const uint16_t* _frm = reinterpret_cast<const uint16_t*>(frm);
43900b57cec5SDimitry Andric     const uint16_t* _frm_end = reinterpret_cast<const uint16_t*>(frm_end);
43910b57cec5SDimitry Andric     const uint16_t* _frm_nxt = _frm;
43920b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
43930b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
43940b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
43950b57cec5SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
43960b57cec5SDimitry Andric                              _Maxcode_, _Mode_);
43970b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
43980b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
43990b57cec5SDimitry Andric     return r;
44000b57cec5SDimitry Andric }
44010b57cec5SDimitry Andric 
44020b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::result
44030b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_in(state_type&,
44040b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
44050b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
44060b57cec5SDimitry Andric {
44070b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
44080b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
44090b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
44100b57cec5SDimitry Andric     uint16_t* _to = reinterpret_cast<uint16_t*>(to);
44110b57cec5SDimitry Andric     uint16_t* _to_end = reinterpret_cast<uint16_t*>(to_end);
44120b57cec5SDimitry Andric     uint16_t* _to_nxt = _to;
44130b57cec5SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
44140b57cec5SDimitry Andric                              _Maxcode_, _Mode_);
44150b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
44160b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
44170b57cec5SDimitry Andric     return r;
44180b57cec5SDimitry Andric }
44190b57cec5SDimitry Andric 
44200b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::result
44210b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_unshift(state_type&,
44220b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
44230b57cec5SDimitry Andric {
44240b57cec5SDimitry Andric     to_nxt = to;
44250b57cec5SDimitry Andric     return noconv;
44260b57cec5SDimitry Andric }
44270b57cec5SDimitry Andric 
44280b57cec5SDimitry Andric int
4429fe6060f1SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_encoding() const noexcept
44300b57cec5SDimitry Andric {
44310b57cec5SDimitry Andric     return 0;
44320b57cec5SDimitry Andric }
44330b57cec5SDimitry Andric 
44340b57cec5SDimitry Andric bool
4435fe6060f1SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_always_noconv() const noexcept
44360b57cec5SDimitry Andric {
44370b57cec5SDimitry Andric     return false;
44380b57cec5SDimitry Andric }
44390b57cec5SDimitry Andric 
44400b57cec5SDimitry Andric int
44410b57cec5SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_length(state_type&,
44420b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
44430b57cec5SDimitry Andric {
44440b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
44450b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
44460b57cec5SDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
44470b57cec5SDimitry Andric }
44480b57cec5SDimitry Andric 
44490b57cec5SDimitry Andric int
4450fe6060f1SDimitry Andric __codecvt_utf8_utf16<char16_t>::do_max_length() const noexcept
44510b57cec5SDimitry Andric {
44520b57cec5SDimitry Andric     if (_Mode_ & consume_header)
44530b57cec5SDimitry Andric         return 7;
44540b57cec5SDimitry Andric     return 4;
44550b57cec5SDimitry Andric }
44560b57cec5SDimitry Andric 
44570b57cec5SDimitry Andric // __codecvt_utf8_utf16<char32_t>
44580b57cec5SDimitry Andric 
44590b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::result
44600b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_out(state_type&,
44610b57cec5SDimitry Andric     const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
44620b57cec5SDimitry Andric     extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
44630b57cec5SDimitry Andric {
44640b57cec5SDimitry Andric     const uint32_t* _frm = reinterpret_cast<const uint32_t*>(frm);
44650b57cec5SDimitry Andric     const uint32_t* _frm_end = reinterpret_cast<const uint32_t*>(frm_end);
44660b57cec5SDimitry Andric     const uint32_t* _frm_nxt = _frm;
44670b57cec5SDimitry Andric     uint8_t* _to = reinterpret_cast<uint8_t*>(to);
44680b57cec5SDimitry Andric     uint8_t* _to_end = reinterpret_cast<uint8_t*>(to_end);
44690b57cec5SDimitry Andric     uint8_t* _to_nxt = _to;
44700b57cec5SDimitry Andric     result r = utf16_to_utf8(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
44710b57cec5SDimitry Andric                              _Maxcode_, _Mode_);
44720b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
44730b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
44740b57cec5SDimitry Andric     return r;
44750b57cec5SDimitry Andric }
44760b57cec5SDimitry Andric 
44770b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::result
44780b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_in(state_type&,
44790b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
44800b57cec5SDimitry Andric     intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
44810b57cec5SDimitry Andric {
44820b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
44830b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
44840b57cec5SDimitry Andric     const uint8_t* _frm_nxt = _frm;
44850b57cec5SDimitry Andric     uint32_t* _to = reinterpret_cast<uint32_t*>(to);
44860b57cec5SDimitry Andric     uint32_t* _to_end = reinterpret_cast<uint32_t*>(to_end);
44870b57cec5SDimitry Andric     uint32_t* _to_nxt = _to;
44880b57cec5SDimitry Andric     result r = utf8_to_utf16(_frm, _frm_end, _frm_nxt, _to, _to_end, _to_nxt,
44890b57cec5SDimitry Andric                              _Maxcode_, _Mode_);
44900b57cec5SDimitry Andric     frm_nxt = frm + (_frm_nxt - _frm);
44910b57cec5SDimitry Andric     to_nxt = to + (_to_nxt - _to);
44920b57cec5SDimitry Andric     return r;
44930b57cec5SDimitry Andric }
44940b57cec5SDimitry Andric 
44950b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::result
44960b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_unshift(state_type&,
44970b57cec5SDimitry Andric     extern_type* to, extern_type*, extern_type*& to_nxt) const
44980b57cec5SDimitry Andric {
44990b57cec5SDimitry Andric     to_nxt = to;
45000b57cec5SDimitry Andric     return noconv;
45010b57cec5SDimitry Andric }
45020b57cec5SDimitry Andric 
45030b57cec5SDimitry Andric int
4504fe6060f1SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_encoding() const noexcept
45050b57cec5SDimitry Andric {
45060b57cec5SDimitry Andric     return 0;
45070b57cec5SDimitry Andric }
45080b57cec5SDimitry Andric 
45090b57cec5SDimitry Andric bool
4510fe6060f1SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_always_noconv() const noexcept
45110b57cec5SDimitry Andric {
45120b57cec5SDimitry Andric     return false;
45130b57cec5SDimitry Andric }
45140b57cec5SDimitry Andric 
45150b57cec5SDimitry Andric int
45160b57cec5SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_length(state_type&,
45170b57cec5SDimitry Andric     const extern_type* frm, const extern_type* frm_end, size_t mx) const
45180b57cec5SDimitry Andric {
45190b57cec5SDimitry Andric     const uint8_t* _frm = reinterpret_cast<const uint8_t*>(frm);
45200b57cec5SDimitry Andric     const uint8_t* _frm_end = reinterpret_cast<const uint8_t*>(frm_end);
45210b57cec5SDimitry Andric     return utf8_to_utf16_length(_frm, _frm_end, mx, _Maxcode_, _Mode_);
45220b57cec5SDimitry Andric }
45230b57cec5SDimitry Andric 
45240b57cec5SDimitry Andric int
4525fe6060f1SDimitry Andric __codecvt_utf8_utf16<char32_t>::do_max_length() const noexcept
45260b57cec5SDimitry Andric {
45270b57cec5SDimitry Andric     if (_Mode_ & consume_header)
45280b57cec5SDimitry Andric         return 7;
45290b57cec5SDimitry Andric     return 4;
45300b57cec5SDimitry Andric }
45310b57cec5SDimitry Andric 
45320b57cec5SDimitry Andric // __narrow_to_utf8<16>
45330b57cec5SDimitry Andric 
45340b57cec5SDimitry Andric __narrow_to_utf8<16>::~__narrow_to_utf8()
45350b57cec5SDimitry Andric {
45360b57cec5SDimitry Andric }
45370b57cec5SDimitry Andric 
45380b57cec5SDimitry Andric // __narrow_to_utf8<32>
45390b57cec5SDimitry Andric 
45400b57cec5SDimitry Andric __narrow_to_utf8<32>::~__narrow_to_utf8()
45410b57cec5SDimitry Andric {
45420b57cec5SDimitry Andric }
45430b57cec5SDimitry Andric 
45440b57cec5SDimitry Andric // __widen_from_utf8<16>
45450b57cec5SDimitry Andric 
45460b57cec5SDimitry Andric __widen_from_utf8<16>::~__widen_from_utf8()
45470b57cec5SDimitry Andric {
45480b57cec5SDimitry Andric }
45490b57cec5SDimitry Andric 
45500b57cec5SDimitry Andric // __widen_from_utf8<32>
45510b57cec5SDimitry Andric 
45520b57cec5SDimitry Andric __widen_from_utf8<32>::~__widen_from_utf8()
45530b57cec5SDimitry Andric {
45540b57cec5SDimitry Andric }
45550b57cec5SDimitry Andric 
4556349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
45570b57cec5SDimitry Andric static bool checked_string_to_wchar_convert(wchar_t& dest,
45580b57cec5SDimitry Andric                                             const char* ptr,
45590b57cec5SDimitry Andric                                             locale_t loc) {
45600b57cec5SDimitry Andric   if (*ptr == '\0')
45610b57cec5SDimitry Andric     return false;
45620b57cec5SDimitry Andric   mbstate_t mb = {};
45630b57cec5SDimitry Andric   wchar_t out;
45640b57cec5SDimitry Andric   size_t ret = __libcpp_mbrtowc_l(&out, ptr, strlen(ptr), &mb, loc);
45650b57cec5SDimitry Andric   if (ret == static_cast<size_t>(-1) || ret == static_cast<size_t>(-2)) {
45660b57cec5SDimitry Andric     return false;
45670b57cec5SDimitry Andric   }
45680b57cec5SDimitry Andric   dest = out;
45690b57cec5SDimitry Andric   return true;
45700b57cec5SDimitry Andric }
4571349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
4572349cc55cSDimitry Andric 
4573349cc55cSDimitry Andric #ifdef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4574349cc55cSDimitry Andric static bool is_narrow_non_breaking_space(const char* ptr) {
4575349cc55cSDimitry Andric   // https://www.fileformat.info/info/unicode/char/202f/index.htm
4576349cc55cSDimitry Andric   return ptr[0] == '\xe2' && ptr[1] == '\x80' && ptr[2] == '\xaf';
4577349cc55cSDimitry Andric }
4578349cc55cSDimitry Andric 
4579349cc55cSDimitry Andric static bool is_non_breaking_space(const char* ptr) {
4580349cc55cSDimitry Andric   // https://www.fileformat.info/info/unicode/char/0a/index.htm
4581349cc55cSDimitry Andric   return ptr[0] == '\xc2' && ptr[1] == '\xa0';
4582349cc55cSDimitry Andric }
4583349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
45840b57cec5SDimitry Andric 
45850b57cec5SDimitry Andric static bool checked_string_to_char_convert(char& dest,
45860b57cec5SDimitry Andric                                            const char* ptr,
45870b57cec5SDimitry Andric                                            locale_t __loc) {
45880b57cec5SDimitry Andric   if (*ptr == '\0')
45890b57cec5SDimitry Andric     return false;
45900b57cec5SDimitry Andric   if (!ptr[1]) {
45910b57cec5SDimitry Andric     dest = *ptr;
45920b57cec5SDimitry Andric     return true;
45930b57cec5SDimitry Andric   }
4594349cc55cSDimitry Andric 
4595349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
45960b57cec5SDimitry Andric   // First convert the MBS into a wide char then attempt to narrow it using
45970b57cec5SDimitry Andric   // wctob_l.
45980b57cec5SDimitry Andric   wchar_t wout;
45990b57cec5SDimitry Andric   if (!checked_string_to_wchar_convert(wout, ptr, __loc))
46000b57cec5SDimitry Andric     return false;
46010b57cec5SDimitry Andric   int res;
46020b57cec5SDimitry Andric   if ((res = __libcpp_wctob_l(wout, __loc)) != char_traits<char>::eof()) {
46030b57cec5SDimitry Andric     dest = res;
46040b57cec5SDimitry Andric     return true;
46050b57cec5SDimitry Andric   }
4606349cc55cSDimitry Andric   // FIXME: Work around specific multibyte sequences that we can reasonably
46070b57cec5SDimitry Andric   // translate into a different single byte.
46080b57cec5SDimitry Andric   switch (wout) {
46090b57cec5SDimitry Andric   case L'\u202F': // narrow non-breaking space
46100b57cec5SDimitry Andric   case L'\u00A0': // non-breaking space
46110b57cec5SDimitry Andric     dest = ' ';
46120b57cec5SDimitry Andric     return true;
46130b57cec5SDimitry Andric   default:
46140b57cec5SDimitry Andric     return false;
46150b57cec5SDimitry Andric   }
4616349cc55cSDimitry Andric #else // _LIBCPP_HAS_NO_WIDE_CHARACTERS
4617349cc55cSDimitry Andric   // FIXME: Work around specific multibyte sequences that we can reasonably
4618349cc55cSDimitry Andric   // translate into a different single byte.
4619349cc55cSDimitry Andric   if (is_narrow_non_breaking_space(ptr) || is_non_breaking_space(ptr)) {
4620349cc55cSDimitry Andric     dest = ' ';
4621349cc55cSDimitry Andric     return true;
4622349cc55cSDimitry Andric   }
4623349cc55cSDimitry Andric 
4624349cc55cSDimitry Andric   return false;
4625349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
46260b57cec5SDimitry Andric   _LIBCPP_UNREACHABLE();
46270b57cec5SDimitry Andric }
46280b57cec5SDimitry Andric 
46290b57cec5SDimitry Andric 
46300b57cec5SDimitry Andric // numpunct<char> && numpunct<wchar_t>
46310b57cec5SDimitry Andric 
46320b57cec5SDimitry Andric locale::id numpunct< char  >::id;
4633349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46340b57cec5SDimitry Andric locale::id numpunct<wchar_t>::id;
4635349cc55cSDimitry Andric #endif
46360b57cec5SDimitry Andric 
46370b57cec5SDimitry Andric numpunct<char>::numpunct(size_t refs)
46380b57cec5SDimitry Andric     : locale::facet(refs),
46390b57cec5SDimitry Andric       __decimal_point_('.'),
46400b57cec5SDimitry Andric       __thousands_sep_(',')
46410b57cec5SDimitry Andric {
46420b57cec5SDimitry Andric }
46430b57cec5SDimitry Andric 
4644349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46450b57cec5SDimitry Andric numpunct<wchar_t>::numpunct(size_t refs)
46460b57cec5SDimitry Andric     : locale::facet(refs),
46470b57cec5SDimitry Andric       __decimal_point_(L'.'),
46480b57cec5SDimitry Andric       __thousands_sep_(L',')
46490b57cec5SDimitry Andric {
46500b57cec5SDimitry Andric }
4651349cc55cSDimitry Andric #endif
46520b57cec5SDimitry Andric 
46530b57cec5SDimitry Andric numpunct<char>::~numpunct()
46540b57cec5SDimitry Andric {
46550b57cec5SDimitry Andric }
46560b57cec5SDimitry Andric 
4657349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46580b57cec5SDimitry Andric numpunct<wchar_t>::~numpunct()
46590b57cec5SDimitry Andric {
46600b57cec5SDimitry Andric }
4661349cc55cSDimitry Andric #endif
46620b57cec5SDimitry Andric 
46630b57cec5SDimitry Andric  char   numpunct< char  >::do_decimal_point() const {return __decimal_point_;}
4664349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46650b57cec5SDimitry Andric wchar_t numpunct<wchar_t>::do_decimal_point() const {return __decimal_point_;}
4666349cc55cSDimitry Andric #endif
46670b57cec5SDimitry Andric 
46680b57cec5SDimitry Andric  char   numpunct< char  >::do_thousands_sep() const {return __thousands_sep_;}
4669349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46700b57cec5SDimitry Andric wchar_t numpunct<wchar_t>::do_thousands_sep() const {return __thousands_sep_;}
4671349cc55cSDimitry Andric #endif
46720b57cec5SDimitry Andric 
46730b57cec5SDimitry Andric string numpunct< char  >::do_grouping() const {return __grouping_;}
4674349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46750b57cec5SDimitry Andric string numpunct<wchar_t>::do_grouping() const {return __grouping_;}
4676349cc55cSDimitry Andric #endif
46770b57cec5SDimitry Andric 
46780b57cec5SDimitry Andric  string numpunct< char  >::do_truename() const {return "true";}
4679349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46800b57cec5SDimitry Andric wstring numpunct<wchar_t>::do_truename() const {return L"true";}
4681349cc55cSDimitry Andric #endif
46820b57cec5SDimitry Andric 
46830b57cec5SDimitry Andric  string numpunct< char  >::do_falsename() const {return "false";}
4684349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
46850b57cec5SDimitry Andric wstring numpunct<wchar_t>::do_falsename() const {return L"false";}
4686349cc55cSDimitry Andric #endif
46870b57cec5SDimitry Andric 
46880b57cec5SDimitry Andric // numpunct_byname<char>
46890b57cec5SDimitry Andric 
46900b57cec5SDimitry Andric numpunct_byname<char>::numpunct_byname(const char* nm, size_t refs)
46910b57cec5SDimitry Andric     : numpunct<char>(refs)
46920b57cec5SDimitry Andric {
46930b57cec5SDimitry Andric     __init(nm);
46940b57cec5SDimitry Andric }
46950b57cec5SDimitry Andric 
46960b57cec5SDimitry Andric numpunct_byname<char>::numpunct_byname(const string& nm, size_t refs)
46970b57cec5SDimitry Andric     : numpunct<char>(refs)
46980b57cec5SDimitry Andric {
46990b57cec5SDimitry Andric     __init(nm.c_str());
47000b57cec5SDimitry Andric }
47010b57cec5SDimitry Andric 
47020b57cec5SDimitry Andric numpunct_byname<char>::~numpunct_byname()
47030b57cec5SDimitry Andric {
47040b57cec5SDimitry Andric }
47050b57cec5SDimitry Andric 
47060b57cec5SDimitry Andric void
47070b57cec5SDimitry Andric numpunct_byname<char>::__init(const char* nm)
47080b57cec5SDimitry Andric {
4709349cc55cSDimitry Andric     typedef numpunct<char> base;
47100b57cec5SDimitry Andric     if (strcmp(nm, "C") != 0)
47110b57cec5SDimitry Andric     {
47120b57cec5SDimitry Andric         __libcpp_unique_locale loc(nm);
47130b57cec5SDimitry Andric         if (!loc)
47140b57cec5SDimitry Andric             __throw_runtime_error("numpunct_byname<char>::numpunct_byname"
47150b57cec5SDimitry Andric                                 " failed to construct for " + string(nm));
47160b57cec5SDimitry Andric 
47170b57cec5SDimitry Andric         lconv* lc = __libcpp_localeconv_l(loc.get());
4718349cc55cSDimitry Andric         if (!checked_string_to_char_convert(__decimal_point_, lc->decimal_point,
4719349cc55cSDimitry Andric                                             loc.get()))
4720349cc55cSDimitry Andric             __decimal_point_ = base::do_decimal_point();
4721349cc55cSDimitry Andric         if (!checked_string_to_char_convert(__thousands_sep_, lc->thousands_sep,
4722349cc55cSDimitry Andric                                             loc.get()))
4723349cc55cSDimitry Andric             __thousands_sep_ = base::do_thousands_sep();
47240b57cec5SDimitry Andric         __grouping_ = lc->grouping;
47250b57cec5SDimitry Andric         // localization for truename and falsename is not available
47260b57cec5SDimitry Andric     }
47270b57cec5SDimitry Andric }
47280b57cec5SDimitry Andric 
47290b57cec5SDimitry Andric // numpunct_byname<wchar_t>
47300b57cec5SDimitry Andric 
4731349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
47320b57cec5SDimitry Andric numpunct_byname<wchar_t>::numpunct_byname(const char* nm, size_t refs)
47330b57cec5SDimitry Andric     : numpunct<wchar_t>(refs)
47340b57cec5SDimitry Andric {
47350b57cec5SDimitry Andric     __init(nm);
47360b57cec5SDimitry Andric }
47370b57cec5SDimitry Andric 
47380b57cec5SDimitry Andric numpunct_byname<wchar_t>::numpunct_byname(const string& nm, size_t refs)
47390b57cec5SDimitry Andric     : numpunct<wchar_t>(refs)
47400b57cec5SDimitry Andric {
47410b57cec5SDimitry Andric     __init(nm.c_str());
47420b57cec5SDimitry Andric }
47430b57cec5SDimitry Andric 
47440b57cec5SDimitry Andric numpunct_byname<wchar_t>::~numpunct_byname()
47450b57cec5SDimitry Andric {
47460b57cec5SDimitry Andric }
47470b57cec5SDimitry Andric 
47480b57cec5SDimitry Andric void
47490b57cec5SDimitry Andric numpunct_byname<wchar_t>::__init(const char* nm)
47500b57cec5SDimitry Andric {
47510b57cec5SDimitry Andric     if (strcmp(nm, "C") != 0)
47520b57cec5SDimitry Andric     {
47530b57cec5SDimitry Andric         __libcpp_unique_locale loc(nm);
47540b57cec5SDimitry Andric         if (!loc)
47550b57cec5SDimitry Andric             __throw_runtime_error("numpunct_byname<wchar_t>::numpunct_byname"
47560b57cec5SDimitry Andric                                 " failed to construct for " + string(nm));
47570b57cec5SDimitry Andric 
47580b57cec5SDimitry Andric         lconv* lc = __libcpp_localeconv_l(loc.get());
47590b57cec5SDimitry Andric         checked_string_to_wchar_convert(__decimal_point_, lc->decimal_point,
47600b57cec5SDimitry Andric                                         loc.get());
47610b57cec5SDimitry Andric         checked_string_to_wchar_convert(__thousands_sep_, lc->thousands_sep,
47620b57cec5SDimitry Andric                                         loc.get());
47630b57cec5SDimitry Andric         __grouping_ = lc->grouping;
47640b57cec5SDimitry Andric         // localization for truename and falsename is not available
47650b57cec5SDimitry Andric     }
47660b57cec5SDimitry Andric }
4767349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
47680b57cec5SDimitry Andric 
47690b57cec5SDimitry Andric // num_get helpers
47700b57cec5SDimitry Andric 
47710b57cec5SDimitry Andric int
47720b57cec5SDimitry Andric __num_get_base::__get_base(ios_base& iob)
47730b57cec5SDimitry Andric {
47740b57cec5SDimitry Andric     ios_base::fmtflags __basefield = iob.flags() & ios_base::basefield;
47750b57cec5SDimitry Andric     if (__basefield == ios_base::oct)
47760b57cec5SDimitry Andric         return 8;
47770b57cec5SDimitry Andric     else if (__basefield == ios_base::hex)
47780b57cec5SDimitry Andric         return 16;
47790b57cec5SDimitry Andric     else if (__basefield == 0)
47800b57cec5SDimitry Andric         return 0;
47810b57cec5SDimitry Andric     return 10;
47820b57cec5SDimitry Andric }
47830b57cec5SDimitry Andric 
47840b57cec5SDimitry Andric const char __num_get_base::__src[33] = "0123456789abcdefABCDEFxX+-pPiInN";
47850b57cec5SDimitry Andric 
47860b57cec5SDimitry Andric void
47870b57cec5SDimitry Andric __check_grouping(const string& __grouping, unsigned* __g, unsigned* __g_end,
47880b57cec5SDimitry Andric                  ios_base::iostate& __err)
47890b57cec5SDimitry Andric {
47900b57cec5SDimitry Andric //  if the grouping pattern is empty _or_ there are no grouping bits, then do nothing
47910b57cec5SDimitry Andric //  we always have at least a single entry in [__g, __g_end); the end of the input sequence
47920b57cec5SDimitry Andric 	if (__grouping.size() != 0 && __g_end - __g > 1)
47930b57cec5SDimitry Andric     {
47940b57cec5SDimitry Andric         reverse(__g, __g_end);
47950b57cec5SDimitry Andric         const char* __ig = __grouping.data();
47960b57cec5SDimitry Andric         const char* __eg = __ig + __grouping.size();
47970b57cec5SDimitry Andric         for (unsigned* __r = __g; __r < __g_end-1; ++__r)
47980b57cec5SDimitry Andric         {
47990b57cec5SDimitry Andric             if (0 < *__ig && *__ig < numeric_limits<char>::max())
48000b57cec5SDimitry Andric             {
48010b57cec5SDimitry Andric                 if (static_cast<unsigned>(*__ig) != *__r)
48020b57cec5SDimitry Andric                 {
48030b57cec5SDimitry Andric                     __err = ios_base::failbit;
48040b57cec5SDimitry Andric                     return;
48050b57cec5SDimitry Andric                 }
48060b57cec5SDimitry Andric             }
48070b57cec5SDimitry Andric             if (__eg - __ig > 1)
48080b57cec5SDimitry Andric                 ++__ig;
48090b57cec5SDimitry Andric         }
48100b57cec5SDimitry Andric         if (0 < *__ig && *__ig < numeric_limits<char>::max())
48110b57cec5SDimitry Andric         {
48120b57cec5SDimitry Andric             if (static_cast<unsigned>(*__ig) < __g_end[-1] || __g_end[-1] == 0)
48130b57cec5SDimitry Andric                 __err = ios_base::failbit;
48140b57cec5SDimitry Andric         }
48150b57cec5SDimitry Andric     }
48160b57cec5SDimitry Andric }
48170b57cec5SDimitry Andric 
48180b57cec5SDimitry Andric void
48190b57cec5SDimitry Andric __num_put_base::__format_int(char* __fmtp, const char* __len, bool __signd,
48200b57cec5SDimitry Andric                              ios_base::fmtflags __flags)
48210b57cec5SDimitry Andric {
4822fe6060f1SDimitry Andric     if ((__flags & ios_base::showpos) &&
4823fe6060f1SDimitry Andric         (__flags & ios_base::basefield) != ios_base::oct &&
4824fe6060f1SDimitry Andric         (__flags & ios_base::basefield) != ios_base::hex &&
4825fe6060f1SDimitry Andric 	__signd)
48260b57cec5SDimitry Andric         *__fmtp++ = '+';
48270b57cec5SDimitry Andric     if (__flags & ios_base::showbase)
48280b57cec5SDimitry Andric         *__fmtp++ = '#';
48290b57cec5SDimitry Andric     while(*__len)
48300b57cec5SDimitry Andric         *__fmtp++ = *__len++;
48310b57cec5SDimitry Andric     if ((__flags & ios_base::basefield) == ios_base::oct)
48320b57cec5SDimitry Andric         *__fmtp = 'o';
48330b57cec5SDimitry Andric     else if ((__flags & ios_base::basefield) == ios_base::hex)
48340b57cec5SDimitry Andric     {
48350b57cec5SDimitry Andric         if (__flags & ios_base::uppercase)
48360b57cec5SDimitry Andric             *__fmtp = 'X';
48370b57cec5SDimitry Andric         else
48380b57cec5SDimitry Andric             *__fmtp = 'x';
48390b57cec5SDimitry Andric     }
48400b57cec5SDimitry Andric     else if (__signd)
48410b57cec5SDimitry Andric         *__fmtp = 'd';
48420b57cec5SDimitry Andric     else
48430b57cec5SDimitry Andric         *__fmtp = 'u';
48440b57cec5SDimitry Andric }
48450b57cec5SDimitry Andric 
48460b57cec5SDimitry Andric bool
48470b57cec5SDimitry Andric __num_put_base::__format_float(char* __fmtp, const char* __len,
48480b57cec5SDimitry Andric                                ios_base::fmtflags __flags)
48490b57cec5SDimitry Andric {
48500b57cec5SDimitry Andric     bool specify_precision = true;
48510b57cec5SDimitry Andric     if (__flags & ios_base::showpos)
48520b57cec5SDimitry Andric         *__fmtp++ = '+';
48530b57cec5SDimitry Andric     if (__flags & ios_base::showpoint)
48540b57cec5SDimitry Andric         *__fmtp++ = '#';
48550b57cec5SDimitry Andric     ios_base::fmtflags floatfield = __flags & ios_base::floatfield;
48560b57cec5SDimitry Andric     bool uppercase = (__flags & ios_base::uppercase) != 0;
48570b57cec5SDimitry Andric     if (floatfield == (ios_base::fixed | ios_base::scientific))
48580b57cec5SDimitry Andric         specify_precision = false;
48590b57cec5SDimitry Andric     else
48600b57cec5SDimitry Andric     {
48610b57cec5SDimitry Andric         *__fmtp++ = '.';
48620b57cec5SDimitry Andric         *__fmtp++ = '*';
48630b57cec5SDimitry Andric     }
48640b57cec5SDimitry Andric     while(*__len)
48650b57cec5SDimitry Andric         *__fmtp++ = *__len++;
48660b57cec5SDimitry Andric     if (floatfield == ios_base::fixed)
48670b57cec5SDimitry Andric     {
48680b57cec5SDimitry Andric         if (uppercase)
48690b57cec5SDimitry Andric             *__fmtp = 'F';
48700b57cec5SDimitry Andric         else
48710b57cec5SDimitry Andric             *__fmtp = 'f';
48720b57cec5SDimitry Andric     }
48730b57cec5SDimitry Andric     else if (floatfield == ios_base::scientific)
48740b57cec5SDimitry Andric     {
48750b57cec5SDimitry Andric         if (uppercase)
48760b57cec5SDimitry Andric             *__fmtp = 'E';
48770b57cec5SDimitry Andric         else
48780b57cec5SDimitry Andric             *__fmtp = 'e';
48790b57cec5SDimitry Andric     }
48800b57cec5SDimitry Andric     else if (floatfield == (ios_base::fixed | ios_base::scientific))
48810b57cec5SDimitry Andric     {
48820b57cec5SDimitry Andric         if (uppercase)
48830b57cec5SDimitry Andric             *__fmtp = 'A';
48840b57cec5SDimitry Andric         else
48850b57cec5SDimitry Andric             *__fmtp = 'a';
48860b57cec5SDimitry Andric     }
48870b57cec5SDimitry Andric     else
48880b57cec5SDimitry Andric     {
48890b57cec5SDimitry Andric         if (uppercase)
48900b57cec5SDimitry Andric             *__fmtp = 'G';
48910b57cec5SDimitry Andric         else
48920b57cec5SDimitry Andric             *__fmtp = 'g';
48930b57cec5SDimitry Andric     }
48940b57cec5SDimitry Andric     return specify_precision;
48950b57cec5SDimitry Andric }
48960b57cec5SDimitry Andric 
48970b57cec5SDimitry Andric char*
48980b57cec5SDimitry Andric __num_put_base::__identify_padding(char* __nb, char* __ne,
48990b57cec5SDimitry Andric                                    const ios_base& __iob)
49000b57cec5SDimitry Andric {
49010b57cec5SDimitry Andric     switch (__iob.flags() & ios_base::adjustfield)
49020b57cec5SDimitry Andric     {
49030b57cec5SDimitry Andric     case ios_base::internal:
49040b57cec5SDimitry Andric         if (__nb[0] == '-' || __nb[0] == '+')
49050b57cec5SDimitry Andric             return __nb+1;
49060b57cec5SDimitry Andric         if (__ne - __nb >= 2 && __nb[0] == '0'
49070b57cec5SDimitry Andric                             && (__nb[1] == 'x' || __nb[1] == 'X'))
49080b57cec5SDimitry Andric             return __nb+2;
49090b57cec5SDimitry Andric         break;
49100b57cec5SDimitry Andric     case ios_base::left:
49110b57cec5SDimitry Andric         return __ne;
49120b57cec5SDimitry Andric     case ios_base::right:
49130b57cec5SDimitry Andric     default:
49140b57cec5SDimitry Andric         break;
49150b57cec5SDimitry Andric     }
49160b57cec5SDimitry Andric     return __nb;
49170b57cec5SDimitry Andric }
49180b57cec5SDimitry Andric 
49190b57cec5SDimitry Andric // time_get
49200b57cec5SDimitry Andric 
49210b57cec5SDimitry Andric static
49220b57cec5SDimitry Andric string*
49230b57cec5SDimitry Andric init_weeks()
49240b57cec5SDimitry Andric {
49250b57cec5SDimitry Andric     static string weeks[14];
49260b57cec5SDimitry Andric     weeks[0]  = "Sunday";
49270b57cec5SDimitry Andric     weeks[1]  = "Monday";
49280b57cec5SDimitry Andric     weeks[2]  = "Tuesday";
49290b57cec5SDimitry Andric     weeks[3]  = "Wednesday";
49300b57cec5SDimitry Andric     weeks[4]  = "Thursday";
49310b57cec5SDimitry Andric     weeks[5]  = "Friday";
49320b57cec5SDimitry Andric     weeks[6]  = "Saturday";
49330b57cec5SDimitry Andric     weeks[7]  = "Sun";
49340b57cec5SDimitry Andric     weeks[8]  = "Mon";
49350b57cec5SDimitry Andric     weeks[9]  = "Tue";
49360b57cec5SDimitry Andric     weeks[10] = "Wed";
49370b57cec5SDimitry Andric     weeks[11] = "Thu";
49380b57cec5SDimitry Andric     weeks[12] = "Fri";
49390b57cec5SDimitry Andric     weeks[13] = "Sat";
49400b57cec5SDimitry Andric     return weeks;
49410b57cec5SDimitry Andric }
49420b57cec5SDimitry Andric 
4943349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
49440b57cec5SDimitry Andric static
49450b57cec5SDimitry Andric wstring*
49460b57cec5SDimitry Andric init_wweeks()
49470b57cec5SDimitry Andric {
49480b57cec5SDimitry Andric     static wstring weeks[14];
49490b57cec5SDimitry Andric     weeks[0]  = L"Sunday";
49500b57cec5SDimitry Andric     weeks[1]  = L"Monday";
49510b57cec5SDimitry Andric     weeks[2]  = L"Tuesday";
49520b57cec5SDimitry Andric     weeks[3]  = L"Wednesday";
49530b57cec5SDimitry Andric     weeks[4]  = L"Thursday";
49540b57cec5SDimitry Andric     weeks[5]  = L"Friday";
49550b57cec5SDimitry Andric     weeks[6]  = L"Saturday";
49560b57cec5SDimitry Andric     weeks[7]  = L"Sun";
49570b57cec5SDimitry Andric     weeks[8]  = L"Mon";
49580b57cec5SDimitry Andric     weeks[9]  = L"Tue";
49590b57cec5SDimitry Andric     weeks[10] = L"Wed";
49600b57cec5SDimitry Andric     weeks[11] = L"Thu";
49610b57cec5SDimitry Andric     weeks[12] = L"Fri";
49620b57cec5SDimitry Andric     weeks[13] = L"Sat";
49630b57cec5SDimitry Andric     return weeks;
49640b57cec5SDimitry Andric }
4965349cc55cSDimitry Andric #endif
49660b57cec5SDimitry Andric 
49670b57cec5SDimitry Andric template <>
49680b57cec5SDimitry Andric const string*
49690b57cec5SDimitry Andric __time_get_c_storage<char>::__weeks() const
49700b57cec5SDimitry Andric {
49710b57cec5SDimitry Andric     static const string* weeks = init_weeks();
49720b57cec5SDimitry Andric     return weeks;
49730b57cec5SDimitry Andric }
49740b57cec5SDimitry Andric 
4975349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
49760b57cec5SDimitry Andric template <>
49770b57cec5SDimitry Andric const wstring*
49780b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__weeks() const
49790b57cec5SDimitry Andric {
49800b57cec5SDimitry Andric     static const wstring* weeks = init_wweeks();
49810b57cec5SDimitry Andric     return weeks;
49820b57cec5SDimitry Andric }
4983349cc55cSDimitry Andric #endif
49840b57cec5SDimitry Andric 
49850b57cec5SDimitry Andric static
49860b57cec5SDimitry Andric string*
49870b57cec5SDimitry Andric init_months()
49880b57cec5SDimitry Andric {
49890b57cec5SDimitry Andric     static string months[24];
49900b57cec5SDimitry Andric     months[0]  = "January";
49910b57cec5SDimitry Andric     months[1]  = "February";
49920b57cec5SDimitry Andric     months[2]  = "March";
49930b57cec5SDimitry Andric     months[3]  = "April";
49940b57cec5SDimitry Andric     months[4]  = "May";
49950b57cec5SDimitry Andric     months[5]  = "June";
49960b57cec5SDimitry Andric     months[6]  = "July";
49970b57cec5SDimitry Andric     months[7]  = "August";
49980b57cec5SDimitry Andric     months[8]  = "September";
49990b57cec5SDimitry Andric     months[9]  = "October";
50000b57cec5SDimitry Andric     months[10] = "November";
50010b57cec5SDimitry Andric     months[11] = "December";
50020b57cec5SDimitry Andric     months[12] = "Jan";
50030b57cec5SDimitry Andric     months[13] = "Feb";
50040b57cec5SDimitry Andric     months[14] = "Mar";
50050b57cec5SDimitry Andric     months[15] = "Apr";
50060b57cec5SDimitry Andric     months[16] = "May";
50070b57cec5SDimitry Andric     months[17] = "Jun";
50080b57cec5SDimitry Andric     months[18] = "Jul";
50090b57cec5SDimitry Andric     months[19] = "Aug";
50100b57cec5SDimitry Andric     months[20] = "Sep";
50110b57cec5SDimitry Andric     months[21] = "Oct";
50120b57cec5SDimitry Andric     months[22] = "Nov";
50130b57cec5SDimitry Andric     months[23] = "Dec";
50140b57cec5SDimitry Andric     return months;
50150b57cec5SDimitry Andric }
50160b57cec5SDimitry Andric 
5017349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
50180b57cec5SDimitry Andric static
50190b57cec5SDimitry Andric wstring*
50200b57cec5SDimitry Andric init_wmonths()
50210b57cec5SDimitry Andric {
50220b57cec5SDimitry Andric     static wstring months[24];
50230b57cec5SDimitry Andric     months[0]  = L"January";
50240b57cec5SDimitry Andric     months[1]  = L"February";
50250b57cec5SDimitry Andric     months[2]  = L"March";
50260b57cec5SDimitry Andric     months[3]  = L"April";
50270b57cec5SDimitry Andric     months[4]  = L"May";
50280b57cec5SDimitry Andric     months[5]  = L"June";
50290b57cec5SDimitry Andric     months[6]  = L"July";
50300b57cec5SDimitry Andric     months[7]  = L"August";
50310b57cec5SDimitry Andric     months[8]  = L"September";
50320b57cec5SDimitry Andric     months[9]  = L"October";
50330b57cec5SDimitry Andric     months[10] = L"November";
50340b57cec5SDimitry Andric     months[11] = L"December";
50350b57cec5SDimitry Andric     months[12] = L"Jan";
50360b57cec5SDimitry Andric     months[13] = L"Feb";
50370b57cec5SDimitry Andric     months[14] = L"Mar";
50380b57cec5SDimitry Andric     months[15] = L"Apr";
50390b57cec5SDimitry Andric     months[16] = L"May";
50400b57cec5SDimitry Andric     months[17] = L"Jun";
50410b57cec5SDimitry Andric     months[18] = L"Jul";
50420b57cec5SDimitry Andric     months[19] = L"Aug";
50430b57cec5SDimitry Andric     months[20] = L"Sep";
50440b57cec5SDimitry Andric     months[21] = L"Oct";
50450b57cec5SDimitry Andric     months[22] = L"Nov";
50460b57cec5SDimitry Andric     months[23] = L"Dec";
50470b57cec5SDimitry Andric     return months;
50480b57cec5SDimitry Andric }
5049349cc55cSDimitry Andric #endif
50500b57cec5SDimitry Andric 
50510b57cec5SDimitry Andric template <>
50520b57cec5SDimitry Andric const string*
50530b57cec5SDimitry Andric __time_get_c_storage<char>::__months() const
50540b57cec5SDimitry Andric {
50550b57cec5SDimitry Andric     static const string* months = init_months();
50560b57cec5SDimitry Andric     return months;
50570b57cec5SDimitry Andric }
50580b57cec5SDimitry Andric 
5059349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
50600b57cec5SDimitry Andric template <>
50610b57cec5SDimitry Andric const wstring*
50620b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__months() const
50630b57cec5SDimitry Andric {
50640b57cec5SDimitry Andric     static const wstring* months = init_wmonths();
50650b57cec5SDimitry Andric     return months;
50660b57cec5SDimitry Andric }
5067349cc55cSDimitry Andric #endif
50680b57cec5SDimitry Andric 
50690b57cec5SDimitry Andric static
50700b57cec5SDimitry Andric string*
50710b57cec5SDimitry Andric init_am_pm()
50720b57cec5SDimitry Andric {
50730b57cec5SDimitry Andric     static string am_pm[2];
50740b57cec5SDimitry Andric     am_pm[0]  = "AM";
50750b57cec5SDimitry Andric     am_pm[1]  = "PM";
50760b57cec5SDimitry Andric     return am_pm;
50770b57cec5SDimitry Andric }
50780b57cec5SDimitry Andric 
5079349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
50800b57cec5SDimitry Andric static
50810b57cec5SDimitry Andric wstring*
50820b57cec5SDimitry Andric init_wam_pm()
50830b57cec5SDimitry Andric {
50840b57cec5SDimitry Andric     static wstring am_pm[2];
50850b57cec5SDimitry Andric     am_pm[0]  = L"AM";
50860b57cec5SDimitry Andric     am_pm[1]  = L"PM";
50870b57cec5SDimitry Andric     return am_pm;
50880b57cec5SDimitry Andric }
5089349cc55cSDimitry Andric #endif
50900b57cec5SDimitry Andric 
50910b57cec5SDimitry Andric template <>
50920b57cec5SDimitry Andric const string*
50930b57cec5SDimitry Andric __time_get_c_storage<char>::__am_pm() const
50940b57cec5SDimitry Andric {
50950b57cec5SDimitry Andric     static const string* am_pm = init_am_pm();
50960b57cec5SDimitry Andric     return am_pm;
50970b57cec5SDimitry Andric }
50980b57cec5SDimitry Andric 
5099349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51000b57cec5SDimitry Andric template <>
51010b57cec5SDimitry Andric const wstring*
51020b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__am_pm() const
51030b57cec5SDimitry Andric {
51040b57cec5SDimitry Andric     static const wstring* am_pm = init_wam_pm();
51050b57cec5SDimitry Andric     return am_pm;
51060b57cec5SDimitry Andric }
5107349cc55cSDimitry Andric #endif
51080b57cec5SDimitry Andric 
51090b57cec5SDimitry Andric template <>
51100b57cec5SDimitry Andric const string&
51110b57cec5SDimitry Andric __time_get_c_storage<char>::__x() const
51120b57cec5SDimitry Andric {
51130b57cec5SDimitry Andric     static string s("%m/%d/%y");
51140b57cec5SDimitry Andric     return s;
51150b57cec5SDimitry Andric }
51160b57cec5SDimitry Andric 
5117349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51180b57cec5SDimitry Andric template <>
51190b57cec5SDimitry Andric const wstring&
51200b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__x() const
51210b57cec5SDimitry Andric {
51220b57cec5SDimitry Andric     static wstring s(L"%m/%d/%y");
51230b57cec5SDimitry Andric     return s;
51240b57cec5SDimitry Andric }
5125349cc55cSDimitry Andric #endif
51260b57cec5SDimitry Andric 
51270b57cec5SDimitry Andric template <>
51280b57cec5SDimitry Andric const string&
51290b57cec5SDimitry Andric __time_get_c_storage<char>::__X() const
51300b57cec5SDimitry Andric {
51310b57cec5SDimitry Andric     static string s("%H:%M:%S");
51320b57cec5SDimitry Andric     return s;
51330b57cec5SDimitry Andric }
51340b57cec5SDimitry Andric 
5135349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51360b57cec5SDimitry Andric template <>
51370b57cec5SDimitry Andric const wstring&
51380b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__X() const
51390b57cec5SDimitry Andric {
51400b57cec5SDimitry Andric     static wstring s(L"%H:%M:%S");
51410b57cec5SDimitry Andric     return s;
51420b57cec5SDimitry Andric }
5143349cc55cSDimitry Andric #endif
51440b57cec5SDimitry Andric 
51450b57cec5SDimitry Andric template <>
51460b57cec5SDimitry Andric const string&
51470b57cec5SDimitry Andric __time_get_c_storage<char>::__c() const
51480b57cec5SDimitry Andric {
51490b57cec5SDimitry Andric     static string s("%a %b %d %H:%M:%S %Y");
51500b57cec5SDimitry Andric     return s;
51510b57cec5SDimitry Andric }
51520b57cec5SDimitry Andric 
5153349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51540b57cec5SDimitry Andric template <>
51550b57cec5SDimitry Andric const wstring&
51560b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__c() const
51570b57cec5SDimitry Andric {
51580b57cec5SDimitry Andric     static wstring s(L"%a %b %d %H:%M:%S %Y");
51590b57cec5SDimitry Andric     return s;
51600b57cec5SDimitry Andric }
5161349cc55cSDimitry Andric #endif
51620b57cec5SDimitry Andric 
51630b57cec5SDimitry Andric template <>
51640b57cec5SDimitry Andric const string&
51650b57cec5SDimitry Andric __time_get_c_storage<char>::__r() const
51660b57cec5SDimitry Andric {
51670b57cec5SDimitry Andric     static string s("%I:%M:%S %p");
51680b57cec5SDimitry Andric     return s;
51690b57cec5SDimitry Andric }
51700b57cec5SDimitry Andric 
5171349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
51720b57cec5SDimitry Andric template <>
51730b57cec5SDimitry Andric const wstring&
51740b57cec5SDimitry Andric __time_get_c_storage<wchar_t>::__r() const
51750b57cec5SDimitry Andric {
51760b57cec5SDimitry Andric     static wstring s(L"%I:%M:%S %p");
51770b57cec5SDimitry Andric     return s;
51780b57cec5SDimitry Andric }
5179349cc55cSDimitry Andric #endif
51800b57cec5SDimitry Andric 
51810b57cec5SDimitry Andric // time_get_byname
51820b57cec5SDimitry Andric 
51830b57cec5SDimitry Andric __time_get::__time_get(const char* nm)
51840b57cec5SDimitry Andric     : __loc_(newlocale(LC_ALL_MASK, nm, 0))
51850b57cec5SDimitry Andric {
51860b57cec5SDimitry Andric     if (__loc_ == 0)
51870b57cec5SDimitry Andric         __throw_runtime_error("time_get_byname"
51880b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
51890b57cec5SDimitry Andric }
51900b57cec5SDimitry Andric 
51910b57cec5SDimitry Andric __time_get::__time_get(const string& nm)
51920b57cec5SDimitry Andric     : __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0))
51930b57cec5SDimitry Andric {
51940b57cec5SDimitry Andric     if (__loc_ == 0)
51950b57cec5SDimitry Andric         __throw_runtime_error("time_get_byname"
51960b57cec5SDimitry Andric                             " failed to construct for " + nm);
51970b57cec5SDimitry Andric }
51980b57cec5SDimitry Andric 
51990b57cec5SDimitry Andric __time_get::~__time_get()
52000b57cec5SDimitry Andric {
52010b57cec5SDimitry Andric     freelocale(__loc_);
52020b57cec5SDimitry Andric }
52030b57cec5SDimitry Andric #if defined(__clang__)
52040b57cec5SDimitry Andric #pragma clang diagnostic ignored "-Wmissing-field-initializers"
52050b57cec5SDimitry Andric #endif
52060b57cec5SDimitry Andric #if defined(__GNUG__)
52070b57cec5SDimitry Andric #pragma GCC   diagnostic ignored "-Wmissing-field-initializers"
52080b57cec5SDimitry Andric #endif
52090b57cec5SDimitry Andric 
52100b57cec5SDimitry Andric template <>
52110b57cec5SDimitry Andric string
52120b57cec5SDimitry Andric __time_get_storage<char>::__analyze(char fmt, const ctype<char>& ct)
52130b57cec5SDimitry Andric {
52140b57cec5SDimitry Andric     tm t = {0};
52150b57cec5SDimitry Andric     t.tm_sec = 59;
52160b57cec5SDimitry Andric     t.tm_min = 55;
52170b57cec5SDimitry Andric     t.tm_hour = 23;
52180b57cec5SDimitry Andric     t.tm_mday = 31;
52190b57cec5SDimitry Andric     t.tm_mon = 11;
52200b57cec5SDimitry Andric     t.tm_year = 161;
52210b57cec5SDimitry Andric     t.tm_wday = 6;
52220b57cec5SDimitry Andric     t.tm_yday = 364;
52230b57cec5SDimitry Andric     t.tm_isdst = -1;
52240b57cec5SDimitry Andric     char buf[100];
52250b57cec5SDimitry Andric     char f[3] = {0};
52260b57cec5SDimitry Andric     f[0] = '%';
52270b57cec5SDimitry Andric     f[1] = fmt;
52280b57cec5SDimitry Andric     size_t n = strftime_l(buf, countof(buf), f, &t, __loc_);
52290b57cec5SDimitry Andric     char* bb = buf;
52300b57cec5SDimitry Andric     char* be = buf + n;
52310b57cec5SDimitry Andric     string result;
52320b57cec5SDimitry Andric     while (bb != be)
52330b57cec5SDimitry Andric     {
52340b57cec5SDimitry Andric         if (ct.is(ctype_base::space, *bb))
52350b57cec5SDimitry Andric         {
52360b57cec5SDimitry Andric             result.push_back(' ');
52370b57cec5SDimitry Andric             for (++bb; bb != be && ct.is(ctype_base::space, *bb); ++bb)
52380b57cec5SDimitry Andric                 ;
52390b57cec5SDimitry Andric             continue;
52400b57cec5SDimitry Andric         }
52410b57cec5SDimitry Andric         char* w = bb;
52420b57cec5SDimitry Andric         ios_base::iostate err = ios_base::goodbit;
52430b57cec5SDimitry Andric         ptrdiff_t i = __scan_keyword(w, be, this->__weeks_, this->__weeks_+14,
52440b57cec5SDimitry Andric                                ct, err, false)
52450b57cec5SDimitry Andric                                - this->__weeks_;
52460b57cec5SDimitry Andric         if (i < 14)
52470b57cec5SDimitry Andric         {
52480b57cec5SDimitry Andric             result.push_back('%');
52490b57cec5SDimitry Andric             if (i < 7)
52500b57cec5SDimitry Andric                 result.push_back('A');
52510b57cec5SDimitry Andric             else
52520b57cec5SDimitry Andric                 result.push_back('a');
52530b57cec5SDimitry Andric             bb = w;
52540b57cec5SDimitry Andric             continue;
52550b57cec5SDimitry Andric         }
52560b57cec5SDimitry Andric         w = bb;
52570b57cec5SDimitry Andric         i = __scan_keyword(w, be, this->__months_, this->__months_+24,
52580b57cec5SDimitry Andric                            ct, err, false)
52590b57cec5SDimitry Andric                            - this->__months_;
52600b57cec5SDimitry Andric         if (i < 24)
52610b57cec5SDimitry Andric         {
52620b57cec5SDimitry Andric             result.push_back('%');
52630b57cec5SDimitry Andric             if (i < 12)
52640b57cec5SDimitry Andric                 result.push_back('B');
52650b57cec5SDimitry Andric             else
52660b57cec5SDimitry Andric                 result.push_back('b');
52670b57cec5SDimitry Andric             if (fmt == 'x' && ct.is(ctype_base::digit, this->__months_[i][0]))
52680b57cec5SDimitry Andric                 result.back() = 'm';
52690b57cec5SDimitry Andric             bb = w;
52700b57cec5SDimitry Andric             continue;
52710b57cec5SDimitry Andric         }
52720b57cec5SDimitry Andric         if (this->__am_pm_[0].size() + this->__am_pm_[1].size() > 0)
52730b57cec5SDimitry Andric         {
52740b57cec5SDimitry Andric             w = bb;
52750b57cec5SDimitry Andric             i = __scan_keyword(w, be, this->__am_pm_, this->__am_pm_+2,
52760b57cec5SDimitry Andric                                ct, err, false) - this->__am_pm_;
52770b57cec5SDimitry Andric             if (i < 2)
52780b57cec5SDimitry Andric             {
52790b57cec5SDimitry Andric                 result.push_back('%');
52800b57cec5SDimitry Andric                 result.push_back('p');
52810b57cec5SDimitry Andric                 bb = w;
52820b57cec5SDimitry Andric                 continue;
52830b57cec5SDimitry Andric             }
52840b57cec5SDimitry Andric         }
52850b57cec5SDimitry Andric         w = bb;
52860b57cec5SDimitry Andric         if (ct.is(ctype_base::digit, *bb))
52870b57cec5SDimitry Andric         {
52880b57cec5SDimitry Andric             switch(__get_up_to_n_digits(bb, be, err, ct, 4))
52890b57cec5SDimitry Andric             {
52900b57cec5SDimitry Andric             case 6:
52910b57cec5SDimitry Andric                 result.push_back('%');
52920b57cec5SDimitry Andric                 result.push_back('w');
52930b57cec5SDimitry Andric                 break;
52940b57cec5SDimitry Andric             case 7:
52950b57cec5SDimitry Andric                 result.push_back('%');
52960b57cec5SDimitry Andric                 result.push_back('u');
52970b57cec5SDimitry Andric                 break;
52980b57cec5SDimitry Andric             case 11:
52990b57cec5SDimitry Andric                 result.push_back('%');
53000b57cec5SDimitry Andric                 result.push_back('I');
53010b57cec5SDimitry Andric                 break;
53020b57cec5SDimitry Andric             case 12:
53030b57cec5SDimitry Andric                 result.push_back('%');
53040b57cec5SDimitry Andric                 result.push_back('m');
53050b57cec5SDimitry Andric                 break;
53060b57cec5SDimitry Andric             case 23:
53070b57cec5SDimitry Andric                 result.push_back('%');
53080b57cec5SDimitry Andric                 result.push_back('H');
53090b57cec5SDimitry Andric                 break;
53100b57cec5SDimitry Andric             case 31:
53110b57cec5SDimitry Andric                 result.push_back('%');
53120b57cec5SDimitry Andric                 result.push_back('d');
53130b57cec5SDimitry Andric                 break;
53140b57cec5SDimitry Andric             case 55:
53150b57cec5SDimitry Andric                 result.push_back('%');
53160b57cec5SDimitry Andric                 result.push_back('M');
53170b57cec5SDimitry Andric                 break;
53180b57cec5SDimitry Andric             case 59:
53190b57cec5SDimitry Andric                 result.push_back('%');
53200b57cec5SDimitry Andric                 result.push_back('S');
53210b57cec5SDimitry Andric                 break;
53220b57cec5SDimitry Andric             case 61:
53230b57cec5SDimitry Andric                 result.push_back('%');
53240b57cec5SDimitry Andric                 result.push_back('y');
53250b57cec5SDimitry Andric                 break;
53260b57cec5SDimitry Andric             case 364:
53270b57cec5SDimitry Andric                 result.push_back('%');
53280b57cec5SDimitry Andric                 result.push_back('j');
53290b57cec5SDimitry Andric                 break;
53300b57cec5SDimitry Andric             case 2061:
53310b57cec5SDimitry Andric                 result.push_back('%');
53320b57cec5SDimitry Andric                 result.push_back('Y');
53330b57cec5SDimitry Andric                 break;
53340b57cec5SDimitry Andric             default:
53350b57cec5SDimitry Andric                 for (; w != bb; ++w)
53360b57cec5SDimitry Andric                     result.push_back(*w);
53370b57cec5SDimitry Andric                 break;
53380b57cec5SDimitry Andric             }
53390b57cec5SDimitry Andric             continue;
53400b57cec5SDimitry Andric         }
53410b57cec5SDimitry Andric         if (*bb == '%')
53420b57cec5SDimitry Andric         {
53430b57cec5SDimitry Andric             result.push_back('%');
53440b57cec5SDimitry Andric             result.push_back('%');
53450b57cec5SDimitry Andric             ++bb;
53460b57cec5SDimitry Andric             continue;
53470b57cec5SDimitry Andric         }
53480b57cec5SDimitry Andric         result.push_back(*bb);
53490b57cec5SDimitry Andric         ++bb;
53500b57cec5SDimitry Andric     }
53510b57cec5SDimitry Andric     return result;
53520b57cec5SDimitry Andric }
53530b57cec5SDimitry Andric 
53540b57cec5SDimitry Andric #if defined(__clang__)
53550b57cec5SDimitry Andric #pragma clang diagnostic ignored "-Wmissing-braces"
53560b57cec5SDimitry Andric #endif
53570b57cec5SDimitry Andric 
5358349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
53590b57cec5SDimitry Andric template <>
53600b57cec5SDimitry Andric wstring
53610b57cec5SDimitry Andric __time_get_storage<wchar_t>::__analyze(char fmt, const ctype<wchar_t>& ct)
53620b57cec5SDimitry Andric {
53630b57cec5SDimitry Andric     tm t = {0};
53640b57cec5SDimitry Andric     t.tm_sec = 59;
53650b57cec5SDimitry Andric     t.tm_min = 55;
53660b57cec5SDimitry Andric     t.tm_hour = 23;
53670b57cec5SDimitry Andric     t.tm_mday = 31;
53680b57cec5SDimitry Andric     t.tm_mon = 11;
53690b57cec5SDimitry Andric     t.tm_year = 161;
53700b57cec5SDimitry Andric     t.tm_wday = 6;
53710b57cec5SDimitry Andric     t.tm_yday = 364;
53720b57cec5SDimitry Andric     t.tm_isdst = -1;
53730b57cec5SDimitry Andric     char buf[100];
53740b57cec5SDimitry Andric     char f[3] = {0};
53750b57cec5SDimitry Andric     f[0] = '%';
53760b57cec5SDimitry Andric     f[1] = fmt;
53770b57cec5SDimitry Andric     strftime_l(buf, countof(buf), f, &t, __loc_);
53780b57cec5SDimitry Andric     wchar_t wbuf[100];
53790b57cec5SDimitry Andric     wchar_t* wbb = wbuf;
53800b57cec5SDimitry Andric     mbstate_t mb = {0};
53810b57cec5SDimitry Andric     const char* bb = buf;
53820b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l( wbb, &bb, countof(wbuf), &mb, __loc_);
53830b57cec5SDimitry Andric     if (j == size_t(-1))
53840b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
53850b57cec5SDimitry Andric     wchar_t* wbe = wbb + j;
53860b57cec5SDimitry Andric     wstring result;
53870b57cec5SDimitry Andric     while (wbb != wbe)
53880b57cec5SDimitry Andric     {
53890b57cec5SDimitry Andric         if (ct.is(ctype_base::space, *wbb))
53900b57cec5SDimitry Andric         {
53910b57cec5SDimitry Andric             result.push_back(L' ');
53920b57cec5SDimitry Andric             for (++wbb; wbb != wbe && ct.is(ctype_base::space, *wbb); ++wbb)
53930b57cec5SDimitry Andric                 ;
53940b57cec5SDimitry Andric             continue;
53950b57cec5SDimitry Andric         }
53960b57cec5SDimitry Andric         wchar_t* w = wbb;
53970b57cec5SDimitry Andric         ios_base::iostate err = ios_base::goodbit;
53980b57cec5SDimitry Andric         ptrdiff_t i = __scan_keyword(w, wbe, this->__weeks_, this->__weeks_+14,
53990b57cec5SDimitry Andric                                ct, err, false)
54000b57cec5SDimitry Andric                                - this->__weeks_;
54010b57cec5SDimitry Andric         if (i < 14)
54020b57cec5SDimitry Andric         {
54030b57cec5SDimitry Andric             result.push_back(L'%');
54040b57cec5SDimitry Andric             if (i < 7)
54050b57cec5SDimitry Andric                 result.push_back(L'A');
54060b57cec5SDimitry Andric             else
54070b57cec5SDimitry Andric                 result.push_back(L'a');
54080b57cec5SDimitry Andric             wbb = w;
54090b57cec5SDimitry Andric             continue;
54100b57cec5SDimitry Andric         }
54110b57cec5SDimitry Andric         w = wbb;
54120b57cec5SDimitry Andric         i = __scan_keyword(w, wbe, this->__months_, this->__months_+24,
54130b57cec5SDimitry Andric                            ct, err, false)
54140b57cec5SDimitry Andric                            - this->__months_;
54150b57cec5SDimitry Andric         if (i < 24)
54160b57cec5SDimitry Andric         {
54170b57cec5SDimitry Andric             result.push_back(L'%');
54180b57cec5SDimitry Andric             if (i < 12)
54190b57cec5SDimitry Andric                 result.push_back(L'B');
54200b57cec5SDimitry Andric             else
54210b57cec5SDimitry Andric                 result.push_back(L'b');
54220b57cec5SDimitry Andric             if (fmt == 'x' && ct.is(ctype_base::digit, this->__months_[i][0]))
54230b57cec5SDimitry Andric                 result.back() = L'm';
54240b57cec5SDimitry Andric             wbb = w;
54250b57cec5SDimitry Andric             continue;
54260b57cec5SDimitry Andric         }
54270b57cec5SDimitry Andric         if (this->__am_pm_[0].size() + this->__am_pm_[1].size() > 0)
54280b57cec5SDimitry Andric         {
54290b57cec5SDimitry Andric             w = wbb;
54300b57cec5SDimitry Andric             i = __scan_keyword(w, wbe, this->__am_pm_, this->__am_pm_+2,
54310b57cec5SDimitry Andric                                ct, err, false) - this->__am_pm_;
54320b57cec5SDimitry Andric             if (i < 2)
54330b57cec5SDimitry Andric             {
54340b57cec5SDimitry Andric                 result.push_back(L'%');
54350b57cec5SDimitry Andric                 result.push_back(L'p');
54360b57cec5SDimitry Andric                 wbb = w;
54370b57cec5SDimitry Andric                 continue;
54380b57cec5SDimitry Andric             }
54390b57cec5SDimitry Andric         }
54400b57cec5SDimitry Andric         w = wbb;
54410b57cec5SDimitry Andric         if (ct.is(ctype_base::digit, *wbb))
54420b57cec5SDimitry Andric         {
54430b57cec5SDimitry Andric             switch(__get_up_to_n_digits(wbb, wbe, err, ct, 4))
54440b57cec5SDimitry Andric             {
54450b57cec5SDimitry Andric             case 6:
54460b57cec5SDimitry Andric                 result.push_back(L'%');
54470b57cec5SDimitry Andric                 result.push_back(L'w');
54480b57cec5SDimitry Andric                 break;
54490b57cec5SDimitry Andric             case 7:
54500b57cec5SDimitry Andric                 result.push_back(L'%');
54510b57cec5SDimitry Andric                 result.push_back(L'u');
54520b57cec5SDimitry Andric                 break;
54530b57cec5SDimitry Andric             case 11:
54540b57cec5SDimitry Andric                 result.push_back(L'%');
54550b57cec5SDimitry Andric                 result.push_back(L'I');
54560b57cec5SDimitry Andric                 break;
54570b57cec5SDimitry Andric             case 12:
54580b57cec5SDimitry Andric                 result.push_back(L'%');
54590b57cec5SDimitry Andric                 result.push_back(L'm');
54600b57cec5SDimitry Andric                 break;
54610b57cec5SDimitry Andric             case 23:
54620b57cec5SDimitry Andric                 result.push_back(L'%');
54630b57cec5SDimitry Andric                 result.push_back(L'H');
54640b57cec5SDimitry Andric                 break;
54650b57cec5SDimitry Andric             case 31:
54660b57cec5SDimitry Andric                 result.push_back(L'%');
54670b57cec5SDimitry Andric                 result.push_back(L'd');
54680b57cec5SDimitry Andric                 break;
54690b57cec5SDimitry Andric             case 55:
54700b57cec5SDimitry Andric                 result.push_back(L'%');
54710b57cec5SDimitry Andric                 result.push_back(L'M');
54720b57cec5SDimitry Andric                 break;
54730b57cec5SDimitry Andric             case 59:
54740b57cec5SDimitry Andric                 result.push_back(L'%');
54750b57cec5SDimitry Andric                 result.push_back(L'S');
54760b57cec5SDimitry Andric                 break;
54770b57cec5SDimitry Andric             case 61:
54780b57cec5SDimitry Andric                 result.push_back(L'%');
54790b57cec5SDimitry Andric                 result.push_back(L'y');
54800b57cec5SDimitry Andric                 break;
54810b57cec5SDimitry Andric             case 364:
54820b57cec5SDimitry Andric                 result.push_back(L'%');
54830b57cec5SDimitry Andric                 result.push_back(L'j');
54840b57cec5SDimitry Andric                 break;
54850b57cec5SDimitry Andric             case 2061:
54860b57cec5SDimitry Andric                 result.push_back(L'%');
54870b57cec5SDimitry Andric                 result.push_back(L'Y');
54880b57cec5SDimitry Andric                 break;
54890b57cec5SDimitry Andric             default:
54900b57cec5SDimitry Andric                 for (; w != wbb; ++w)
54910b57cec5SDimitry Andric                     result.push_back(*w);
54920b57cec5SDimitry Andric                 break;
54930b57cec5SDimitry Andric             }
54940b57cec5SDimitry Andric             continue;
54950b57cec5SDimitry Andric         }
54960b57cec5SDimitry Andric         if (ct.narrow(*wbb, 0) == '%')
54970b57cec5SDimitry Andric         {
54980b57cec5SDimitry Andric             result.push_back(L'%');
54990b57cec5SDimitry Andric             result.push_back(L'%');
55000b57cec5SDimitry Andric             ++wbb;
55010b57cec5SDimitry Andric             continue;
55020b57cec5SDimitry Andric         }
55030b57cec5SDimitry Andric         result.push_back(*wbb);
55040b57cec5SDimitry Andric         ++wbb;
55050b57cec5SDimitry Andric     }
55060b57cec5SDimitry Andric     return result;
55070b57cec5SDimitry Andric }
5508349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
55090b57cec5SDimitry Andric 
55100b57cec5SDimitry Andric template <>
55110b57cec5SDimitry Andric void
55120b57cec5SDimitry Andric __time_get_storage<char>::init(const ctype<char>& ct)
55130b57cec5SDimitry Andric {
55140b57cec5SDimitry Andric     tm t = {0};
55150b57cec5SDimitry Andric     char buf[100];
55160b57cec5SDimitry Andric     // __weeks_
55170b57cec5SDimitry Andric     for (int i = 0; i < 7; ++i)
55180b57cec5SDimitry Andric     {
55190b57cec5SDimitry Andric         t.tm_wday = i;
55200b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%A", &t, __loc_);
55210b57cec5SDimitry Andric         __weeks_[i] = buf;
55220b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%a", &t, __loc_);
55230b57cec5SDimitry Andric         __weeks_[i+7] = buf;
55240b57cec5SDimitry Andric     }
55250b57cec5SDimitry Andric     // __months_
55260b57cec5SDimitry Andric     for (int i = 0; i < 12; ++i)
55270b57cec5SDimitry Andric     {
55280b57cec5SDimitry Andric         t.tm_mon = i;
55290b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%B", &t, __loc_);
55300b57cec5SDimitry Andric         __months_[i] = buf;
55310b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%b", &t, __loc_);
55320b57cec5SDimitry Andric         __months_[i+12] = buf;
55330b57cec5SDimitry Andric     }
55340b57cec5SDimitry Andric     // __am_pm_
55350b57cec5SDimitry Andric     t.tm_hour = 1;
55360b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%p", &t, __loc_);
55370b57cec5SDimitry Andric     __am_pm_[0] = buf;
55380b57cec5SDimitry Andric     t.tm_hour = 13;
55390b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%p", &t, __loc_);
55400b57cec5SDimitry Andric     __am_pm_[1] = buf;
55410b57cec5SDimitry Andric     __c_ = __analyze('c', ct);
55420b57cec5SDimitry Andric     __r_ = __analyze('r', ct);
55430b57cec5SDimitry Andric     __x_ = __analyze('x', ct);
55440b57cec5SDimitry Andric     __X_ = __analyze('X', ct);
55450b57cec5SDimitry Andric }
55460b57cec5SDimitry Andric 
5547349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
55480b57cec5SDimitry Andric template <>
55490b57cec5SDimitry Andric void
55500b57cec5SDimitry Andric __time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct)
55510b57cec5SDimitry Andric {
55520b57cec5SDimitry Andric     tm t = {0};
55530b57cec5SDimitry Andric     char buf[100];
55540b57cec5SDimitry Andric     wchar_t wbuf[100];
55550b57cec5SDimitry Andric     wchar_t* wbe;
55560b57cec5SDimitry Andric     mbstate_t mb = {0};
55570b57cec5SDimitry Andric     // __weeks_
55580b57cec5SDimitry Andric     for (int i = 0; i < 7; ++i)
55590b57cec5SDimitry Andric     {
55600b57cec5SDimitry Andric         t.tm_wday = i;
55610b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%A", &t, __loc_);
55620b57cec5SDimitry Andric         mb = mbstate_t();
55630b57cec5SDimitry Andric         const char* bb = buf;
55640b57cec5SDimitry Andric         size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5565e8d8bef9SDimitry Andric         if (j == size_t(-1) || j == 0)
55660b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
55670b57cec5SDimitry Andric         wbe = wbuf + j;
55680b57cec5SDimitry Andric         __weeks_[i].assign(wbuf, wbe);
55690b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%a", &t, __loc_);
55700b57cec5SDimitry Andric         mb = mbstate_t();
55710b57cec5SDimitry Andric         bb = buf;
55720b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5573e8d8bef9SDimitry Andric         if (j == size_t(-1) || j == 0)
55740b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
55750b57cec5SDimitry Andric         wbe = wbuf + j;
55760b57cec5SDimitry Andric         __weeks_[i+7].assign(wbuf, wbe);
55770b57cec5SDimitry Andric     }
55780b57cec5SDimitry Andric     // __months_
55790b57cec5SDimitry Andric     for (int i = 0; i < 12; ++i)
55800b57cec5SDimitry Andric     {
55810b57cec5SDimitry Andric         t.tm_mon = i;
55820b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%B", &t, __loc_);
55830b57cec5SDimitry Andric         mb = mbstate_t();
55840b57cec5SDimitry Andric         const char* bb = buf;
55850b57cec5SDimitry Andric         size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5586e8d8bef9SDimitry Andric         if (j == size_t(-1) || j == 0)
55870b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
55880b57cec5SDimitry Andric         wbe = wbuf + j;
55890b57cec5SDimitry Andric         __months_[i].assign(wbuf, wbe);
55900b57cec5SDimitry Andric         strftime_l(buf, countof(buf), "%b", &t, __loc_);
55910b57cec5SDimitry Andric         mb = mbstate_t();
55920b57cec5SDimitry Andric         bb = buf;
55930b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
5594e8d8bef9SDimitry Andric         if (j == size_t(-1) || j == 0)
55950b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
55960b57cec5SDimitry Andric         wbe = wbuf + j;
55970b57cec5SDimitry Andric         __months_[i+12].assign(wbuf, wbe);
55980b57cec5SDimitry Andric     }
55990b57cec5SDimitry Andric     // __am_pm_
56000b57cec5SDimitry Andric     t.tm_hour = 1;
56010b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%p", &t, __loc_);
56020b57cec5SDimitry Andric     mb = mbstate_t();
56030b57cec5SDimitry Andric     const char* bb = buf;
56040b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
56050b57cec5SDimitry Andric     if (j == size_t(-1))
56060b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
56070b57cec5SDimitry Andric     wbe = wbuf + j;
56080b57cec5SDimitry Andric     __am_pm_[0].assign(wbuf, wbe);
56090b57cec5SDimitry Andric     t.tm_hour = 13;
56100b57cec5SDimitry Andric     strftime_l(buf, countof(buf), "%p", &t, __loc_);
56110b57cec5SDimitry Andric     mb = mbstate_t();
56120b57cec5SDimitry Andric     bb = buf;
56130b57cec5SDimitry Andric     j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
56140b57cec5SDimitry Andric     if (j == size_t(-1))
56150b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
56160b57cec5SDimitry Andric     wbe = wbuf + j;
56170b57cec5SDimitry Andric     __am_pm_[1].assign(wbuf, wbe);
56180b57cec5SDimitry Andric     __c_ = __analyze('c', ct);
56190b57cec5SDimitry Andric     __r_ = __analyze('r', ct);
56200b57cec5SDimitry Andric     __x_ = __analyze('x', ct);
56210b57cec5SDimitry Andric     __X_ = __analyze('X', ct);
56220b57cec5SDimitry Andric }
5623349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
56240b57cec5SDimitry Andric 
56250b57cec5SDimitry Andric template <class CharT>
56260b57cec5SDimitry Andric struct _LIBCPP_HIDDEN __time_get_temp
56270b57cec5SDimitry Andric     : public ctype_byname<CharT>
56280b57cec5SDimitry Andric {
56290b57cec5SDimitry Andric     explicit __time_get_temp(const char* nm)
56300b57cec5SDimitry Andric         : ctype_byname<CharT>(nm, 1) {}
56310b57cec5SDimitry Andric     explicit __time_get_temp(const string& nm)
56320b57cec5SDimitry Andric         : ctype_byname<CharT>(nm, 1) {}
56330b57cec5SDimitry Andric };
56340b57cec5SDimitry Andric 
56350b57cec5SDimitry Andric template <>
56360b57cec5SDimitry Andric __time_get_storage<char>::__time_get_storage(const char* __nm)
56370b57cec5SDimitry Andric     : __time_get(__nm)
56380b57cec5SDimitry Andric {
56390b57cec5SDimitry Andric     const __time_get_temp<char> ct(__nm);
56400b57cec5SDimitry Andric     init(ct);
56410b57cec5SDimitry Andric }
56420b57cec5SDimitry Andric 
56430b57cec5SDimitry Andric template <>
56440b57cec5SDimitry Andric __time_get_storage<char>::__time_get_storage(const string& __nm)
56450b57cec5SDimitry Andric     : __time_get(__nm)
56460b57cec5SDimitry Andric {
56470b57cec5SDimitry Andric     const __time_get_temp<char> ct(__nm);
56480b57cec5SDimitry Andric     init(ct);
56490b57cec5SDimitry Andric }
56500b57cec5SDimitry Andric 
5651349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
56520b57cec5SDimitry Andric template <>
56530b57cec5SDimitry Andric __time_get_storage<wchar_t>::__time_get_storage(const char* __nm)
56540b57cec5SDimitry Andric     : __time_get(__nm)
56550b57cec5SDimitry Andric {
56560b57cec5SDimitry Andric     const __time_get_temp<wchar_t> ct(__nm);
56570b57cec5SDimitry Andric     init(ct);
56580b57cec5SDimitry Andric }
56590b57cec5SDimitry Andric 
56600b57cec5SDimitry Andric template <>
56610b57cec5SDimitry Andric __time_get_storage<wchar_t>::__time_get_storage(const string& __nm)
56620b57cec5SDimitry Andric     : __time_get(__nm)
56630b57cec5SDimitry Andric {
56640b57cec5SDimitry Andric     const __time_get_temp<wchar_t> ct(__nm);
56650b57cec5SDimitry Andric     init(ct);
56660b57cec5SDimitry Andric }
5667349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
56680b57cec5SDimitry Andric 
56690b57cec5SDimitry Andric template <>
56700b57cec5SDimitry Andric time_base::dateorder
56710b57cec5SDimitry Andric __time_get_storage<char>::__do_date_order() const
56720b57cec5SDimitry Andric {
56730b57cec5SDimitry Andric     unsigned i;
56740b57cec5SDimitry Andric     for (i = 0; i < __x_.size(); ++i)
56750b57cec5SDimitry Andric         if (__x_[i] == '%')
56760b57cec5SDimitry Andric             break;
56770b57cec5SDimitry Andric     ++i;
56780b57cec5SDimitry Andric     switch (__x_[i])
56790b57cec5SDimitry Andric     {
56800b57cec5SDimitry Andric     case 'y':
56810b57cec5SDimitry Andric     case 'Y':
56820b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
56830b57cec5SDimitry Andric             if (__x_[i] == '%')
56840b57cec5SDimitry Andric                 break;
56850b57cec5SDimitry Andric         if (i == __x_.size())
56860b57cec5SDimitry Andric             break;
56870b57cec5SDimitry Andric         ++i;
56880b57cec5SDimitry Andric         switch (__x_[i])
56890b57cec5SDimitry Andric         {
56900b57cec5SDimitry Andric         case 'm':
56910b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
56920b57cec5SDimitry Andric                 if (__x_[i] == '%')
56930b57cec5SDimitry Andric                     break;
56940b57cec5SDimitry Andric             if (i == __x_.size())
56950b57cec5SDimitry Andric                 break;
56960b57cec5SDimitry Andric             ++i;
56970b57cec5SDimitry Andric             if (__x_[i] == 'd')
56980b57cec5SDimitry Andric                 return time_base::ymd;
56990b57cec5SDimitry Andric             break;
57000b57cec5SDimitry Andric         case 'd':
57010b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57020b57cec5SDimitry Andric                 if (__x_[i] == '%')
57030b57cec5SDimitry Andric                     break;
57040b57cec5SDimitry Andric             if (i == __x_.size())
57050b57cec5SDimitry Andric                 break;
57060b57cec5SDimitry Andric             ++i;
57070b57cec5SDimitry Andric             if (__x_[i] == 'm')
57080b57cec5SDimitry Andric                 return time_base::ydm;
57090b57cec5SDimitry Andric             break;
57100b57cec5SDimitry Andric         }
57110b57cec5SDimitry Andric         break;
57120b57cec5SDimitry Andric     case 'm':
57130b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
57140b57cec5SDimitry Andric             if (__x_[i] == '%')
57150b57cec5SDimitry Andric                 break;
57160b57cec5SDimitry Andric         if (i == __x_.size())
57170b57cec5SDimitry Andric             break;
57180b57cec5SDimitry Andric         ++i;
57190b57cec5SDimitry Andric         if (__x_[i] == 'd')
57200b57cec5SDimitry Andric         {
57210b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57220b57cec5SDimitry Andric                 if (__x_[i] == '%')
57230b57cec5SDimitry Andric                     break;
57240b57cec5SDimitry Andric             if (i == __x_.size())
57250b57cec5SDimitry Andric                 break;
57260b57cec5SDimitry Andric             ++i;
57270b57cec5SDimitry Andric             if (__x_[i] == 'y' || __x_[i] == 'Y')
57280b57cec5SDimitry Andric                 return time_base::mdy;
57290b57cec5SDimitry Andric             break;
57300b57cec5SDimitry Andric         }
57310b57cec5SDimitry Andric         break;
57320b57cec5SDimitry Andric     case 'd':
57330b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
57340b57cec5SDimitry Andric             if (__x_[i] == '%')
57350b57cec5SDimitry Andric                 break;
57360b57cec5SDimitry Andric         if (i == __x_.size())
57370b57cec5SDimitry Andric             break;
57380b57cec5SDimitry Andric         ++i;
57390b57cec5SDimitry Andric         if (__x_[i] == 'm')
57400b57cec5SDimitry Andric         {
57410b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57420b57cec5SDimitry Andric                 if (__x_[i] == '%')
57430b57cec5SDimitry Andric                     break;
57440b57cec5SDimitry Andric             if (i == __x_.size())
57450b57cec5SDimitry Andric                 break;
57460b57cec5SDimitry Andric             ++i;
57470b57cec5SDimitry Andric             if (__x_[i] == 'y' || __x_[i] == 'Y')
57480b57cec5SDimitry Andric                 return time_base::dmy;
57490b57cec5SDimitry Andric             break;
57500b57cec5SDimitry Andric         }
57510b57cec5SDimitry Andric         break;
57520b57cec5SDimitry Andric     }
57530b57cec5SDimitry Andric     return time_base::no_order;
57540b57cec5SDimitry Andric }
57550b57cec5SDimitry Andric 
5756349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
57570b57cec5SDimitry Andric template <>
57580b57cec5SDimitry Andric time_base::dateorder
57590b57cec5SDimitry Andric __time_get_storage<wchar_t>::__do_date_order() const
57600b57cec5SDimitry Andric {
57610b57cec5SDimitry Andric     unsigned i;
57620b57cec5SDimitry Andric     for (i = 0; i < __x_.size(); ++i)
57630b57cec5SDimitry Andric         if (__x_[i] == L'%')
57640b57cec5SDimitry Andric             break;
57650b57cec5SDimitry Andric     ++i;
57660b57cec5SDimitry Andric     switch (__x_[i])
57670b57cec5SDimitry Andric     {
57680b57cec5SDimitry Andric     case L'y':
57690b57cec5SDimitry Andric     case L'Y':
57700b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
57710b57cec5SDimitry Andric             if (__x_[i] == L'%')
57720b57cec5SDimitry Andric                 break;
57730b57cec5SDimitry Andric         if (i == __x_.size())
57740b57cec5SDimitry Andric             break;
57750b57cec5SDimitry Andric         ++i;
57760b57cec5SDimitry Andric         switch (__x_[i])
57770b57cec5SDimitry Andric         {
57780b57cec5SDimitry Andric         case L'm':
57790b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57800b57cec5SDimitry Andric                 if (__x_[i] == L'%')
57810b57cec5SDimitry Andric                     break;
57820b57cec5SDimitry Andric             if (i == __x_.size())
57830b57cec5SDimitry Andric                 break;
57840b57cec5SDimitry Andric             ++i;
57850b57cec5SDimitry Andric             if (__x_[i] == L'd')
57860b57cec5SDimitry Andric                 return time_base::ymd;
57870b57cec5SDimitry Andric             break;
57880b57cec5SDimitry Andric         case L'd':
57890b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
57900b57cec5SDimitry Andric                 if (__x_[i] == L'%')
57910b57cec5SDimitry Andric                     break;
57920b57cec5SDimitry Andric             if (i == __x_.size())
57930b57cec5SDimitry Andric                 break;
57940b57cec5SDimitry Andric             ++i;
57950b57cec5SDimitry Andric             if (__x_[i] == L'm')
57960b57cec5SDimitry Andric                 return time_base::ydm;
57970b57cec5SDimitry Andric             break;
57980b57cec5SDimitry Andric         }
57990b57cec5SDimitry Andric         break;
58000b57cec5SDimitry Andric     case L'm':
58010b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
58020b57cec5SDimitry Andric             if (__x_[i] == L'%')
58030b57cec5SDimitry Andric                 break;
58040b57cec5SDimitry Andric         if (i == __x_.size())
58050b57cec5SDimitry Andric             break;
58060b57cec5SDimitry Andric         ++i;
58070b57cec5SDimitry Andric         if (__x_[i] == L'd')
58080b57cec5SDimitry Andric         {
58090b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
58100b57cec5SDimitry Andric                 if (__x_[i] == L'%')
58110b57cec5SDimitry Andric                     break;
58120b57cec5SDimitry Andric             if (i == __x_.size())
58130b57cec5SDimitry Andric                 break;
58140b57cec5SDimitry Andric             ++i;
58150b57cec5SDimitry Andric             if (__x_[i] == L'y' || __x_[i] == L'Y')
58160b57cec5SDimitry Andric                 return time_base::mdy;
58170b57cec5SDimitry Andric             break;
58180b57cec5SDimitry Andric         }
58190b57cec5SDimitry Andric         break;
58200b57cec5SDimitry Andric     case L'd':
58210b57cec5SDimitry Andric         for (++i; i < __x_.size(); ++i)
58220b57cec5SDimitry Andric             if (__x_[i] == L'%')
58230b57cec5SDimitry Andric                 break;
58240b57cec5SDimitry Andric         if (i == __x_.size())
58250b57cec5SDimitry Andric             break;
58260b57cec5SDimitry Andric         ++i;
58270b57cec5SDimitry Andric         if (__x_[i] == L'm')
58280b57cec5SDimitry Andric         {
58290b57cec5SDimitry Andric             for (++i; i < __x_.size(); ++i)
58300b57cec5SDimitry Andric                 if (__x_[i] == L'%')
58310b57cec5SDimitry Andric                     break;
58320b57cec5SDimitry Andric             if (i == __x_.size())
58330b57cec5SDimitry Andric                 break;
58340b57cec5SDimitry Andric             ++i;
58350b57cec5SDimitry Andric             if (__x_[i] == L'y' || __x_[i] == L'Y')
58360b57cec5SDimitry Andric                 return time_base::dmy;
58370b57cec5SDimitry Andric             break;
58380b57cec5SDimitry Andric         }
58390b57cec5SDimitry Andric         break;
58400b57cec5SDimitry Andric     }
58410b57cec5SDimitry Andric     return time_base::no_order;
58420b57cec5SDimitry Andric }
5843349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
58440b57cec5SDimitry Andric 
58450b57cec5SDimitry Andric // time_put
58460b57cec5SDimitry Andric 
58470b57cec5SDimitry Andric __time_put::__time_put(const char* nm)
58480b57cec5SDimitry Andric     : __loc_(newlocale(LC_ALL_MASK, nm, 0))
58490b57cec5SDimitry Andric {
58500b57cec5SDimitry Andric     if (__loc_ == 0)
58510b57cec5SDimitry Andric         __throw_runtime_error("time_put_byname"
58520b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
58530b57cec5SDimitry Andric }
58540b57cec5SDimitry Andric 
58550b57cec5SDimitry Andric __time_put::__time_put(const string& nm)
58560b57cec5SDimitry Andric     : __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0))
58570b57cec5SDimitry Andric {
58580b57cec5SDimitry Andric     if (__loc_ == 0)
58590b57cec5SDimitry Andric         __throw_runtime_error("time_put_byname"
58600b57cec5SDimitry Andric                             " failed to construct for " + nm);
58610b57cec5SDimitry Andric }
58620b57cec5SDimitry Andric 
58630b57cec5SDimitry Andric __time_put::~__time_put()
58640b57cec5SDimitry Andric {
58650b57cec5SDimitry Andric     if (__loc_ != _LIBCPP_GET_C_LOCALE)
58660b57cec5SDimitry Andric         freelocale(__loc_);
58670b57cec5SDimitry Andric }
58680b57cec5SDimitry Andric 
58690b57cec5SDimitry Andric void
58700b57cec5SDimitry Andric __time_put::__do_put(char* __nb, char*& __ne, const tm* __tm,
58710b57cec5SDimitry Andric                      char __fmt, char __mod) const
58720b57cec5SDimitry Andric {
58730b57cec5SDimitry Andric     char fmt[] = {'%', __fmt, __mod, 0};
58740b57cec5SDimitry Andric     if (__mod != 0)
58750b57cec5SDimitry Andric         swap(fmt[1], fmt[2]);
58760b57cec5SDimitry Andric     size_t n = strftime_l(__nb, countof(__nb, __ne), fmt, __tm, __loc_);
58770b57cec5SDimitry Andric     __ne = __nb + n;
58780b57cec5SDimitry Andric }
58790b57cec5SDimitry Andric 
5880349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
58810b57cec5SDimitry Andric void
58820b57cec5SDimitry Andric __time_put::__do_put(wchar_t* __wb, wchar_t*& __we, const tm* __tm,
58830b57cec5SDimitry Andric                      char __fmt, char __mod) const
58840b57cec5SDimitry Andric {
58850b57cec5SDimitry Andric     char __nar[100];
58860b57cec5SDimitry Andric     char* __ne = __nar + 100;
58870b57cec5SDimitry Andric     __do_put(__nar, __ne, __tm, __fmt, __mod);
58880b57cec5SDimitry Andric     mbstate_t mb = {0};
58890b57cec5SDimitry Andric     const char* __nb = __nar;
58900b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l(__wb, &__nb, countof(__wb, __we), &mb, __loc_);
58910b57cec5SDimitry Andric     if (j == size_t(-1))
58920b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
58930b57cec5SDimitry Andric     __we = __wb + j;
58940b57cec5SDimitry Andric }
5895349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
58960b57cec5SDimitry Andric 
58970b57cec5SDimitry Andric // moneypunct_byname
58980b57cec5SDimitry Andric 
58990b57cec5SDimitry Andric template <class charT>
59000b57cec5SDimitry Andric static
59010b57cec5SDimitry Andric void
59020b57cec5SDimitry Andric __init_pat(money_base::pattern& pat, basic_string<charT>& __curr_symbol_,
59030b57cec5SDimitry Andric            bool intl, char cs_precedes, char sep_by_space, char sign_posn,
59040b57cec5SDimitry Andric            charT space_char)
59050b57cec5SDimitry Andric {
59060b57cec5SDimitry Andric     const char sign = static_cast<char>(money_base::sign);
59070b57cec5SDimitry Andric     const char space = static_cast<char>(money_base::space);
59080b57cec5SDimitry Andric     const char none = static_cast<char>(money_base::none);
59090b57cec5SDimitry Andric     const char symbol = static_cast<char>(money_base::symbol);
59100b57cec5SDimitry Andric     const char value = static_cast<char>(money_base::value);
59110b57cec5SDimitry Andric     const bool symbol_contains_sep = intl && __curr_symbol_.size() == 4;
59120b57cec5SDimitry Andric 
59130b57cec5SDimitry Andric     // Comments on case branches reflect 'C11 7.11.2.1 The localeconv
59140b57cec5SDimitry Andric     // function'. "Space between sign and symbol or value" means that
59150b57cec5SDimitry Andric     // if the sign is adjacent to the symbol, there's a space between
59160b57cec5SDimitry Andric     // them, and otherwise there's a space between the sign and value.
59170b57cec5SDimitry Andric     //
59180b57cec5SDimitry Andric     // C11's localeconv specifies that the fourth character of an
59190b57cec5SDimitry Andric     // international curr_symbol is used to separate the sign and
59200b57cec5SDimitry Andric     // value when sep_by_space says to do so. C++ can't represent
59210b57cec5SDimitry Andric     // that, so we just use a space.  When sep_by_space says to
59220b57cec5SDimitry Andric     // separate the symbol and value-or-sign with a space, we rearrange the
59230b57cec5SDimitry Andric     // curr_symbol to put its spacing character on the correct side of
59240b57cec5SDimitry Andric     // the symbol.
59250b57cec5SDimitry Andric     //
59260b57cec5SDimitry Andric     // We also need to avoid adding an extra space between the sign
59270b57cec5SDimitry Andric     // and value when the currency symbol is suppressed (by not
59280b57cec5SDimitry Andric     // setting showbase).  We match glibc's strfmon by interpreting
59290b57cec5SDimitry Andric     // sep_by_space==1 as "omit the space when the currency symbol is
59300b57cec5SDimitry Andric     // absent".
59310b57cec5SDimitry Andric     //
59320b57cec5SDimitry Andric     // Users who want to get this right should use ICU instead.
59330b57cec5SDimitry Andric 
59340b57cec5SDimitry Andric     switch (cs_precedes)
59350b57cec5SDimitry Andric     {
59360b57cec5SDimitry Andric     case 0:  // value before curr_symbol
59370b57cec5SDimitry Andric         if (symbol_contains_sep) {
59380b57cec5SDimitry Andric             // Move the separator to before the symbol, to place it
59390b57cec5SDimitry Andric             // between the value and symbol.
59400b57cec5SDimitry Andric             rotate(__curr_symbol_.begin(), __curr_symbol_.begin() + 3,
59410b57cec5SDimitry Andric                    __curr_symbol_.end());
59420b57cec5SDimitry Andric         }
59430b57cec5SDimitry Andric         switch (sign_posn)
59440b57cec5SDimitry Andric         {
59450b57cec5SDimitry Andric         case 0:  // Parentheses surround the quantity and currency symbol.
59460b57cec5SDimitry Andric             pat.field[0] = sign;
59470b57cec5SDimitry Andric             pat.field[1] = value;
59480b57cec5SDimitry Andric             pat.field[2] = none;  // Any space appears in the symbol.
59490b57cec5SDimitry Andric             pat.field[3] = symbol;
59500b57cec5SDimitry Andric             switch (sep_by_space)
59510b57cec5SDimitry Andric             {
59520b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
59530b57cec5SDimitry Andric                 // This case may have changed between C99 and C11;
59540b57cec5SDimitry Andric                 // assume the currency symbol matches the intention.
59550b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
59560b57cec5SDimitry Andric                 // The "sign" is two parentheses, so no space here either.
59570b57cec5SDimitry Andric                 return;
59580b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
59590b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
59600b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
59610b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
59620b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
59630b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
59640b57cec5SDimitry Andric                 }
59650b57cec5SDimitry Andric                 return;
59660b57cec5SDimitry Andric             default:
59670b57cec5SDimitry Andric                 break;
59680b57cec5SDimitry Andric             }
59690b57cec5SDimitry Andric             break;
59700b57cec5SDimitry Andric         case 1:  // The sign string precedes the quantity and currency symbol.
59710b57cec5SDimitry Andric             pat.field[0] = sign;
59720b57cec5SDimitry Andric             pat.field[3] = symbol;
59730b57cec5SDimitry Andric             switch (sep_by_space)
59740b57cec5SDimitry Andric             {
59750b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
59760b57cec5SDimitry Andric                 pat.field[1] = value;
59770b57cec5SDimitry Andric                 pat.field[2] = none;
59780b57cec5SDimitry Andric                 return;
59790b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
59800b57cec5SDimitry Andric                 pat.field[1] = value;
59810b57cec5SDimitry Andric                 pat.field[2] = none;
59820b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
59830b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
59840b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
59850b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
59860b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
59870b57cec5SDimitry Andric                 }
59880b57cec5SDimitry Andric                 return;
59890b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
59900b57cec5SDimitry Andric                 pat.field[1] = space;
59910b57cec5SDimitry Andric                 pat.field[2] = value;
59920b57cec5SDimitry Andric                 if (symbol_contains_sep) {
59930b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
59940b57cec5SDimitry Andric                     // has already appeared after the sign.
59950b57cec5SDimitry Andric                     __curr_symbol_.erase(__curr_symbol_.begin());
59960b57cec5SDimitry Andric                 }
59970b57cec5SDimitry Andric                 return;
59980b57cec5SDimitry Andric             default:
59990b57cec5SDimitry Andric                 break;
60000b57cec5SDimitry Andric             }
60010b57cec5SDimitry Andric             break;
60020b57cec5SDimitry Andric         case 2:  // The sign string succeeds the quantity and currency symbol.
60030b57cec5SDimitry Andric             pat.field[0] = value;
60040b57cec5SDimitry Andric             pat.field[3] = sign;
60050b57cec5SDimitry Andric             switch (sep_by_space)
60060b57cec5SDimitry Andric             {
60070b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
60080b57cec5SDimitry Andric                 pat.field[1] = none;
60090b57cec5SDimitry Andric                 pat.field[2] = symbol;
60100b57cec5SDimitry Andric                 return;
60110b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
60120b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
60130b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
60140b57cec5SDimitry Andric                     // setting pat.field[1]=space so that when
60150b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
60160b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
60170b57cec5SDimitry Andric                 }
60180b57cec5SDimitry Andric                 pat.field[1] = none;
60190b57cec5SDimitry Andric                 pat.field[2] = symbol;
60200b57cec5SDimitry Andric                 return;
60210b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
60220b57cec5SDimitry Andric                 pat.field[1] = symbol;
60230b57cec5SDimitry Andric                 pat.field[2] = space;
60240b57cec5SDimitry Andric                 if (symbol_contains_sep) {
60250b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
60260b57cec5SDimitry Andric                     // should not be removed if showbase is absent.
60270b57cec5SDimitry Andric                     __curr_symbol_.erase(__curr_symbol_.begin());
60280b57cec5SDimitry Andric                 }
60290b57cec5SDimitry Andric                 return;
60300b57cec5SDimitry Andric             default:
60310b57cec5SDimitry Andric                 break;
60320b57cec5SDimitry Andric             }
60330b57cec5SDimitry Andric             break;
60340b57cec5SDimitry Andric         case 3:  // The sign string immediately precedes the currency symbol.
60350b57cec5SDimitry Andric             pat.field[0] = value;
60360b57cec5SDimitry Andric             pat.field[3] = symbol;
60370b57cec5SDimitry Andric             switch (sep_by_space)
60380b57cec5SDimitry Andric             {
60390b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
60400b57cec5SDimitry Andric                 pat.field[1] = none;
60410b57cec5SDimitry Andric                 pat.field[2] = sign;
60420b57cec5SDimitry Andric                 return;
60430b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
60440b57cec5SDimitry Andric                 pat.field[1] = space;
60450b57cec5SDimitry Andric                 pat.field[2] = sign;
60460b57cec5SDimitry Andric                 if (symbol_contains_sep) {
60470b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
60480b57cec5SDimitry Andric                     // has already appeared before the sign.
60490b57cec5SDimitry Andric                     __curr_symbol_.erase(__curr_symbol_.begin());
60500b57cec5SDimitry Andric                 }
60510b57cec5SDimitry Andric                 return;
60520b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
60530b57cec5SDimitry Andric                 pat.field[1] = sign;
60540b57cec5SDimitry Andric                 pat.field[2] = none;
60550b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
60560b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
60570b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
60580b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
60590b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
60600b57cec5SDimitry Andric                 }
60610b57cec5SDimitry Andric                 return;
60620b57cec5SDimitry Andric             default:
60630b57cec5SDimitry Andric                 break;
60640b57cec5SDimitry Andric             }
60650b57cec5SDimitry Andric             break;
60660b57cec5SDimitry Andric         case 4:  // The sign string immediately succeeds the currency symbol.
60670b57cec5SDimitry Andric             pat.field[0] = value;
60680b57cec5SDimitry Andric             pat.field[3] = sign;
60690b57cec5SDimitry Andric             switch (sep_by_space)
60700b57cec5SDimitry Andric             {
60710b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
60720b57cec5SDimitry Andric                 pat.field[1] = none;
60730b57cec5SDimitry Andric                 pat.field[2] = symbol;
60740b57cec5SDimitry Andric                 return;
60750b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
60760b57cec5SDimitry Andric                 pat.field[1] = none;
60770b57cec5SDimitry Andric                 pat.field[2] = symbol;
60780b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
60790b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
60800b57cec5SDimitry Andric                     // setting pat.field[1]=space so that when
60810b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
60820b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
60830b57cec5SDimitry Andric                 }
60840b57cec5SDimitry Andric                 return;
60850b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
60860b57cec5SDimitry Andric                 pat.field[1] = symbol;
60870b57cec5SDimitry Andric                 pat.field[2] = space;
60880b57cec5SDimitry Andric                 if (symbol_contains_sep) {
60890b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
60900b57cec5SDimitry Andric                     // should not disappear when showbase is absent.
60910b57cec5SDimitry Andric                     __curr_symbol_.erase(__curr_symbol_.begin());
60920b57cec5SDimitry Andric                 }
60930b57cec5SDimitry Andric                 return;
60940b57cec5SDimitry Andric             default:
60950b57cec5SDimitry Andric                 break;
60960b57cec5SDimitry Andric             }
60970b57cec5SDimitry Andric             break;
60980b57cec5SDimitry Andric         default:
60990b57cec5SDimitry Andric             break;
61000b57cec5SDimitry Andric         }
61010b57cec5SDimitry Andric         break;
61020b57cec5SDimitry Andric     case 1:  // curr_symbol before value
61030b57cec5SDimitry Andric         switch (sign_posn)
61040b57cec5SDimitry Andric         {
61050b57cec5SDimitry Andric         case 0:  // Parentheses surround the quantity and currency symbol.
61060b57cec5SDimitry Andric             pat.field[0] = sign;
61070b57cec5SDimitry Andric             pat.field[1] = symbol;
61080b57cec5SDimitry Andric             pat.field[2] = none;  // Any space appears in the symbol.
61090b57cec5SDimitry Andric             pat.field[3] = value;
61100b57cec5SDimitry Andric             switch (sep_by_space)
61110b57cec5SDimitry Andric             {
61120b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
61130b57cec5SDimitry Andric                 // This case may have changed between C99 and C11;
61140b57cec5SDimitry Andric                 // assume the currency symbol matches the intention.
61150b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
61160b57cec5SDimitry Andric                 // The "sign" is two parentheses, so no space here either.
61170b57cec5SDimitry Andric                 return;
61180b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
61190b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
61200b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
61210b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
61220b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
61230b57cec5SDimitry Andric                     __curr_symbol_.insert(0, 1, space_char);
61240b57cec5SDimitry Andric                 }
61250b57cec5SDimitry Andric                 return;
61260b57cec5SDimitry Andric             default:
61270b57cec5SDimitry Andric                 break;
61280b57cec5SDimitry Andric             }
61290b57cec5SDimitry Andric             break;
61300b57cec5SDimitry Andric         case 1:  // The sign string precedes the quantity and currency symbol.
61310b57cec5SDimitry Andric             pat.field[0] = sign;
61320b57cec5SDimitry Andric             pat.field[3] = value;
61330b57cec5SDimitry Andric             switch (sep_by_space)
61340b57cec5SDimitry Andric             {
61350b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
61360b57cec5SDimitry Andric                 pat.field[1] = symbol;
61370b57cec5SDimitry Andric                 pat.field[2] = none;
61380b57cec5SDimitry Andric                 return;
61390b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
61400b57cec5SDimitry Andric                 pat.field[1] = symbol;
61410b57cec5SDimitry Andric                 pat.field[2] = none;
61420b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
61430b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
61440b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
61450b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
61460b57cec5SDimitry Andric                     __curr_symbol_.push_back(space_char);
61470b57cec5SDimitry Andric                 }
61480b57cec5SDimitry Andric                 return;
61490b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
61500b57cec5SDimitry Andric                 pat.field[1] = space;
61510b57cec5SDimitry Andric                 pat.field[2] = symbol;
61520b57cec5SDimitry Andric                 if (symbol_contains_sep) {
61530b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
61540b57cec5SDimitry Andric                     // has already appeared after the sign.
61550b57cec5SDimitry Andric                     __curr_symbol_.pop_back();
61560b57cec5SDimitry Andric                 }
61570b57cec5SDimitry Andric                 return;
61580b57cec5SDimitry Andric             default:
61590b57cec5SDimitry Andric                 break;
61600b57cec5SDimitry Andric             }
61610b57cec5SDimitry Andric             break;
61620b57cec5SDimitry Andric         case 2:  // The sign string succeeds the quantity and currency symbol.
61630b57cec5SDimitry Andric             pat.field[0] = symbol;
61640b57cec5SDimitry Andric             pat.field[3] = sign;
61650b57cec5SDimitry Andric             switch (sep_by_space)
61660b57cec5SDimitry Andric             {
61670b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
61680b57cec5SDimitry Andric                 pat.field[1] = none;
61690b57cec5SDimitry Andric                 pat.field[2] = value;
61700b57cec5SDimitry Andric                 return;
61710b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
61720b57cec5SDimitry Andric                 pat.field[1] = none;
61730b57cec5SDimitry Andric                 pat.field[2] = value;
61740b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
61750b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
61760b57cec5SDimitry Andric                     // setting pat.field[1]=space so that when
61770b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
61780b57cec5SDimitry Andric                     __curr_symbol_.push_back(space_char);
61790b57cec5SDimitry Andric                 }
61800b57cec5SDimitry Andric                 return;
61810b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
61820b57cec5SDimitry Andric                 pat.field[1] = value;
61830b57cec5SDimitry Andric                 pat.field[2] = space;
61840b57cec5SDimitry Andric                 if (symbol_contains_sep) {
61850b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
61860b57cec5SDimitry Andric                     // will appear before the sign.
61870b57cec5SDimitry Andric                     __curr_symbol_.pop_back();
61880b57cec5SDimitry Andric                 }
61890b57cec5SDimitry Andric                 return;
61900b57cec5SDimitry Andric             default:
61910b57cec5SDimitry Andric                 break;
61920b57cec5SDimitry Andric             }
61930b57cec5SDimitry Andric             break;
61940b57cec5SDimitry Andric         case 3:  // The sign string immediately precedes the currency symbol.
61950b57cec5SDimitry Andric             pat.field[0] = sign;
61960b57cec5SDimitry Andric             pat.field[3] = value;
61970b57cec5SDimitry Andric             switch (sep_by_space)
61980b57cec5SDimitry Andric             {
61990b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
62000b57cec5SDimitry Andric                 pat.field[1] = symbol;
62010b57cec5SDimitry Andric                 pat.field[2] = none;
62020b57cec5SDimitry Andric                 return;
62030b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
62040b57cec5SDimitry Andric                 pat.field[1] = symbol;
62050b57cec5SDimitry Andric                 pat.field[2] = none;
62060b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
62070b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
62080b57cec5SDimitry Andric                     // setting pat.field[2]=space so that when
62090b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
62100b57cec5SDimitry Andric                     __curr_symbol_.push_back(space_char);
62110b57cec5SDimitry Andric                 }
62120b57cec5SDimitry Andric                 return;
62130b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
62140b57cec5SDimitry Andric                 pat.field[1] = space;
62150b57cec5SDimitry Andric                 pat.field[2] = symbol;
62160b57cec5SDimitry Andric                 if (symbol_contains_sep) {
62170b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
62180b57cec5SDimitry Andric                     // has already appeared after the sign.
62190b57cec5SDimitry Andric                     __curr_symbol_.pop_back();
62200b57cec5SDimitry Andric                 }
62210b57cec5SDimitry Andric                 return;
62220b57cec5SDimitry Andric             default:
62230b57cec5SDimitry Andric                 break;
62240b57cec5SDimitry Andric             }
62250b57cec5SDimitry Andric             break;
62260b57cec5SDimitry Andric         case 4:  // The sign string immediately succeeds the currency symbol.
62270b57cec5SDimitry Andric             pat.field[0] = symbol;
62280b57cec5SDimitry Andric             pat.field[3] = value;
62290b57cec5SDimitry Andric             switch (sep_by_space)
62300b57cec5SDimitry Andric             {
62310b57cec5SDimitry Andric             case 0:  // No space separates the currency symbol and value.
62320b57cec5SDimitry Andric                 pat.field[1] = sign;
62330b57cec5SDimitry Andric                 pat.field[2] = none;
62340b57cec5SDimitry Andric                 return;
62350b57cec5SDimitry Andric             case 1:  // Space between currency-and-sign or currency and value.
62360b57cec5SDimitry Andric                 pat.field[1] = sign;
62370b57cec5SDimitry Andric                 pat.field[2] = space;
62380b57cec5SDimitry Andric                 if (symbol_contains_sep) {
62390b57cec5SDimitry Andric                     // Remove the separator from the symbol, since it
62400b57cec5SDimitry Andric                     // should not disappear when showbase is absent.
62410b57cec5SDimitry Andric                     __curr_symbol_.pop_back();
62420b57cec5SDimitry Andric                 }
62430b57cec5SDimitry Andric                 return;
62440b57cec5SDimitry Andric             case 2:  // Space between sign and currency or value.
62450b57cec5SDimitry Andric                 pat.field[1] = none;
62460b57cec5SDimitry Andric                 pat.field[2] = sign;
62470b57cec5SDimitry Andric                 if (!symbol_contains_sep) {
62480b57cec5SDimitry Andric                     // We insert the space into the symbol instead of
62490b57cec5SDimitry Andric                     // setting pat.field[1]=space so that when
62500b57cec5SDimitry Andric                     // showbase is not set, the space goes away too.
62510b57cec5SDimitry Andric                     __curr_symbol_.push_back(space_char);
62520b57cec5SDimitry Andric                 }
62530b57cec5SDimitry Andric                 return;
62540b57cec5SDimitry Andric            default:
62550b57cec5SDimitry Andric                 break;
62560b57cec5SDimitry Andric             }
62570b57cec5SDimitry Andric             break;
62580b57cec5SDimitry Andric         default:
62590b57cec5SDimitry Andric             break;
62600b57cec5SDimitry Andric         }
62610b57cec5SDimitry Andric         break;
62620b57cec5SDimitry Andric     default:
62630b57cec5SDimitry Andric         break;
62640b57cec5SDimitry Andric     }
62650b57cec5SDimitry Andric     pat.field[0] = symbol;
62660b57cec5SDimitry Andric     pat.field[1] = sign;
62670b57cec5SDimitry Andric     pat.field[2] = none;
62680b57cec5SDimitry Andric     pat.field[3] = value;
62690b57cec5SDimitry Andric }
62700b57cec5SDimitry Andric 
62710b57cec5SDimitry Andric template<>
62720b57cec5SDimitry Andric void
62730b57cec5SDimitry Andric moneypunct_byname<char, false>::init(const char* nm)
62740b57cec5SDimitry Andric {
62750b57cec5SDimitry Andric     typedef moneypunct<char, false> base;
62760b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
62770b57cec5SDimitry Andric     if (!loc)
62780b57cec5SDimitry Andric         __throw_runtime_error("moneypunct_byname"
62790b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
62800b57cec5SDimitry Andric 
62810b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
62820b57cec5SDimitry Andric     if (!checked_string_to_char_convert(__decimal_point_,
62830b57cec5SDimitry Andric                                         lc->mon_decimal_point,
62840b57cec5SDimitry Andric                                         loc.get()))
62850b57cec5SDimitry Andric       __decimal_point_ = base::do_decimal_point();
62860b57cec5SDimitry Andric     if (!checked_string_to_char_convert(__thousands_sep_,
62870b57cec5SDimitry Andric                                         lc->mon_thousands_sep,
62880b57cec5SDimitry Andric                                         loc.get()))
62890b57cec5SDimitry Andric       __thousands_sep_ = base::do_thousands_sep();
62900b57cec5SDimitry Andric 
62910b57cec5SDimitry Andric     __grouping_ = lc->mon_grouping;
62920b57cec5SDimitry Andric     __curr_symbol_ = lc->currency_symbol;
62930b57cec5SDimitry Andric     if (lc->frac_digits != CHAR_MAX)
62940b57cec5SDimitry Andric         __frac_digits_ = lc->frac_digits;
62950b57cec5SDimitry Andric     else
62960b57cec5SDimitry Andric         __frac_digits_ = base::do_frac_digits();
62970b57cec5SDimitry Andric     if (lc->p_sign_posn == 0)
62980b57cec5SDimitry Andric         __positive_sign_ = "()";
62990b57cec5SDimitry Andric     else
63000b57cec5SDimitry Andric         __positive_sign_ = lc->positive_sign;
63010b57cec5SDimitry Andric     if (lc->n_sign_posn == 0)
63020b57cec5SDimitry Andric         __negative_sign_ = "()";
63030b57cec5SDimitry Andric     else
63040b57cec5SDimitry Andric         __negative_sign_ = lc->negative_sign;
63050b57cec5SDimitry Andric     // Assume the positive and negative formats will want spaces in
63060b57cec5SDimitry Andric     // the same places in curr_symbol since there's no way to
63070b57cec5SDimitry Andric     // represent anything else.
63080b57cec5SDimitry Andric     string_type __dummy_curr_symbol = __curr_symbol_;
63090b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, false,
63100b57cec5SDimitry Andric                lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, ' ');
63110b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, false,
63120b57cec5SDimitry Andric                lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, ' ');
63130b57cec5SDimitry Andric }
63140b57cec5SDimitry Andric 
63150b57cec5SDimitry Andric template<>
63160b57cec5SDimitry Andric void
63170b57cec5SDimitry Andric moneypunct_byname<char, true>::init(const char* nm)
63180b57cec5SDimitry Andric {
63190b57cec5SDimitry Andric     typedef moneypunct<char, true> base;
63200b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
63210b57cec5SDimitry Andric     if (!loc)
63220b57cec5SDimitry Andric         __throw_runtime_error("moneypunct_byname"
63230b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
63240b57cec5SDimitry Andric 
63250b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
63260b57cec5SDimitry Andric     if (!checked_string_to_char_convert(__decimal_point_,
63270b57cec5SDimitry Andric                                         lc->mon_decimal_point,
63280b57cec5SDimitry Andric                                         loc.get()))
63290b57cec5SDimitry Andric       __decimal_point_ = base::do_decimal_point();
63300b57cec5SDimitry Andric     if (!checked_string_to_char_convert(__thousands_sep_,
63310b57cec5SDimitry Andric                                         lc->mon_thousands_sep,
63320b57cec5SDimitry Andric                                         loc.get()))
63330b57cec5SDimitry Andric       __thousands_sep_ = base::do_thousands_sep();
63340b57cec5SDimitry Andric     __grouping_ = lc->mon_grouping;
63350b57cec5SDimitry Andric     __curr_symbol_ = lc->int_curr_symbol;
63360b57cec5SDimitry Andric     if (lc->int_frac_digits != CHAR_MAX)
63370b57cec5SDimitry Andric         __frac_digits_ = lc->int_frac_digits;
63380b57cec5SDimitry Andric     else
63390b57cec5SDimitry Andric         __frac_digits_ = base::do_frac_digits();
63400b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
63410b57cec5SDimitry Andric     if (lc->p_sign_posn == 0)
63420b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
63430b57cec5SDimitry Andric     if (lc->int_p_sign_posn == 0)
63440b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
63450b57cec5SDimitry Andric         __positive_sign_ = "()";
63460b57cec5SDimitry Andric     else
63470b57cec5SDimitry Andric         __positive_sign_ = lc->positive_sign;
63480b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
63490b57cec5SDimitry Andric     if(lc->n_sign_posn == 0)
63500b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
63510b57cec5SDimitry Andric     if (lc->int_n_sign_posn == 0)
63520b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
63530b57cec5SDimitry Andric         __negative_sign_ = "()";
63540b57cec5SDimitry Andric     else
63550b57cec5SDimitry Andric         __negative_sign_ = lc->negative_sign;
63560b57cec5SDimitry Andric     // Assume the positive and negative formats will want spaces in
63570b57cec5SDimitry Andric     // the same places in curr_symbol since there's no way to
63580b57cec5SDimitry Andric     // represent anything else.
63590b57cec5SDimitry Andric     string_type __dummy_curr_symbol = __curr_symbol_;
63600b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
63610b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, true,
63620b57cec5SDimitry Andric                lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, ' ');
63630b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, true,
63640b57cec5SDimitry Andric                lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, ' ');
63650b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
63660b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, true,
63670b57cec5SDimitry Andric                lc->int_p_cs_precedes, lc->int_p_sep_by_space,
63680b57cec5SDimitry Andric                lc->int_p_sign_posn, ' ');
63690b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, true,
63700b57cec5SDimitry Andric                lc->int_n_cs_precedes, lc->int_n_sep_by_space,
63710b57cec5SDimitry Andric                lc->int_n_sign_posn, ' ');
63720b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
63730b57cec5SDimitry Andric }
63740b57cec5SDimitry Andric 
6375349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
63760b57cec5SDimitry Andric template<>
63770b57cec5SDimitry Andric void
63780b57cec5SDimitry Andric moneypunct_byname<wchar_t, false>::init(const char* nm)
63790b57cec5SDimitry Andric {
63800b57cec5SDimitry Andric     typedef moneypunct<wchar_t, false> base;
63810b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
63820b57cec5SDimitry Andric     if (!loc)
63830b57cec5SDimitry Andric         __throw_runtime_error("moneypunct_byname"
63840b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
63850b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
63860b57cec5SDimitry Andric     if (!checked_string_to_wchar_convert(__decimal_point_,
63870b57cec5SDimitry Andric                                          lc->mon_decimal_point,
63880b57cec5SDimitry Andric                                          loc.get()))
63890b57cec5SDimitry Andric       __decimal_point_ = base::do_decimal_point();
63900b57cec5SDimitry Andric     if (!checked_string_to_wchar_convert(__thousands_sep_,
63910b57cec5SDimitry Andric                                          lc->mon_thousands_sep,
63920b57cec5SDimitry Andric                                          loc.get()))
63930b57cec5SDimitry Andric       __thousands_sep_ = base::do_thousands_sep();
63940b57cec5SDimitry Andric     __grouping_ = lc->mon_grouping;
63950b57cec5SDimitry Andric     wchar_t wbuf[100];
63960b57cec5SDimitry Andric     mbstate_t mb = {0};
63970b57cec5SDimitry Andric     const char* bb = lc->currency_symbol;
63980b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
63990b57cec5SDimitry Andric     if (j == size_t(-1))
64000b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
64010b57cec5SDimitry Andric     wchar_t* wbe = wbuf + j;
64020b57cec5SDimitry Andric     __curr_symbol_.assign(wbuf, wbe);
64030b57cec5SDimitry Andric     if (lc->frac_digits != CHAR_MAX)
64040b57cec5SDimitry Andric         __frac_digits_ = lc->frac_digits;
64050b57cec5SDimitry Andric     else
64060b57cec5SDimitry Andric         __frac_digits_ = base::do_frac_digits();
64070b57cec5SDimitry Andric     if (lc->p_sign_posn == 0)
64080b57cec5SDimitry Andric         __positive_sign_ = L"()";
64090b57cec5SDimitry Andric     else
64100b57cec5SDimitry Andric     {
64110b57cec5SDimitry Andric         mb = mbstate_t();
64120b57cec5SDimitry Andric         bb = lc->positive_sign;
64130b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
64140b57cec5SDimitry Andric         if (j == size_t(-1))
64150b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
64160b57cec5SDimitry Andric         wbe = wbuf + j;
64170b57cec5SDimitry Andric         __positive_sign_.assign(wbuf, wbe);
64180b57cec5SDimitry Andric     }
64190b57cec5SDimitry Andric     if (lc->n_sign_posn == 0)
64200b57cec5SDimitry Andric         __negative_sign_ = L"()";
64210b57cec5SDimitry Andric     else
64220b57cec5SDimitry Andric     {
64230b57cec5SDimitry Andric         mb = mbstate_t();
64240b57cec5SDimitry Andric         bb = lc->negative_sign;
64250b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
64260b57cec5SDimitry Andric         if (j == size_t(-1))
64270b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
64280b57cec5SDimitry Andric         wbe = wbuf + j;
64290b57cec5SDimitry Andric         __negative_sign_.assign(wbuf, wbe);
64300b57cec5SDimitry Andric     }
64310b57cec5SDimitry Andric     // Assume the positive and negative formats will want spaces in
64320b57cec5SDimitry Andric     // the same places in curr_symbol since there's no way to
64330b57cec5SDimitry Andric     // represent anything else.
64340b57cec5SDimitry Andric     string_type __dummy_curr_symbol = __curr_symbol_;
64350b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, false,
64360b57cec5SDimitry Andric                lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, L' ');
64370b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, false,
64380b57cec5SDimitry Andric                lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, L' ');
64390b57cec5SDimitry Andric }
64400b57cec5SDimitry Andric 
64410b57cec5SDimitry Andric template<>
64420b57cec5SDimitry Andric void
64430b57cec5SDimitry Andric moneypunct_byname<wchar_t, true>::init(const char* nm)
64440b57cec5SDimitry Andric {
64450b57cec5SDimitry Andric     typedef moneypunct<wchar_t, true> base;
64460b57cec5SDimitry Andric     __libcpp_unique_locale loc(nm);
64470b57cec5SDimitry Andric     if (!loc)
64480b57cec5SDimitry Andric         __throw_runtime_error("moneypunct_byname"
64490b57cec5SDimitry Andric                             " failed to construct for " + string(nm));
64500b57cec5SDimitry Andric 
64510b57cec5SDimitry Andric     lconv* lc = __libcpp_localeconv_l(loc.get());
64520b57cec5SDimitry Andric     if (!checked_string_to_wchar_convert(__decimal_point_,
64530b57cec5SDimitry Andric                                          lc->mon_decimal_point,
64540b57cec5SDimitry Andric                                          loc.get()))
64550b57cec5SDimitry Andric       __decimal_point_ = base::do_decimal_point();
64560b57cec5SDimitry Andric     if (!checked_string_to_wchar_convert(__thousands_sep_,
64570b57cec5SDimitry Andric                                          lc->mon_thousands_sep,
64580b57cec5SDimitry Andric                                          loc.get()))
64590b57cec5SDimitry Andric       __thousands_sep_ = base::do_thousands_sep();
64600b57cec5SDimitry Andric     __grouping_ = lc->mon_grouping;
64610b57cec5SDimitry Andric     wchar_t wbuf[100];
64620b57cec5SDimitry Andric     mbstate_t mb = {0};
64630b57cec5SDimitry Andric     const char* bb = lc->int_curr_symbol;
64640b57cec5SDimitry Andric     size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
64650b57cec5SDimitry Andric     if (j == size_t(-1))
64660b57cec5SDimitry Andric         __throw_runtime_error("locale not supported");
64670b57cec5SDimitry Andric     wchar_t* wbe = wbuf + j;
64680b57cec5SDimitry Andric     __curr_symbol_.assign(wbuf, wbe);
64690b57cec5SDimitry Andric     if (lc->int_frac_digits != CHAR_MAX)
64700b57cec5SDimitry Andric         __frac_digits_ = lc->int_frac_digits;
64710b57cec5SDimitry Andric     else
64720b57cec5SDimitry Andric         __frac_digits_ = base::do_frac_digits();
64730b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
64740b57cec5SDimitry Andric     if (lc->p_sign_posn == 0)
64750b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
64760b57cec5SDimitry Andric     if (lc->int_p_sign_posn == 0)
64770b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
64780b57cec5SDimitry Andric         __positive_sign_ = L"()";
64790b57cec5SDimitry Andric     else
64800b57cec5SDimitry Andric     {
64810b57cec5SDimitry Andric         mb = mbstate_t();
64820b57cec5SDimitry Andric         bb = lc->positive_sign;
64830b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
64840b57cec5SDimitry Andric         if (j == size_t(-1))
64850b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
64860b57cec5SDimitry Andric         wbe = wbuf + j;
64870b57cec5SDimitry Andric         __positive_sign_.assign(wbuf, wbe);
64880b57cec5SDimitry Andric     }
64890b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
64900b57cec5SDimitry Andric     if (lc->n_sign_posn == 0)
64910b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
64920b57cec5SDimitry Andric     if (lc->int_n_sign_posn == 0)
64930b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
64940b57cec5SDimitry Andric         __negative_sign_ = L"()";
64950b57cec5SDimitry Andric     else
64960b57cec5SDimitry Andric     {
64970b57cec5SDimitry Andric         mb = mbstate_t();
64980b57cec5SDimitry Andric         bb = lc->negative_sign;
64990b57cec5SDimitry Andric         j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, loc.get());
65000b57cec5SDimitry Andric         if (j == size_t(-1))
65010b57cec5SDimitry Andric             __throw_runtime_error("locale not supported");
65020b57cec5SDimitry Andric         wbe = wbuf + j;
65030b57cec5SDimitry Andric         __negative_sign_.assign(wbuf, wbe);
65040b57cec5SDimitry Andric     }
65050b57cec5SDimitry Andric     // Assume the positive and negative formats will want spaces in
65060b57cec5SDimitry Andric     // the same places in curr_symbol since there's no way to
65070b57cec5SDimitry Andric     // represent anything else.
65080b57cec5SDimitry Andric     string_type __dummy_curr_symbol = __curr_symbol_;
65090b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
65100b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, true,
65110b57cec5SDimitry Andric                lc->p_cs_precedes, lc->p_sep_by_space, lc->p_sign_posn, L' ');
65120b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, true,
65130b57cec5SDimitry Andric                lc->n_cs_precedes, lc->n_sep_by_space, lc->n_sign_posn, L' ');
65140b57cec5SDimitry Andric #else // _LIBCPP_MSVCRT
65150b57cec5SDimitry Andric     __init_pat(__pos_format_, __dummy_curr_symbol, true,
65160b57cec5SDimitry Andric                lc->int_p_cs_precedes, lc->int_p_sep_by_space,
65170b57cec5SDimitry Andric                lc->int_p_sign_posn, L' ');
65180b57cec5SDimitry Andric     __init_pat(__neg_format_, __curr_symbol_, true,
65190b57cec5SDimitry Andric                lc->int_n_cs_precedes, lc->int_n_sep_by_space,
65200b57cec5SDimitry Andric                lc->int_n_sign_posn, L' ');
65210b57cec5SDimitry Andric #endif // !_LIBCPP_MSVCRT
65220b57cec5SDimitry Andric }
6523349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
65240b57cec5SDimitry Andric 
65250b57cec5SDimitry Andric void __do_nothing(void*) {}
65260b57cec5SDimitry Andric 
65270b57cec5SDimitry Andric void __throw_runtime_error(const char* msg)
65280b57cec5SDimitry Andric {
65290b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
65300b57cec5SDimitry Andric     throw runtime_error(msg);
65310b57cec5SDimitry Andric #else
65320b57cec5SDimitry Andric     (void)msg;
65330b57cec5SDimitry Andric     _VSTD::abort();
65340b57cec5SDimitry Andric #endif
65350b57cec5SDimitry Andric }
65360b57cec5SDimitry Andric 
65370b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<char>;
6538349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<wchar_t>;)
65390b57cec5SDimitry Andric 
65400b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<char>;
6541349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_get<wchar_t>;)
65420b57cec5SDimitry Andric 
65430b57cec5SDimitry Andric                            template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<char>;
6544349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_get<wchar_t>;)
65450b57cec5SDimitry Andric 
65460b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<char>;
6547349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS num_put<wchar_t>;)
65480b57cec5SDimitry Andric 
65490b57cec5SDimitry Andric                            template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<char>;
6550349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template struct _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __num_put<wchar_t>;)
65510b57cec5SDimitry Andric 
65520b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<char>;
6553349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<wchar_t>;)
65540b57cec5SDimitry Andric 
65550b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<char>;
6556349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<wchar_t>;)
65570b57cec5SDimitry Andric 
65580b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<char>;
6559349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<wchar_t>;)
65600b57cec5SDimitry Andric 
65610b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<char>;
6562349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<wchar_t>;)
65630b57cec5SDimitry Andric 
65640b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, false>;
65650b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<char, true>;
6566349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, false>;)
6567349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct<wchar_t, true>;)
65680b57cec5SDimitry Andric 
65690b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, false>;
65700b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<char, true>;
6571349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, false>;)
6572349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS moneypunct_byname<wchar_t, true>;)
65730b57cec5SDimitry Andric 
65740b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<char>;
6575349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_get<wchar_t>;)
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_put<char>;
6581349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS money_put<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 messages<char>;
6587349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages<wchar_t>;)
65880b57cec5SDimitry Andric 
65890b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<char>;
6590349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS messages_byname<wchar_t>;)
65910b57cec5SDimitry Andric 
65920b57cec5SDimitry Andric                            template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char, char, mbstate_t>;
6593349cc55cSDimitry Andric _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<wchar_t, char, mbstate_t>;)
6594e8d8bef9SDimitry Andric template class _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char16_t, char, mbstate_t>;
6595e8d8bef9SDimitry Andric template class _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char32_t, char, mbstate_t>;
6596fe6060f1SDimitry Andric #ifndef _LIBCPP_HAS_NO_CHAR8_T
6597e8d8bef9SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char16_t, char8_t, mbstate_t>;
6598e8d8bef9SDimitry Andric template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS codecvt_byname<char32_t, char8_t, mbstate_t>;
6599e8d8bef9SDimitry Andric #endif
66000b57cec5SDimitry Andric 
66010b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
6602