// xlocnum internal header (from <locale>) -*-c++-*-
// Copyright 2009-2017 IAR Systems AB.
#ifndef _XLOCNUM_
#define _XLOCNUM_

#ifndef _SYSTEM_BUILD
  #pragma system_include
#endif

#include <climits>
#include <cmath>
//#include <cstdio>
#include <cstdlib>
#include <streambuf>

#ifdef _LOCALE_DECIMAL_POINT
#undef _LOCALE_DECIMAL_POINT
#endif

#if _DLIB_FULL_LOCALE_SUPPORT
  #define _LOCALE_DECIMAL_POINT (::localeconv()->decimal_point[0])
#else
  #define _LOCALE_DECIMAL_POINT ('.')
#endif

// TEXT-TO-NUMERIC CONVERSION FUNCTIONS
extern "C" {
  extern float __iar_Sto32(const char *, char **, __int32_t, int *);
  #if __DOUBLE_SIZE__ == 8
    extern double __iar_Sto64(const char *, char **, __int32_t, int *);
    #define __iar_Stod __iar_Sto64
  #else
    #define __iar_Stod __iar_Sto32
  #endif

  extern long __iar_Stolx(const char *, char **, int, int *);
  extern unsigned long __iar_Stoulx(const char *, char **, int, int *);
  extern long long __iar_Stollx(const char *, char **, int, int *);
  extern unsigned long long __iar_Stoullx(const char *, char **, int, int *);
} /* extern "C" */

namespace std {

#define _VIRTUAL      virtual

#if _DLIB_FULL_LOCALE_SUPPORT
  #define _IOS_BASE_GETLOC _Iosbase.getloc()
  #define _IOS_BASE_GETLOC2 ,_Iosbase.getloc()
  #define _LOC             _Loc
#else
  #define _IOS_BASE_GETLOC
  #define _IOS_BASE_GETLOC2
  #define _LOC
#endif

// TEMPLATE FUNCTION _Find_elem
template<class _Elem> inline
size_t _Find_elem(_Elem *_Base, _Elem _Ch)
{       // lookup _Ch in NUL-terminated string _Base
  _Elem *_Ptr = _Base;
  for (; *_Ptr != (_Elem)0 && *_Ptr != _Ch; ++_Ptr)
    ;
  return (size_t)(_Ptr - _Base);
}

#if _DLIB_WIDE_CHARACTERS
inline wchar_t *_Maklocwcs(const wchar_t *_Ptr)
{       // copy NTWCS to allocated storage
  size_t _Count = ::wcslen(_Ptr) + 1;
  wchar_t *_Ptrdest = (wchar_t *)::malloc(_Count * sizeof (wchar_t));
  if (!_Ptrdest)
    __iar_Raise_bad_alloc();
  ::wmemcpy(_Ptrdest, _Ptr, _Count);
  return _Ptrdest;
}
#endif

// TEMPLATE CLASS numpunct
template<class _Elem>
class numpunct
  #if _DLIB_FULL_LOCALE_SUPPORT
  : public locale::facet
  #endif
{       // facet for defining numeric punctuation text
public:
  typedef basic_string<_Elem, char_traits<_Elem>, allocator<_Elem> >
  string_type;
  typedef _Elem char_type;

  #if _DLIB_FULL_LOCALE_SUPPORT
    static locale::id id;   // unique facet id
  #endif

  _Elem decimal_point() const
  {       // return decimal point
    return do_decimal_point();
  }

  _Elem thousands_sep() const
  {       // return thousands separator
    return do_thousands_sep();
  }

  string grouping() const
  {       // return grouping string
    return do_grouping();
  }

  string_type falsename() const
  {       // return name for false
    return do_falsename();
  }

  string_type truename() const
  {       // return name for true
    return do_truename();
  }

  #if _DLIB_FULL_LOCALE_SUPPORT
    explicit numpunct(size_t _Refs = 0)
      : locale::facet(_Refs)
    {       // construct from current locale
      _Locinfo _Lobj;
      _Init(_Lobj);
      if (_Kseparator == 0)
        _Kseparator =   // NB: differs from "C" locale
          _MAKLOCCHR(_Elem, ',', _Lobj._Getcvt());
    }
  #else /* !_DLIB_FULL_LOCALE_SUPPORT */
    explicit numpunct()
    {
      _Init();
      if (_Kseparator == 0)
        _Kseparator =   // NB: differs from "C" locale
          _MAKLOCCHR(_Elem, ',', _Lobj._Getcvt());
    }
  #endif

  #if _DLIB_FULL_LOCALE_SUPPORT
    numpunct(const _Locinfo& _Lobj, size_t _Refs = 0)
      : locale::facet(_Refs)
    {       // construct from specified locale
      _Init(_Lobj);
    }
  #else
    //  numpunct()
    //  {
    //    _Init();
    //  }
  #endif

  #if _DLIB_FULL_LOCALE_SUPPORT
    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 numpunct<_Elem>(_Ploc->_GetLocinfo(), 0);
//          _Locinfo(_Ploc->c_str()), 0, true);
      return _X_NUMERIC;
    }
  #endif

#if _DLIB_FULL_LOCALE_SUPPORT
protected:
#endif
  _VIRTUAL ~numpunct() _NOEXCEPT
  {       // destroy the object
    _Tidy();
  }
protected:
  #if _DLIB_FULL_LOCALE_SUPPORT
    numpunct(const char *_Locname, size_t _Refs = 0)
      : locale::facet(_Refs)
    {       // construct from specified locale
      // Possibly lock thread
      _Locinfo _Lobj(_Locname);
      _Init(_Lobj);
    }
  #endif

  #if _DLIB_FULL_LOCALE_SUPPORT
    template<class _Elem2>
    void _Getvals(_Elem2, const lconv *_Ptr, _Locinfo::_Cvtvec _Cvt)
    {       // get values
      _Dp = _MAKLOCCHR(_Elem2, _Ptr->decimal_point[0], _Cvt);
      _Kseparator = _MAKLOCCHR(_Elem2, _Ptr->thousands_sep[0], _Cvt);
    }

    void _Init(const _Locinfo& _Lobj)
    {       // initialize from _Lobj
      const lconv *_Ptr = _Lobj._Getlconv_for_numeric();
      _Locinfo::_Cvtvec _Cvt = _Lobj._Getcvt();       // conversion information

      _Grouping = 0;
      _Falsename = 0;
      _Truename = 0;

      _TRY_BEGIN
        _Grouping = _MAKLOCSTR(char, _Ptr->grouping, _Lobj._Getcvt());
        _Falsename = _MAKLOCSTR(_Elem, _Lobj._Getfalse(), _Cvt);
        _Truename = _MAKLOCSTR(_Elem, _Lobj._Gettrue(), _Cvt);
      _CATCH_ALL
        _Tidy();
        _RERAISE;
      _CATCH_END

      _Getvals((_Elem)0, _Ptr, _Cvt);
    }
  #else /* !_DLIB_FULL_LOCALE_SUPPORT */
    template<class _Elem2>
    void _Getvals(_Elem2 /* , const lconv *_Ptr */)
    {       // get values
      _Dp = _MAKLOCCHR(_Elem2,
                       /* _Ptr->decimal_point[0] */ '.',
                       _Lobj._Getcvt());
      _Kseparator = _MAKLOCCHR(_Elem2,
                               /* _Ptr->thousands_sep[0] */ '\0',
                               _Lobj._Getcvt());
    }

    void _Init()
    {       // initialize from _Lobj
      /* const lconv *_Ptr = localeconv(); */

      _Grouping = 0;
      _Falsename = 0;
      _Truename = 0;

      _TRY_BEGIN
        _Grouping = _MAKLOCSTR(char, "", _Lobj._Getcvt());
        _Falsename = _MAKLOCSTR(_Elem, "false", _Lobj._Getcvt());
        _Truename = _MAKLOCSTR(_Elem, "true", _Lobj._Getcvt());
      _CATCH_ALL
        _Tidy();
        _RERAISE;
      _CATCH_END

      _Getvals((_Elem)0 /* , _Ptr */);
    }
  #endif /* _DLIB_FULL_LOCALE_SUPPORT */

  _VIRTUAL _Elem do_decimal_point() const
  {       // return decimal point
    return _Dp;
  }

  _VIRTUAL _Elem do_thousands_sep() const
  {       // return thousands separator
    return _Kseparator;
  }

  _VIRTUAL string do_grouping() const
  {       // return grouping string
    return string(_Grouping);
  }

