/***************************************************************************
 *
 * _locale.h - definition of the std::locale class
 *
 * This is an internal header file used to implement the C++ Standard
 * Library. It should never be #included directly by a program.
 *
 * $Id: _locale.h 597181 2007-11-21 18:59:19Z faridz $
 *
 ***************************************************************************
 *
 * Licensed to the Apache Software  Foundation (ASF) under one or more
 * contributor  license agreements.  See  the NOTICE  file distributed
 * with  this  work  for  additional information  regarding  copyright
 * ownership.   The ASF  licenses this  file to  you under  the Apache
 * License, Version  2.0 (the  "License"); you may  not use  this file
 * except in  compliance with the License.   You may obtain  a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the  License is distributed on an  "AS IS" BASIS,
 * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY  KIND, either  express or
 * implied.   See  the License  for  the  specific language  governing
 * permissions and limitations under the License.
 *
 * Copyright 1994-2005 Rogue Wave Software.
 * 
 **************************************************************************/

#ifndef _RWSTD_LOC_LOCALE_INCLUDED
#define _RWSTD_LOC_LOCALE_INCLUDED


#include <string>

#include <loc/_facet.h>
#include <rw/_defs.h>


_RWSTD_NAMESPACE (__rw) { 

enum __rw_locale_category {
    __rw_cat_none     = 0x0100,
    __rw_cat_collate  = 0x0200,
    __rw_cat_ctype    = 0x0400,
    __rw_cat_monetary = 0x0800,
    __rw_cat_numeric  = 0x1000,
    __rw_cat_time     = 0x2000,
    __rw_cat_messages = 0x4000,
    __rw_cat_all      = 0x7e00
};


class _RWSTD_EXPORT __rw_locale;

inline const __rw_facet*
__rw_get_std_facet (const _STD::locale&, __rw_facet::_C_facet_type,
                    __rw_facet::_C_ctor_t*);

inline const __rw_facet*
__rw_get_facet_by_id (const _STD::locale&,
                      const __rw_facet_id&,
                      const __rw_facet*);

// called from has_facet and use_facet to strips top level
// const-qualifier from the type of Facet
template <class _Facet>
inline const __rw_facet*
__rw_get_facet (const _STD::locale&, const _Facet*);

}   // namespace __rw


