| // ---------------------------------------------------------------------------- |
| // 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<class Ch, class Tr, class Alloc> |
| void basic_altstringbuf<Ch, Tr, Alloc>:: |
| 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<class Ch, class Tr, class Alloc> |
| void basic_altstringbuf<Ch, Tr, Alloc>:: |
| str (const string_type& s) { |
| size_type sz=s.size(); |
| if(sz != 0 && mode_ & (::std::ios_base::in | ::std::ios_base::out) ) { |
| #ifdef _RWSTD_NO_CLASS_PARTIAL_SPEC |
| void *vd_ptr = alloc_.allocate(sz, is_allocated_? eback() : 0); |
| Ch *new_ptr = static_cast<Ch *>(vd_ptr); |
| #else |
| Ch *new_ptr = alloc_.allocate(sz, is_allocated_? eback() : 0); |
| #endif |
| // 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<int>(sz)); |
| if(gptr() == NULL) |
| streambuf_t::setg(new_ptr, NULL, new_ptr); |
| } |
| is_allocated_ = true; |
| } |
| else |
| dealloc(); |
| } |
| template<class Ch, class Tr, class Alloc> |
| Ch* basic_altstringbuf<Ch, Tr, Alloc>:: |
| 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<class Ch, class Tr, class Alloc> |
| typename std::basic_string<Ch,Tr,Alloc>::size_type |
| basic_altstringbuf<Ch, Tr, Alloc>:: |
| size () const { |
| if(mode_ & ::std::ios_base::out && pptr()) |
| return static_cast<size_type>(pend() - pbase()); |
| else if(mode_ & ::std::ios_base::in && gptr()) |
| return static_cast<size_type>(egptr() - eback()); |
| else |
| return 0; |
| } |
| |
| template<class Ch, class Tr, class Alloc> |
| typename std::basic_string<Ch,Tr,Alloc>::size_type |
| basic_altstringbuf<Ch, Tr, Alloc>:: |
| cur_size () const { |
| if(mode_ & ::std::ios_base::out && pptr()) |
| return static_cast<streamsize>( pptr() - pbase()); |
| else if(mode_ & ::std::ios_base::in && gptr()) |
| return static_cast<streamsize>( gptr() - eback()); |
| else |
| return 0; |
| } |
| |
| template<class Ch, class Tr, class Alloc> |
| typename basic_altstringbuf<Ch, Tr, Alloc>::pos_type |
| basic_altstringbuf<Ch, Tr, Alloc>:: |
| 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<off_type>(putend_ - gptr()); |
| else if(way == ::std::ios_base::beg) |
| off += static_cast<off_type>(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<int>(off)); |
| if(which & ::std::ios_base::out && pptr() != NULL) |
| // update pptr to match gptr |
| streambuf_t::pbump(static_cast<int>(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<off_type>(putend_ - pptr()); |
| else if(way == ::std::ios_base::beg) |
| off += static_cast<off_type>(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<int>(off)); |
| else |
| off = off_type(-1); |
| } |
| else // neither in nor out |
| off = off_type(-1); |
| return (pos_type(off)); |
| } |
| //- end seekoff(..) |
| |
| |
| template<class Ch, class Tr, class Alloc> |
| typename basic_altstringbuf<Ch, Tr, Alloc>::pos_type |
| basic_altstringbuf<Ch, Tr, Alloc>:: |
| 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<int>(eback() - gptr() + off)); |
| if(which & ::std::ios_base::out && pptr() != NULL) { |
| // update pptr to match gptr |
| streambuf_t::pbump(static_cast<int>(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<int>(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<class Ch, class Tr, class Alloc> |
| typename basic_altstringbuf<Ch, Tr, Alloc>::int_type |
| basic_altstringbuf<Ch, Tr, Alloc>:: |
| 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<class Ch, class Tr, class Alloc> |
| typename basic_altstringbuf<Ch, Tr, Alloc>::int_type |
| basic_altstringbuf<Ch, Tr, Alloc>:: |
| 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<class Ch, class Tr, class Alloc> |
| typename basic_altstringbuf<Ch, Tr, Alloc>::int_type |
| basic_altstringbuf<Ch, Tr, Alloc>:: |
| 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<std::size_t>::max)() |
| - add_size < new_size) ) |
| add_size /= 2; |
| if(0 < add_size) { |
| new_size += add_size; |
| #ifdef _RWSTD_NO_CLASS_PARTIAL_SPEC |
| void *vdptr = alloc_.allocate(new_size, is_allocated_? oldptr : 0); |
| newptr = static_cast<Ch *>(vdptr); |
| #else |
| newptr = alloc_.allocate(new_size, is_allocated_? oldptr : 0); |
| #endif |
| } |
| |
| 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<int>(pptr()-pbase()); |
| int gptr_count = static_cast<int>(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<class Ch, class Tr, class Alloc> |
| void basic_altstringbuf<Ch, Tr, Alloc>:: 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 |
| |