  _VIRTUAL string_type do_falsename() const
  {       // return name for false
    return string_type(_Falsename);
  }

  _VIRTUAL string_type do_truename() const
  {       // return name for true
    return string_type(_Truename);
  }

private:
  void _Tidy()
  {       // free all storage
    ::free((void *)_Grouping);
    ::free((void *)_Falsename);
    ::free((void *)_Truename);
  }

  const char *_Grouping;  // grouping string, "" for "C" locale
  _Elem _Dp;      // decimal point, '.' for "C" locale
  _Elem _Kseparator;      // thousands separator, '\0' for "C" locale
  const _Elem *_Falsename;        // name for false, "false" for "C" locale
  const _Elem *_Truename; // name for true, "true" for "C" locale
};

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

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

  protected:
    _VIRTUAL ~numpunct_byname() _NOEXCEPT
    {       // destroy the object
    }
  };

  // STATIC numpunct::id OBJECT
  template<class _Elem>
  locale::id numpunct<_Elem>::id;
#endif /* _DLIB_FULL_LOCALE_SUPPORT */

// TEMPLATE CLASS num_get
template<class _Elem,
         class _InIt = istreambuf_iterator<_Elem, char_traits<_Elem> > >
class num_get
  #if _DLIB_FULL_LOCALE_SUPPORT
  : public locale::facet
  #endif
{       // facet for converting text to encoded numbers
public:
  typedef numpunct<_Elem> _Mypunct;
  typedef basic_string<_Elem, char_traits<_Elem>, allocator<_Elem> >
  _Mystr;

  #if _DLIB_FULL_LOCALE_SUPPORT
    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 num_get<_Elem, _InIt>(_Ploc->_GetLocinfo());
//          _Locinfo(_Ploc->c_str()));
      return _X_NUMERIC;
    }

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

#if _DLIB_FULL_LOCALE_SUPPORT
protected:
#endif
  _VIRTUAL ~num_get() _NOEXCEPT
  {       // destroy the object
  }

protected:
  #if _DLIB_FULL_LOCALE_SUPPORT
    void _Init(const _Locinfo&)
    {       // initialize from _Locinfo object
    }
  #endif

public:
  #if _DLIB_FULL_LOCALE_SUPPORT
    explicit num_get(size_t _Refs = 0)
      : locale::facet(_Refs)
    {       // construct from current locale
      // Possibly lock thread
      _Locinfo _Lobj;
      _Init(_Lobj);
    }

    num_get(const _Locinfo& _Lobj, size_t _Refs = 0)
      : locale::facet(_Refs)
    {       // construct from specified locale
      _Init(_Lobj);
    }
  #else /* _DLIB_FULL_LOCALE_SUPPORT */
    num_get()
    {
    }
  #endif /* _DLIB_FULL_LOCALE_SUPPORT */

  typedef _Elem char_type;
  typedef _InIt iter_type;

  _InIt get(_InIt _First, _InIt _Last,
            ios_base& _Iosbase,     ios_base::iostate& _State,
            bool& _Val) const
  {       // get bool from [_First, _Last) into _Val
    return do_get(_First, _Last, _Iosbase, _State, _Val);
  }

  _InIt get(_InIt _First, _InIt _Last,
            ios_base& _Iosbase,     ios_base::iostate& _State,
            unsigned short& _Val) const
  {       // get unsigned short from [_First, _Last) into _Val
    return do_get(_First, _Last, _Iosbase, _State, _Val);
  }

  _InIt get(_InIt _First, _InIt _Last,
            ios_base& _Iosbase,     ios_base::iostate& _State,
            unsigned int& _Val) const
  {       // get unsigned int from [_First, _Last) into _Val
    return do_get(_First, _Last, _Iosbase, _State, _Val);
  }

  _InIt get(_InIt _First, _InIt _Last,
            ios_base& _Iosbase, ios_base::iostate& _State,
            long& _Val) const
  {       // get long from [_First, _Last) into _Val
    return do_get(_First, _Last, _Iosbase, _State, _Val);
  }

  _InIt get(_InIt _First, _InIt _Last,
            ios_base& _Iosbase, ios_base::iostate& _State,
            unsigned long& _Val) const
  {       // get unsigned long from [_First, _Last) into _Val
    return do_get(_First, _Last, _Iosbase, _State, _Val);
  }

  _InIt get(_InIt _First, _InIt _Last,
            ios_base& _Iosbase, ios_base::iostate& _State,
            long long& _Val) const
  {       // get long long from [_First, _Last) into _Val
    return do_get(_First, _Last, _Iosbase, _State, _Val);
  }

  _InIt get(_InIt _First, _InIt _Last,
            ios_base& _Iosbase, ios_base::iostate& _State,
            unsigned long long& _Val) const
  {       // get unsigned long long from [_First, _Last) into _Val
    return do_get(_First, _Last, _Iosbase, _State, _Val);
  }

  _InIt get(_InIt _First, _InIt _Last,
            ios_base& _Iosbase, ios_base::iostate& _State,
            float& _Val) const
  {       // get float from [_First, _Last) into _Val
    return do_get(_First, _Last, _Iosbase, _State, _Val);
  }

  _InIt get(_InIt _First, _InIt _Last,
            ios_base& _Iosbase, ios_base::iostate& _State,
            double& _Val) const
  {       // get double from [_First, _Last) into _Val
    return do_get(_First, _Last, _Iosbase, _State, _Val);
  }

  _InIt get(_InIt _First, _InIt _Last,
            ios_base& _Iosbase, ios_base::iostate& _State,
            long double& _Val) const
  {       // get long double from [_First, _Last) into _Val
    return do_get(_First, _Last, _Iosbase, _State, _Val);
  }

  _InIt get(_InIt _First, _InIt _Last,
            ios_base& _Iosbase, ios_base::iostate& _State,
            void *& _Val) const
  {       // get void pointer from [_First, _Last) into _Val
    return do_get(_First, _Last, _Iosbase, _State, _Val);
  }

