//===------------------------- locale.cpp ---------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#define _LIBCPP_EXTERN_TEMPLATE(...) extern template __VA_ARGS__;
// On Solaris, we need to define something to make the C99 parts of localeconv
// visible.
#ifdef __sun__
#define _LCONV_C99
#endif
#include "string"
#include "locale"
#include "codecvt"
#include "vector"
#include "algorithm"
#include "typeinfo"
#ifndef _LIBCPP_NO_EXCEPTIONS
# include "type_traits"
#endif
#include "clocale"
#include "cstring"
#include "cwctype"
#include "__sso_allocator"
#if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
#include <support/win32/locale_win32.h>
#elif !defined(__ANDROID__)
#include <langinfo.h>
#endif
#include <stdlib.h>
#include <stdio.h>
// On Linux, wint_t and wchar_t have different signed-ness, and this causes
// lots of noise in the build log, but no bugs that I know of.
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wsign-conversion"
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#ifdef __cloc_defined
locale_t __cloc() {
// In theory this could create a race condition. In practice
// the race condition is non-fatal since it will just create
// a little resource leak. Better approach would be appreciated.
static locale_t result = newlocale(LC_ALL_MASK, "C", 0);
return result;
}
#endif // __cloc_defined
namespace {
struct release
{
void operator()(locale::facet* p) {p->__release_shared();}
};
template <class T, class A0>
inline
T&
make(A0 a0)
{
static typename aligned_storage<sizeof(T)>::type buf;
::new (&buf) T(a0);
return *reinterpret_cast<T*>(&buf);
}
template <class T, class A0, class A1>
inline
T&
make(A0 a0, A1 a1)
{
static typename aligned_storage<sizeof(T)>::type buf;
::new (&buf) T(a0, a1);
return *reinterpret_cast<T*>(&buf);
}
template <class T, class A0, class A1, class A2>
inline
T&
make(A0 a0, A1 a1, A2 a2)
{
static typename aligned_storage<sizeof(T)>::type buf;
::new (&buf) T(a0, a1, a2);
return *reinterpret_cast<T*>(&buf);
}
template <typename T, size_t N>
inline
_LIBCPP_CONSTEXPR
size_t
countof(const T (&)[N])
{
return N;
}
template <typename T>
inline
_LIBCPP_CONSTEXPR
size_t
countof(const T * const begin, const T * const end)
{
return static_cast<size_t>(end - begin);
}
}
#if defined(_AIX)
// Set priority to INT_MIN + 256 + 150
# pragma priority ( -2147483242 )
#endif
const locale::category locale::none;
const locale::category locale::collate;
const locale::category locale::ctype;
const locale::category locale::monetary;
const locale::category locale::numeric;
const locale::category locale::time;
const locale::category locale::messages;
const locale::category locale::all;
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpadded"
#endif
class _LIBCPP_HIDDEN locale::__imp
: public facet
{
enum {N = 28};
#if defined(_LIBCPP_MSVC)
// FIXME: MSVC doesn't support aligned parameters by value.
// I can't get the __sso_allocator to work here
// for MSVC I think for this reason.
vector<facet*> facets_;
#else
vector<facet*, __sso_allocator<facet*, N> > facets_;
#endif
string name_;
public:
explicit __imp(size_t refs = 0);
explicit __imp(const string& name, size_t refs = 0);
__imp(const __imp&);
__imp(const __imp&, const string&, locale::category c);
__imp(const __imp& other, const __imp& one, locale::category c);
__imp(const __imp&, facet* f, long id);
~__imp();
const string& name() const {return name_;}
bool has_facet(long id) const
{return static_cast<size_t>(id) < facets_.size() && facets_[static_cast<size_t>(id)];}
const locale::facet* use_facet(long id) const;
static const locale& make_classic();
static locale& make_global();
private:
void install(facet* f, long id);
template <class F> void install(F* f) {install(f, f->id.__get());}
template <class F> void install_from(const __imp& other);
};
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
locale::__imp::__imp(size_t refs)
: facet(refs),
facets_(N),
name_("C")
{
facets_.clear();
install(&make<_VSTD::collate<char> >(1u));
install(&make<_VSTD::collate<wchar_t> >(1u));
install(&make<_VSTD::ctype<char> >(nullptr, false, 1u));
install(&make<_VSTD::ctype<wchar_t> >(1u));
install(&make<codecvt<char, char, mbstate_t> >(1u));
install(&make<codecvt<wchar_t, char, mbstate_t> >(1u));
install(&make<codecvt<char16_t, char, mbstate_t> >(1u));
install(&make<codecvt<char32_t, char, mbstate_t> >(1u));
install(&make<numpunct<char> >(1u));
install(&make<numpunct<wchar_t> >(1u));
install(&make<num_get<char> >(1u));
install(&make<num_get<wchar_t> >(1u));
install(&make<num_put<char> >(1u));
install(&make<num_put<wchar_t> >(1u));
install(&make<moneypunct<char, false> >(1u));
install(&make<moneypunct<char, true> >(1u));
install(&make<moneypunct<wchar_t, false> >(1u));
install(&make<moneypunct<wchar_t, true> >(1u));
install(&make<money_get<char> >(1u));
install(&make<money_get<wchar_t> >(1u));
install(&make<money_put<char> >(1u));
install(&make<money_put<wchar_t> >(1u));
install(&make<time_get<char> >(1u));
install(&make<time_get<wchar_t> >(1u));
install(&make<time_put<char> >(1u));
install(&make<time_put<wchar_t> >(1u));
install(&make<_VSTD::messages<char> >(1u));
install(&make<_VSTD::messages<wchar_t> >(1u));
}
locale::__imp::__imp(const string& name, size_t refs)
: facet(refs),
facets_(N),
name_(name)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
try
{
#endif // _LIBCPP_NO_EXCEPTIONS
facets_ = locale::classic().__locale_->facets_;
for (unsigned i = 0; i < facets_.size(); ++i)
if (facets_[i])
facets_[i]->__add_shared();
install(new collate_byname<char>(name_));
install(new collate_byname<wchar_t>(name_));
install(new ctype_byname<char>(name_));
install(new ctype_byname<wchar_t>(name_));
install(new codecvt_byname<char, char, mbstate_t>(name_));
install(new codecvt_byname<wchar_t, char, mbstate_t>(name_));
install(new codecvt_byname<char16_t, char, mbstate_t>(name_));
install(new codecvt_byname<char32_t, char, mbstate_t>(name_));
install(new numpunct_byname<char>(name_));
install(new numpunct_byname<wchar_t>(name_));
install(new moneypunct_byname<char, false>(name_));
install(new moneypunct_byname<char, true>(name_));
install(new moneypunct_byname<wchar_t, false>(name_));
install(new moneypunct_byname<wchar_t, true>(name_));
install(new time_get_byname<char>(name_));
install(new time_get_byname<wchar_t>(name_));
install(new time_put_byname<char>(name_));
install(new time_put_byname<wchar_t>(name_));
install(new messages_byname<char>(name_));
install(new messages_byname<wchar_t>(name_));
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
for (unsigned i = 0; i < facets_.size(); ++i)
if (facets_[i])
facets_[i]->__release_shared();
throw;
}
#endif // _LIBCPP_NO_EXCEPTIONS
}
// NOTE avoid the `base class should be explicitly initialized in the
// copy constructor` warning emitted by GCC
#if defined(__clang__) || _GNUC_VER >= 406
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wextra"
#endif
locale::__imp::__imp(const __imp& other)
: facets_(max<size_t>(N, other.facets_.size())),
name_(other.name_)
{
facets_ = other.facets_;
for (unsigned i = 0; i < facets_.size(); ++i)
if (facets_[i])
face