// Copyright (c) 2001 John Panzer
// Permission is granted to use this code without restriction as
// long as this copyright notice appears in all source files.
#ifndef VAR_CHAR_BUF_H_INCLUDED
#define VAR_CHAR_BUF_H_INCLUDED
#include <string> // For char_traits
#include xs_defs.h // Utility macros
XS_NAMESPACE(xstr)
// Variable character buffer class which uses a
// small internal buffer along with a dynamic overflow
// buffer.
template <size_t SIZE,
class CharT = char,
class Traits = std::char_traits<CharT>,
class Alloc = std::allocator<CharT> >
class var_char_buf {
public:
...(typedefs same as those in fixed_char_buf)...
typedef Alloc allocator_type;
typedef Traits traits_type;
static const size_type npos;
// Constructors:
var_char_buf(allocator_type const &a=allocator_type())
: _buffer(_internal_buf),
_end(_internal_buf),
_num_chars_allocated(0) {}
var_char_buf(var_char_buf const &s)
: _buffer(_internal_buf),
_end(_internal_buf),
_num_chars_allocated(0) {
range_initialize(s.begin(), s.end());
}
~var_char_buf() {release_resources();}
// Copy operator:
var_char_buf &operator=(var_char_buf const &s) {
range_initialize(s.begin(), s.end());
}
// Insert:
template <class InputIter>
void insert(iterator pos, InputIter first, InputIter last) {
if (first!=last) {
size_type xtra = std::distance(first,last);
size_type newlen = _end-_buffer+xtra;
if (newlen >= capacity()) {
size_type ipos = pos-_buffer;
reserve(newlen);
pos = _buffer+ipos;
}
if (pos!=_end)
Traits::move(pos+xtra,pos,_end-pos);
std::copy(first,last,pos);
_end += xtra; // Expand end point
}
}
// Erase:
iterator erase(iterator first, iterator last) {
if (first != last) {
Traits::move(first, last, (_end - last) + 1);
const iterator new_finish = _end - (last - first);
_end = new_finish;
}
return first;
}
// STL container member function interface:
const allocator_type &get_allocator() const {
return _allocator;
}
iterator begin() {return _buffer;}
const_iterator begin() const {return _buffer;}
iterator end() {return _end;}
const_iterator end() const {return _end;}
void clear() {_end = _buffer;}
size_t max_size() const {
return std::min((size_t)0xFFFF,_allocator.max_size());
}
bool empty() const { return (_end == _buffer); }
size_type size() const {return _end - _buffer;}
void swap(var_char_buf& s) {
int len = _end - _buffer;
if (_buffer == _internal_buf)
for(int i=0;i<SIZE;++i) {
std::swap(_buffer[i],s._buffer[i]);
}
else
std::swap(_buffer,s._buffer);
std::swap(_num_chars_allocated,s._num_chars_allocated);
_end = s.size()+_buffer;
s._end = len+s._buffer;
}
// String interface member functions:
void reserve(size_type requested_chars= 0) {
if (requested_chars < SIZE && (_buffer==_internal_buf))
return;
if (requested_chars < _num_chars_allocated)
return;
if (requested_chars > max_size())
throw std::length_error(Max size exceeded);
CharT *p = _allocator.allocate(requested_chars+1);
size_type sz = size();
Traits::move(p,_buffer,sz);
release_resources();
_buffer = p;
_end = _buffer + sz;
_num_chars_allocated = requested_chars+1;
}
size_type capacity() const {
return _num_chars_allocated ?
_num_chars_allocated : SIZE;
}
const CharT* c_str() const {
*_end = CharT(); // Null terminate.
return _buffer;
}
const CharT* data() const {
return _buffer;
}
protected:
void release_resources() {
if (_buffer != _internal_buf) {
_allocator.deallocate(_buffer,
_num_chars_allocated);
}
}
// Initializes with n copies of given element:
void element_initialize(size_type n, value_type c) {
reserve(n); // TODO: Can reserve throw?
std::uninitialized_fill_n(begin(), n, c);
_end = begin()+n;
}
// Initializes with given range of elements:
template <class InputIter>
void range_initialize(InputIter first, InputIter last) {
size_type n = std::distance(first,last);
if (n >= SIZE)
reserve(n);
std::uninitialized_copy(first,last,_buffer);
_end = _buffer+n;
}
private:
CharT *_buffer; // Start of text in string
mutable CharT *_end ; // End of text in _buffer
CharT _internal_buf[SIZE+1]; // Space for SIZE elems+null
size_type _num_chars_allocated; // Size of dynamic block
static const allocator_type _allocator;
};
...(size_type and _allocator same as in fixed_char_buf)...
XS_END_NAMESPACE
#endif
End of Listing