_RWSTD_NAMESPACE (std) {


// 22.1.2, p1
template <class _Facet>
inline const _Facet&
use_facet (const locale &__loc _RWSTD_DUMMY_ARG (const _Facet* = 0))
{
    // Facet could be a const SomeFacet; strip the const qualifier
    // and, for non-standard facets, use dynamic_cast to make sure
    // that the dynamic type of `pfacet' is the same as Facet
    const _RW::__rw_facet* const __pfacet =
        _RW::__rw_get_facet (__loc, (_Facet*)0);

    _RWSTD_REQUIRES (__pfacet,
                     (_RWSTD_ERROR_BAD_CAST,
                      _RWSTD_FUNC ("use_facet (const locale&)")));

    return *_RWSTD_STATIC_CAST (const _Facet*, __pfacet);
}


// 22.1.2, p5
template <class _Facet>
inline bool
has_facet (const locale &__loc _RWSTD_DUMMY_ARG (const _Facet* = 0))
{
    // Facet could be a const SomeFacet; strip the const qualifier 
    const _RW::__rw_facet* const __pfacet =
        _RW::__rw_get_facet (__loc, (_Facet*)0);

    return 0 != __pfacet;
}


// forward declare standard facets before referencing them below
_EXPORT template <class _InternT, class _ExternT, class _StateT>
class codecvt;

_EXPORT template <class _CharT>
class collate;

_EXPORT template <class _CharT>
class ctype;

_EXPORT template <class _CharT, class _Iter>
struct money_get;

_EXPORT template <class _CharT, class _Iter>
struct money_put;

_EXPORT template <class _CharT, bool _Intl>
struct moneypunct;

_EXPORT template <class _CharT, class _Iter>
struct num_get;

_EXPORT template <class _CharT, class _Iter>
struct num_put;

_EXPORT template <class _CharT>
struct numpunct;

_EXPORT template <class _CharT, class _Iter>
class time_get;

_EXPORT template <class _CharT, class _Iter>
struct time_put;

_EXPORT template <class _CharT>
class messages;

 
// 22.1.1
struct _RWSTD_CLASS_EXPORT locale
{
    // 22.1.1.1.1, p1
    typedef int category;

    // 22.1.1.1.2
    typedef _RW::__rw_facet facet;

    // 22.1.1.1.3
    typedef _RW::__rw_facet_id id;

    // values (including none) must not conflict with any LC_XXX constants
    _RWSTD_STATIC_CONST (category, none     = _RW::__rw_cat_none);
    _RWSTD_STATIC_CONST (category, collate  = _RW::__rw_cat_collate);
    _RWSTD_STATIC_CONST (category, ctype    = _RW::__rw_cat_ctype);
    _RWSTD_STATIC_CONST (category, monetary = _RW::__rw_cat_monetary);
    _RWSTD_STATIC_CONST (category, numeric  = _RW::__rw_cat_numeric);
    _RWSTD_STATIC_CONST (category, time     = _RW::__rw_cat_time);
    _RWSTD_STATIC_CONST (category, messages = _RW::__rw_cat_messages);
    _RWSTD_STATIC_CONST (category, all      = _RW::__rw_cat_all);

    // 22.1.1.2, p1
    _RWSTD_MEMBER_EXPORT locale () _THROWS (());

    // 22.1.1.2, p3
    _RWSTD_MEMBER_EXPORT locale (const locale&) _THROWS (());

    // 22.1.1.2, p6
    _RWSTD_MEMBER_EXPORT _EXPLICIT locale (const char*);

    // 22.1.1.2, p9
    _RWSTD_MEMBER_EXPORT locale (const locale&, const char*, category);

#ifndef _RWSTD_NO_MEMBER_TEMPLATES

    // 22.1.1.2, p12
    template <class _Facet>
    locale (const locale&, _Facet*);

#  ifndef _RWSTD_NO_TEMPLATE_ON_RETURN_TYPE

    // 22.1.1.3, p1
    template <class _Facet>
    locale combine (const locale&) const;

#  endif   // _RWSTD_NO_TEMPLATE_ON_RETURN_TYPE

    // 22.1.1.4, p3
    template <class _CharT, class _Traits, class _Allocator>
    bool operator() (const basic_string<_CharT, _Traits, _Allocator>&,
                     const basic_string<_CharT, _Traits, _Allocator>&) const;

#else   // if defined (_RWSTD_NO_MEMBER_TEMPLATES)

    template <class _Facet>
    locale (const locale &__rhs, _Facet *__facet)
        : _C_body (0) {
        // initialize facet's member id to point to Facet::id
        if (__facet && !__facet->_C_pid) {
        // unusual cast (to size_t** rather than size_t*&)
        // done to work around an HP aCC 3.3x bug
            *_RWSTD_CONST_CAST (_RWSTD_SIZE_T**, &__facet->_C_pid) =
                &_Facet::id._C_id;
        }

        // uninitialized Facet::id will be initialized by has_facet<>()

        // prevent passing `facet' the ctor if it is installed
        // in `rhs' to potentially avoid creating a whole new body
        if (   has_facet<_Facet>(__rhs)
            && &use_facet<_Facet>(__rhs) == __facet)
            __facet = 0;

        *this = locale (*__rhs._C_body, __facet);
    }

#  ifndef _RWSTD_NO_TEMPLATE_ON_RETURN_TYPE

    template <class _Facet>
    locale combine (const locale &__rhs) const {
        // unitialized Facet::id will be initialized by has_facet<>()

        _RWSTD_REQUIRES (has_facet<_Facet>(__rhs),
                         (_RWSTD_ERROR_FACET_NOT_FOUND,
                         _RWSTD_FUNC ("locale::combine (const locale&)"),
                         _Facet::id._C_id, __rhs.name ().c_str ()));

        return locale (__rhs, &use_facet<_Facet>(__rhs));
    }

#  endif   // _RWSTD_NO_TEMPLATE_ON_RETURN_TYPE

    template <class _CharT, class _Traits, class _Allocator>
    bool
    operator() (const basic_string<_CharT, _Traits, _Allocator> &__x,
                const basic_string<_CharT, _Traits, _Allocator> &__y) const {
        // qualify collate to distinguish it from locale::collate
        return use_facet<_STD::collate<_CharT> >(*this)
            .compare (__x.data (), __x.data () + __x.length (),
                      __y.data (), __y.data () + __y.length ()) < 0;
    }

#endif   // _RWSTD_NO_MEMBER_TEMPLATES


    // 22.1.1.2, p14
    _RWSTD_MEMBER_EXPORT locale (const locale&, const locale&, category);

    // 22.1.1.2, p16
    _RWSTD_MEMBER_EXPORT ~locale() _THROWS (());

    // 22.1.1.2, p4
    _RWSTD_MEMBER_EXPORT const locale& operator= (const locale&) _THROWS (());

    // 22.1.1.3, p5
    _RWSTD_MEMBER_EXPORT string name () const;

    // 22.1.1.4, p1
    _RWSTD_MEMBER_EXPORT bool operator== (const locale&) const;

    // 22.1.1.4, p2
    _RWSTD_MEMBER_EXPORT bool operator!= (const locale &__rhs) const {
        return !(*this == __rhs);
    }

    // 22.1.1.5, p1
    _RWSTD_MEMBER_EXPORT static locale global (const locale&);

    // 22.1.1.5, p4
    _RWSTD_MEMBER_EXPORT static const locale& classic ();

private:

    _RWSTD_MEMBER_EXPORT _EXPLICIT locale (_RW::__rw_locale &__rhs) 
        _THROWS (())
        : _C_body (&__rhs) { }

    _RWSTD_MEMBER_EXPORT locale (_RW::__rw_locale&, const facet*);

    _RW::__rw_locale *_C_body;     // reference-counted body

#if    defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x540

   // working around a SunPro member access control bug (see PR #25910)
public:

#endif   // SunPro <= 5.4

    // (try to) retrieve a facet from a locale given an id
    // may initialize the id if it isn't initialized yet
    _RWSTD_MEMBER_EXPORT const facet*
    _C_get_facet (const id&) const;

    _RWSTD_MEMBER_EXPORT const facet*
    _C_get_std_facet (facet::_C_facet_type, facet::_C_ctor_t*) const;

    friend class  _RW::__rw_locale;
    friend struct _RW::__rw_access;

    // function arguments below are qualified to work around
    // a SunPro 5.5 and prior bug (PR #28626)
    friend const facet*
    _RW::__rw_get_std_facet (const _STD::locale&,
                             _RW::__rw_facet::_C_facet_type,
                             _RW::__rw_facet::_C_ctor_t*);

    friend const _RW::__rw_facet*
    _RW::__rw_get_facet_by_id (const _STD::locale&,
                               const _RW::__rw_facet_id&,
                               const _RW::__rw_facet*);
};

}   // namespace std