protected:
  _VIRTUAL _InIt do_get(_InIt _First, _InIt _Last,
                        ios_base& _Iosbase, ios_base::iostate& _State,
                        bool& _Val) const
  {       // get bool from [_First, _Last) into _Val
    _DEBUG_RANGE(_First, _Last);
    int _Ans = -1;  // negative answer indicates failure

    if (_Iosbase.flags() & ios_base::boolalpha)
    {       // get false name or true name
      typedef typename _Mystr::size_type _Mystrsize;
      const _Mypunct& _Punct_fac = use_facet< _Mypunct >(_IOS_BASE_GETLOC);
      _Mystr _Str((_Mystrsize)1, (char_type)0);
      _Str += _Punct_fac.falsename();
      _Str += (char_type)0;
      _Str += _Punct_fac.truename();  // construct "\0false\0true"
      _Ans = _Getloctxt(_First, _Last, (size_t)2, _Str.c_str());
    }
    else
    {       // get zero or nonzero integer
      char _Ac[_MAX_INT_DIG], *_Ep;
      int _Errno = 0;
      const unsigned long _Ulo = ::__iar_Stoulx(_Ac, &_Ep,
                                                _Getifld(_Ac, _First, _Last,
                                                         _Iosbase.flags()
                                                         _IOS_BASE_GETLOC2),
                                                &_Errno);
      if (_Ep != _Ac && _Errno == 0 && _Ulo <= 1)
        _Ans = _Ulo;
    }

    if (_First == _Last)
      _State |= ios_base::eofbit;
    if (_Ans < 0)
      _State |= ios_base::failbit;
    else
      _Val = _Ans != 0;       // deliver value
    return _First;
  }

  _VIRTUAL _InIt do_get(_InIt _First, _InIt _Last,
                        ios_base& _Iosbase, ios_base::iostate& _State,
                        unsigned short& _Val) const
  {       // get unsigned short from [_First, _Last) into _Val
    _DEBUG_RANGE(_First, _Last);
    char _Ac[_MAX_INT_DIG], *_Ep;
    int _Errno = 0;
    int _Base = _Getifld(_Ac, _First, _Last, _Iosbase.flags()
                         _IOS_BASE_GETLOC2);     // gather field into _Ac
    char *_Ptr = _Ac[0] == '-' ? _Ac + 1 : _Ac;     // point past any sign
    const unsigned long _Ans =
                   ::__iar_Stoulx(_Ptr, &_Ep, _Base, &_Errno);      // convert

    if (_First == _Last)
      _State |= ios_base::eofbit;
    if (_Ep == _Ptr || _Errno != 0 || USHRT_MAX < _Ans)
      _State |= ios_base::failbit;
    else
      _Val = (unsigned short)(_Ac[0] == '-' ? 0 -_Ans : _Ans);  // deliver value
    return _First;
  }

  _VIRTUAL _InIt do_get(_InIt _First, _InIt _Last,
                        ios_base& _Iosbase, ios_base::iostate& _State,
                        unsigned int& _Val) const
  {       // get unsigned int from [_First, _Last) into _Val
    _DEBUG_RANGE(_First, _Last);
    char _Ac[_MAX_INT_DIG], *_Ep;
    int _Errno = 0;
    int _Base = _Getifld(_Ac, _First, _Last, _Iosbase.flags()
                         _IOS_BASE_GETLOC2);     // gather field into _Ac
    char *_Ptr = _Ac[0] == '-' ? _Ac + 1 : _Ac;     // point past any sign
    const unsigned long _Ans =
                    ::__iar_Stoulx(_Ptr, &_Ep, _Base, &_Errno);      // convert

    if (_First == _Last)
      _State |= ios_base::eofbit;
    if (     _Ep == _Ptr || _Errno != 0
        #if __INT_SIZE__ != __LONG_SIZE__
          || UINT_MAX < _Ans
        #endif
       )
      _State |= ios_base::failbit;
    else
      _Val = _Ac[0] == '-' ? 0 -_Ans : _Ans;  // deliver value
    return _First;
  }

  _VIRTUAL _InIt do_get(_InIt _First, _InIt _Last,
                        ios_base& _Iosbase, ios_base::iostate& _State,
                        long& _Val) const
  {       // get long from [_First, _Last) into _Val
    _DEBUG_RANGE(_First, _Last);
    char _Ac[_MAX_INT_DIG], *_Ep;
    int _Errno = 0;
    const long _Ans = ::__iar_Stolx(_Ac, &_Ep,
                                    _Getifld(_Ac, _First, _Last,
                                             _Iosbase.flags()
                                             _IOS_BASE_GETLOC2), &_Errno);
                                                     // gather field, convert

    if (_First == _Last)
      _State |= ios_base::eofbit;
    if (_Ep == _Ac || _Errno != 0)
      _State |= ios_base::failbit;
    else
      _Val = _Ans;    // deliver value
    return _First;
  }

  _VIRTUAL _InIt do_get(_InIt _First, _InIt _Last,
                        ios_base& _Iosbase, ios_base::iostate& _State,
                        unsigned long& _Val) const
  {       // get unsigned long from [_First, _Last) into _Val
    _DEBUG_RANGE(_First, _Last);
    char _Ac[_MAX_INT_DIG], *_Ep;
    int _Errno = 0;
    const unsigned long _Ans = ::__iar_Stoulx(_Ac, &_Ep,
                                              _Getifld(_Ac, _First, _Last,
                                                       _Iosbase.flags()
                                                       _IOS_BASE_GETLOC2),
                                              &_Errno); // gather field, convert

    if (_First == _Last)
      _State |= ios_base::eofbit;
    if (_Ep == _Ac || _Errno != 0)
      _State |= ios_base::failbit;
    else
      _Val = _Ans;    // deliver value
    return _First;
  }

  _VIRTUAL _InIt do_get(_InIt _First, _InIt _Last,
                        ios_base& _Iosbase, ios_base::iostate& _State,
                        long long& _Val) const
  {       // get long long from [_First, _Last) into _Val
    _DEBUG_RANGE(_First, _Last);
    char _Ac[_MAX_INT_DIG], *_Ep;
    int _Errno = 0;
    const long long _Ans = ::__iar_Stollx(_Ac, &_Ep,
                                          _Getifld(_Ac, _First, _Last,
                                                   _Iosbase.flags()
                                                   _IOS_BASE_GETLOC2),
                                          &_Errno);   // gather field, convert

    if (_First == _Last)
      _State |= ios_base::eofbit;
    if (_Ep == _Ac || _Errno != 0)
      _State |= ios_base::failbit;
    else
      _Val = _Ans;    // deliver value
    return _First;
  }

  _VIRTUAL _InIt do_get(_InIt _First, _InIt _Last,
                        ios_base& _Iosbase, ios_base::iostate& _State,
                        unsigned long long& _Val) const
  {       // get unsigned long long from [_First, _Last) into _Val
    _DEBUG_RANGE(_First, _Last);
    char _Ac[_MAX_INT_DIG], *_Ep;
    int _Errno = 0;
    const unsigned long long _Ans = ::__iar_Stoullx(_Ac, &_Ep,
                                                    _Getifld(_Ac, _First, _Last,
                                                             _Iosbase.flags()
                                                             _IOS_BASE_GETLOC2),
                                              &_Errno); // gather field, convert

    if (_First == _Last)
      _State |= ios_base::eofbit;
    if (_Ep == _Ac || _Errno != 0)
      _State |= ios_base::failbit;
    else
      _Val = _Ans;    // deliver value
    return _First;
  }

  _VIRTUAL _InIt do_get(_InIt _First, _InIt _Last,
                        ios_base& _Iosbase, ios_base::iostate& _State,
                        float& _Val) const
  {       // get float from [_First, _Last) into _Val
    _DEBUG_RANGE(_First, _Last);
    char _Ac[_MAX_EXP_DIG + _MAX_SIG_DIG + 16], *_Ep;
    int _Errno = 0;
    int _Hexexp = 0;
    float _Ans = ::__iar_Sto32(_Ac, &_Ep,
                               _Getffld(_Ac, _First, _Last,
                                        _Iosbase, &_Hexexp), &_Errno);
                                                    // gather field, convert

    if (_Hexexp != 0)
      _Ans = ::ldexpf(_Ans, 4 * _Hexexp);

    if (_First == _Last)
      _State |= ios_base::eofbit;
    if (_Ep == _Ac || _Errno != 0)
      _State |= ios_base::failbit;
    else
      _Val = _Ans;    // deliver value
    return _First;
  }

  _VIRTUAL _InIt do_get(_InIt _First, _InIt _Last,
                        ios_base& _Iosbase, ios_base::iostate& _State,
                        double& _Val) const
  {       // get double from [_First, _Last) into _Val
    _DEBUG_RANGE(_First, _Last);
    char _Ac[_MAX_EXP_DIG + _MAX_SIG_DIG + 16], *_Ep;
    int _Errno = 0;
    int _Hexexp = 0;
    double _Ans = (double)::__iar_Stod(_Ac, &_Ep,
                                       _Getffld(_Ac, _First, _Last,
                                                _Iosbase, &_Hexexp), &_Errno);
                                                  // gather field, convert

    if (_Hexexp != 0)
      _Ans = ::ldexp(_Ans, 4 * _Hexexp);

    if (_First == _Last)
      _State |= ios_base::eofbit;
    if (_Ep == _Ac || _Errno != 0)
      _State |= ios_base::failbit;
    else
      _Val = _Ans;    // deliver value
    return _First;
  }

  _VIRTUAL _InIt do_get(_InIt _First, _InIt _Last,
                        ios_base& _Iosbase, ios_base::iostate& _State,
                        long double& _Val) const
  {       // get long double from [_First, _Last) into _Val
    _DEBUG_RANGE(_First, _Last);
    char _Ac[_MAX_EXP_DIG + _MAX_SIG_DIG + 16], *_Ep;
    int _Errno = 0;
    int _Hexexp = 0;
    long double _Ans = (long double)
      ::__iar_Stod(_Ac, &_Ep,
                   _Getffld(_Ac, _First, _Last,
                            _Iosbase, &_Hexexp),
                   &_Errno);  // gather field, convert

    if (_Hexexp != 0)
      _Ans = ::ldexpl(_Ans, 4 * _Hexexp);

    if (_First == _Last)
      _State |= ios_base::eofbit;
    if (_Ep == _Ac || _Errno != 0)
      _State |= ios_base::failbit;
    else
      _Val = _Ans;    // deliver value
    return _First;
  }

  _VIRTUAL _InIt do_get(_InIt _First, _InIt _Last,
                        ios_base& _Iosbase, ios_base::iostate& _State,
                        void *& _Val) const
  {       // get void pointer from [_First, _Last) into _Val
    _DEBUG_RANGE(_First, _Last);
    char _Ac[_MAX_INT_DIG], *_Ep;
    int _Errno = 0;

    int _Base = _Getifld(_Ac, _First, _Last, ios_base::hex
                         _IOS_BASE_GETLOC2);     // gather field
    const unsigned long long _Ans =
        (sizeof (void *) == sizeof (unsigned long))
      ? (unsigned long long)::__iar_Stoulx(_Ac, &_Ep, _Base, &_Errno)
      : ::__iar_Stoullx(_Ac, &_Ep, _Base, &_Errno);

    if (_First == _Last)
      _State |= ios_base::eofbit;
    if (_Ep == _Ac || _Errno != 0)
      _State |= ios_base::failbit;
    else
    {
      #pragma diag_suppress = Pe1053
      /* It is okay to cast to a smaller pointer here. */
      _Val = (void *) _Ans;      // deliver value
      #pragma diag_default = Pe1053
    }
    return _First;
  }

