// ---------------------------------------------------------------------------- // alt_sstream_impl.hpp : alternative stringstream, templates implementation // ---------------------------------------------------------------------------- // Copyright Samuel Krempp 2003. Use, modification, and distribution are // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // See http://www.boost.org/libs/format for library home page // ---------------------------------------------------------------------------- #ifndef BOOST_SK_ALT_SSTREAM_IMPL_HPP #define BOOST_SK_ALT_SSTREAM_IMPL_HPP namespace boost { namespace io { // --- Implementation ------------------------------------------------------// template void basic_altstringbuf:: clear_buffer () { const Ch * p = pptr(); const Ch * b = pbase(); if(p != NULL && p != b) { seekpos(0, ::std::ios_base::out); } p = gptr(); b = eback(); if(p != NULL && p != b) { seekpos(0, ::std::ios_base::in); } } template void basic_altstringbuf:: str (const string_type& s) { size_type sz=s.size(); if(sz != 0 && mode_ & (::std::ios_base::in | ::std::ios_base::out) ) { Ch *new_ptr = alloc_.allocate(sz, is_allocated_? eback() : 0); // if this didnt throw, we're safe, update the buffer dealloc(); sz = s.copy(new_ptr, sz); putend_ = new_ptr + sz; if(mode_ & ::std::ios_base::in) streambuf_t::setg(new_ptr, new_ptr, new_ptr + sz); if(mode_ & ::std::ios_base::out) { streambuf_t::setp(new_ptr, new_ptr + sz); if(mode_ & (::std::ios_base::app | ::std::ios_base::ate)) streambuf_t::pbump(static_cast(sz)); if(gptr() == NULL) streambuf_t::setg(new_ptr, NULL, new_ptr); } is_allocated_ = true; } else dealloc(); } template Ch* basic_altstringbuf:: begin () const { if(mode_ & ::std::ios_base::out && pptr() != NULL) return pbase(); else if(mode_ & ::std::ios_base::in && gptr() != NULL) return eback(); return NULL; } template typename std::basic_string::size_type basic_altstringbuf:: size () const { if(mode_ & ::std::ios_base::out && pptr()) return static_cast(pend() - pbase()); else if(mode_ & ::std::ios_base::in && gptr()) return static_cast(egptr() - eback()); else return 0; } template typename std::basic_string::size_type basic_altstringbuf:: cur_size () const { if(mode_ & ::std::ios_base::out && pptr()) return static_cast( pptr() - pbase()); else if(mode_ & ::std::ios_base::in && gptr()) return static_cast( gptr() - eback()); else return 0; } template typename basic_altstringbuf::pos_type basic_altstringbuf:: seekoff (off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which) { if(pptr() != NULL && putend_ < pptr()) putend_ = pptr(); if(which & ::std::ios_base::in && gptr() != NULL) { // get area if(way == ::std::ios_base::end) off += static_cast(putend_ - gptr()); else if(way == ::std::ios_base::beg) off += static_cast(eback() - gptr()); else if(way != ::std::ios_base::cur || (which & ::std::ios_base::out) ) // (altering in&out is only supported if way is beg or end, not cur) return pos_type(off_type(-1)); if(eback() <= off+gptr() && off+gptr() <= putend_ ) { // set gptr streambuf_t::gbump(static_cast(off)); if(which & ::std::ios_base::out && pptr() != NULL) // update pptr to match gptr streambuf_t::pbump(static_cast(gptr()-pptr())); } else off = off_type(-1); } else if(which & ::std::ios_base::out && pptr() != NULL) { // put area if(way == ::std::ios_base::end) off += static_cast(putend_ - pptr()); else if(way == ::std::ios_base::beg) off += static_cast(pbase() - pptr()); else if(way != ::std::ios_base::beg) return pos_type(off_type(-1)); if(pbase() <= off+pptr() && off+pptr() <= putend_) // set pptr streambuf_t::pbump(static_cast(off)); else off = off_type(-1); } else // neither in nor out off = off_type(-1); return (pos_type(off)); } //- end seekoff(..) template typename basic_altstringbuf::pos_type basic_altstringbuf:: seekpos (pos_type pos, ::std::ios_base::openmode which) { off_type off = off_type(pos); // operation guaranteed by §27.4.3.2 table 88 if(pptr() != NULL && putend_ < pptr()) putend_ = pptr(); if(off != off_type(-1)) { if(which & ::std::ios_base::in && gptr() != NULL) { // get area if(0 <= off && off <= putend_ - eback()) { streambuf_t::gbump(static_cast(eback() - gptr() + off)); if(which & ::std::ios_base::out && pptr() != NULL) { // update pptr to match gptr streambuf_t::pbump(static_cast(gptr()-pptr())); } } else off = off_type(-1); } else if(which & ::std::ios_base::out && pptr() != NULL) { // put area if(0 <= off && off <= putend_ - eback()) streambuf_t::pbump(static_cast(eback() - pptr() + off)); else off = off_type(-1); } else // neither in nor out off = off_type(-1); return (pos_type(off)); } else { BOOST_ASSERT(0); // §27.4.3.2 allows undefined-behaviour here return pos_type(off_type(-1)); } } // -end seekpos(..) template typename basic_altstringbuf::int_type basic_altstringbuf:: underflow () { if(gptr() == NULL) // no get area -> nothing to get. return (compat_traits_type::eof()); else if(gptr() < egptr()) // ok, in buffer return (compat_traits_type::to_int_type(*gptr())); else if(mode_ & ::std::ios_base::in && pptr() != NULL && (gptr() < pptr() || gptr() < putend_) ) { // expand get area if(putend_ < pptr()) putend_ = pptr(); // remember pptr reached this far streambuf_t::setg(eback(), gptr(), putend_); return (compat_traits_type::to_int_type(*gptr())); } else // couldnt get anything. EOF. return (compat_traits_type::eof()); } // -end underflow(..) template typename basic_altstringbuf::int_type basic_altstringbuf:: pbackfail (int_type meta) { if(gptr() != NULL && (eback() < gptr()) && (mode_ & (::std::ios_base::out) || compat_traits_type::eq_int_type(compat_traits_type::eof(), meta) || compat_traits_type::eq(compat_traits_type::to_char_type(meta), gptr()[-1]) ) ) { streambuf_t::gbump(-1); // back one character if(!compat_traits_type::eq_int_type(compat_traits_type::eof(), meta)) // put-back meta into get area *gptr() = compat_traits_type::to_char_type(meta); return (compat_traits_type::not_eof(meta)); } else return (compat_traits_type::eof()); // failed putback } // -end pbackfail(..) template typename basic_altstringbuf::int_type basic_altstringbuf:: overflow (int_type meta) { #ifdef BOOST_MSVC #pragma warning(push) #pragma warning(disable:4996) #endif if(compat_traits_type::eq_int_type(compat_traits_type::eof(), meta)) return compat_traits_type::not_eof(meta); // nothing to do else if(pptr() != NULL && pptr() < epptr()) { streambuf_t::sputc(compat_traits_type::to_char_type(meta)); return meta; } else if(! (mode_ & ::std::ios_base::out)) // no write position, and cant make one return compat_traits_type::eof(); else { // make a write position available std::size_t prev_size = pptr() == NULL ? 0 : epptr() - eback(); std::size_t new_size = prev_size; // exponential growth : size *= 1.5 std::size_t add_size = new_size / 2; if(add_size < alloc_min) add_size = alloc_min; Ch * newptr = NULL, *oldptr = eback(); // make sure adding add_size wont overflow size_t while (0 < add_size && ((std::numeric_limits::max)() - add_size < new_size) ) add_size /= 2; if(0 < add_size) { new_size += add_size; newptr = alloc_.allocate(new_size, is_allocated_? oldptr : 0); } if(0 < prev_size) compat_traits_type::copy(newptr, oldptr, prev_size); if(is_allocated_) alloc_.deallocate(oldptr, prev_size); is_allocated_=true; if(prev_size == 0) { // first allocation putend_ = newptr; streambuf_t::setp(newptr, newptr + new_size); if(mode_ & ::std::ios_base::in) streambuf_t::setg(newptr, newptr, newptr + 1); else streambuf_t::setg(newptr, 0, newptr); } else { // update pointers putend_ = putend_ - oldptr + newptr; int pptr_count = static_cast(pptr()-pbase()); int gptr_count = static_cast(gptr()-eback()); streambuf_t::setp(pbase() - oldptr + newptr, newptr + new_size); streambuf_t::pbump(pptr_count); if(mode_ & ::std::ios_base::in) streambuf_t::setg(newptr, newptr + gptr_count, pptr() + 1); else streambuf_t::setg(newptr, 0, newptr); } streambuf_t::sputc(compat_traits_type::to_char_type(meta)); return meta; } #ifdef BOOST_MSVC #pragma warning(pop) #endif } // -end overflow(..) template void basic_altstringbuf:: dealloc() { if(is_allocated_) alloc_.deallocate(eback(), (pptr() != NULL ? epptr() : egptr()) - eback()); is_allocated_ = false; streambuf_t::setg(0, 0, 0); streambuf_t::setp(0, 0); putend_ = NULL; } }// N.S. io } // N.S. boost #endif // include guard