// locale standard header -*-c++-*-
// Copyright 2009-2017 IAR Systems AB.
#ifndef _LOCALE_
#define _LOCALE_

#ifndef _SYSTEM_BUILD
  #pragma system_include
#endif

#include <yvals.h>

#if !_DLIB_FULL_LOCALE_SUPPORT
  #error "This library configuration does not support locale, either use \
          another existing library configuration or define a new and rebuild \
          the library."
#endif

#include <string>
#include <xlocbuf>
#include <xlocmes>
#include <xlocmon>
#include <xlocnum>
#include <xloctime>

/* Module consistency. */
#pragma rtmodel="__dlib_full_locale_support", \
  _STRINGIFY(_DLIB_FULL_LOCALE_SUPPORT)

namespace std {

// TEMPLATE CLASS collate
template<class _Elem>
class collate
  : public locale::facet
{       // facet for ordering sequences of elements
public:
  typedef _Elem char_type;
  typedef basic_string<_Elem, char_traits<_Elem>,
                       allocator<_Elem> > string_type;

  int compare(const _Elem *_First1, const _Elem *_Last1,
              const _Elem *_First2, const _Elem *_Last2) const
  {       // compare [_First1, _Last1) to [_First2, _Last2)
    return do_compare(_First1, _Last1, _First2, _Last2);
  }

  string_type transform(const _Elem *_First, const _Elem *_Last) const
  {       // transform [_First, _Last) to key string
    return do_transform(_First, _Last);
  }

  long hash(const _Elem *_First, const _Elem *_Last) const
  {       // compute hash code for [_First, _Last)
    return do_hash(_First, _Last);
  }

  static locale::id id;   // unique facet id

  explicit collate(size_t _Refs = 0)
    : locale::facet(_Refs)
  {       // construct from current locale
    // Possibly lock thread
    _Locinfo _Lobj;
    _Init(_Lobj);
  }

  collate(const _Locinfo& _Lobj, size_t _Refs = 0)
    : locale::facet(_Refs)
  {       // construct from specified locale
    _Init(_Lobj);
  }

  static size_t _Getcat(const locale::facet **_Ppf = 0,
                        const locale *_Ploc = 0)
  {       // return locale category mask and construct standard facet
    if (_Ppf != 0 && *_Ppf == 0)
      *_Ppf = new collate<_Elem>(
        _Locinfo(_Ploc->name().c_str()));
    return _X_COLLATE;
  }

protected:
  ~collate() _NOEXCEPT
  {       // destroy the object
  }

protected:
  collate(const char *_Locname, size_t _Refs = 0)
    : locale::facet(_Refs)
  {       // construct from specified locale
    // Possibly lock thread
    _Locinfo _Lobj(_Locname);
    _Init(_Lobj);
  }

  void _Init(const _Locinfo& _Lobj)
  {       // initialize from _Lobj
    _Coll = _Lobj._Getcoll();
  }

  virtual int do_compare(const _Elem *_First1, const _Elem *_Last1,
                         const _Elem *_First2, const _Elem *_Last2) const
  {       // compare [_First1, _Last1) to [_First2, _Last2)
    _DEBUG_RANGE(_First1, _Last1);
    _DEBUG_RANGE(_First2, _Last2);
    int _Ans = _LStrcoll(_First1, _Last1, _First2, _Last2, &_Coll);
    return _Ans < 0 ? -1 : _Ans == 0 ? 0 : +1;
  }

  virtual string_type do_transform(const _Elem *_First,
                                   const _Elem *_Last) const
  {       // transform [_First, _Last) to key string
    _DEBUG_RANGE(_First, _Last);
    size_t _Count;
    string_type _Str;

    for (_Count = _Last - _First; 0 < _Count; )
    {       // grow string if locale-specific strxfrm fails
      _Str.resize(_Count);
      if ((_Count = _LStrxfrm(&*_Str.begin(),
                              &*_Str.begin() + _Str.size(),
                              _First, _Last, &_Coll)) <= _Str.size())
        break;
    }
    _Str.resize(_Count);
    return _Str;
  }

  #pragma no_arith_checks
  virtual long do_hash(const _Elem *_First,
                       const _Elem *_Last) const
  {       // compute hash code for [_First, _Last)
    _DEBUG_RANGE(_First, _Last);
    return (long)_Hash_seq((const unsigned char *)_First,
                            (_Last - _First) * sizeof (_Elem));
  }

private:
  _Locinfo::_Collvec _Coll;       // used by _LStrcoll and _XStrxfrm
};

// STATIC collate::id OBJECT
template<class _Elem>
locale::id collate<_Elem>::id;

// TEMPLATE CLASS collate_byname
template<class _Elem>
class collate_byname
  : public collate<_Elem>
{       // collate for named locale
public:
  explicit collate_byname(const char *_Locname, size_t _Refs = 0)
    : collate<_Elem>(_Locname, _Refs)
  {       // construct for named locale
  }

  explicit collate_byname(const string& _Str, size_t _Refs = 0)
    : collate<_Elem>(_Locinfo(_Str.c_str()), _Refs)
  {       // construct for named locale
  }

protected:
  virtual ~collate_byname() _NOEXCEPT
  {       // destroy the object
  }
};

// locale SUPPORT TEMPLATES

#define _HAS(loc, fac) has_facet<fac>(loc)

template<class _Facet> inline
bool has_facet(const locale& _Loc) _THROW0()
{       // test if facet is in locale
  // Possibly lock thread
  size_t _Id = _Facet::id;
  return _Loc._Getfacet(_Id) != 0 || _Facet::_Getcat() != (size_t)(-1);
}

template<class _Elem,
         class _Traits,
         class _Alloc> inline
bool locale::operator()(const basic_string<_Elem, _Traits, _Alloc>& _Left,
                       const basic_string<_Elem, _Traits, _Alloc>& _Right) const
{       // compare _Left and _Right strings using collate facet in locale
  const std::collate<_Elem>& _Coll_fac =
    use_facet<std::collate<_Elem> >(*this);

  return    _Coll_fac.compare(_Left.c_str(), _Left.c_str() + _Left.size(),
                              _Right.c_str(), _Right.c_str() + _Right.size())
          < 0;
}

// ctype TEMPLATE FUNCTIONS
template<class _Elem> inline
bool (isalnum)(_Elem _Ch, const locale& _Loc)
{       // test if character is alphanumeric, locale specific
  return use_facet< ctype<_Elem> >(_Loc).is(ctype_base::alnum, _Ch);
}

template<class _Elem> inline
bool (isalpha)(_Elem _Ch, const locale& _Loc)
{       // test if character is alphabetic, locale specific
  return use_facet< ctype<_Elem> >(_Loc).is(ctype_base::alpha, _Ch);
}

template<class _Elem> inline
bool (isblank)(_Elem _Ch, const locale& _Loc)
{       // test if character is blank, locale specific
  return use_facet< ctype<_Elem> >(_Loc).is(ctype_base::blank, _Ch);
}

template<class _Elem> inline
bool (iscntrl)(_Elem _Ch, const locale& _Loc)
{       // test if character is control, locale specific
  return use_facet< ctype<_Elem> >(_Loc).is(ctype_base::cntrl, _Ch);
}

template<class _Elem> inline
bool (isdigit)(_Elem _Ch, const locale& _Loc)
{       // test if character is digit, locale specific
  return use_facet< ctype<_Elem> >(_Loc).is(ctype_base::digit, _Ch);
}

template<class _Elem> inline
bool (isgraph)(_Elem _Ch, const locale& _Loc)
{       // test if character is graphic, locale specific
  return use_facet< ctype<_Elem> >(_Loc).is(ctype_base::graph, _Ch);
}

template<class _Elem> inline
bool (islower)(_Elem _Ch, const locale& _Loc)
{       // test if character is lower case, locale specific
  return use_facet< ctype<_Elem> >(_Loc).is(ctype_base::lower, _Ch);
}

template<class _Elem> inline
bool (isprint)(_Elem _Ch, const locale& _Loc)
{       // test if character is printing, locale specific
  return use_facet< ctype<_Elem> >(_Loc).is(ctype_base::print, _Ch);
}

template<class _Elem> inline
bool (ispunct)(_Elem _Ch, const locale& _Loc)
{       // test if character is punctuation, locale specific
  return use_facet< ctype<_Elem> >(_Loc).is(ctype_base::punct, _Ch);
}

template<class _Elem> inline
bool (isspace)(_Elem _Ch, const locale& _Loc)
{       // test if character is whitespace, locale specific
  return use_facet< ctype<_Elem> >(_Loc).is(ctype_base::space, _Ch);
}

template<class _Elem> inline
bool (isupper)(_Elem _Ch, const locale& _Loc)
{       // test if character is upper case, locale specific
  return use_facet< ctype<_Elem> >(_Loc).is(ctype_base::upper, _Ch);
}

template<class _Elem> inline
bool (isxdigit)(_Elem _Ch, const locale& _Loc)
{       // test if character is hexadecimal digit, locale specific
  return use_facet< ctype<_Elem> >(_Loc).is(ctype_base::xdigit, _Ch);
}

template<class _Elem> inline
_Elem (tolower)(_Elem _Ch, const locale& _Loc)
{       // convert character to lower case, locale specific
  return use_facet< ctype<_Elem> >(_Loc).tolower(_Ch);
}

template<class _Elem> inline
_Elem (toupper)(_Elem _Ch, const locale& _Loc)
{       // convert character to upper case, locale specific
  return use_facet< ctype<_Elem> >(_Loc).toupper(_Ch);
}

} /* namespace std */

#endif /* _LOCALE_ */

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0576 */