_RWSTD_NAMESPACE (__rw) {

inline const __rw_facet*
__rw_get_facet_by_id (const _STD::locale &__loc,
                      const __rw_facet_id      &__id,
                      const __rw_facet*)
{
    // initialize Facet::id and retrieve facet if it's installed
    return __loc._C_get_facet (__id);
}


template <class _Facet>
inline const __rw_facet*
__rw_get_facet (const _STD::locale &__loc, const _Facet *__dummy)
{
    // resolves either to one of the overloads of __rw_get_facet_by_id
    // defined for the set of standard facets or the overload for the base
    // locale::facet* if _Facet is not derived from any of the former
    const __rw_facet* const __pfacet =
        __rw_get_facet_by_id (__loc, _Facet::id, __dummy);

    return _RWSTD_DYNAMIC_CAST (const _Facet*, __pfacet);
}


inline const __rw_facet*
__rw_get_std_facet (const _STD::locale  &__loc,
                    __rw_facet::_C_facet_type  __type,
                    __rw_facet::_C_ctor_t     *__ctor)
{
    // expose an implementation detail of locale body for efficiency
    struct _Facets {
        __rw_facet *__facets [__rw_facet::_C_last_type / 2];
    };

    const _Facets* const __pfacets =
        _RWSTD_REINTERPRET_CAST (const _Facets*, __loc._C_body);

    _RWSTD_ASSERT (0 != __pfacets);

    const __rw_facet *__facet = __pfacets->__facets [__type >> 1];

    if (!__facet)
        __facet = __loc._C_get_std_facet (__type, __ctor);

#if !defined (__HP_aCC) || _RWSTD_HP_aCC_MINOR > 3800

    // working around an HP aCC ICE (PR #28838)
    _RWSTD_ASSERT (0 != __facet);

#endif   // HP aCC

    return __facet;
}


// functions' type must be __rw_facet::_C_ctor_t
// i.e., as if they were declared as follows:
//     __rw_facet::_C_ctor_t __rw_ct_ctype;
// the declaration above causes a Compaq C++ 6.5 ICE (PR #30188)
_RWSTD_EXPORT __rw_facet* __rw_ct_ctype (_RWSTD_SIZE_T, const char*);
_RWSTD_EXPORT __rw_facet* __rw_ct_numpunct (_RWSTD_SIZE_T, const char*);
_RWSTD_EXPORT __rw_facet* __rw_ct_num_get (_RWSTD_SIZE_T, const char*);
_RWSTD_EXPORT __rw_facet* __rw_ct_num_put (_RWSTD_SIZE_T, const char*);


#define _RWSTD_OVERLOAD_GET_FACET(F)                 \
    _RWSTD_EXPORT const __rw_facet*                  \
    __rw_get_facet_by_id (const _STD::locale&,       \
                          const __rw_facet_id&, const F*)

#define _Facet(name, T, U)   _STD::name<T, U >

#define _InIter(T)    _STD::istreambuf_iterator< T, _STD::char_traits<T > >
#define _OutIter(T)   _STD::ostreambuf_iterator< T, _STD::char_traits<T > >

// convenience typedefs to allow them to be used as macro arguments
typedef _STD::codecvt<char, char, _RWSTD_MBSTATE_T>    __rw_codecvt_c;
typedef _Facet (moneypunct, char, false)               __rw_mpunct_c_0;
typedef _Facet (moneypunct, char, true)                __rw_mpunct_c_1;
typedef _Facet (money_get, char, _InIter (char))       __rw_mget_c;
typedef _Facet (money_put, char, _OutIter (char))      __rw_mput_c;
typedef _Facet (num_get, char, _InIter (char))         __rw_nget_c;
typedef _Facet (num_put, char, _OutIter (char))        __rw_nput_c;
typedef _Facet (time_get, char, _InIter (char))        __rw_tget_c;
typedef _Facet (time_put, char, _OutIter (char))       __rw_tput_c;


// inline definitions of heavily used use_facet specializations
// for iostream efficiency

_RWSTD_SPECIALIZED_FUNCTION
inline const __rw_facet*
__rw_get_facet (const _STD::locale &__loc, const _STD::ctype<char>*)
{
    return __rw_get_std_facet (__loc, __rw_facet::_C_ctype,
                               __rw_ct_ctype);
}


_RWSTD_SPECIALIZED_FUNCTION
inline const __rw_facet*
__rw_get_facet (const _STD::locale &__loc, const _STD::numpunct<char>*)
{
    return __rw_get_std_facet (__loc, __rw_facet::_C_numpunct,
                               __rw_ct_numpunct);
}


_RWSTD_SPECIALIZED_FUNCTION
inline const __rw_facet*
__rw_get_facet (const _STD::locale &__loc, const __rw_nget_c*)
{
    return __rw_get_std_facet (__loc, __rw_facet::_C_num_get,
                               __rw_ct_num_get);
}


_RWSTD_SPECIALIZED_FUNCTION
inline const __rw_facet*
__rw_get_facet (const _STD::locale &__loc, const __rw_nput_c*)
{
    return __rw_get_std_facet (__loc, __rw_facet::_C_num_put,
                               __rw_ct_num_put);
}


// declarations of __rw_get_facet_by_id overloads
_RWSTD_OVERLOAD_GET_FACET (_STD::ctype<char>);
_RWSTD_OVERLOAD_GET_FACET (__rw_codecvt_c);
_RWSTD_OVERLOAD_GET_FACET (_STD::collate<char>);
_RWSTD_OVERLOAD_GET_FACET (__rw_mget_c);
_RWSTD_OVERLOAD_GET_FACET (__rw_mput_c);
_RWSTD_OVERLOAD_GET_FACET (__rw_mpunct_c_0);
_RWSTD_OVERLOAD_GET_FACET (__rw_mpunct_c_1);
_RWSTD_OVERLOAD_GET_FACET (__rw_nget_c);
_RWSTD_OVERLOAD_GET_FACET (__rw_nput_c);
_RWSTD_OVERLOAD_GET_FACET (_STD::numpunct<char>);
_RWSTD_OVERLOAD_GET_FACET (__rw_tget_c);
_RWSTD_OVERLOAD_GET_FACET (__rw_tput_c);
_RWSTD_OVERLOAD_GET_FACET (_STD::messages<char>);

#ifndef _RWSTD_NO_WCHAR_T

typedef _STD::codecvt<wchar_t, char, _RWSTD_MBSTATE_T>    __rw_codecvt_w;
typedef _Facet (moneypunct, wchar_t, false)               __rw_mpunct_w_0;
typedef _Facet (moneypunct, wchar_t, true)                __rw_mpunct_w_1;
typedef _Facet (money_get, wchar_t, _InIter (wchar_t))    __rw_mget_w;
typedef _Facet (money_put, wchar_t, _OutIter (wchar_t))   __rw_mput_w;
typedef _Facet (num_get, wchar_t, _InIter (wchar_t))      __rw_nget_w;
typedef _Facet (num_put, wchar_t, _OutIter (wchar_t))     __rw_nput_w;
typedef _Facet (time_get, wchar_t, _InIter (wchar_t))     __rw_tget_w;
typedef _Facet (time_put, wchar_t, _OutIter (wchar_t))    __rw_tput_w;

_RWSTD_OVERLOAD_GET_FACET (_STD::ctype<wchar_t>);
_RWSTD_OVERLOAD_GET_FACET (__rw_codecvt_w);
_RWSTD_OVERLOAD_GET_FACET (_STD::collate<wchar_t>);
_RWSTD_OVERLOAD_GET_FACET (__rw_mget_w);
_RWSTD_OVERLOAD_GET_FACET (__rw_mput_w);
_RWSTD_OVERLOAD_GET_FACET (__rw_mpunct_w_0);
_RWSTD_OVERLOAD_GET_FACET (__rw_mpunct_w_1);
_RWSTD_OVERLOAD_GET_FACET (__rw_nget_w);
_RWSTD_OVERLOAD_GET_FACET (__rw_nput_w);
_RWSTD_OVERLOAD_GET_FACET (_STD::numpunct<wchar_t>);
_RWSTD_OVERLOAD_GET_FACET (__rw_tget_w);
_RWSTD_OVERLOAD_GET_FACET (__rw_tput_w);
_RWSTD_OVERLOAD_GET_FACET (_STD::messages<wchar_t>);

#endif   // _RWSTD_NO_WCHAR_T

// clean up
#undef _RWSTD_OVERLOAD_GET_FACET
#undef _Facet
#undef _InIter
#undef _OutIter


}   // namespace __rw