private:
  int _Getifld(char *_Ac,
               _InIt& _First, _InIt& _Last, ios_base::fmtflags _Basefield
               #if _DLIB_FULL_LOCALE_SUPPORT
                 ,const locale& _Loc
               #endif
               ) const
  {       // get integer field from [_First, _Last) into _Ac
    const _Mypunct& _Punct_fac = use_facet< _Mypunct >(_LOC);
    const string _Grouping = _Punct_fac.grouping();
    const _Elem _Kseparator =   _Grouping.size() == 0
                              ? (_Elem)0 : _Punct_fac.thousands_sep();

    enum {
      _NUMGET_SIGNOFF = 22,
      _NUMGET_XOFF = 24
    };
    static const char _Src[] = {"0123456789ABCDEFabcdef-+Xx"};
    _Elem _Atoms[sizeof (_Src)];
    const ctype<_Elem>& _Ctype_fac = use_facet< ctype<_Elem> >(_LOC);
    _Ctype_fac.widen(&_Src[0], &_Src[sizeof (_Src)], _Atoms);

    char *_Ptr = _Ac;

    if (_First == _Last)
      ;       // empty field
    else if (*_First == _Atoms[_NUMGET_SIGNOFF + 1])
      *_Ptr++ = '+', ++_First;        // gather plus sign
    else if (*_First == _Atoms[_NUMGET_SIGNOFF])
      *_Ptr++ = '-', ++_First;        // gather minus sign

    _Basefield &= ios_base::basefield;
    int _Base = _Basefield ==   ios_base::oct
                              ? 8 : _Basefield == ios_base::hex
                              ? 16 : _Basefield == ios_base::_Fmtzero
                              ? 0 : 10;

    bool _Seendigit = false;        // seen a digit in input
    bool _Nonzero = false;  // seen a nonzero digit in input

    if (_First != _Last && *_First == _Atoms[0])
    {       // leading zero, look for 0x, 0X
      _Seendigit = true, ++_First;
      if (   _First != _Last
          && (   *_First == _Atoms[_NUMGET_XOFF + 1]
              || *_First == _Atoms[_NUMGET_XOFF])
          && (_Base == 0 || _Base == 16))
        _Base = 16, _Seendigit = false, ++_First;
      else if (_Base == 0)
        _Base = 8;
    }

    size_t _Dlen = _Base == 0 || _Base == 10 ? 10 : _Base == 8 ? 8 : 16 + 6;
    string _Groups((size_t)1, (char)_Seendigit);
    size_t _Group = 0;

    for (char *const _Pe = &_Ac[_MAX_INT_DIG - 1];
         _First != _Last; ++_First)
    {       // look for digits and separators
      size_t _Idx = _Find_elem(_Atoms, *_First);
      if (_Idx < _Dlen)
      {       // got a digit, characterize it and add to group size
        *_Ptr = _Src[_Idx];
        if ((_Nonzero || *_Ptr != '0') && _Ptr < _Pe)
          ++_Ptr, _Nonzero = true;
        _Seendigit = true;
        if (_Groups[_Group] != CHAR_MAX)
          ++_Groups[_Group];
      }
      else if (   _Groups[_Group] == '\0'
               || _Kseparator == (_Elem)0
               || *_First != _Kseparator)
        break;  // not a group separator, done
      else
      {       // add a new group to _Groups string
        _Groups.append((string::size_type)1, '\0');
        ++_Group;
      }
    }

    if (_Group == 0)
      ;       // no thousands separators seen
    else if ('\0' < _Groups[_Group])
      ++_Group;       // add trailing group to group count
    else
      _Seendigit = false;     // trailing separator, fail

    for (const char *_Pg = &_Grouping[0]; _Seendigit && 0 < _Group; )
      if (*_Pg == CHAR_MAX)
        break;  // end of grouping constraints to check
      else if (   (0 < --_Group && *_Pg != _Groups[_Group])
               || (0 == _Group && *_Pg < _Groups[_Group]))
        _Seendigit = false;     // bad group size, fail
      else if ('\0' < _Pg[1])
        ++_Pg;  // group size okay, advance to next test

    if (_Seendigit && !_Nonzero)
      *_Ptr++ = '0';  // zero field, replace stripped zero(s)
    else if (!_Seendigit)
      _Ptr = _Ac;     // roll back pointer to indicate failure
    *_Ptr = '\0';
    return _Base;
  }

  int _Getffld(char *_Ac,
               _InIt& _First, _InIt &_Last,
               ios_base& _Iosbase, int *_Phexexp) const
  {       // get floating-point field from [_First, _Last) into _Ac
    if ((_Iosbase.flags() & ios_base::floatfield) == ios_base::hexfloat)
      return (_Getffldx(_Ac, _First, _Last,
                        _Iosbase, _Phexexp));   // hex format

    const _Mypunct& _Punct_fac = use_facet< _Mypunct >(_IOS_BASE_GETLOC);
    const string _Grouping = _Punct_fac.grouping();
    char *_Ptr = _Ac;
    bool _Bad = false;
    bool _Sticky = false;

    enum {
      _NUMGET_SIGNOFF = 10,
      _NUMGET_EOFF = 12
    };
    static const char _Src[] = {"0123456789-+Ee"};
    _Elem _Atoms[sizeof (_Src)];
    const ctype<_Elem>& _Ctype_fac =
      use_facet< ctype<_Elem> >(_IOS_BASE_GETLOC);
    _Ctype_fac.widen(&_Src[0], &_Src[sizeof (_Src)], _Atoms);

    if (_First == _Last)
      ;       // empty field
    else if (*_First == _Atoms[_NUMGET_SIGNOFF + 1])
      *_Ptr++ = '+', ++_First;        // gather plus sign
    else if (*_First == _Atoms[_NUMGET_SIGNOFF])
      *_Ptr++ = '-', ++_First;        // gather minus sign

    char *_Leading = _Ptr;	// remember backstop
    *_Ptr++ = '0';	// backstop carries from sticky bit

    bool _Seendigit = false;        // seen a digit in input
    int _Significant = 0;   // number of significant digits
    int _Pten = 0;  // power of 10 multiplier
    size_t _Idx;

    const char *_Pg = &_Grouping[0];
    if (*_Pg == CHAR_MAX || *_Pg <= '\0')
      for (;
           _First != _Last && (_Idx = _Find_elem(_Atoms, *_First)) < 10;
           _Seendigit = true, ++_First)
        if (_MAX_SIG_DIG <= _Significant)
        {	// enough digits, scale by 10 and update _Sticky
          ++_Pten;
          if (0 < _Idx)
            _Sticky = true;
        }
        else if (_Idx == 0 && _Significant == 0)
          ;       // drop leading zeros
        else
        {       // save a significant digit
          *_Ptr++ = _Src[_Idx];
          ++_Significant;
        }
    else
    {       // grouping specified, gather digits and group sizes
      const _Elem _Kseparator =   _Grouping.size() == 0
                                ? (_Elem)0 : _Punct_fac.thousands_sep();
      string _Groups((size_t)1, '\0');
      size_t _Group = 0;

      for (; _First != _Last; ++_First)
        if ((_Idx = _Find_elem(_Atoms, *_First)) < 10)
        {       // got a digit, add to group size
          _Seendigit = true;
          if (_MAX_SIG_DIG <= _Significant)
          {	// enough digits, scale by 10 and update _Sticky
            ++_Pten;
            if (0 < _Idx)
              _Sticky = true;
          }
          else if (_Idx == 0 && _Significant == 0)
            ;       // drop leading zeros
          else
          {       // save a significant digit
            *_Ptr++ = _Src[_Idx];
            ++_Significant;
          }
          if (_Groups[_Group] != CHAR_MAX)
            ++_Groups[_Group];
        }
        else if (   _Groups[_Group] == '\0'
                 || _Kseparator == (_Elem)0
                 || *_First != _Kseparator)
          break;  // not a group separator, done
        else
        {       // add a new group to _Groups string
          _Groups.append((size_t)1, '\0');
          ++_Group;
        }
      if (_Group == 0)
        ;       // no thousands separators seen
      else if ('\0' < _Groups[_Group])
        ++_Group;       // add trailing group to group count
      else
        _Bad = true;    // trailing separator, fail

      while (!_Bad && 0 < _Group)
        if (*_Pg == CHAR_MAX)
          break;  // end of grouping constraints to check
        else if (   (0 < --_Group && *_Pg != _Groups[_Group])
                 || (0 == _Group && *_Pg < _Groups[_Group]))
          _Bad = true;    // bad group size, fail
        else if ('\0' < _Pg[1])
          ++_Pg;  // group size okay, advance to next test
    }

    if (_First != _Last && *_First == _Punct_fac.decimal_point())
      *_Ptr++ = _LOCALE_DECIMAL_POINT, ++_First;     // add .

    if (_Significant == 0)
    {       // 0000. so far
      for (;
           _First != _Last && *_First == _Atoms[0];
           _Seendigit = true, ++_First)
        --_Pten;        // just count leading fraction zeros
      if (_Pten < 0)
        *_Ptr++ = '0', ++_Pten; // put one back
    }

    for (;
         _First != _Last && (_Idx = _Find_elem(_Atoms, *_First)) < 10;
         _Seendigit = true, ++_First)
      if (_Significant < _MAX_SIG_DIG)
      {       // save a significant fraction digit
        *_Ptr++ = _Src[_Idx];
        ++_Significant;
      }
      else if (0 < _Idx)
        _Sticky = true;	// just update _Sticky

    if (_Sticky)
    {	// increment ls digit in memory of those lost
      char *_Px = _Ptr;
      for (; --_Px != _Leading; )
      {	// add in carry
        if (*_Px == _LOCALE_DECIMAL_POINT)
          ;	// skip over decimal point
        else if (*_Px != '9')
        {	// carry stops here
          ++*_Px;
          break;
        }
        else
          *_Px = '0';	// propagate carry
      }

      if (_Px == _Leading)
      {	// change "999..." to "1000..." and scale _Pten
        *_Px = '1';
        ++_Pten;
      }
    }

    if (   _Seendigit && _First != _Last
        && (   *_First == _Atoms[_NUMGET_EOFF + 1]
            || *_First == _Atoms[_NUMGET_EOFF]))
    {       // 'e' or 'E', collect exponent
      *_Ptr++ = 'e', ++_First;
      _Seendigit = false, _Significant = 0;

      if (_First == _Last)
        ;       // 'e' or 'E' is last element
      else if (*_First == _Atoms[_NUMGET_SIGNOFF + 1])
        *_Ptr++ = '+', ++_First;        // gather plus sign
      else if (*_First == _Atoms[_NUMGET_SIGNOFF])
        *_Ptr++ = '-', ++_First;        // gather minus sign
      for (; _First != _Last && *_First == _Atoms[0]; )
        _Seendigit = true, ++_First;    // strip leading zeros
      if (_Seendigit)
        *_Ptr++ = '0';  // put one back
      for (;
           _First != _Last && (_Idx = _Find_elem(_Atoms, *_First)) < 10;
           _Seendigit = true, ++_First)
        if (_Significant < _MAX_EXP_DIG)
        {       // save a significant exponent digit
          *_Ptr++ = _Src[_Idx];
          ++_Significant;
        }
    }

    if (_Bad || !_Seendigit)
      _Ptr = _Ac;     // roll back pointer to indicate failure
    *_Ptr = '\0';
    return _Pten;
  }

 int _Getffldx(char *_Ac,
                _InIt& _First, _InIt &_Last,
                ios_base& _Iosbase, int *_Phexexp) const
  {       // get hex floating-point field from [_First, _Last) into _Ac
    const _Mypunct& _Punct_fac = use_facet< _Mypunct >(_IOS_BASE_GETLOC);
    const string _Grouping = _Punct_fac.grouping();

    enum {
      _NUMGET_SIGNOFF = 22,
      _NUMGET_XOFF = 24,
      _NUMGET_POFF = 26
    };
    static const char _Src[] = {"0123456789ABCDEFabcdef-+XxPp"};
    _Elem _Atoms[sizeof (_Src)];
    const ctype<_Elem>& _Ctype_fac =
      use_facet< ctype<_Elem> >(_IOS_BASE_GETLOC);
    _Ctype_fac.widen(&_Src[0], &_Src[sizeof (_Src)], _Atoms);

    char *_Ptr = _Ac;
    bool _Bad = false;
    size_t _Idx;

    if (_First == _Last)
      ;       // empty field
    else if (*_First == _Atoms[_NUMGET_SIGNOFF + 1])
      *_Ptr++ = '+', ++_First;        // gather plus sign
    else if (*_First == _Atoms[_NUMGET_SIGNOFF])
      *_Ptr++ = '-', ++_First;        // gather minus sign

    *_Ptr++ = '0';
    *_Ptr++ = 'x';

    bool _Seendigit = false;        // seen a digit in input
    int _Significant = 0;   // number of significant digits
    int _Phex = 0;  // power of 10 multiplier

    if (_First == _Last || *_First != _Atoms[0])
      ;
    else if (   ++_First != _Last
             && (   *_First == _Atoms[_NUMGET_XOFF + 1]
                 || *_First == _Atoms[_NUMGET_XOFF]))
      ++_First;       // discard any 0x or 0X
    else
      _Seendigit = true;      // '0' not followed by 'x' or 'X'

    const char *_Pg = &_Grouping[0];
    if (*_Pg == CHAR_MAX || *_Pg <= '\0')
      for (;
              _First != _Last
           && (_Idx = _Find_elem(_Atoms, *_First)) < _NUMGET_SIGNOFF;
           _Seendigit = true, ++_First)
        if (_MAX_SIG_DIG <= _Significant)
          ++_Phex;        // just scale by 10
        else if (_Idx == 0 && _Significant == 0)
          ;       // drop leading zeros
        else
        {       // save a significant digit
          *_Ptr++ = _Src[_Idx];
          ++_Significant;
        }
    else
    {       // grouping specified, gather digits and group sizes
      const _Elem _Kseparator =   _Grouping.size() == 0
                                ? (_Elem)0 : _Punct_fac.thousands_sep();
      string _Groups((size_t)1, '\0');
      size_t _Group = 0;

      for (; _First != _Last; ++_First)
        if ((_Idx = _Find_elem(_Atoms, *_First)) < _NUMGET_SIGNOFF)
        {       // got a digit, add to group size
          _Seendigit = true;
          if (_MAX_SIG_DIG <= _Significant)
            ++_Phex;        // just scale by 10
          else if (_Idx == 0 && _Significant == 0)
            ;       // drop leading zeros
          else
          {       // save a significant digit
            *_Ptr++ = _Src[_Idx];
            ++_Significant;
          }
          if (_Groups[_Group] != CHAR_MAX)
            ++_Groups[_Group];
        }
        else if (   _Groups[_Group] == '\0'
                 || _Kseparator == (_Elem)0
                 || *_First != _Kseparator)
          break;  // not a group separator, done
        else
        {       // add a new group to _Groups string
          _Groups.append((size_t)1, '\0');
          ++_Group;
        }
      if (_Group == 0)
        ;       // no thousands separators seen
      else if ('\0' < _Groups[_Group])
        ++_Group;       // add trailing group to group count
      else
        _Bad = true;    // trailing separator, fail

      while (!_Bad && 0 < _Group)
        if (*_Pg == CHAR_MAX)
          break;  // end of grouping constraints to check
        else if (   (0 < --_Group && *_Pg != _Groups[_Group])
                 || (0 == _Group && *_Pg < _Groups[_Group]))
          _Bad = true;    // bad group size, fail
        else if ('\0' < _Pg[1])
          ++_Pg;  // group size okay, advance to next test
    }

    if (_Seendigit && _Significant == 0)
      *_Ptr++ = '0';  // save at least one leading digit

    if (_First != _Last && *_First == _Punct_fac.decimal_point())
      *_Ptr++ = _LOCALE_DECIMAL_POINT, ++_First;     // add .

    if (_Significant == 0)
    {       // 0000. so far
      for (;
           _First != _Last && *_First == _Atoms[0];
           _Seendigit = true, ++_First)
        --_Phex;        // just count leading fraction zeros
      if (_Phex < 0)
        *_Ptr++ = '0', ++_Phex; // put one back
    }

    for (;
            _First != _Last
         && (_Idx = _Find_elem(_Atoms, *_First)) < _NUMGET_SIGNOFF;
         _Seendigit = true, ++_First)
      if (_Significant < _MAX_SIG_DIG)
      {       // save a significant fraction digit
        *_Ptr++ = _Src[_Idx];
        ++_Significant;
      }

    if (   _Seendigit && _First != _Last
        && (   *_First == _Atoms[_NUMGET_POFF + 1]
            || *_First == _Atoms[_NUMGET_POFF]))
    {       // 'p' or 'P', collect exponent
      *_Ptr++ = 'p', ++_First;
      _Seendigit = false, _Significant = 0;

      if (_First == _Last)
        ;       // 'p' or 'P' is last element
      else if (*_First == _Atoms[_NUMGET_SIGNOFF + 1])
        *_Ptr++ = '+', ++_First;        // gather plus sign
      else if (*_First == _Atoms[_NUMGET_SIGNOFF])
        *_Ptr++ = '-', ++_First;        // gather minus sign
      for (; _First != _Last && *_First == _Atoms[0]; )
        _Seendigit = true, ++_First;    // strip leading zeros
      if (_Seendigit)
        *_Ptr++ = '0';  // put one back
      for (; _First != _Last
             && (_Idx = _Find_elem(_Atoms, *_First)) < _NUMGET_SIGNOFF;
           _Seendigit = true, ++_First)
        if (_Significant < _MAX_EXP_DIG)
        {       // save a significant exponent digit
          *_Ptr++ = _Src[_Idx];
          ++_Significant;
        }
    }

    if (_Bad || !_Seendigit)
      _Ptr = _Ac;     // roll back pointer to indicate failure
    *_Ptr = '\0';
    *_Phexexp = _Phex;      // power of 16 multiplier
    return 0;     // power of 10 multiplier
  }

};

