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