1310 lines
37 KiB
Plaintext
1310 lines
37 KiB
Plaintext
// xstring internal header (from <string>)
|
|
#pragma once
|
|
#ifndef _XSTRING_
|
|
#define _XSTRING_
|
|
#include <xmemory>
|
|
|
|
#pragma pack(push,8)
|
|
#pragma warning(push,3)
|
|
#pragma warning(disable: 4251)
|
|
_STD_BEGIN
|
|
|
|
// CLASS _String_base
|
|
class _CRTIMP2 _String_base
|
|
{ // ultimate base class for basic_string to hold error reporters
|
|
public:
|
|
void _Xlen() const; // report a length_error
|
|
|
|
void _Xran() const; // report an out_of_range error
|
|
};
|
|
|
|
// TEMPLATE CLASS _String_val
|
|
template<class _Ty,
|
|
class _Alloc>
|
|
class _String_val
|
|
: public _String_base
|
|
{ // base class for basic_string to hold allocator _Alval
|
|
protected:
|
|
typedef typename _Alloc::_TEMPLATE_MEMBER
|
|
rebind<_Ty>::other _Alty;
|
|
|
|
_String_val(_Alty _Al = _Alty())
|
|
: _Alval(_Al)
|
|
{ // construct allocator from _Al
|
|
}
|
|
|
|
_Alty _Alval; // allocator object for strings
|
|
};
|
|
|
|
// TEMPLATE CLASS basic_string
|
|
template<class _Elem,
|
|
class _Traits = char_traits<_Elem>,
|
|
class _Ax = allocator<_Elem> >
|
|
class basic_string
|
|
: public _String_val<_Elem, _Ax>
|
|
{ // null-terminated transparent array of elements
|
|
public:
|
|
typedef basic_string<_Elem, _Traits, _Ax> _Myt;
|
|
typedef _String_val<_Elem, _Ax> _Mybase;
|
|
typedef typename _Mybase::_Alty _Alloc;
|
|
typedef typename _Alloc::size_type size_type;
|
|
typedef typename _Alloc::difference_type difference_type;
|
|
typedef typename _Alloc::pointer _Tptr;
|
|
typedef typename _Alloc::const_pointer _Ctptr;
|
|
typedef _Tptr pointer;
|
|
typedef _Ctptr const_pointer;
|
|
typedef typename _Alloc::reference reference;
|
|
typedef typename _Alloc::const_reference const_reference;
|
|
typedef typename _Alloc::value_type value_type;
|
|
typedef _Ptrit<value_type, difference_type, _Tptr,
|
|
reference, _Tptr, reference> iterator;
|
|
typedef _Ptrit<value_type, difference_type, _Ctptr,
|
|
const_reference, _Tptr, reference> const_iterator;
|
|
typedef std::reverse_iterator<iterator>
|
|
reverse_iterator;
|
|
typedef std::reverse_iterator<const_iterator>
|
|
const_reverse_iterator;
|
|
|
|
basic_string()
|
|
: _Mybase()
|
|
{ // construct empty string
|
|
_Tidy();
|
|
}
|
|
|
|
explicit basic_string(const _Alloc& _Al)
|
|
: _Mybase(_Al)
|
|
{ // construct empty string with allocator
|
|
_Tidy();
|
|
}
|
|
|
|
basic_string(const _Myt& _Right)
|
|
: _Mybase(_Right._Alval)
|
|
{ // construct by copying _Right
|
|
_Tidy();
|
|
assign(_Right, 0, npos);
|
|
}
|
|
|
|
basic_string(const _Myt& _Right, size_type _Roff,
|
|
size_type _Count = npos)
|
|
: _Mybase()
|
|
{ // construct from _Right [_Roff, _Roff + _Count)
|
|
_Tidy();
|
|
assign(_Right, _Roff, _Count);
|
|
}
|
|
|
|
basic_string(const _Myt& _Right, size_type _Roff, size_type _Count,
|
|
const _Alloc& _Al)
|
|
: _Mybase(_Al)
|
|
{ // construct from _Right [_Roff, _Roff + _Count) with allocator
|
|
_Tidy();
|
|
assign(_Right, _Roff, _Count);
|
|
}
|
|
|
|
basic_string(const _Elem *_Ptr, size_type _Count)
|
|
: _Mybase()
|
|
{ // construct from [_Ptr, _Ptr + _Count)
|
|
_Tidy();
|
|
assign(_Ptr, _Count);
|
|
}
|
|
|
|
basic_string(const _Elem *_Ptr, size_type _Count, const _Alloc& _Al)
|
|
: _Mybase(_Al)
|
|
{ // construct from [_Ptr, _Ptr + _Count) with allocator
|
|
_Tidy();
|
|
assign(_Ptr, _Count);
|
|
}
|
|
|
|
basic_string(const _Elem *_Ptr)
|
|
: _Mybase()
|
|
{ // construct from [_Ptr, <null>)
|
|
_Tidy();
|
|
assign(_Ptr);
|
|
}
|
|
|
|
basic_string(const _Elem *_Ptr, const _Alloc& _Al)
|
|
: _Mybase(_Al)
|
|
{ // construct from [_Ptr, <null>) with allocator
|
|
_Tidy();
|
|
assign(_Ptr);
|
|
}
|
|
|
|
basic_string(size_type _Count, _Elem _Ch)
|
|
: _Mybase()
|
|
{ // construct from _Count * _Ch
|
|
_Tidy();
|
|
assign(_Count, _Ch);
|
|
}
|
|
|
|
basic_string(size_type _Count, _Elem _Ch, const _Alloc& _Al)
|
|
: _Mybase(_Al)
|
|
{ // construct from _Count * _Ch with allocator
|
|
_Tidy();
|
|
assign(_Count, _Ch);
|
|
}
|
|
|
|
template<class _It>
|
|
basic_string(_It _First, _It _Last)
|
|
: _Mybase()
|
|
{ // construct from [_First, _Last)
|
|
_Tidy();
|
|
_Construct(_First, _Last, _Iter_cat(_First));
|
|
}
|
|
|
|
template<class _It>
|
|
basic_string(_It _First, _It _Last, const _Alloc& _Al)
|
|
: _Mybase(_Al)
|
|
{ // construct from [_First, _Last) with allocator
|
|
_Tidy();
|
|
_Construct(_First, _Last, _Iter_cat(_First));
|
|
}
|
|
|
|
template<class _It>
|
|
void _Construct(_It _Count, _It _Ch, _Int_iterator_tag)
|
|
{ // initialize from _Count * _Ch
|
|
assign((size_type)_Count, (_Elem)_Ch);
|
|
}
|
|
|
|
template<class _It>
|
|
void _Construct(_It _First, _It _Last, input_iterator_tag)
|
|
{ // initialize from [_First, _Last), input iterators
|
|
_TRY_BEGIN
|
|
for (; _First != _Last; ++_First)
|
|
append((size_type)1, (_Elem)*_First);
|
|
_CATCH_ALL
|
|
_Tidy(true);
|
|
_RERAISE;
|
|
_CATCH_END
|
|
}
|
|
|
|
template<class _It>
|
|
void _Construct(_It _First, _It _Last, forward_iterator_tag)
|
|
{ // initialize from [_First, _Last), forward iterators
|
|
size_type _Count = 0;
|
|
_Distance(_First, _Last, _Count);
|
|
reserve(_Count);
|
|
|
|
_TRY_BEGIN
|
|
for (; _First != _Last; ++_First)
|
|
append((size_type)1, (_Elem)*_First);
|
|
_CATCH_ALL
|
|
_Tidy(true);
|
|
_RERAISE;
|
|
_CATCH_END
|
|
}
|
|
|
|
basic_string(const_pointer _First, const_pointer _Last)
|
|
: _Mybase()
|
|
{ // construct from [_First, _Last), const pointers
|
|
_Tidy();
|
|
if (_First != _Last)
|
|
assign(&*_First, _Last - _First);
|
|
}
|
|
|
|
basic_string(const_iterator _First, const_iterator _Last)
|
|
: _Mybase()
|
|
{ // construct from [_First, _Last), const_iterators
|
|
_Tidy();
|
|
if (_First != _Last)
|
|
assign(&*_First, _Last - _First);
|
|
}
|
|
|
|
~basic_string()
|
|
{ // destroy the string
|
|
_Tidy(true);
|
|
}
|
|
|
|
typedef _Traits traits_type;
|
|
typedef _Alloc allocator_type;
|
|
|
|
static const size_type npos; // generic bad/missing length/position
|
|
|
|
_Myt& operator=(const _Myt& _Right)
|
|
{ // assign _Right
|
|
return (assign(_Right));
|
|
}
|
|
|
|
_Myt& operator=(const _Elem *_Ptr)
|
|
{ // assign [_Ptr, <null>)
|
|
return (assign(_Ptr));
|
|
}
|
|
|
|
_Myt& operator=(_Elem _Ch)
|
|
{ // assign 1 * _Ch
|
|
return (assign(1, _Ch));
|
|
}
|
|
|
|
_Myt& operator+=(const _Myt& _Right)
|
|
{ // append _Right
|
|
return (append(_Right));
|
|
}
|
|
|
|
_Myt& operator+=(const _Elem *_Ptr)
|
|
{ // append [_Ptr, <null>)
|
|
return (append(_Ptr));
|
|
}
|
|
|
|
_Myt& operator+=(_Elem _Ch)
|
|
{ // append 1 * _Ch
|
|
return (append((size_type)1, _Ch));
|
|
}
|
|
|
|
_Myt& append(const _Myt& _Right)
|
|
{ // append _Right
|
|
return (append(_Right, 0, npos));
|
|
}
|
|
|
|
_Myt& append(const _Myt& _Right, size_type _Roff, size_type _Count)
|
|
{ // append _Right [_Roff, _Roff + _Count)
|
|
if (_Right.size() < _Roff)
|
|
_String_base::_Xran(); // _Roff off end
|
|
size_type _Num = _Right.size() - _Roff;
|
|
if (_Num < _Count)
|
|
_Count = _Num; // trim _Count to size
|
|
if (npos - _Mysize <= _Count)
|
|
_String_base::_Xlen(); // result too long
|
|
|
|
if (0 < _Count && _Grow(_Num = _Mysize + _Count))
|
|
{ // make room and append new stuff
|
|
_Traits::copy(_Myptr() + _Mysize,
|
|
_Right._Myptr() + _Roff, _Count);
|
|
_Eos(_Num);
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
_Myt& append(const _Elem *_Ptr, size_type _Count)
|
|
{ // append [_Ptr, _Ptr + _Count)
|
|
if (_Inside(_Ptr))
|
|
return (append(*this, _Ptr - _Myptr(), _Count)); // substring
|
|
if (npos - _Mysize <= _Count)
|
|
_String_base::_Xlen(); // result too long
|
|
|
|
size_type _Num;
|
|
if (0 < _Count && _Grow(_Num = _Mysize + _Count))
|
|
{ // make room and append new stuff
|
|
_Traits::copy(_Myptr() + _Mysize, _Ptr, _Count);
|
|
_Eos(_Num);
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
_Myt& append(const _Elem *_Ptr)
|
|
{ // append [_Ptr, <null>)
|
|
return (append(_Ptr, _Traits::length(_Ptr)));
|
|
}
|
|
|
|
_Myt& append(size_type _Count, _Elem _Ch)
|
|
{ // append _Count * _Ch
|
|
if (npos - _Mysize <= _Count)
|
|
_String_base::_Xlen(); // result too long
|
|
|
|
size_type _Num;
|
|
if (0 < _Count && _Grow(_Num = _Mysize + _Count))
|
|
{ // make room and append new stuff using assign
|
|
_Traits::assign(_Myptr() + _Mysize, _Count, _Ch);
|
|
_Eos(_Num);
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
template<class _It>
|
|
_Myt& append(_It _First, _It _Last)
|
|
{ // append [_First, _Last)
|
|
return (_Append(_First, _Last, _Iter_cat(_First)));
|
|
}
|
|
|
|
template<class _It>
|
|
_Myt& _Append(_It _Count, _It _Ch, _Int_iterator_tag)
|
|
{ // append _Count * _Ch
|
|
return (append((size_type)_Count, (_Elem)_Ch));
|
|
}
|
|
|
|
template<class _It>
|
|
_Myt& _Append(_It _First, _It _Last, input_iterator_tag)
|
|
{ // append [_First, _Last), input iterators
|
|
return (replace(end(), end(), _First, _Last));
|
|
}
|
|
|
|
_Myt& append(const_pointer _First, const_pointer _Last)
|
|
{ // append [_First, _Last), const pointers
|
|
return (replace(end(), end(), _First, _Last));
|
|
}
|
|
|
|
_Myt& append(const_iterator _First, const_iterator _Last)
|
|
{ // append [_First, _Last), const_iterators
|
|
return (replace(end(), end(), _First, _Last));
|
|
}
|
|
|
|
_Myt& assign(const _Myt& _Right)
|
|
{ // assign _Right
|
|
return (assign(_Right, 0, npos));
|
|
}
|
|
|
|
_Myt& assign(const _Myt& _Right, size_type _Roff, size_type _Count)
|
|
{ // assign _Right [_Roff, _Roff + _Count)
|
|
if (_Right.size() < _Roff)
|
|
_String_base::_Xran(); // _Roff off end
|
|
size_type _Num = _Right.size() - _Roff;
|
|
if (_Count < _Num)
|
|
_Num = _Count; // trim _Num to size
|
|
|
|
if (this == &_Right)
|
|
erase((size_type)(_Roff + _Num)), erase(0, _Roff); // substring
|
|
else if (_Grow(_Num, true))
|
|
{ // make room and assign new stuff
|
|
_Traits::copy(_Myptr(), _Right._Myptr() + _Roff, _Num);
|
|
_Eos(_Num);
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
_Myt& assign(const _Elem *_Ptr, size_type _Num)
|
|
{ // assign [_Ptr, _Ptr + _Num)
|
|
if (_Inside(_Ptr))
|
|
return (assign(*this, _Ptr - _Myptr(), _Num)); // substring
|
|
|
|
if (_Grow(_Num, true))
|
|
{ // make room and assign new stuff
|
|
_Traits::copy(_Myptr(), _Ptr, _Num);
|
|
_Eos(_Num);
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
_Myt& assign(const _Elem *_Ptr)
|
|
{ // assign [_Ptr, <null>)
|
|
return (assign(_Ptr, _Traits::length(_Ptr)));
|
|
}
|
|
|
|
_Myt& assign(size_type _Count, _Elem _Ch)
|
|
{ // assign _Count * _Ch
|
|
if (_Count == npos)
|
|
_String_base::_Xlen(); // result too long
|
|
|
|
if (_Grow(_Count, true))
|
|
{ // make room and assign new stuff
|
|
_Traits::assign(_Myptr(), _Count, _Ch);
|
|
_Eos(_Count);
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
template<class _It>
|
|
_Myt& assign(_It _First, _It _Last)
|
|
{ // assign [First, _Last)
|
|
return (_Assign(_First, _Last, _Iter_cat(_First)));
|
|
}
|
|
|
|
template<class _It>
|
|
_Myt& _Assign(_It _Count, _It _Ch, _Int_iterator_tag)
|
|
{ // assign _Count * _Ch
|
|
return (assign((size_type)_Count, (_Elem)_Ch));
|
|
}
|
|
|
|
template<class _It>
|
|
_Myt& _Assign(_It _First, _It _Last, input_iterator_tag)
|
|
{ // assign [First, _Last), input iterators
|
|
return (replace(begin(), end(), _First, _Last));
|
|
}
|
|
|
|
_Myt& assign(const_pointer _First, const_pointer _Last)
|
|
{ // assign [First, _Last), const pointers
|
|
return (replace(begin(), end(), _First, _Last));
|
|
}
|
|
|
|
_Myt& assign(const_iterator _First, const_iterator _Last)
|
|
{ // assign [First, _Last), const_iterators
|
|
return (replace(begin(), end(), _First, _Last));
|
|
}
|
|
|
|
_Myt& insert(size_type _Off, const _Myt& _Right)
|
|
{ // insert _Right at _Off
|
|
return (insert(_Off, _Right, 0, npos));
|
|
}
|
|
|
|
_Myt& insert(size_type _Off, const _Myt& _Right, size_type _Roff,
|
|
size_type _Count)
|
|
{ // insert _Right [_Roff, _Roff + _Count) at _Off
|
|
if (_Mysize < _Off || _Right.size() < _Roff)
|
|
_String_base::_Xran(); // _Off or _Roff off end
|
|
size_type _Num = _Right.size() - _Roff;
|
|
if (_Num < _Count)
|
|
_Count = _Num; // trim _Count to size
|
|
if (npos - _Mysize <= _Count)
|
|
_String_base::_Xlen(); // result too long
|
|
|
|
if (0 < _Count && _Grow(_Num = _Mysize + _Count))
|
|
{ // make room and insert new stuff
|
|
_Traits::move(_Myptr() + _Off + _Count,
|
|
_Myptr() + _Off, _Mysize - _Off); // empty out hole
|
|
if (this == &_Right)
|
|
_Traits::move(_Myptr() + _Off,
|
|
_Myptr() + (_Off < _Roff ? _Roff + _Count : _Roff),
|
|
_Count); // substring
|
|
else
|
|
_Traits::copy(_Myptr() + _Off,
|
|
_Right._Myptr() + _Roff, _Count); // fill hole
|
|
_Eos(_Num);
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
_Myt& insert(size_type _Off, const _Elem *_Ptr, size_type _Count)
|
|
{ // insert [_Ptr, _Ptr + _Count) at _Off
|
|
if (_Inside(_Ptr))
|
|
return (insert(_Off, *this,
|
|
_Ptr - _Myptr(), _Count)); // substring
|
|
if (_Mysize < _Off)
|
|
_String_base::_Xran(); // _Off off end
|
|
if (npos - _Mysize <= _Count)
|
|
_String_base::_Xlen(); // result too long
|
|
size_type _Num;
|
|
if (0 < _Count && _Grow(_Num = _Mysize + _Count))
|
|
{ // make room and insert new stuff
|
|
_Traits::move(_Myptr() + _Off + _Count,
|
|
_Myptr() + _Off, _Mysize - _Off); // empty out hole
|
|
_Traits::copy(_Myptr() + _Off, _Ptr, _Count); // fill hole
|
|
_Eos(_Num);
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
_Myt& insert(size_type _Off, const _Elem *_Ptr)
|
|
{ // insert [_Ptr, <null>) at _Off
|
|
return (insert(_Off, _Ptr, _Traits::length(_Ptr)));
|
|
}
|
|
|
|
_Myt& insert(size_type _Off, size_type _Count, _Elem _Ch)
|
|
{ // insert _Count * _Ch at _Off
|
|
if (_Mysize < _Off)
|
|
_String_base::_Xran(); // _Off off end
|
|
if (npos - _Mysize <= _Count)
|
|
_String_base::_Xlen(); // result too long
|
|
size_type _Num;
|
|
if (0 < _Count && _Grow(_Num = _Mysize + _Count))
|
|
{ // make room and insert new stuff
|
|
_Traits::move(_Myptr() + _Off + _Count,
|
|
_Myptr() + _Off, _Mysize - _Off); // empty out hole
|
|
_Traits::assign(_Myptr() + _Off, _Count, _Ch); // fill hole
|
|
_Eos(_Num);
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
iterator insert(iterator _Where)
|
|
{ // insert <null> at _Where
|
|
return (insert(_Where, _Elem()));
|
|
}
|
|
|
|
iterator insert(iterator _Where, _Elem _Ch)
|
|
{ // insert _Ch at _Where
|
|
size_type _Off = _Pdif(_Where, begin());
|
|
insert(_Off, 1, _Ch);
|
|
return (begin() + _Off);
|
|
}
|
|
|
|
void insert(iterator _Where, size_type _Count, _Elem _Ch)
|
|
{ // insert _Count * _Elem at _Where
|
|
size_type _Off = _Pdif(_Where, begin());
|
|
insert(_Off, _Count, _Ch);
|
|
}
|
|
|
|
template<class _It>
|
|
void insert(iterator _Where, _It _First, _It _Last)
|
|
{ // insert [_First, _Last) at _Where
|
|
_Insert(_Where, _First, _Last, _Iter_cat(_First));
|
|
}
|
|
|
|
template<class _It>
|
|
void _Insert(iterator _Where, _It _Count, _It _Ch,
|
|
_Int_iterator_tag)
|
|
{ // insert _Count * _Ch at _Where
|
|
insert(_Where, (size_type)_Count, (_Elem)_Ch);
|
|
}
|
|
|
|
template<class _It>
|
|
void _Insert(iterator _Where, _It _First, _It _Last,
|
|
input_iterator_tag)
|
|
{ // insert [_First, _Last) at _Where, input iterators
|
|
replace(_Where, _Where, _First, _Last);
|
|
}
|
|
|
|
void insert(iterator _Where, const_pointer _First, const_pointer _Last)
|
|
{ // insert [_First, _Last) at _Where, const pointers
|
|
replace(_Where, _Where, _First, _Last);
|
|
}
|
|
|
|
void insert(iterator _Where, const_iterator _First, const_iterator _Last)
|
|
{ // insert [_First, _Last) at _Where, const_iterators
|
|
replace(_Where, _Where, _First, _Last);
|
|
}
|
|
|
|
_Myt& erase(size_type _Off = 0, size_type _Count = npos)
|
|
{ // erase elements [_Off, _Off + _Count)
|
|
if (_Mysize < _Off)
|
|
_String_base::_Xran(); // _Off off end
|
|
if (_Mysize - _Off < _Count)
|
|
_Count = _Mysize - _Off; // trim _Count
|
|
if (0 < _Count)
|
|
{ // move elements down
|
|
_Traits::move(_Myptr() + _Off, _Myptr() + _Off + _Count,
|
|
_Mysize - _Off - _Count);
|
|
size_type _Newsize = _Mysize - _Count;
|
|
if (_Grow(_Newsize))
|
|
_Eos(_Newsize);
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
iterator erase(iterator _Where)
|
|
{ // erase element at _Where
|
|
size_type _Count = _Pdif(_Where, begin());
|
|
erase(_Count, 1);
|
|
return (iterator(_Myptr() + _Count));
|
|
}
|
|
|
|
iterator erase(iterator _First, iterator _Last)
|
|
{ // erase substring [_First, _Last)
|
|
size_type _Count = _Pdif(_First, begin());
|
|
erase(_Count, _Pdif(_Last, _First));
|
|
return (iterator(_Myptr() + _Count));
|
|
}
|
|
|
|
void clear()
|
|
{ // erase all
|
|
erase(begin(), end());
|
|
}
|
|
|
|
_Myt& replace(size_type _Off, size_type _N0, const _Myt& _Right)
|
|
{ // replace [_Off, _Off + _N0) with _Right
|
|
return (replace(_Off, _N0, _Right, 0, npos));
|
|
}
|
|
|
|
_Myt& replace(size_type _Off, size_type _N0, const _Myt& _Right,
|
|
size_type _Roff, size_type _Count)
|
|
{ // replace [_Off, _Off + _N0) with _Right [_Roff, _Roff + _Count)
|
|
if (_Mysize < _Off || _Right.size() < _Roff)
|
|
_String_base::_Xran(); // _Off or _Roff off end
|
|
if (_Mysize - _Off < _N0)
|
|
_N0 = _Mysize - _Off; // trim _N0 to size
|
|
size_type _Num = _Right.size() - _Roff;
|
|
if (_Num < _Count)
|
|
_Count = _Num; // trim _Count to size
|
|
if (npos - _Count <= _Mysize - _N0)
|
|
_String_base::_Xlen(); // result too long
|
|
|
|
size_type _Nm = _Mysize - _N0 - _Off; // length of preserved tail
|
|
size_type _Newsize = _Mysize + _Count - _N0;
|
|
if (_Mysize < _Newsize)
|
|
_Grow(_Newsize);
|
|
|
|
if (this != &_Right)
|
|
{ // no overlap, just move down and copy in new stuff
|
|
_Traits::move(_Myptr() + _Off + _Count,
|
|
_Myptr() + _Off + _N0, _Nm); // empty hole
|
|
_Traits::copy(_Myptr() + _Off,
|
|
_Right._Myptr() + _Roff, _Count); // fill hole
|
|
}
|
|
else if (_Count <= _N0)
|
|
{ // hole doesn't get larger, just copy in substring
|
|
_Traits::move(_Myptr() + _Off,
|
|
_Myptr() + _Roff, _Count); // fill hole
|
|
_Traits::move(_Myptr() + _Off + _Count,
|
|
_Myptr() + _Off + _N0, _Nm); // move tail down
|
|
}
|
|
else if (_Roff <= _Off)
|
|
{ // hole gets larger, substring begins before hole
|
|
_Traits::move(_Myptr() + _Off + _Count,
|
|
_Myptr() + _Off + _N0, _Nm); // move tail down
|
|
_Traits::move(_Myptr() + _Off,
|
|
_Myptr() + _Roff, _Count); // fill hole
|
|
}
|
|
else if (_Off + _N0 <= _Roff)
|
|
{ // hole gets larger, substring begins after hole
|
|
_Traits::move(_Myptr() + _Off + _Count,
|
|
_Myptr() + _Off + _N0, _Nm); // move tail down
|
|
_Traits::move(_Myptr() + _Off,
|
|
_Myptr() + (_Roff + _Count - _N0), _Count); // fill hole
|
|
}
|
|
else
|
|
{ // hole gets larger, substring begins in hole
|
|
_Traits::move(_Myptr() + _Off,
|
|
_Myptr() + _Roff, _N0); // fill old hole
|
|
_Traits::move(_Myptr() + _Off + _Count,
|
|
_Myptr() + _Off + _N0, _Nm); // move tail down
|
|
_Traits::move(_Myptr() + _Off + _N0, _Myptr() + _Roff + _Count,
|
|
_Count - _N0); // fill rest of new hole
|
|
}
|
|
|
|
if (_Mysize < _Newsize || _Grow(_Newsize))
|
|
_Eos(_Newsize); // truncate if need be and terminate
|
|
return (*this);
|
|
}
|
|
|
|
_Myt& replace(size_type _Off, size_type _N0, const _Elem *_Ptr,
|
|
size_type _Count)
|
|
{ // replace [_Off, _Off + _N0) with [_Ptr, _Ptr + _Count)
|
|
if (_Inside(_Ptr))
|
|
return (replace(_Off, _N0, *this,
|
|
_Ptr - _Myptr(), _Count)); // substring, replace carefully
|
|
if (_Mysize < _Off)
|
|
_String_base::_Xran(); // _Off off end
|
|
if (_Mysize - _Off < _N0)
|
|
_N0 = _Mysize - _Off; // trim _N0 to size
|
|
if (npos - _Count <= _Mysize - _N0)
|
|
_String_base::_Xlen(); // result too long
|
|
size_type _Nm = _Mysize - _N0 - _Off;
|
|
|
|
if (_Count < _N0)
|
|
_Traits::move(_Myptr() + _Off + _Count,
|
|
_Myptr() + _Off + _N0, _Nm); // smaller hole, move tail up
|
|
size_type _Num;
|
|
if ((0 < _Count || 0 < _N0) && _Grow(_Num = _Mysize + _Count - _N0))
|
|
{ // make room and rearrange
|
|
if (_N0 < _Count)
|
|
_Traits::move(_Myptr() + _Off + _Count,
|
|
_Myptr() + _Off + _N0, _Nm); // move tail down
|
|
_Traits::copy(_Myptr() + _Off, _Ptr, _Count); // fill hole
|
|
_Eos(_Num);
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
_Myt& replace(size_type _Off, size_type _N0, const _Elem *_Ptr)
|
|
{ // replace [_Off, _Off + _N0) with [_Ptr, <null>)
|
|
return (replace(_Off, _N0, _Ptr, _Traits::length(_Ptr)));
|
|
}
|
|
|
|
_Myt& replace(size_type _Off, size_type _N0,
|
|
size_type _Count, _Elem _Ch)
|
|
{ // replace [_Off, _Off + _N0) with _Count * _Ch
|
|
if (_Mysize < _Off)
|
|
_String_base::_Xran(); // _Off off end
|
|
if (_Mysize - _Off < _N0)
|
|
_N0 = _Mysize - _Off; // trim _N0 to size
|
|
if (npos - _Count <= _Mysize - _N0)
|
|
_String_base::_Xlen(); // result too long
|
|
size_type _Nm = _Mysize - _N0 - _Off;
|
|
|
|
if (_Count < _N0)
|
|
_Traits::move(_Myptr() + _Off + _Count,
|
|
_Myptr() + _Off + _N0, _Nm); // smaller hole, move tail up
|
|
size_type _Num;
|
|
if ((0 < _Count || 0 < _N0) && _Grow(_Num = _Mysize + _Count - _N0))
|
|
{ // make room and rearrange
|
|
if (_N0 < _Count)
|
|
_Traits::move(_Myptr() + _Off + _Count,
|
|
_Myptr() + _Off + _N0, _Nm); // move tail down
|
|
_Traits::assign(_Myptr() + _Off, _Count, _Ch); // fill hole
|
|
_Eos(_Num);
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
_Myt& replace(iterator _First, iterator _Last, const _Myt& _Right)
|
|
{ // replace [_First, _Last) with _Right
|
|
return (replace(
|
|
_Pdif(_First, begin()), _Pdif(_Last, _First), _Right));
|
|
}
|
|
|
|
_Myt& replace(iterator _First, iterator _Last, const _Elem *_Ptr,
|
|
size_type _Count)
|
|
{ // replace [_First, _Last) with [_Ptr, _Ptr + _Count)
|
|
return (replace(
|
|
_Pdif(_First, begin()), _Pdif(_Last, _First), _Ptr, _Count));
|
|
}
|
|
|
|
_Myt& replace(iterator _First, iterator _Last, const _Elem *_Ptr)
|
|
{ // replace [_First, _Last) with [_Ptr, <null>)
|
|
return (replace(
|
|
_Pdif(_First, begin()), _Pdif(_Last, _First), _Ptr));
|
|
}
|
|
|
|
_Myt& replace(iterator _First, iterator _Last,
|
|
size_type _Count, _Elem _Ch)
|
|
{ // replace [_First, _Last) with _Count * _Ch
|
|
return (replace(
|
|
_Pdif(_First, begin()), _Pdif(_Last, _First), _Count, _Ch));
|
|
}
|
|
|
|
template<class _It>
|
|
_Myt& replace(iterator _First, iterator _Last,
|
|
_It _First2, _It _Last2)
|
|
{ // replace [_First, _Last) with [_First2, _Last2)
|
|
return (_Replace(_First, _Last,
|
|
_First2, _Last2, _Iter_cat(_First2)));
|
|
}
|
|
|
|
template<class _It>
|
|
_Myt& _Replace(iterator _First, iterator _Last,
|
|
_It _Count, _It _Ch, _Int_iterator_tag)
|
|
{ // replace [_First, _Last) with _Count * _Ch
|
|
return (replace(_First, _Last, (size_type)_Count, (_Elem)_Ch));
|
|
}
|
|
|
|
template<class _It>
|
|
_Myt& _Replace(iterator _First, iterator _Last,
|
|
_It _First2, _It _Last2, input_iterator_tag)
|
|
{ // replace [_First, _Last) with [_First2, _Last2), input iterators
|
|
_Myt _Right(_First2, _Last2);
|
|
replace(_First, _Last, _Right);
|
|
return (*this);
|
|
}
|
|
|
|
_Myt& replace(iterator _First, iterator _Last,
|
|
const_pointer _First2, const_pointer _Last2)
|
|
{ // replace [_First, _Last) with [_First2, _Last2), const pointers
|
|
if (_First2 == _Last2)
|
|
erase(_Pdif(_First, begin()), _Pdif(_Last, _First));
|
|
else
|
|
replace(_Pdif(_First, begin()), _Pdif(_Last, _First),
|
|
&*_First2, _Last2 - _First2);
|
|
return (*this);
|
|
}
|
|
|
|
_Myt& replace(iterator _First, iterator _Last,
|
|
const_iterator _First2, const_iterator _Last2)
|
|
{ // replace [_First, _Last) with [_First2, _Last2), const_iterators
|
|
if (_First2 == _Last2)
|
|
erase(_Pdif(_First, begin()), _Pdif(_Last, _First));
|
|
else
|
|
replace(_Pdif(_First, begin()), _Pdif(_Last, _First),
|
|
&*_First2, _Last2 - _First2);
|
|
return (*this);
|
|
}
|
|
|
|
iterator begin()
|
|
{ // return iterator for beginning of mutable sequence
|
|
return (iterator(_Myptr()));
|
|
}
|
|
|
|
const_iterator begin() const
|
|
{ // return iterator for beginning of nonmutable sequence
|
|
return (const_iterator(_Myptr()));
|
|
}
|
|
|
|
iterator end()
|
|
{ // return iterator for end of mutable sequence
|
|
return (iterator(_Myptr() + _Mysize));
|
|
}
|
|
|
|
const_iterator end() const
|
|
{ // return iterator for end of nonmutable sequence
|
|
return (const_iterator(_Myptr() + _Mysize));
|
|
}
|
|
|
|
reverse_iterator rbegin()
|
|
{ // return iterator for beginning of reversed mutable sequence
|
|
return (reverse_iterator(end()));
|
|
}
|
|
|
|
const_reverse_iterator rbegin() const
|
|
{ // return iterator for beginning of reversed nonmutable sequence
|
|
return (const_reverse_iterator(end()));
|
|
}
|
|
|
|
reverse_iterator rend()
|
|
{ // return iterator for end of reversed mutable sequence
|
|
return (reverse_iterator(begin()));
|
|
}
|
|
|
|
const_reverse_iterator rend() const
|
|
{ // return iterator for end of reversed nonmutable sequence
|
|
return (const_reverse_iterator(begin()));
|
|
}
|
|
|
|
reference at(size_type _Off)
|
|
{ // subscript mutable sequence with checking
|
|
if (_Mysize <= _Off)
|
|
_String_base::_Xran(); // _Off off end
|
|
return (_Myptr()[_Off]);
|
|
}
|
|
|
|
const_reference at(size_type _Off) const
|
|
{ // subscript nonmutable sequence with checking
|
|
if (_Mysize <= _Off)
|
|
_String_base::_Xran(); // _Off off end
|
|
return (_Myptr()[_Off]);
|
|
}
|
|
|
|
reference operator[](size_type _Off)
|
|
{ // subscript mutable sequence
|
|
return (_Myptr()[_Off]);
|
|
}
|
|
|
|
const_reference operator[](size_type _Off) const
|
|
{ // subscript nonmutable sequence
|
|
return (_Myptr()[_Off]);
|
|
}
|
|
|
|
void push_back(_Elem _Ch)
|
|
{ // insert element at end
|
|
insert(end(), _Ch);
|
|
}
|
|
|
|
const _Elem *c_str() const
|
|
{ // return pointer to null-terminated nonmutable array
|
|
return (_Myptr());
|
|
}
|
|
|
|
const _Elem *data() const
|
|
{ // return pointer to nonmutable array
|
|
return (c_str());
|
|
}
|
|
|
|
size_type length() const
|
|
{ // return length of sequence
|
|
return (_Mysize);
|
|
}
|
|
|
|
size_type size() const
|
|
{ // return length of sequence
|
|
return (_Mysize);
|
|
}
|
|
|
|
size_type max_size() const
|
|
{ // return maximum possible length of sequence
|
|
size_type _Num = _Mybase::_Alval.max_size();
|
|
return (_Num <= 1 ? 1 : _Num - 1);
|
|
}
|
|
|
|
void resize(size_type _Newsize)
|
|
{ // determine new length, padding with null elements as needed
|
|
resize(_Newsize, _Elem());
|
|
}
|
|
|
|
void resize(size_type _Newsize, _Elem _Ch)
|
|
{ // determine new length, padding with _Ch elements as needed
|
|
if (_Newsize <= _Mysize)
|
|
erase(_Newsize);
|
|
else
|
|
append(_Newsize - _Mysize, _Ch);
|
|
}
|
|
|
|
size_type capacity() const
|
|
{ // return current length of allocated storage
|
|
return (_Myres);
|
|
}
|
|
|
|
void reserve(size_type _Newcap = 0)
|
|
{ // determine new minimum length of allocated storage
|
|
if (_Myres < _Newcap)
|
|
_Grow(_Newcap);
|
|
}
|
|
|
|
bool empty() const
|
|
{ // test if sequence is empty
|
|
return (_Mysize == 0);
|
|
}
|
|
|
|
size_type copy(_Elem *_Ptr, size_type _Count, size_type _Off = 0) const
|
|
{ // copy [_Off, _Off + _Count) to [_Ptr, _Ptr + _Count)
|
|
if (_Mysize < _Off)
|
|
_String_base::_Xran(); // _Off off end
|
|
if (_Mysize - _Off < _Count)
|
|
_Count = _Mysize - _Off;
|
|
_Traits::copy(_Ptr, _Myptr() + _Off, _Count);
|
|
return (_Count);
|
|
}
|
|
|
|
void swap(_Myt& _Right)
|
|
{ // exchange contents with _Right
|
|
if (_Mybase::_Alval == _Right._Alval)
|
|
{ // same allocator, swap control information
|
|
_Bxty _Tbx = _Bx;
|
|
_Bx = _Right._Bx, _Right._Bx = _Tbx;
|
|
|
|
size_type _Tlen = _Mysize;
|
|
_Mysize = _Right._Mysize, _Right._Mysize = _Tlen;
|
|
|
|
size_type _Tres = _Myres;
|
|
_Myres = _Right._Myres, _Right._Myres = _Tres;
|
|
}
|
|
else
|
|
{ // different allocator, do multiple assigns
|
|
_Myt _Tmp = *this; *this = _Right, _Right = _Tmp;
|
|
}
|
|
}
|
|
|
|
friend void swap(_Myt& _Left, _Myt& _Right)
|
|
{ // swap _Left and _Right strings
|
|
_Left.swap(_Right);
|
|
}
|
|
|
|
size_type find(const _Myt& _Right, size_type _Off = 0) const
|
|
{ // look for _Right beginnng at or after _Off
|
|
return (find(_Right._Myptr(), _Off, _Right.size()));
|
|
}
|
|
|
|
size_type find(const _Elem *_Ptr, size_type _Off,
|
|
size_type _Count) const
|
|
{ // look for [_Ptr, _Ptr + _Count) beginnng at or after _Off
|
|
if (_Count == 0 && _Off <= _Mysize)
|
|
return (_Off); // null string always matches (if inside string)
|
|
|
|
size_type _Nm;
|
|
if (_Off < _Mysize && _Count <= (_Nm = _Mysize - _Off))
|
|
{ // room for match, look for it
|
|
const _Elem *_Uptr, *_Vptr;
|
|
for (_Nm -= _Count - 1, _Vptr = _Myptr() + _Off;
|
|
(_Uptr = _Traits::find(_Vptr, _Nm, *_Ptr)) != 0;
|
|
_Nm -= _Uptr - _Vptr + 1, _Vptr = _Uptr + 1)
|
|
if (_Traits::compare(_Uptr, _Ptr, _Count) == 0)
|
|
return (_Uptr - _Myptr()); // found a match
|
|
}
|
|
|
|
return (npos); // no match
|
|
}
|
|
|
|
size_type find(const _Elem *_Ptr, size_type _Off = 0) const
|
|
{ // look for [_Ptr, <null>) beginnng at or after _Off
|
|
return (find(_Ptr, _Off, _Traits::length(_Ptr)));
|
|
}
|
|
|
|
size_type find(_Elem _Ch, size_type _Off = 0) const
|
|
{ // look for _Ch at or after _Off
|
|
return (find((const _Elem *)&_Ch, _Off, 1));
|
|
}
|
|
|
|
size_type rfind(const _Myt& _Right, size_type _Off = npos) const
|
|
{ // look for _Right beginning before _Off
|
|
return (rfind(_Right._Myptr(), _Off, _Right.size()));
|
|
}
|
|
|
|
size_type rfind(const _Elem *_Ptr, size_type _Off,
|
|
size_type _Count) const
|
|
{ // look for [_Ptr, _Ptr + _Count) beginning before _Off
|
|
if (_Count == 0)
|
|
return (_Off < _Mysize ? _Off : _Mysize); // null always matches
|
|
if (_Count <= _Mysize)
|
|
{ // room for match, look for it
|
|
const _Elem *_Uptr = _Myptr() +
|
|
(_Off < _Mysize - _Count ? _Off : _Mysize - _Count);
|
|
for (; ; --_Uptr)
|
|
if (_Traits::eq(*_Uptr, *_Ptr)
|
|
&& _Traits::compare(_Uptr, _Ptr, _Count) == 0)
|
|
return (_Uptr - _Myptr()); // found a match
|
|
else if (_Uptr == _Myptr())
|
|
break; // at beginning, no more chance for match
|
|
}
|
|
|
|
return (npos); // no match
|
|
}
|
|
|
|
size_type rfind(const _Elem *_Ptr, size_type _Off = npos) const
|
|
{ // look for [_Ptr, <null>) beginning before _Off
|
|
return (rfind(_Ptr, _Off, _Traits::length(_Ptr)));
|
|
}
|
|
|
|
size_type rfind(_Elem _Ch, size_type _Off = npos) const
|
|
{ // look for _Ch before _Off
|
|
return (rfind((const _Elem *)&_Ch, _Off, 1));
|
|
}
|
|
|
|
size_type find_first_of(const _Myt& _Right,
|
|
size_type _Off = 0) const
|
|
{ // look for one of _Right at or after _Off
|
|
return (find_first_of(_Right._Myptr(), _Off, _Right.size()));
|
|
}
|
|
|
|
size_type find_first_of(const _Elem *_Ptr, size_type _Off,
|
|
size_type _Count) const
|
|
{ // look for one of [_Ptr, _Ptr + _Count) at or after _Off
|
|
if (0 < _Count && _Off < _Mysize)
|
|
{ // room for match, look for it
|
|
const _Elem *const _Vptr = _Myptr() + _Mysize;
|
|
for (const _Elem *_Uptr = _Myptr() + _Off; _Uptr < _Vptr; ++_Uptr)
|
|
if (_Traits::find(_Ptr, _Count, *_Uptr) != 0)
|
|
return (_Uptr - _Myptr()); // found a match
|
|
}
|
|
|
|
return (npos); // no match
|
|
}
|
|
|
|
size_type find_first_of(const _Elem *_Ptr, size_type _Off = 0) const
|
|
{ // look for one of [_Ptr, <null>) at or after _Off
|
|
return (find_first_of(_Ptr, _Off, _Traits::length(_Ptr)));
|
|
}
|
|
|
|
size_type find_first_of(_Elem _Ch, size_type _Off = 0) const
|
|
{ // look for _Ch at or after _Off
|
|
return (find((const _Elem *)&_Ch, _Off, 1));
|
|
}
|
|
|
|
size_type find_last_of(const _Myt& _Right,
|
|
size_type _Off = npos) const
|
|
{ // look for one of _Right before _Off
|
|
return (find_last_of(_Right._Myptr(), _Off, _Right.size()));
|
|
}
|
|
|
|
size_type find_last_of(const _Elem *_Ptr, size_type _Off,
|
|
size_type _Count) const
|
|
{ // look for one of [_Ptr, _Ptr + _Count) before _Off
|
|
if (0 < _Count && 0 < _Mysize)
|
|
for (const _Elem *_Uptr = _Myptr()
|
|
+ (_Off < _Mysize ? _Off : _Mysize - 1); ; --_Uptr)
|
|
if (_Traits::find(_Ptr, _Count, *_Uptr) != 0)
|
|
return (_Uptr - _Myptr()); // found a match
|
|
else if (_Uptr == _Myptr())
|
|
break; // at beginning, no more chance for match
|
|
|
|
return (npos); // no match
|
|
}
|
|
|
|
size_type find_last_of(const _Elem *_Ptr,
|
|
size_type _Off = npos) const
|
|
{ // look for one of [_Ptr, <null>) before _Off
|
|
return (find_last_of(_Ptr, _Off, _Traits::length(_Ptr)));
|
|
}
|
|
|
|
size_type find_last_of(_Elem _Ch, size_type _Off = npos) const
|
|
{ // look for _Ch before _Off
|
|
return (rfind((const _Elem *)&_Ch, _Off, 1));
|
|
}
|
|
|
|
size_type find_first_not_of(const _Myt& _Right,
|
|
size_type _Off = 0) const
|
|
{ // look for none of _Right at or after _Off
|
|
return (find_first_not_of(_Right._Myptr(), _Off,
|
|
_Right.size()));
|
|
}
|
|
|
|
size_type find_first_not_of(const _Elem *_Ptr, size_type _Off,
|
|
size_type _Count) const
|
|
{ // look for none of [_Ptr, _Ptr + _Count) at or after _Off
|
|
if (_Off < _Mysize)
|
|
{ // room for match, look for it
|
|
const _Elem *const _Vptr = _Myptr() + _Mysize;
|
|
for (const _Elem *_Uptr = _Myptr() + _Off; _Uptr < _Vptr; ++_Uptr)
|
|
if (_Traits::find(_Ptr, _Count, *_Uptr) == 0)
|
|
return (_Uptr - _Myptr());
|
|
}
|
|
return (npos);
|
|
}
|
|
|
|
size_type find_first_not_of(const _Elem *_Ptr,
|
|
size_type _Off = 0) const
|
|
{ // look for one of [_Ptr, <null>) at or after _Off
|
|
return (find_first_not_of(_Ptr, _Off, _Traits::length(_Ptr)));
|
|
}
|
|
|
|
size_type find_first_not_of(_Elem _Ch, size_type _Off = 0) const
|
|
{ // look for non _Ch at or after _Off
|
|
return (find_first_not_of((const _Elem *)&_Ch, _Off, 1));
|
|
}
|
|
|
|
size_type find_last_not_of(const _Myt& _Right,
|
|
size_type _Off = npos) const
|
|
{ // look for none of _Right before _Off
|
|
return (find_last_not_of(_Right._Myptr(), _Off, _Right.size()));
|
|
}
|
|
|
|
size_type find_last_not_of(const _Elem *_Ptr, size_type _Off,
|
|
size_type _Count) const
|
|
{ // look for none of [_Ptr, _Ptr + _Count) before _Off
|
|
if (0 < _Mysize)
|
|
for (const _Elem *_Uptr = _Myptr()
|
|
+ (_Off < _Mysize ? _Off : _Mysize - 1); ; --_Uptr)
|
|
if (_Traits::find(_Ptr, _Count, *_Uptr) == 0)
|
|
return (_Uptr - _Myptr());
|
|
else if (_Uptr == _Myptr())
|
|
break;
|
|
return (npos);
|
|
}
|
|
|
|
size_type find_last_not_of(const _Elem *_Ptr,
|
|
size_type _Off = npos) const
|
|
{ // look for none of [_Ptr, <null>) before _Off
|
|
return (find_last_not_of(_Ptr, _Off, _Traits::length(_Ptr)));
|
|
}
|
|
|
|
size_type find_last_not_of(_Elem _Ch, size_type _Off = npos) const
|
|
{ // look for non _Ch before _Off
|
|
return (find_last_not_of((const _Elem *)&_Ch, _Off, 1));
|
|
}
|
|
|
|
_Myt substr(size_type _Off = 0, size_type _Count = npos) const
|
|
{ // return [_Off, _Off + _Count) as new string
|
|
return (_Myt(*this, _Off, _Count));
|
|
}
|
|
|
|
int compare(const _Myt& _Right) const
|
|
{ // compare [0, _Mysize) with _Right
|
|
return (compare(0, _Mysize, _Right._Myptr(), _Right.size()));
|
|
}
|
|
|
|
int compare(size_type _Off, size_type _N0,
|
|
const _Myt& _Right) const
|
|
{ // compare [_Off, _Off + _N0) with _Right
|
|
return (compare(_Off, _N0, _Right, 0, npos));
|
|
}
|
|
|
|
int compare(size_type _Off, size_type _N0, const _Myt& _Right,
|
|
size_type _Roff, size_type _Count) const
|
|
{ // compare [_Off, _Off + _N0) with _Right [_Roff, _Roff + _Count)
|
|
if (_Right.size() < _Roff)
|
|
_String_base::_Xran(); // _Off off end
|
|
if (_Right._Mysize - _Roff < _Count)
|
|
_Count = _Right._Mysize - _Roff; // trim _Count to size
|
|
return (compare(_Off, _N0, _Right._Myptr() + _Roff, _Count));
|
|
}
|
|
|
|
int compare(const _Elem *_Ptr) const
|
|
{ // compare [0, _Mysize) with [_Ptr, <null>)
|
|
return (compare(0, _Mysize, _Ptr, _Traits::length(_Ptr)));
|
|
}
|
|
|
|
int compare(size_type _Off, size_type _N0, const _Elem *_Ptr) const
|
|
{ // compare [_Off, _Off + _N0) with [_Ptr, <null>)
|
|
return (compare(_Off, _N0, _Ptr, _Traits::length(_Ptr)));
|
|
}
|
|
|
|
int compare(size_type _Off, size_type _N0, const _Elem *_Ptr,
|
|
size_type _Count) const
|
|
{ // compare [_Off, _Off + _N0) with [_Ptr, _Ptr + _Count)
|
|
if (_Mysize < _Off)
|
|
_String_base::_Xran(); // _Off off end
|
|
if (_Mysize - _Off < _N0)
|
|
_N0 = _Mysize - _Off; // trim _N0 to size
|
|
|
|
size_type _Ans = _N0 == 0 ? 0
|
|
: _Traits::compare(_Myptr() + _Off, _Ptr,
|
|
_N0 < _Count ? _N0 : _Count);
|
|
return (_Ans != 0 ? (int)_Ans : _N0 < _Count ? -1
|
|
: _N0 == _Count ? 0 : +1);
|
|
}
|
|
|
|
allocator_type get_allocator() const
|
|
{ // return allocator object for values
|
|
return (_Mybase::_Alval);
|
|
}
|
|
|
|
enum
|
|
{ // length of internal buffer, [1, 16]
|
|
_BUF_SIZE = 16 / sizeof (_Elem) < 1 ? 1
|
|
: 16 / sizeof(_Elem)};
|
|
private:
|
|
enum
|
|
{ // roundup mask for allocated buffers, [0, 15]
|
|
_ALLOC_MASK = sizeof (_Elem) <= 1 ? 15
|
|
: sizeof (_Elem) <= 2 ? 7
|
|
: sizeof (_Elem) <= 4 ? 3
|
|
: sizeof (_Elem) <= 8 ? 1 : 0};
|
|
|
|
void _Copy(size_type _Newsize, size_type _Oldlen)
|
|
{ // copy _Oldlen elements to newly allocated buffer
|
|
size_type _Newres = _Newsize | _ALLOC_MASK;
|
|
if (max_size() < _Newres)
|
|
_Newres = _Newsize; // undo roundup if too big
|
|
_Elem *_Ptr;
|
|
|
|
_TRY_BEGIN
|
|
_Ptr = _Mybase::_Alval.allocate(_Newres + 1, (void *)0);
|
|
_CATCH_ALL
|
|
_Newres = _Newsize; // allocation failed, undo roundup and retry
|
|
_TRY_BEGIN
|
|
_Ptr = _Mybase::_Alval.allocate(_Newres + 1, (void *)0);
|
|
_CATCH_ALL
|
|
_Tidy(true); // failed again, discard storage and reraise
|
|
_RERAISE;
|
|
_CATCH_END
|
|
_CATCH_END
|
|
|
|
if (0 < _Oldlen)
|
|
_Traits::copy(_Ptr, _Myptr(), _Oldlen); // copy existing elements
|
|
_Tidy(true);
|
|
_Bx._Ptr = _Ptr;
|
|
_Myres = _Newres;
|
|
_Eos(_Oldlen);
|
|
}
|
|
|
|
void _Eos(size_type _Newsize)
|
|
{ // set new length and null terminator
|
|
_Traits::assign(_Myptr()[_Mysize = _Newsize], _Elem());
|
|
}
|
|
|
|
bool _Grow(size_type _Newsize, bool _Trim = false)
|
|
{ // ensure buffer is big enough, trim to size if _Trim is true
|
|
if (max_size() < _Newsize)
|
|
_String_base::_Xlen(); // result too long
|
|
if (_Myres < _Newsize)
|
|
_Copy(_Newsize, _Trim ? 0 : _Mysize); // reallocate to grow
|
|
else if (_Trim && _Newsize < _BUF_SIZE)
|
|
_Tidy(true); // deallocate if assigning small string
|
|
else if (_Newsize == 0)
|
|
_Eos(0); // new size is zero, just null terminate
|
|
return (0 < _Newsize); // return true only if more work to do
|
|
}
|
|
|
|
bool _Inside(const _Elem *_Ptr)
|
|
{ // test if _Ptr points inside string
|
|
return (_Myptr() <= _Ptr && _Ptr < _Myptr() + _Mysize);
|
|
}
|
|
|
|
static size_type __cdecl _Pdif(const_iterator _P2,
|
|
const_iterator _P1)
|
|
{ // compute safe iterator difference
|
|
return (_P2.base() == 0 ? 0 : _P2 - _P1);
|
|
}
|
|
|
|
_Elem *_Myptr()
|
|
{ // determine current pointer to buffer for mutable string
|
|
return (_BUF_SIZE <= _Myres ? _Bx._Ptr : _Bx._Buf);
|
|
}
|
|
|
|
const _Elem *_Myptr() const
|
|
{ // determine current pointer to buffer for nonmutable string
|
|
return (_BUF_SIZE <= _Myres ? _Bx._Ptr : _Bx._Buf);
|
|
}
|
|
|
|
void _Tidy(bool _Built = false)
|
|
{ // initialize buffer, deallocating any storage
|
|
if (!_Built)
|
|
;
|
|
else if (_BUF_SIZE <= _Myres)
|
|
_Mybase::_Alval.deallocate(_Myptr(), _Myres + 1);
|
|
_Myres = _BUF_SIZE - 1;
|
|
_Eos(0);
|
|
}
|
|
|
|
union _Bxty
|
|
{ // storage for small buffer or pointer to larger one
|
|
_Elem _Buf[_BUF_SIZE];
|
|
_Elem *_Ptr;
|
|
} _Bx;
|
|
|
|
size_type _Mysize; // current length of string
|
|
size_type _Myres; // current storage reserved for string
|
|
};
|
|
|
|
// STATIC npos OBJECT
|
|
template<class _Elem,
|
|
class _Traits,
|
|
class _Alloc>
|
|
const /* typename */ basic_string<_Elem, _Traits, _Alloc>::size_type
|
|
basic_string<_Elem, _Traits, _Alloc>::npos =
|
|
(basic_string<_Elem, _Traits, _Alloc>::size_type)(-1);
|
|
|
|
typedef basic_string<char, char_traits<char>, allocator<char> >
|
|
string;
|
|
typedef basic_string<wchar_t, char_traits<wchar_t>,
|
|
allocator<wchar_t> > wstring;
|
|
|
|
#ifdef _DLL_CPPLIB
|
|
template class _CRTIMP2 basic_string<char, char_traits<char>,
|
|
allocator<char> >;
|
|
template class _CRTIMP2 basic_string<wchar_t, char_traits<wchar_t>,
|
|
allocator<wchar_t> >;
|
|
#endif // _DLL_CPPLIB
|
|
_STD_END
|
|
#pragma warning(default: 4251)
|
|
#pragma warning(pop)
|
|
#pragma pack(pop)
|
|
|
|
#endif /* _XSTRING */
|
|
|
|
/*
|
|
* Copyright (c) 1992-2001 by P.J. Plauger. ALL RIGHTS RESERVED.
|
|
* Consult your license regarding permissions and restrictions.
|
|
V3.10:0009 */
|