#if _DLIB_FULL_LOCALE_SUPPORT
  // STATIC num_get::id OBJECT
  template<class _Elem,
           class _InIt>
  locale::id num_get<_Elem, _InIt>::id;
#endif

// TEMPLATE CLASS num_put
template<class _Elem,
         class _OutIt = ostreambuf_iterator<_Elem, char_traits<_Elem> > >
class num_put
  #if _DLIB_FULL_LOCALE_SUPPORT
  : public locale::facet
  #endif
{       // facet for converting encoded numbers to text
public:
  typedef numpunct<_Elem> _Mypunct;
  typedef basic_string<_Elem, char_traits<_Elem>, allocator<_Elem> >
  _Mystr;

  #if _DLIB_FULL_LOCALE_SUPPORT
    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 num_put<_Elem, _OutIt>(_Ploc->_GetLocinfo());
//          _Locinfo(_Ploc->c_str()));
      return _X_NUMERIC;
    }

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

#if _DLIB_FULL_LOCALE_SUPPORT
protected:
#endif
  _VIRTUAL ~num_put() _NOEXCEPT
  {       // destroy the object
  }

protected:
  #if _DLIB_FULL_LOCALE_SUPPORT
    void _Init(const _Locinfo&)
    {       // initialize from _Locinfo object
    }
  #endif

