/* Copyright (C) 2006-2008 River Tarnell . */ /* * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely. This software is provided 'as-is', without any express or implied * warranty. */ /* @(#) $Id$ */ #include #include #include "fray.h" template typename alloc::template rebind >::other basic_fray::_alloc; template typename basic_fray::size_type const basic_fray::npos; namespace fray_impl { template alloc fray_root::_alloc; template fray_root::fray_root(ch const *begin, size_type len) : _refs(1) { _string = _alloc.allocate(len + sizeof(ch)); tr::copy(_string, begin, len); _string[len] = '\0'; _end = _string + len; } template fray_root::fray_root(size_type len) : _refs(1) , _string(0) , _end(0) { _string = _alloc.allocate(len + sizeof(ch)); _string[len] = '\0'; _end = _string + len; } template fray_root::~fray_root() { assert(_refs == 0); _alloc.deallocate(_string, (_end - _string) + sizeof(ch)); } template int fray_root::ref(void) { assert(_refs > 0); return ++_refs; } template int fray_root::deref(void) { assert(_refs > 0); return --_refs; } } // namespace fray_impl template bool operator!= (fray_iterator const &a, fray_iterator const &b) { return !(a == b); } template bool operator> (fray_iterator const &a, fray_iterator const &b) { return !(a < b) && !(a == b); } template bool operator<= (fray_iterator const &a, fray_iterator const &b) { return (a < b) || (a == b); } template bool operator>= (fray_iterator const &a, fray_iterator const &b) { return (b < a) || (a == b); } template basic_fray::basic_fray() { ch empty[1] = { 0 }; _root = _alloc.allocate(1); _root = new (_alloc.allocate(1)) fray_impl::fray_root(empty, 0); _begin = _root->_string; _end = _root->_end; } template basic_fray::basic_fray(ch const *cstring, size_type len) { _root = new (_alloc.allocate(1)) fray_impl::fray_root(cstring, len); _begin = _root->_string; _end = _root->_end; } template basic_fray::basic_fray(ch const *cstring) { int len = tr::length(cstring); _root = new (_alloc.allocate(1)) fray_impl::fray_root(cstring, len); _begin = _root->_string; _end = _root->_end; } template template basic_fray::basic_fray(std::basic_string const &s) { _root = new (_alloc.allocate(1)) fray_impl::fray_root(s.data(), s.size()); _begin = _root->_string; _end = _root->_end; } template basic_fray::basic_fray( typename basic_fray::size_type n, ch c) { _root = new (_alloc.allocate(1)) fray_impl::fray_root(n); _begin = _root->_string; _end = _root->_end; tr::assign(_root->_string, n, c); } template basic_fray::basic_fray(basic_fray const &other) : _root(other._root) , _begin(other._begin) , _end(other._end) { _root->ref(); } template basic_fray::basic_fray(fray_impl::fray_root *root) : _root(root) , _begin(root->_string) , _end(root->_end) { } template template basic_fray::basic_fray(InputIterator first, InputIterator last) { _root = new (_alloc.allocate(1)) fray_impl::fray_root(last - first); _begin = _root->_string; _end = _root->_end; ch *s = _root->_string; std::copy(first, last, s); } template void basic_fray::assign (basic_fray const &other) { _deref_root(); _root = other._root; _root->ref(); _begin = other._begin; _end = other._end; } template basic_fray & basic_fray::operator= (basic_fray const &other) { if (this == &other) return *this; assign(other); return *this; } template template basic_fray & basic_fray::operator= (std::basic_string const &other) { assign(other); return *this; } template template void basic_fray::assign (std::basic_string const &s) { _deref_root(); _root = new (_alloc.allocate(1)) fray_impl::fray_root(s.data(), s.size()); _begin = _root->_string; _end = _root->_end; } template basic_fray & basic_fray::operator= (ch const *cstring) { assign(cstring); return *this; } template void basic_fray::assign (ch const *cstring) { assign(cstring, tr::length(cstring)); } template void basic_fray::assign (ch const *cstring, size_type len) { _deref_root(); _root = new (_alloc.allocate(1)) fray_impl::fray_root(cstring, len); _begin = _root->_string; _end = _root->_end; } template void basic_fray::assign( typename basic_fray::iterator begin, typename basic_fray::iterator end) { assign(begin._pos, end._pos - begin._pos); } template basic_fray basic_fray::substr( typename basic_fray::size_type off, typename basic_fray::size_type count) const { if ((count == npos) || count + off > length()) count = length() - off; return basic_fray(_begin + off, count); } template basic_fray::~basic_fray() { _deref_root(); } template template void basic_fray::print(std::basic_ostream &strm) const { strm << std::basic_string(_begin, _end); } template typename basic_fray::size_type basic_fray::length(void) const { return _end - _begin; } template typename basic_fray::size_type basic_fray::size(void) const { return length(); } template typename basic_fray::iterator basic_fray::begin(void) const { return iterator(_begin); } template typename basic_fray::iterator basic_fray::end(void) const { return iterator(_end); } template typename basic_fray::size_type basic_fray::find(ch c, typename basic_fray::size_type pos) const { ch const *found, *b = _begin + pos; found = tr::find(b, _end - b, c); if (found == NULL) return npos; return found - _begin; } template typename basic_fray::size_type basic_fray::find( basic_fray const &s, typename basic_fray::size_type pos) const { ch const *found, *b = _begin + pos; found = std::search(b, _end, s.begin(), s.end()); if (found == _end) return npos; return found - _begin; } template ch const * basic_fray::c_str(void) const { /* * If this fray ends with the end of the root, c_str simply returns _begin, * because the fray root is always nul terminated. Otherwise, we * re-root this fray to a root containing only the contents of this * fray. * * This design saves copying in the common case of c_str() on a full * fray, and the degenerate case requires copying with any implementation, * because the nul terminator has to be inserted somewhere. */ if (_end == _root->_end) return _begin; fray_impl::fray_root *newroot = new (_alloc.allocate(1)) fray_impl::fray_root(_begin, length()); _deref_root(); _root = newroot; return _begin; } template std::basic_string basic_fray::str(void) const { return std::basic_string(_begin, _end); } template ch const * basic_fray::data(void) const { return _begin; } template ch basic_fray::operator[] (typename basic_fray::size_type n) const { return *(begin() + n); } template bool basic_fray::empty(void) const { return length() == 0; } template basic_fray basic_fray::append(basic_fray const &other) const { return append(other._begin, other._end); } template basic_fray basic_fray::append(ch const *cstring) const { return append(cstring, cstring + tr::length(cstring)); } template basic_fray basic_fray::append(ch c) const { ch s[2] = {c, 0}; return append(s, s + 1); } template basic_fray basic_fray::append(ch const *b, ch const *e) const { size_type alen = (e - b), newlen = length() + alen; fray_impl::fray_root *newroot = new (_alloc.allocate(1)) fray_impl::fray_root(newlen); tr::copy(newroot->_string, _begin, length()); tr::copy(newroot->_string + length(), b, alen); newroot->_end = newroot->_string + newlen; return basic_fray(newroot); } template basic_fray basic_fray::prepend(basic_fray const &other) const { return prepend(other._begin, other._end); } template basic_fray basic_fray::prepend(ch const *cstring) const { return prepend(cstring, cstring + tr::length(cstring)); } template basic_fray basic_fray::prepend(ch c) const { ch s[2] = {c, 0}; return prepend(s, s + 1); } template basic_fray basic_fray::prepend(ch const *b, ch const *e) const { size_type alen = (e - b), newlen = length() + alen; fray_impl::fray_root *newroot = new (_alloc.allocate(1)) fray_impl::fray_root(newlen); tr::copy(newroot->_string, b, alen); tr::copy(newroot->_string + alen, _begin, length()); newroot->_end = newroot->_string + newlen; return basic_fray(newroot); } template void basic_fray::swap(basic_fray &other) { std::swap(_root, other._root); std::swap(_begin, other._begin); std::swap(_end, other._end); } template void basic_fray::_deref_root(void) const { if (!_root) return; if (_root->deref() == 0) { _alloc.destroy(_root); _alloc.deallocate(_root, 1); } } template template int basic_fray::compare(basic_fray const &other) const { int i, alen = length(), blen = other.length(); i = tr_::compare(_begin, other._begin, std::min(alen, blen)); if (i == 0) return alen - blen; /* shorter string is lesser */ return i; } template std::basic_ostream & operator<< (std::basic_ostream &strm, basic_fray const &s) { s.print(strm); return strm; } template std::basic_istream & operator>> (std::basic_istream &strm, basic_fray &s) { std::basic_string st; strm >> st; if (strm) s = st; return strm; } template basic_fray operator+ (basic_fray const &a, basic_fray const &b) { return a.append(b); } template basic_fray operator+ (basic_fray const &a, std::basic_string const &b) { return a.append(b.data(), b.data() + b.size()); } template basic_fray operator+ (std::basic_string const &a, basic_fray const &b) { return b.prepend(a.begin(), a.end()); } template basic_fray operator+ (basic_fray const &a, ch const *cstring) { return a.append(cstring); } template basic_fray operator+ (ch const *cstring, basic_fray const &a) { return a.prepend(cstring); } template basic_fray operator+ (basic_fray const &s, ch c) { return s.append(c); } template basic_fray operator+ (ch c, basic_fray const &s) { return s.prepend(c); } namespace std { template void swap(basic_fray &a, basic_fray &b) { a.swap(b); } } template int trcompare(basic_fray const &a, basic_fray const &b) { return a.template compare(b); } template int trcompare(basic_fray const &a, ch const *b) { return a.template compare(basic_fray(b)); } template int trcompare(ch const *a, basic_fray const &b) { return -b.template compare(basic_fray(a)); } template int trcompare(ch const *a, ch const *b) { int i, alen = traits::length(a), blen = traits::length(b); i = traits::compare(a, b, std::min(alen, blen)); if (i == 0) return alen - blen; /* shorter string is lesser */ return i; } template int compare(basic_fray const &a, basic_fray const &b) { return trcompare(a, b); } template int compare(basic_fray const &a, ch const *b) { return trcompare(a, b); } template int compare(ch const *a, basic_fray const &b) { return trcompare(a, b); } template int compare(ch const *a, ch const *b) { return trcompare >(a, b); } template bool operator< (basic_fray const &a, basic_fray const &b) { return compare(a, b) < 0; } template bool operator< (basic_fray const &a, ch const *b) { return compare(a, b) < 0; } template bool operator< (ch const *a, basic_fray const &b) { return compare(a, b) < 0; } template bool operator== (basic_fray const &a, basic_fray const &b) { return compare(a, b) == 0; } template bool operator== (basic_fray const &a, ch const *b) { return compare(a, b) == 0; } template bool operator== (ch const *a, basic_fray const &b) { return compare(a, b) == 0; } template bool operator!= (basic_fray const &a, basic_fray const &b) { return !(a == b); } template bool operator!= (ch const *a, basic_fray const &b) { return !(a == b); } template bool operator!= (basic_fray const &a, ch const *b) { return !(a == b); } template bool operator> (basic_fray const &a, basic_fray const &b) { return compare(a, b) > 0; } template bool operator> (basic_fray const &a, ch const *b) { return compare(a, b) > 0; } template bool operator> (ch const *a, basic_fray const &b) { return compare(a, b) > 0; } template bool operator<= (basic_fray const &a, basic_fray const &b) { return !(a > b); } template bool operator<= (basic_fray const &a, ch const *b) { return !(a > b); } template bool operator<= (ch const *a, basic_fray const &b) { return !(a > b); } template bool operator>= (basic_fray const &a, basic_fray const &b) { return !(a < b); } template bool operator>= (basic_fray const &a, ch const *b) { return !(a < b); } template bool operator>= (ch const *a, basic_fray const &b) { return !(a < b); } /* * For boost.hash. */ template std::size_t hash_value(basic_fray const &s) { return boost::hash_range(s.begin(), s.end()); } template std::istream & getline(std::basic_istream &strm, basic_fray &s) { std::basic_string str; getline(strm, str); if (strm) s = str; return strm; }