Listing 2: var_char_buf.h — Header for fixed/variable string implementation

// 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 —