public:
  #if _DLIB_FULL_LOCALE_SUPPORT
    explicit num_put(size_t _Refs = 0)
      : locale::facet(_Refs)
    {       // construct from current locale
      // Possibly lock thread
      _Locinfo _Lobj;
      _Init(_Lobj);
    }

    num_put(const _Locinfo& _Lobj, size_t _Refs = 0)
      : locale::facet(_Refs)
    {       // construct from specified locale
      _Init(_Lobj);
    }
  #else /* _DLIB_FULL_LOCALE_SUPPORT */
    explicit num_put()
    {
    }
  #endif /* _DLIB_FULL_LOCALE_SUPPORT */

  typedef _Elem char_type;
  typedef _OutIt iter_type;

  _OutIt put(_OutIt _Dest,
             ios_base& _Iosbase, _Elem _Fill, bool _Val) const
  {       // put formatted bool to _Dest
    #pragma library_requirement_override _Printf = qualifiers, flags
    return do_put(_Dest, _Iosbase, _Fill, _Val);
  }

  _OutIt put(_OutIt _Dest,
             ios_base& _Iosbase, _Elem _Fill, long _Val) const
  {       // put formatted long to _Dest
    #pragma library_requirement_override _Printf = qualifiers, flags
    return do_put(_Dest, _Iosbase, _Fill, _Val);
  }

  _OutIt put(_OutIt _Dest,
             ios_base& _Iosbase, _Elem _Fill, unsigned long _Val) const
  {       // put formatted unsigned long to _Dest
    #pragma library_requirement_override _Printf = qualifiers, flags
    return do_put(_Dest, _Iosbase, _Fill, _Val);
  }

  _OutIt put(_OutIt _Dest,
             ios_base& _Iosbase, _Elem _Fill, long long _Val) const
  {       // put formatted long long to _Dest
    #pragma library_requirement_override _Printf = qualifiers, flags, \
                                                   long_longs
    return do_put(_Dest, _Iosbase, _Fill, _Val);
  }

  _OutIt put(_OutIt _Dest,
             ios_base& _Iosbase, _Elem _Fill, unsigned long long _Val) const
  {       // put formatted unsigned long long to _Dest
    #pragma library_requirement_override _Printf = qualifiers, flags, \
                                                   long_longs
    return do_put(_Dest, _Iosbase, _Fill, _Val);
  }

  _OutIt put(_OutIt _Dest,
             ios_base& _Iosbase, _Elem _Fill, double _Val) const
  {       // put formatted double to _Dest
    #pragma library_requirement_override _Printf = qualifiers, flags, \
                                                widths, floats, hex_floats
    return do_put(_Dest, _Iosbase, _Fill, _Val);
  }

  _OutIt put(_OutIt _Dest,
             ios_base& _Iosbase, _Elem _Fill, long double _Val) const
  {       // put formatted long double to _Dest
    #pragma library_requirement_override _Printf = qualifiers, flags, \
                                                widths, floats, hex_floats
    return do_put(_Dest, _Iosbase, _Fill, _Val);
  }

  _OutIt put(_OutIt _Dest,
             ios_base& _Iosbase, _Elem _Fill, const void *_Val) const
  {       // put formatted void pointer to _Dest
    #pragma library_requirement_override _Printf =
    return do_put(_Dest, _Iosbase, _Fill, _Val);
  }

protected:
  _VIRTUAL _OutIt do_put(_OutIt _Dest,
                         ios_base& _Iosbase, _Elem _Fill, bool _Val) const
  {       // put formatted bool to _Dest
    _DEBUG_POINTER(_Dest);
    if (!(_Iosbase.flags() & ios_base::boolalpha))
      return do_put(_Dest, _Iosbase, _Fill, (long)_Val);
    else
    {       // put "false" or "true"
      const _Mypunct& _Punct_fac = use_facet< _Mypunct >(_IOS_BASE_GETLOC);
      _Mystr _Str;
      if (_Val)
        _Str.assign(_Punct_fac.truename());
      else
        _Str.assign(_Punct_fac.falsename());

      size_t _Fillcount =      _Iosbase.width() <= 0
                            || (size_t)_Iosbase.width() <= _Str.size()
                          ? 0 : (size_t)_Iosbase.width() - _Str.size();

      if ((_Iosbase.flags() & ios_base::adjustfield) != ios_base::left)
      {       // put leading fill
        _Dest = _Rep(_Dest, _Fill, _Fillcount);
        _Fillcount = 0;
      }
      _Dest = _Put(_Dest, _Str.c_str(), _Str.size()); // put field
      _Iosbase.width(0);
      return _Rep(_Dest, _Fill, _Fillcount);        // put trailing fill
    }
  }

  _VIRTUAL _OutIt do_put(_OutIt _Dest,
                         ios_base& _Iosbase, _Elem _Fill, long _Val) const
  {       // put formatted long to _Dest
    char _Buf[2 * _MAX_INT_DIG], _Fmt[6];
    _Ifmt(_Fmt, "ld", _Iosbase.flags());
    #pragma library_requirement_override _Printf =
    int _BufSize = ::sprintf(_Buf, _Fmt, _Val);
    return _Iput(_Dest, _Iosbase, _Fill, _Buf, _BufSize);
  }

  _VIRTUAL _OutIt do_put(_OutIt _Dest,
                      ios_base& _Iosbase, _Elem _Fill, unsigned long _Val) const
  {       // put formatted unsigned long to _Dest
    char _Buf[2 * _MAX_INT_DIG], _Fmt[6];
    _Ifmt(_Fmt, "lu", _Iosbase.flags());
    #pragma library_requirement_override _Printf =
    int _BufSize = ::sprintf(_Buf, _Fmt, _Val);
    return _Iput(_Dest, _Iosbase, _Fill, _Buf, _BufSize);
  }

  _VIRTUAL _OutIt do_put(_OutIt _Dest,
                       ios_base& _Iosbase, _Elem _Fill, long long _Val) const
  {       // put formatted long long to _Dest
    char _Buf[2 * _MAX_INT_DIG], _Fmt[8];
    _Ifmt(_Fmt, "Ld", _Iosbase.flags());
    #pragma library_requirement_override _Printf =
    int _BufSize = ::sprintf(_Buf, _Fmt, _Val);
    return _Iput(_Dest, _Iosbase, _Fill, _Buf, _BufSize);
  }

  _VIRTUAL _OutIt do_put(_OutIt _Dest,
                       ios_base& _Iosbase, _Elem _Fill, unsigned long long _Val) const
  {       // put formatted unsigned long long to _Dest
    char _Buf[2 * _MAX_INT_DIG], _Fmt[8];
    _Ifmt(_Fmt, "Lu", _Iosbase.flags());
    #pragma library_requirement_override _Printf =
    int _BufSize = ::sprintf(_Buf, _Fmt, _Val);
    return _Iput(_Dest, _Iosbase, _Fill, _Buf, _BufSize);
  }

