// sstream standard header -*-c++-*-
// Copyright 2003-2017 IAR Systems AB.
#ifndef _SSTREAM_
#define _SSTREAM_

#ifndef _SYSTEM_BUILD
  #pragma system_include
#endif

#include <string>

namespace std {

// TEMPLATE CLASS basic_stringbuf
template<class _Elem,
         class _Traits,
         class _Alloc>
class basic_stringbuf
  : public basic_streambuf<_Elem, _Traits>
{       // stream buffer maintaining an allocated character array
public:
  typedef basic_stringbuf<_Elem, _Traits, _Alloc> _Myt;
  typedef _Alloc allocator_type;
  typedef basic_streambuf<_Elem, _Traits> _Mysb;
  typedef basic_string<_Elem, _Traits, _Alloc> _Mystr;

  explicit basic_stringbuf(ios_base::openmode _Mode =
                           ios_base::in | ios_base::out)
  {       // construct empty character buffer from mode
    _Init(0, 0, _Getstate(_Mode));
  }

  explicit basic_stringbuf(const _Mystr& _Str,
                       ios_base::openmode _Mode = ios_base::in | ios_base::out)
  {       // construct character buffer from string, mode
    _Init(_Str.c_str(), _Str.size(), _Getstate(_Mode));
  }

  basic_stringbuf(_Myt&& _Right)
  {       // construct by moving _Right
    _Assign_rv(std::forward<_Myt>(_Right));
  }

  _Myt& operator=(_Myt&& _Right)
  {       // assign from _Right
    _Assign_rv(std::forward<_Myt>(_Right));
    return *this;
  }

  void _Assign_rv(_Myt&& _Right)
  {       // assign by moving _Right
    if (this != &_Right)
    {       // different, worth moving
      _Tidy();
      this->swap(_Right);
    }
  }

  void swap(_Myt& _Right)
  {       // swap with _Right
    if (this != &_Right)
    {       // different, worth swapping
      _Mysb::swap(_Right);
      std::swap(_Seekhigh, _Right._Seekhigh);
      std::swap(_Mystate, _Right._Mystate);
      _Swap_adl(_Al, _Right._Al);
    }
  }

  basic_stringbuf(const _Myt&) = delete;
  _Myt& operator=(const _Myt&) = delete;

  virtual ~basic_stringbuf() _NOEXCEPT
  {       // destroy the object
    _Tidy();
  }

  enum
  {       // constants for bits in stream state
    _Allocated = 1, // set if character array storage has been allocated
    _Constant = 2,  // set if character array nonmutable
    _Noread = 4,    // set if character array cannot be read
    _Append = 8,    // set if all writes are appends
    _Atend = 16};   // set if initial writes are appends
  typedef int _Strstate;

  typedef typename _Traits::int_type int_type;
  typedef typename _Traits::pos_type pos_type;
  typedef typename _Traits::off_type off_type;

  _NOINLINE _Mystr str() const
  {       // return string copy of character array
    if (!(_Mystate & _Constant) && _Mysb::pptr() != 0)
    {       // writable, make string from write buffer
      _Mystr _Str(_Mysb::pbase(), (  _Seekhigh < _Mysb::pptr()
                                   ? _Mysb::pptr()
                                   : _Seekhigh) - _Mysb::pbase());
      return _Str;
    }
    else if (!(_Mystate & _Noread) && _Mysb::gptr() != 0)
    {       // readable, make string from read buffer
      _Mystr _Str(_Mysb::eback(), _Mysb::egptr() - _Mysb::eback());
      return _Str;
    }
    else
    {       // inaccessible, return empty string
      _Mystr _Nul;
      return _Nul;
    }
  }

  void str(const _Mystr& _Newstr)
  {       // replace character array from string
    _Tidy();
    _Init(_Newstr.c_str(), _Newstr.size(), _Mystate);
  }

protected:
  virtual int_type overflow(int_type _Meta = _Traits::eof())
  {       // put an element to stream
    if (_Mystate & _Constant)
      return _Traits::eof();        // array nonmutable, fail
    else if (_Traits::eq_int_type(_Traits::eof(), _Meta))
      return _Traits::not_eof(_Meta);       // EOF, return success code

    if (   _Mystate & _Append
        && _Mysb::pptr() != 0
        && _Mysb::pptr() < _Seekhigh)
      _Mysb::setp(_Mysb::pbase(), _Seekhigh, _Mysb::epptr());

    if (   _Mysb::pptr() != 0
        && _Mysb::pptr() < _Mysb::epptr())
    {       // room in buffer, store it
      *_Mysb::_Pninc() = _Traits::to_char_type(_Meta);
      return _Meta;
    }
    else
    {       // grow buffer and store element
      size_t _Oldsize =   _Mysb::pptr() == 0
                        ? 0
                        : _Mysb::epptr() - _Mysb::eback();
      size_t _Newsize = _Oldsize;
      size_t _Inc =   _Newsize / 2 < _MINSIZE
                    ? _MINSIZE
                    : _Newsize / 2;      // grow by 50 per cent

      while (0 < _Inc && INT_MAX - _Inc < _Newsize)
        _Inc /= 2;      // increment causes overflow, halve it
      if (_Inc == 0)
        return _Traits::eof();        // buffer can't grow, fail

      _Newsize += _Inc;

      _Elem *_Newptr = _Al.allocate(_Newsize);
      _Elem *_Oldptr = _Mysb::eback();

      if (0 < _Oldsize)
        _Traits::copy(_Newptr, _Oldptr, _Oldsize);

      if (_Oldsize == 0)
      {       // first growth, set up pointers
        _Seekhigh = _Newptr;
        _Mysb::setp(_Newptr, _Newptr + _Newsize);
        if (_Mystate & _Noread)
          _Mysb::setg(_Newptr, 0, _Newptr);
        else
          _Mysb::setg(_Newptr, _Newptr, _Newptr + 1);
      }
      else
      {       // not first growth, adjust pointers
        _Seekhigh = _Newptr + (_Seekhigh - _Oldptr);
        _Mysb::setp(_Newptr + (_Mysb::pbase() - _Oldptr),
                    _Newptr + (_Mysb::pptr() - _Oldptr),
                    _Newptr + _Newsize);
        if (_Mystate & _Noread)
          _Mysb::setg(_Newptr, 0, _Newptr);
        else
          _Mysb::setg(_Newptr,
                      _Newptr + (_Mysb::gptr() - _Oldptr),
                      _Mysb::pptr() + 1);
      }

      if (_Mystate & _Allocated)
        _Al.deallocate(_Oldptr, _Oldsize);
      _Mystate |= _Allocated;

      *_Mysb::_Pninc() = _Traits::to_char_type(_Meta);
      return _Meta;
    }
  }

  virtual int_type pbackfail(int_type _Meta = _Traits::eof())
  {       // put an element back to stream
    if (   _Mysb::gptr() == 0
        || _Mysb::gptr() <= _Mysb::eback()
        || (   !_Traits::eq_int_type(_Traits::eof(), _Meta)
            && !_Traits::eq(_Traits::to_char_type(_Meta), _Mysb::gptr()[-1])
            && _Mystate & _Constant))
      return _Traits::eof();        // can't put back, fail
    else
    {       // back up one position and store put-back character
      _Mysb::gbump(-1);
      if (!_Traits::eq_int_type(_Traits::eof(), _Meta))
        *_Mysb::gptr() = _Traits::to_char_type(_Meta);
      return _Traits::not_eof(_Meta);
    }
  }

  virtual int_type underflow()
  {       // get an element from stream, but don't point past it
    if (_Mysb::gptr() == 0)
      return _Traits::eof();        // no character buffer, fail
    else if (_Mysb::gptr() < _Mysb::egptr())
      return _Traits::to_int_type(*_Mysb::gptr());  // return buffered
    else if (   _Mystate & _Noread
             || _Mysb::pptr() == 0
             || (_Mysb::pptr() <= _Mysb::gptr() && _Seekhigh <= _Mysb::gptr()))
      return _Traits::eof();        // can't read, fail
    else
    {       // extend read buffer into written area, then return buffered
      if (_Seekhigh < _Mysb::pptr())
        _Seekhigh = _Mysb::pptr();
      _Mysb::setg(_Mysb::eback(), _Mysb::gptr(), _Seekhigh);
      return _Traits::to_int_type(*_Mysb::gptr());
    }
  }

  virtual pos_type seekoff(off_type _Off,
                           ios_base::seekdir _Way,
                       ios_base::openmode _Which = ios_base::in | ios_base::out)
  {       // change position by _Off, according to _Way, _Mode
    if (_Mysb::pptr() != 0 && _Seekhigh < _Mysb::pptr())
      _Seekhigh = _Mysb::pptr();      // update high-water pointer

    if (_Which & ios_base::in && _Mysb::gptr() != 0)
    {       // position within read buffer
      if (_Way == ios_base::end)
        _Off += (off_type)(_Seekhigh - _Mysb::eback());
      else if (   _Way == ios_base::cur
               && (_Which & ios_base::out) == 0)
        _Off += (off_type)(_Mysb::gptr() - _Mysb::eback());
      else if (_Way != ios_base::beg)
        _Off = _BADOFF;

      if (0 <= _Off && _Off <= _Seekhigh - _Mysb::eback())
      {       // change read position
        _Mysb::gbump((int)(_Mysb::eback() - _Mysb::gptr() + _Off));
        if (_Which & ios_base::out && _Mysb::pptr() != 0)
          _Mysb::setp(_Mysb::pbase(), _Mysb::gptr(),
                      _Mysb::epptr());        // change write position to match
      }
      else
        _Off = _BADOFF;
    }
    else if (_Which & ios_base::out && _Mysb::pptr() != 0)
    {       // position within write buffer
      if (_Way == ios_base::end)
        _Off += (off_type)(_Seekhigh - _Mysb::eback());
      else if (_Way == ios_base::cur)
        _Off += (off_type)(_Mysb::pptr() - _Mysb::eback());
      else if (_Way != ios_base::beg)
        _Off = _BADOFF;

      if (0 <= _Off && _Off <= _Seekhigh - _Mysb::eback())
        _Mysb::pbump((int)(_Mysb::eback()
                           - _Mysb::pptr() + _Off));   // change write position
      else
        _Off = _BADOFF;
    }
    else if (_Off != 0)
      _Off = _BADOFF; // neither read nor write buffer selected, fail
    return pos_type(_Off);
  }

  virtual pos_type seekpos(pos_type _Ptr,
                       ios_base::openmode _Mode = ios_base::in | ios_base::out)
  {       // change position to _Pos, according to _Mode
    streamoff _Off = (streamoff)_Ptr;
    if (_Mysb::pptr() != 0 && _Seekhigh < _Mysb::pptr())
      _Seekhigh = _Mysb::pptr();      // update high-water pointer

    if (_Off == _BADOFF)
      ;
    else if (_Mode & ios_base::in && _Mysb::gptr() != 0)
    {       // position within read buffer
      if (0 <= _Off && _Off <= _Seekhigh - _Mysb::eback())
      {       // change read position
        _Mysb::gbump((int)(_Mysb::eback() - _Mysb::gptr() + _Off));
        if (_Mode & ios_base::out && _Mysb::pptr() != 0)
          _Mysb::setp(_Mysb::pbase(), _Mysb::gptr(),
                      _Mysb::epptr());        // change write position to match
      }
      else
        _Off = _BADOFF;
    }
    else if (_Mode & ios_base::out && _Mysb::pptr() != 0)
    {       // position within write buffer
      if (0 <= _Off && _Off <= _Seekhigh - _Mysb::eback())
        _Mysb::pbump((int)(_Mysb::eback()
                           - _Mysb::pptr() + _Off));  // change write position
      else
        _Off = _BADOFF;
    }
    else
      _Off = _BADOFF; // neither read nor write buffer selected, fail
    return streampos(_Off);
  }

  void _Init(const _Elem *_Ptr,
             size_t _Count, _Strstate _State)
  {       // initialize buffer to [_Ptr, _Ptr + _Count), set state
    _Seekhigh = 0;
    _Mystate = _State;

    if (   _Count != 0
        && (_Mystate & (_Noread | _Constant)) != (_Noread | _Constant))
    {       // finite buffer that can be read or written, set it up
      _Elem *_Pnew = _Al.allocate(_Count);
      _Traits::copy(_Pnew, _Ptr, _Count);
      _Seekhigh = _Pnew + _Count;

      if (!(_Mystate & _Noread))
        _Mysb::setg(_Pnew, _Pnew, _Pnew + _Count);        // setup read buffer
      if (!(_Mystate & _Constant))
      {       // setup write buffer, and maybe read buffer
        _Mysb::setp(_Pnew,
                    (_Mystate & (_Atend | _Append)) ? _Pnew + _Count : _Pnew,
                    _Pnew + _Count);
        if (_Mysb::gptr() == 0)
          _Mysb::setg(_Pnew, 0, _Pnew);
      }
      _Mystate |= _Allocated;
    }
  }

  #pragma no_arith_checks
  void _Tidy()
  {       // discard any allocated buffer and clear pointers
    if (_Mystate & _Allocated)
      _Al.deallocate(_Mysb::eback(),
                     (  _Mysb::pptr() != 0
                      ? _Mysb::epptr()
                      : _Mysb::egptr()) - _Mysb::eback());
    _Mysb::setg(0, 0, 0);
    _Mysb::setp(0, 0);
    _Seekhigh = 0;
    _Mystate &= ~_Allocated;
  }

private:
  enum
  {       // constant for minimum buffer size
    _MINSIZE = 32};

  _Strstate _Getstate(ios_base::openmode _Mode)
  {       // convert open mode to stream state bits
    _Strstate _State = (_Strstate)0;
    if (!(_Mode & ios_base::in))
      _State |= _Noread;
    if (!(_Mode & ios_base::out))
      _State |= _Constant;
    if (_Mode & ios_base::app)
      _State |= _Append;
    if (_Mode & ios_base::ate)
      _State |= _Atend;
    return _State;
  }

  _Elem *_Seekhigh;       // the high-water pointer in character array
  _Strstate _Mystate;     // the stream state
  allocator_type _Al;     // the allocator object
};

// basic_stringbuf TEMPLATE OPERATORS
template<class _Elem,
         class _Traits,
         class _Alloc> inline
void swap(basic_stringbuf<_Elem, _Traits, _Alloc>& _Left,
          basic_stringbuf<_Elem, _Traits, _Alloc>& _Right)
{       // swap _Left and _Right basic_stringbufs
  _Left.swap(_Right);
}

// TEMPLATE CLASS basic_istringstream
template<class _Elem,
         class _Traits,
         class _Alloc>
class basic_istringstream
  : public basic_istream<_Elem, _Traits>
{       // input stream associated with a character array
public:
  typedef basic_istringstream<_Elem, _Traits, _Alloc> _Myt;
  typedef basic_istream<_Elem, _Traits> _Mybase;
  typedef _Alloc allocator_type;
  typedef basic_stringbuf<_Elem, _Traits, _Alloc> _Mysb;
  typedef basic_string<_Elem, _Traits, _Alloc> _Mystr;

  explicit basic_istringstream(ios_base::openmode _Mode = ios_base::in)
    : _Mybase(&_Stringbuffer),
      _Stringbuffer(_Mode | ios_base::in)
  {       // construct empty readable character buffer
  }

  explicit basic_istringstream(const _Mystr& _Str,
                               ios_base::openmode _Mode = ios_base::in)
    : _Mybase(&_Stringbuffer),
      _Stringbuffer(_Str, _Mode | ios_base::in)
  {       // construct readable character buffer from NTCS
  }

  basic_istringstream(_Myt&& _Right)
    : _Mybase(&_Stringbuffer)
  {       // construct by moving _Right
    _Assign_rv(std::forward<_Myt>(_Right));
  }

  _Myt& operator=(_Myt&& _Right)
  {       // move from _Right
    _Assign_rv(std::forward<_Myt>(_Right));
    return *this;
  }

  void _Assign_rv(_Myt&& _Right)
  {       // assign by moving _Right
    if (this != &_Right)
    {       // different, worth moving
      _Stringbuffer.str(_Mystr());
      this->swap(_Right);
    }
  }

  void swap(_Myt& _Right)
  {       // swap with _Right
    if (this != &_Right)
    {       // different, swap base and buffer
      _Mybase::swap(_Right);
      _Stringbuffer.swap(_Right._Stringbuffer);
    }
  }

  basic_istringstream(const _Myt&) = delete;
  _Myt& operator=(const _Myt&) = delete;

  virtual ~basic_istringstream() _NOEXCEPT
  {       // destroy the object
  }

  _Mysb *rdbuf() const
  {       // return pointer to file buffer
    return (_Mysb *)&_Stringbuffer;
  }

  _Mystr str() const
  {       // return string copy of character array
    return _Stringbuffer.str();
  }

  void str(const _Mystr& _Newstr)
  {       // replace character array from string
    _Stringbuffer.str(_Newstr);
  }

private:
  _Mysb _Stringbuffer;    // the string buffer
};

// basic_istringstream TEMPLATE OPERATORS
template<class _Elem,
         class _Traits,
         class _Alloc> inline
void swap(basic_istringstream<_Elem, _Traits, _Alloc>& _Left,
          basic_istringstream<_Elem, _Traits, _Alloc>& _Right)
{       // swap _Left and _Right basic_istringstreams
  _Left.swap(_Right);
}

// TEMPLATE CLASS basic_ostringstream
template<class _Elem,
         class _Traits,
         class _Alloc>
class basic_ostringstream
  : public basic_ostream<_Elem, _Traits>
{       // output stream associated with a character array
public:
  typedef basic_ostringstream<_Elem, _Traits, _Alloc> _Myt;
  typedef basic_ostream<_Elem, _Traits> _Mybase;
  typedef _Alloc allocator_type;
  typedef basic_stringbuf<_Elem, _Traits, _Alloc> _Mysb;
  typedef basic_string<_Elem, _Traits, _Alloc> _Mystr;

  explicit basic_ostringstream(ios_base::openmode _Mode = ios_base::out)
    : _Mybase(&_Stringbuffer),
      _Stringbuffer(_Mode | ios_base::out)
  {       // construct empty writable character buffer
  }

  explicit basic_ostringstream(const _Mystr& _Str,
                               ios_base::openmode _Mode = ios_base::out)
    : _Mybase(&_Stringbuffer),
      _Stringbuffer(_Str, _Mode | ios_base::out)
  {       // construct writable character buffer from NTCS
  }

  basic_ostringstream(_Myt&& _Right)
    : _Mybase(&_Stringbuffer)
  {       // construct by moving _Right
    _Assign_rv(std::forward<_Myt>(_Right));
  }

  _Myt& operator=(_Myt&& _Right)
  {       // move from _Right
    _Assign_rv(std::forward<_Myt>(_Right));
    return *this;
  }

  void _Assign_rv(_Myt&& _Right)
  {       // assign by moving _Right
    if (this != &_Right)
    {       // different, worth moving
      _Stringbuffer.str(_Mystr());
      this->swap(_Right);
    }
  }

  void swap(_Myt& _Right)
  {       // swap with _Right
    if (this != &_Right)
    {       // different, swap base and buffer
      _Mybase::swap(_Right);
      _Stringbuffer.swap(_Right._Stringbuffer);
    }
  }

  basic_ostringstream(const _Myt&) = delete;
  _Myt& operator=(const _Myt&) = delete;

  virtual ~basic_ostringstream() _NOEXCEPT
  {       // destroy the object
  }

  _Mysb *rdbuf() const
  {       // return pointer to buffer
    return (_Mysb *)&_Stringbuffer;
  }

  _Mystr str() const
  {       // return string copy of character array
    return _Stringbuffer.str();
  }

  void str(const _Mystr& _Newstr)
  {       // replace character array from string
    _Stringbuffer.str(_Newstr);
  }

private:
  _Mysb _Stringbuffer;    // the string buffer
};

// basic_ostringstream TEMPLATE OPERATORS
template<class _Elem,
         class _Traits,
         class _Alloc> inline
void swap(basic_ostringstream<_Elem, _Traits, _Alloc>& _Left,
          basic_ostringstream<_Elem, _Traits, _Alloc>& _Right)
{       // swap _Left and _Right basic_ostringstreams
  _Left.swap(_Right);
}

// TEMPLATE CLASS basic_stringstream
template<class _Elem,
         class _Traits,
         class _Alloc>
class basic_stringstream
  : public basic_iostream<_Elem, _Traits>
{       // input/output stream associated with a character array
public:
  typedef basic_stringstream<_Elem, _Traits, _Alloc> _Myt;
  typedef basic_iostream<_Elem, _Traits> _Mybase;
  typedef _Elem char_type;
  typedef _Traits traits_type;
  typedef _Alloc allocator_type;
  typedef typename _Traits::int_type int_type;
  typedef typename _Traits::pos_type pos_type;
  typedef typename _Traits::off_type off_type;
  typedef basic_stringbuf<_Elem, _Traits, _Alloc> _Mysb;
  typedef basic_string<_Elem, _Traits, _Alloc> _Mystr;

  explicit basic_stringstream(ios_base::openmode _Mode =
                              ios_base::in | ios_base::out)
    : _Mybase(&_Stringbuffer),
      _Stringbuffer(_Mode)
  {       // construct empty character buffer
  }

  explicit basic_stringstream(const _Mystr& _Str,
                        ios_base::openmode _Mode = ios_base::in | ios_base::out)
    : _Mybase(&_Stringbuffer),
      _Stringbuffer(_Str, _Mode)
  {       // construct character buffer from NTCS
  }

  basic_stringstream(_Myt&& _Right)
    : _Mybase(&_Stringbuffer)
  {       // construct by moving _Right
    _Assign_rv(std::forward<_Myt>(_Right));
  }

  _Myt& operator=(_Myt&& _Right)
  {       // move from _Right
    _Assign_rv(std::forward<_Myt>(_Right));
    return *this;
  }

  void _Assign_rv(_Myt&& _Right)
  {       // assign by moving _Right
    if (this != &_Right)
    {       // different, worth moving
      _Stringbuffer.str(_Mystr());
      this->swap(_Right);
    }
  }

  void swap(_Myt& _Right)
  {       // swap with _Right
    if (this != &_Right)
    {       // different, swap base and buffer
      _Mybase::swap(_Right);
      _Stringbuffer.swap(_Right._Stringbuffer);
    }
  }

  basic_stringstream(const _Myt&) = delete;
  _Myt& operator=(const _Myt&) = delete;

  virtual ~basic_stringstream() _NOEXCEPT
  {       // destroy the object
  }

  _Mysb *rdbuf() const
  {       // return pointer to buffer
    return (_Mysb *)&_Stringbuffer;
  }

  _Mystr str() const
  {       // return string copy of character array
    return _Stringbuffer.str();
  }

  void str(const _Mystr& _Newstr)
  {       // replace character array from string
    _Stringbuffer.str(_Newstr);
  }

private:
  _Mysb _Stringbuffer;    // the string buffer
};

// basic_stringstream TEMPLATE OPERATORS
template<class _Elem,
         class _Traits,
         class _Alloc> inline
void swap(basic_stringstream<_Elem, _Traits, _Alloc>& _Left,
          basic_stringstream<_Elem, _Traits, _Alloc>& _Right)
{       // swap _Left and _Right basic_stringstreams
  _Left.swap(_Right);
}

} /* namespace std */

#endif /* _SSTREAM_ */

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