_RWSTD_NAMESPACE (std) {


#ifndef _RWSTD_NO_MEMBER_TEMPLATES

template <class _Facet>
inline locale::locale (const locale &__rhs, _Facet *__facet)
    : _C_body (0)
{
    // initialize facet's member id to point to Facet::id
    if (__facet && !__facet->_C_pid) {
        // unusual cast (to size_t** rather than size_t*&)
        // done to work around an HP aCC 3.3x bug
        *_RWSTD_CONST_CAST (_RWSTD_SIZE_T**, &__facet->_C_pid) =
            &_Facet::id._C_id;
    }

    // uninitialized Facet::id will be initialized by has_facet<>()

    // prevent passing `facet' the ctor if it is installed in `rhs'
    // to potentially avoid creating a whole new locale body
    if (_RW::__rw_get_facet (__rhs, (_Facet*)0) == __facet)
        __facet = 0;

    *this = locale (*__rhs._C_body, __facet);
}


#  ifndef _RWSTD_NO_TEMPLATE_ON_RETURN_TYPE

template <class _Facet>
inline locale locale::combine (const locale &__rhs) const
{
    // unitialized Facet::id will be initialized by has_facet<>()

    _RWSTD_REQUIRES (has_facet<_Facet>(__rhs),
                     (_RWSTD_ERROR_FACET_NOT_FOUND,
                      _RWSTD_FUNC ("locale::combine (const locale&)"),
                      _Facet::id._C_id, __rhs.name ().c_str ()));

    return locale (*this, &use_facet<_Facet>(__rhs));
}

#  endif   // _RWSTD_NO_TEMPLATE_ON_RETURN_TYPE


template <class _CharT, class _Traits, class _Allocator>
inline bool
locale::operator() (const basic_string<_CharT, _Traits, _Allocator> &__x,
                    const basic_string<_CharT, _Traits, _Allocator> &__y) const
{
    // qualify collate to distinguish it from locale::collate
    return use_facet<_STD::collate<_CharT> >(*this)
        .compare (__x.data (), __x.data () + __x.length (),
                  __y.data (), __y.data () + __y.length ()) < 0;
}


#endif   // _RWSTD_NO_MEMBER_TEMPLATES


}   // namespace std


#endif   // _RWSTD_LOC_LOCALE_INCLUDED