#define MAXZEROS (__SIZE_T_MAX__ < 5000 ? 100 : 5000)

  __SOFTFP
  _VIRTUAL _OutIt do_put(_OutIt _Dest,
                         ios_base& _Iosbase, _Elem _Fill, double _Val) const
  {       // put formatted double to _Dest
    char _Buf[_MAX_EXP_DIG + _MAX_SIG_DIG + 64], _Fmt[8];
    streamsize _Precision =      _Iosbase.precision() <= 0
                              && !(_Iosbase.flags() & ios_base::fixed)
                            ? 6 : _Iosbase.precision();     // desired precision
    int _Significance =   _MAX_SIG_DIG < _Precision
                        ? _MAX_SIG_DIG : (int)_Precision;
                                                    // actual sprintf precision
    _Precision -= _Significance;
    size_t _Beforepoint = 0;        // zeros to add before decimal point
    size_t _Afterpoint = 0; // zeros to add after decimal point

    if (   (_Iosbase.flags() & ios_base::floatfield) == ios_base::fixed
        && _Val * 0.5 != _Val)  // skip -Inf, 0, Inf
    {       // scale silly fixed-point value
      bool _Signed = _Val < 0;
      if (_Signed)
        _Val = -_Val;

      for (; 1e35 <= _Val && _Beforepoint < MAXZEROS; _Beforepoint += 10)
        _Val /= 1e10;   // drop 10 zeros before decimal point

      if (0 < _Val)
        for (;
             10 <= _Precision && _Val <= 1e-35 && _Afterpoint < MAXZEROS;
             _Afterpoint += 10)
        {       // drop 10 zeros after decimal point
          _Val *= 1e10;
          _Precision -= 10;
        }

      if (_Signed)
        _Val = -_Val;
    }

    _Ffmt(_Fmt, 0, _Iosbase.flags());
    bool _Hexfloat = (_Iosbase.flags() & ios_base::fixed)
                  && (_Iosbase.flags() & ios_base::scientific);
    int _BufSize = 0;
    if (_Hexfloat)
    {
      #pragma library_requirement_override _Printf =
      _BufSize = ::sprintf(_Buf, _Fmt, _Val);
    }
    else
    {
      #pragma library_requirement_override _Printf =
      _BufSize = ::sprintf(_Buf, _Fmt, _Significance, _Val);
    }
    return _Fput(_Dest, _Iosbase, _Fill, _Buf, _Beforepoint, _Afterpoint,
                 _Precision, _BufSize); // convert and put
  }

  __SOFTFP
  _VIRTUAL _OutIt do_put(_OutIt _Dest,
                        ios_base& _Iosbase, _Elem _Fill, long double _Val) const
  {       // put formatted long double to _Dest
    char _Buf[_MAX_EXP_DIG + _MAX_SIG_DIG + 64], _Fmt[8];
    streamsize _Precision =      _Iosbase.precision() <= 0
                              && !(_Iosbase.flags() & ios_base::fixed)
                            ? 6 : _Iosbase.precision();     // desired precision
    int _Significance =   _MAX_SIG_DIG < _Precision
                        ? _MAX_SIG_DIG : (int)_Precision;
                                                    // actual sprintf precision
    _Precision -= _Significance;
    size_t _Beforepoint = 0;        // zeros to add before decimal point
    size_t _Afterpoint = 0; // zeros to add after decimal point

    if ((_Iosbase.flags() & ios_base::floatfield) == ios_base::fixed)
    {       // scale silly fixed-point value
      bool _Signed = _Val < 0;
      if (_Signed)
        _Val = -_Val;

      for (; 1e35 <= _Val && _Beforepoint < MAXZEROS; _Beforepoint += 10)
        _Val /= 1e10;   // drop 10 zeros before decimal point

      if (0 < _Val)
        for (;
             10 <= _Precision && _Val <= 1e-35 && _Afterpoint < MAXZEROS;
             _Afterpoint += 10)
        {       // drop 10 zeros after decimal point
          _Val *= 1e10;
          _Precision -= 10;
        }

      if (_Signed)
        _Val = -_Val;
    }

    _Ffmt(_Fmt, 'L', _Iosbase.flags());
    #pragma library_requirement_override _Printf =
    int _BufSize = ::sprintf(_Buf, _Fmt, _Significance, _Val);
    return _Fput(_Dest, _Iosbase, _Fill, _Buf, _Beforepoint, _Afterpoint,
                 _Precision, _BufSize); // convert and put
  }

  _VIRTUAL _OutIt do_put(_OutIt _Dest,
                       ios_base& _Iosbase, _Elem _Fill, const void *_Val) const
  {       // put formatted void pointer to _Dest
    char _Buf[2 * _MAX_INT_DIG];
    #pragma library_requirement_override _Printf =
    int _BufSize = ::sprintf(_Buf, "%p", _Val);
    return _Iput(_Dest, _Iosbase, _Fill, _Buf, _BufSize);
  }

private:
  char *_Ffmt(char *_Fmt,
              char _Spec, ios_base::fmtflags _Flags) const
  {       // generate sprintf format for floating-point
    char *_Ptr = _Fmt;
    *_Ptr++ = '%';

    if (_Flags & ios_base::showpos)
      *_Ptr++ = '+';
    if (_Flags & ios_base::showpoint)
      *_Ptr++ = '#';
    bool _Hexfloat = (_Flags & ios_base::fixed)
                  && (_Flags & ios_base::scientific);
    if (!_Hexfloat)
    {
      *_Ptr++ = '.';
      *_Ptr++ = '*';  // for precision argument
    }
    if (_Spec != '\0')
      *_Ptr++ = _Spec;        // 'L' qualifier for long double only

    ios_base::fmtflags _Ffl = _Flags & ios_base::floatfield;
    if (_Flags & ios_base::uppercase)
        *_Ptr++ = _Ffl == ios_base::fixed
      ? 'f' : _Ffl == ios_base::hexfloat
      ? 'A'      // added with TR1
            : _Ffl == ios_base::scientific
      ? 'E' : 'G';     // specifier
    else
        *_Ptr++ = _Ffl == ios_base::fixed
      ? 'f' : _Ffl == ios_base::hexfloat
      ? 'a'      // added with TR1
            : _Ffl == ios_base::scientific
      ? 'e' : 'g';     // specifier

    *_Ptr = '\0';
    return _Fmt;
  }

  _OutIt _Fput(_OutIt _Dest,
               ios_base& _Iosbase, _Elem _Fill, const char *_Buf,
               size_t _Beforepoint, size_t _Afterpoint,
               size_t _Trailing, size_t _Count) const
  {       // put formatted floating-point to _Dest
    _DEBUG_POINTER(_Dest);
    size_t _Prefix =   0 < _Count && (*_Buf == '+' || *_Buf == '-')
                     ? 1 : 0;

    const char *_Exps;
    if ((_Iosbase.flags() & ios_base::floatfield) != ios_base::hexfloat)
      _Exps = "eE";
    else
    {       // correct for hexadecimal floating-point
      _Exps = "pP";
      if (   _Prefix + 2 <= _Count && _Buf[_Prefix] == '0'
          && (_Buf[_Prefix + 1] == 'x' || _Buf[_Prefix + 1] == 'X'))
        _Prefix += 2;
    }
    const size_t _Eoff = ::strcspn(&_Buf[0], _Exps); // find exponent
    char _Dp[2] = {"."};
    _Dp[0] = _LOCALE_DECIMAL_POINT;
    const size_t _Poff = ::strcspn(&_Buf[0], &_Dp[0]);   // find decimal point

    const ctype<_Elem>& _Ctype_fac =
      use_facet< ctype<_Elem> >(_IOS_BASE_GETLOC);
    const _Elem _E0 = _Ctype_fac.widen('0');

    _Mystr _Groupstring(_Count, _Elem(0));  // reserve space
    _Ctype_fac.widen(&_Buf[0], &_Buf[_Count], &_Groupstring[0]);

    const _Mypunct& _Punct_fac = use_facet< _Mypunct >(_IOS_BASE_GETLOC);
    const string _Grouping = _Punct_fac.grouping();
    const _Elem _Kseparator = _Punct_fac.thousands_sep();

    size_t _Off = _Beforepoint;     // offset of (effective) decimal point
    if (_Poff == _Count)
    {       // no decimal point, ignore _Afterpoint and _Trailing
      _Off += _Eoff;
      _Groupstring.insert(_Eoff, _Beforepoint, _E0);
    }
    else
    {       // fill in zeros around decimal point
      _Off += _Poff;
      _Groupstring.insert(_Eoff, _Trailing, _E0);
      _Groupstring.insert(_Poff + 1, _Afterpoint, _E0);
      _Groupstring[_Poff] = _Punct_fac.decimal_point();
      _Groupstring.insert(_Poff, _Beforepoint, _E0);
    }

    const char *_Pg = &_Grouping[0];
    while (   *_Pg != CHAR_MAX && '\0' < *_Pg
           && (size_t)*_Pg < _Off - _Prefix)
    {       // add thousands separator
      _Groupstring.insert(_Off -= *_Pg, (size_t)1, _Kseparator);
      if ('\0' < _Pg[1])
        ++_Pg;  // not last group, advance
    }

    _Count = _Groupstring.size();
    size_t _Fillcount =      _Iosbase.width() <= 0
                          || (size_t)_Iosbase.width() <= _Count
                        ? 0 : (size_t)_Iosbase.width() - _Count;

    ios_base::fmtflags _Adjustfield = _Iosbase.flags() & ios_base::adjustfield;
    if (   _Adjustfield != ios_base::left
        && _Adjustfield != ios_base::internal)
    {       // put leading fill
      _Dest = _Rep(_Dest, _Fill, _Fillcount);
      _Fillcount = 0;
      _Dest = _Put(_Dest, &_Groupstring[0], _Prefix);
    }
    else if (_Adjustfield == ios_base::internal)
    {       // put internal fill
      _Dest = _Put(_Dest, &_Groupstring[0], _Prefix);
      _Dest = _Rep(_Dest, _Fill, _Fillcount);
      _Fillcount = 0;
    }
    else
      _Dest = _Put(_Dest, &_Groupstring[0], _Prefix);

    _Dest = _Put(_Dest, &_Groupstring[_Prefix], _Count - _Prefix);
    _Iosbase.width(0);
    return _Rep(_Dest, _Fill, _Fillcount);        // put trailing fill
  }

  char *_Ifmt(char *_Fmt,
              const char *_Spec, ios_base::fmtflags _Flags) const
  {       // generate sprintf format for integer
    char *_Ptr = _Fmt;
    *_Ptr++ = '%';

    if (_Flags & ios_base::showpos)
      *_Ptr++ = '+';
    if (_Flags & ios_base::showbase)
      *_Ptr++ = '#';
    if (_Spec[0] != 'L')
      *_Ptr++ = _Spec[0];     // qualifier
    else
    {       /* change L to ll */
      *_Ptr++ = 'l';
      *_Ptr++ = 'l';
    }

    ios_base::fmtflags _Basefield = _Flags & ios_base::basefield;
    *_Ptr++ =   _Basefield == ios_base::oct
              ? 'o' : _Basefield != ios_base::hex
              ? _Spec[1]        // 'd' or 'u'
                         : _Flags & ios_base::uppercase
              ? 'X' : 'x';
    *_Ptr = '\0';
    return _Fmt;
  }

  _OutIt _Iput(_OutIt _Dest,
               ios_base& _Iosbase, _Elem _Fill, char *_Buf, size_t _Count) const
  {       // put formatted integer to _Dest
    _DEBUG_POINTER(_Dest);
    size_t _Prefix =   0 < _Count && (*_Buf == '+' || *_Buf == '-')
                     ? 1 : 0;
    if (   (_Iosbase.flags() & ios_base::basefield) == ios_base::hex
        && _Prefix + 2 <= _Count && _Buf[_Prefix] == '0'
        && (_Buf[_Prefix + 1] == 'x' || _Buf[_Prefix + 1] == 'X'))
      _Prefix += 2;

    const ctype<_Elem>& _Ctype_fac =
      use_facet< ctype<_Elem> >(_IOS_BASE_GETLOC);
    _Mystr _Groupstring(_Count, _Elem(0));  // reserve space
    _Ctype_fac.widen(&_Buf[0], &_Buf[_Count], &_Groupstring[0]);

    const _Mypunct& _Punct_fac = use_facet< _Mypunct >(_IOS_BASE_GETLOC);
    const string _Grouping = _Punct_fac.grouping();
    const char *_Pg = &_Grouping[0];
    if (*_Pg != CHAR_MAX && '\0' < *_Pg)
    {       // grouping specified, add thousands separators
      const _Elem _Kseparator = _Punct_fac.thousands_sep();
      while (   *_Pg != CHAR_MAX
             && '\0' < *_Pg
             && (size_t)*_Pg < _Count - _Prefix)
      {       // insert thousands separator
        _Count -= *_Pg;
        _Groupstring.insert(_Count, 1, _Kseparator);
        if ('\0' < _Pg[1])
          ++_Pg;  // not last group, advance
      }
    }

    _Count = _Groupstring.size();
    size_t _Fillcount =       _Iosbase.width() <= 0
                           || (size_t)_Iosbase.width() <= _Count
                         ? 0 : (size_t)_Iosbase.width() - _Count;

    ios_base::fmtflags _Adjustfield = _Iosbase.flags() & ios_base::adjustfield;
    if (   _Adjustfield != ios_base::left
        && _Adjustfield != ios_base::internal)
    {       // put leading fill
      _Dest = _Rep(_Dest, _Fill, _Fillcount);
      _Fillcount = 0;
      _Dest = _Put(_Dest, &_Groupstring[0], _Prefix);
    }
    else if (_Adjustfield == ios_base::internal)
    {       // put internal fill
      _Dest = _Put(_Dest, &_Groupstring[0], _Prefix);
      _Dest = _Rep(_Dest, _Fill, _Fillcount);
      _Fillcount = 0;
    }
    else
      _Dest = _Put(_Dest, &_Groupstring[0], _Prefix);

    _Dest = _Put(_Dest, &_Groupstring[_Prefix], _Count - _Prefix);
    _Iosbase.width(0);
    return _Rep(_Dest, _Fill, _Fillcount);        // put trailing fill
  }

  _OutIt _Put(_OutIt _Dest,
              const _Elem *_Ptr, size_t _Count) const
  {       // put [_Ptr, _Ptr + _Count) to _Dest
    for (; 0 < _Count; --_Count, ++_Dest, ++_Ptr)
      *_Dest = *_Ptr;
    return _Dest;
  }

  _OutIt _Rep(_OutIt _Dest,
              _Elem _Ch, size_t _Count) const
  {       // put _Count * _Ch to _Dest
    for (; 0 < _Count; --_Count, ++_Dest)
      *_Dest = _Ch;
    return _Dest;
  }
};

#if _DLIB_FULL_LOCALE_SUPPORT
  // STATIC num_put::id OBJECT
  template<class _Elem,
           class _OutIt>
  locale::id num_put<_Elem, _OutIt>::id;
#endif

#undef _IOS_BASE_GETLOC
#undef _IOS_BASE_GETLOC2
#undef _LOC

} /* namespace std */

#endif /* _XLOCNUM_ */

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