| ////////////////////////////////////////////////////////////////////////////// |
| // |
| // (C) Copyright Ion Gaztanaga 2005-2009. Distributed under 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/interprocess for documentation. |
| // |
| ////////////////////////////////////////////////////////////////////////////// |
| // |
| // This file comes from SGI's sstream file. Modified by Ion Gaztanaga 2005. |
| // Changed internal SGI string to a generic, templatized vector. Added efficient |
| // internal buffer get/set/swap functions, so that we can obtain/establish the |
| // internal buffer without any reallocation or copy. Kill those temporaries! |
| /////////////////////////////////////////////////////////////////////////////// |
| /* |
| * Copyright (c) 1998 |
| * Silicon Graphics Computer Systems, Inc. |
| * |
| * Permission to use, copy, modify, distribute and sell this software |
| * and its documentation for any purpose is hereby granted without fee, |
| * provided that the above copyright notice appear in all copies and |
| * that both that copyright notice and this permission notice appear |
| * in supporting documentation. Silicon Graphics makes no |
| * representations about the suitability of this software for any |
| * purpose. It is provided "as is" without express or implied warranty. |
| */ |
| |
| //!\file |
| //!This file defines basic_vectorbuf, basic_ivectorstream, |
| //!basic_ovectorstream, and basic_vectorstreamclasses. These classes |
| //!represent streamsbufs and streams whose sources or destinations are |
| //!STL-like vectors that can be swapped with external vectors to avoid |
| //!unnecessary allocations/copies. |
| |
| #ifndef BOOST_INTERPROCESS_VECTORSTREAM_HPP |
| #define BOOST_INTERPROCESS_VECTORSTREAM_HPP |
| |
| #include <boost/interprocess/detail/config_begin.hpp> |
| #include <boost/interprocess/detail/workaround.hpp> |
| |
| #include <iosfwd> |
| #include <ios> |
| #include <istream> |
| #include <ostream> |
| #include <string> // char traits |
| #include <cstddef> // ptrdiff_t |
| #include <boost/interprocess/interprocess_fwd.hpp> |
| #include <boost/assert.hpp> |
| |
| namespace boost { namespace interprocess { |
| |
| //!A streambuf class that controls the transmission of elements to and from |
| //!a basic_ivectorstream, basic_ovectorstream or basic_vectorstream. |
| //!It holds a character vector specified by CharVector template parameter |
| //!as its formatting buffer. The vector must have contiguous storage, like |
| //!std::vector, boost::interprocess::vector or boost::interprocess::basic_string |
| template <class CharVector, class CharTraits> |
| class basic_vectorbuf |
| : public std::basic_streambuf<typename CharVector::value_type, CharTraits> |
| { |
| public: |
| typedef CharVector vector_type; |
| typedef typename CharVector::value_type char_type; |
| typedef typename CharTraits::int_type int_type; |
| typedef typename CharTraits::pos_type pos_type; |
| typedef typename CharTraits::off_type off_type; |
| typedef CharTraits traits_type; |
| |
| /// @cond |
| private: |
| typedef std::basic_streambuf<char_type, traits_type> base_t; |
| |
| basic_vectorbuf(const basic_vectorbuf&); |
| basic_vectorbuf & operator =(const basic_vectorbuf&); |
| /// @endcond |
| |
| public: |
| //!Constructor. Throws if vector_type default |
| //!constructor throws. |
| explicit basic_vectorbuf(std::ios_base::openmode mode |
| = std::ios_base::in | std::ios_base::out) |
| : base_t(), m_mode(mode) |
| { this->initialize_pointers(); } |
| |
| //!Constructor. Throws if |
| //!vector_type(const VectorParameter ¶m) throws. |
| template<class VectorParameter> |
| explicit basic_vectorbuf(const VectorParameter ¶m, |
| std::ios_base::openmode mode |
| = std::ios_base::in | std::ios_base::out) |
| : base_t(), m_mode(mode), m_vect(param) |
| { this->initialize_pointers(); } |
| |
| virtual ~basic_vectorbuf(){} |
| |
| public: |
| |
| //!Swaps the underlying vector with the passed vector. |
| //!This function resets the read/write position in the stream. |
| //!Does not throw. |
| void swap_vector(vector_type &vect) |
| { |
| if (this->m_mode & std::ios_base::out){ |
| //Update high water if necessary |
| //And resize vector to remove extra size |
| if (mp_high_water < base_t::pptr()){ |
| //Restore the vector's size if necessary |
| mp_high_water = base_t::pptr(); |
| } |
| //This does not reallocate |
| m_vect.resize(mp_high_water - (m_vect.size() ? &m_vect[0] : 0)); |
| } |
| //Now swap vector |
| m_vect.swap(vect); |
| this->initialize_pointers(); |
| } |
| |
| //!Returns a const reference to the internal vector. |
| //!Does not throw. |
| const vector_type &vector() const |
| { |
| if (this->m_mode & std::ios_base::out){ |
| if (mp_high_water < base_t::pptr()){ |
| //Restore the vector's size if necessary |
| mp_high_water = base_t::pptr(); |
| } |
| //This shouldn't reallocate |
| typedef typename vector_type::size_type size_type; |
| char_type *old_ptr = base_t::pbase(); |
| size_type high_pos = size_type(mp_high_water-old_ptr); |
| if(m_vect.size() > high_pos){ |
| m_vect.resize(high_pos); |
| //But we must update end write pointer because vector size is now shorter |
| int old_pos = base_t::pptr() - base_t::pbase(); |
| const_cast<basic_vectorbuf*>(this)->base_t::setp(old_ptr, old_ptr + high_pos); |
| const_cast<basic_vectorbuf*>(this)->base_t::pbump(old_pos); |
| } |
| } |
| return m_vect; |
| } |
| |
| //!Preallocates memory from the internal vector. |
| //!Resets the stream to the first position. |
| //!Throws if the internals vector's memory allocation throws. |
| void reserve(typename vector_type::size_type size) |
| { |
| if (this->m_mode & std::ios_base::out && size > m_vect.size()){ |
| typename vector_type::difference_type write_pos = base_t::pptr() - base_t::pbase(); |
| typename vector_type::difference_type read_pos = base_t::gptr() - base_t::eback(); |
| //Now update pointer data |
| m_vect.reserve(size); |
| this->initialize_pointers(); |
| base_t::pbump((int)write_pos); |
| if(this->m_mode & std::ios_base::in){ |
| base_t::gbump((int)read_pos); |
| } |
| } |
| } |
| |
| //!Calls clear() method of the internal vector. |
| //!Resets the stream to the first position. |
| void clear() |
| { m_vect.clear(); this->initialize_pointers(); } |
| |
| /// @cond |
| private: |
| //Maximizes high watermark to the initial vector size, |
| //initializes read and write iostream buffers to the capacity |
| //and resets stream positions |
| void initialize_pointers() |
| { |
| // The initial read position is the beginning of the vector. |
| if(!(m_mode & std::ios_base::out)){ |
| if(m_vect.empty()){ |
| this->setg(0, 0, 0); |
| } |
| else{ |
| this->setg(&m_vect[0], &m_vect[0], &m_vect[0] + m_vect.size()); |
| } |
| } |
| |
| // The initial write position is the beginning of the vector. |
| if(m_mode & std::ios_base::out){ |
| //First get real size |
| int real_size = (int)m_vect.size(); |
| //Then maximize size for high watermarking |
| m_vect.resize(m_vect.capacity()); |
| BOOST_ASSERT(m_vect.size() == m_vect.capacity()); |
| //Set high watermarking with the expanded size |
| mp_high_water = m_vect.size() ? (&m_vect[0] + real_size) : 0; |
| //Now set formatting pointers |
| if(m_vect.empty()){ |
| this->setp(0, 0); |
| if(m_mode & std::ios_base::in) |
| this->setg(0, 0, 0); |
| } |
| else{ |
| char_type *p = &m_vect[0]; |
| this->setp(p, p + m_vect.size()); |
| if(m_mode & std::ios_base::in) |
| this->setg(p, p, p + real_size); |
| } |
| if (m_mode & (std::ios_base::app | std::ios_base::ate)){ |
| base_t::pbump((int)real_size); |
| } |
| } |
| } |
| |
| protected: |
| virtual int_type underflow() |
| { |
| if (base_t::gptr() == 0) |
| return CharTraits::eof(); |
| if(m_mode & std::ios_base::out){ |
| if (mp_high_water < base_t::pptr()) |
| mp_high_water = base_t::pptr(); |
| if (base_t::egptr() < mp_high_water) |
| base_t::setg(base_t::eback(), base_t::gptr(), mp_high_water); |
| } |
| if (base_t::gptr() < base_t::egptr()) |
| return CharTraits::to_int_type(*base_t::gptr()); |
| return CharTraits::eof(); |
| } |
| |
| virtual int_type pbackfail(int_type c = CharTraits::eof()) |
| { |
| if(this->gptr() != this->eback()) { |
| if(!CharTraits::eq_int_type(c, CharTraits::eof())) { |
| if(CharTraits::eq(CharTraits::to_char_type(c), this->gptr()[-1])) { |
| this->gbump(-1); |
| return c; |
| } |
| else if(m_mode & std::ios_base::out) { |
| this->gbump(-1); |
| *this->gptr() = c; |
| return c; |
| } |
| else |
| return CharTraits::eof(); |
| } |
| else { |
| this->gbump(-1); |
| return CharTraits::not_eof(c); |
| } |
| } |
| else |
| return CharTraits::eof(); |
| } |
| |
| virtual int_type overflow(int_type c = CharTraits::eof()) |
| { |
| if(m_mode & std::ios_base::out) { |
| if(!CharTraits::eq_int_type(c, CharTraits::eof())) { |
| typedef typename vector_type::difference_type dif_t; |
| //The new output position is the previous one plus one |
| //because 'overflow' requires putting 'c' on the buffer |
| dif_t new_outpos = base_t::pptr() - base_t::pbase() + 1; |
| //Adjust high water if necessary |
| dif_t hipos = mp_high_water - base_t::pbase(); |
| if (hipos < new_outpos) |
| hipos = new_outpos; |
| //Insert the new data |
| m_vect.push_back(CharTraits::to_char_type(c)); |
| m_vect.resize(m_vect.capacity()); |
| BOOST_ASSERT(m_vect.size() == m_vect.capacity()); |
| char_type* p = const_cast<char_type*>(&m_vect[0]); |
| //A reallocation might have happened, update pointers |
| base_t::setp(p, p + (dif_t)m_vect.size()); |
| mp_high_water = p + hipos; |
| if (m_mode & std::ios_base::in) |
| base_t::setg(p, p + (base_t::gptr() - base_t::eback()), mp_high_water); |
| //Update write position to the old position + 1 |
| base_t::pbump((int)new_outpos); |
| return c; |
| } |
| else // c is EOF, so we don't have to do anything |
| return CharTraits::not_eof(c); |
| } |
| else // Overflow always fails if it's read-only. |
| return CharTraits::eof(); |
| } |
| |
| virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir, |
| std::ios_base::openmode mode |
| = std::ios_base::in | std::ios_base::out) |
| { |
| //Get seek mode |
| bool in(0 != (mode & std::ios_base::in)), out(0 != (mode & std::ios_base::out)); |
| //Test for logic errors |
| if(!in & !out) |
| return pos_type(off_type(-1)); |
| else if((in && out) && (dir == std::ios_base::cur)) |
| return pos_type(off_type(-1)); |
| else if((in && (!(m_mode & std::ios_base::in) || this->gptr() == 0)) || |
| (out && (!(m_mode & std::ios_base::out) || this->pptr() == 0))) |
| return pos_type(off_type(-1)); |
| |
| off_type newoff; |
| //Just calculate the end of the stream. If the stream is read-only |
| //the limit is the size of the vector. Otherwise, the high water mark |
| //will mark the real size. |
| off_type limit; |
| if(m_mode & std::ios_base::out){ |
| //Update high water marking because pptr() is going to change and it might |
| //have been updated since last overflow() |
| if(mp_high_water < base_t::pptr()) |
| mp_high_water = base_t::pptr(); |
| //Update read limits in case high water mark was changed |
| if(m_mode & std::ios_base::in){ |
| if (base_t::egptr() < mp_high_water) |
| base_t::setg(base_t::eback(), base_t::gptr(), mp_high_water); |
| } |
| limit = static_cast<off_type>(mp_high_water - base_t::pbase()); |
| } |
| else{ |
| limit = static_cast<off_type>(m_vect.size()); |
| } |
| |
| switch(dir) { |
| case std::ios_base::beg: |
| newoff = 0; |
| break; |
| case std::ios_base::end: |
| newoff = limit; |
| break; |
| case std::ios_base::cur: |
| newoff = in ? static_cast<std::streamoff>(this->gptr() - this->eback()) |
| : static_cast<std::streamoff>(this->pptr() - this->pbase()); |
| break; |
| default: |
| return pos_type(off_type(-1)); |
| } |
| |
| newoff += off; |
| |
| if (newoff < 0 || newoff > limit) |
| return pos_type(-1); |
| if (m_mode & std::ios_base::app && mode & std::ios_base::out && newoff != limit) |
| return pos_type(-1); |
| //This can reassign pointers |
| //if(m_vect.size() != m_vect.capacity()) |
| //this->initialize_pointers(); |
| if (in) |
| base_t::setg(base_t::eback(), base_t::eback() + newoff, base_t::egptr()); |
| if (out){ |
| base_t::setp(base_t::pbase(), base_t::epptr()); |
| base_t::pbump(newoff); |
| } |
| return pos_type(newoff); |
| } |
| |
| virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode |
| = std::ios_base::in | std::ios_base::out) |
| { return seekoff(pos - pos_type(off_type(0)), std::ios_base::beg, mode); } |
| |
| private: |
| std::ios_base::openmode m_mode; |
| mutable vector_type m_vect; |
| mutable char_type* mp_high_water; |
| /// @endcond |
| }; |
| |
| //!A basic_istream class that holds a character vector specified by CharVector |
| //!template parameter as its formatting buffer. The vector must have |
| //!contiguous storage, like std::vector, boost::interprocess::vector or |
| //!boost::interprocess::basic_string |
| template <class CharVector, class CharTraits> |
| class basic_ivectorstream |
| /// @cond |
| : private basic_vectorbuf<CharVector, CharTraits> |
| /// @endcond |
| , public std::basic_istream<typename CharVector::value_type, CharTraits> |
| { |
| public: |
| typedef CharVector vector_type; |
| typedef typename std::basic_ios |
| <typename CharVector::value_type, CharTraits>::char_type char_type; |
| typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type; |
| typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type; |
| typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type; |
| typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type; |
| |
| /// @cond |
| private: |
| typedef basic_vectorbuf<CharVector, CharTraits> vectorbuf_t; |
| typedef std::basic_istream<char_type, CharTraits> base_t; |
| |
| vectorbuf_t & m_buf() { return *this; } |
| const vectorbuf_t & m_buf() const{ return *this; } |
| /// @endcond |
| |
| public: |
| //!Constructor. Throws if vector_type default |
| //!constructor throws. |
| basic_ivectorstream(std::ios_base::openmode mode = std::ios_base::in) |
| : vectorbuf_t(mode | std::ios_base::in), base_t(&m_buf()) |
| {} |
| |
| //!Constructor. Throws if vector_type(const VectorParameter ¶m) |
| //!throws. |
| template<class VectorParameter> |
| basic_ivectorstream(const VectorParameter ¶m, |
| std::ios_base::openmode mode = std::ios_base::in) |
| : vectorbuf_t(param, mode | std::ios_base::in), base_t(&m_buf()) |
| {} |
| |
| ~basic_ivectorstream(){}; |
| |
| public: |
| //!Returns the address of the stored |
| //!stream buffer. |
| basic_vectorbuf<CharVector, CharTraits>* rdbuf() const |
| { return const_cast<basic_vectorbuf<CharVector, CharTraits>*>(&m_buf()); } |
| |
| //!Swaps the underlying vector with the passed vector. |
| //!This function resets the read position in the stream. |
| //!Does not throw. |
| void swap_vector(vector_type &vect) |
| { m_buf().swap_vector(vect); } |
| |
| //!Returns a const reference to the internal vector. |
| //!Does not throw. |
| const vector_type &vector() const |
| { return m_buf().vector(); } |
| |
| //!Calls reserve() method of the internal vector. |
| //!Resets the stream to the first position. |
| //!Throws if the internals vector's reserve throws. |
| void reserve(typename vector_type::size_type size) |
| { m_buf().reserve(size); } |
| |
| //!Calls clear() method of the internal vector. |
| //!Resets the stream to the first position. |
| void clear() |
| { m_buf().clear(); } |
| }; |
| |
| //!A basic_ostream class that holds a character vector specified by CharVector |
| //!template parameter as its formatting buffer. The vector must have |
| //!contiguous storage, like std::vector, boost::interprocess::vector or |
| //!boost::interprocess::basic_string |
| template <class CharVector, class CharTraits> |
| class basic_ovectorstream |
| /// @cond |
| : private basic_vectorbuf<CharVector, CharTraits> |
| /// @endcond |
| , public std::basic_ostream<typename CharVector::value_type, CharTraits> |
| { |
| public: |
| typedef CharVector vector_type; |
| typedef typename std::basic_ios |
| <typename CharVector::value_type, CharTraits>::char_type char_type; |
| typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type; |
| typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type; |
| typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type; |
| typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type; |
| |
| /// @cond |
| private: |
| typedef basic_vectorbuf<CharVector, CharTraits> vectorbuf_t; |
| typedef std::basic_ostream<char_type, CharTraits> base_t; |
| |
| vectorbuf_t & m_buf() { return *this; } |
| const vectorbuf_t & m_buf()const { return *this; } |
| /// @endcond |
| |
| public: |
| //!Constructor. Throws if vector_type default |
| //!constructor throws. |
| basic_ovectorstream(std::ios_base::openmode mode = std::ios_base::out) |
| : vectorbuf_t(mode | std::ios_base::out), base_t(&m_buf()) |
| {} |
| |
| //!Constructor. Throws if vector_type(const VectorParameter ¶m) |
| //!throws. |
| template<class VectorParameter> |
| basic_ovectorstream(const VectorParameter ¶m, |
| std::ios_base::openmode mode = std::ios_base::out) |
| : vectorbuf_t(param, mode | std::ios_base::out), base_t(&m_buf()) |
| {} |
| |
| ~basic_ovectorstream(){} |
| |
| public: |
| //!Returns the address of the stored |
| //!stream buffer. |
| basic_vectorbuf<CharVector, CharTraits>* rdbuf() const |
| { return const_cast<basic_vectorbuf<CharVector, CharTraits>*>(&m_buf()); } |
| |
| //!Swaps the underlying vector with the passed vector. |
| //!This function resets the write position in the stream. |
| //!Does not throw. |
| void swap_vector(vector_type &vect) |
| { m_buf().swap_vector(vect); } |
| |
| //!Returns a const reference to the internal vector. |
| //!Does not throw. |
| const vector_type &vector() const |
| { return m_buf().vector(); } |
| |
| //!Calls reserve() method of the internal vector. |
| //!Resets the stream to the first position. |
| //!Throws if the internals vector's reserve throws. |
| void reserve(typename vector_type::size_type size) |
| { m_buf().reserve(size); } |
| }; |
| |
| |
| //!A basic_iostream class that holds a character vector specified by CharVector |
| //!template parameter as its formatting buffer. The vector must have |
| //!contiguous storage, like std::vector, boost::interprocess::vector or |
| //!boost::interprocess::basic_string |
| template <class CharVector, class CharTraits> |
| class basic_vectorstream |
| : public std::basic_iostream<typename CharVector::value_type, CharTraits> |
| |
| { |
| public: |
| typedef CharVector vector_type; |
| typedef typename std::basic_ios |
| <typename CharVector::value_type, CharTraits>::char_type char_type; |
| typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type; |
| typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type; |
| typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type; |
| typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type; |
| |
| /// @cond |
| private: |
| typedef std::basic_ios<char_type, CharTraits> basic_ios_t; |
| typedef std::basic_iostream<char_type, CharTraits> base_t; |
| /// @endcond |
| |
| public: |
| //!Constructor. Throws if vector_type default |
| //!constructor throws. |
| basic_vectorstream(std::ios_base::openmode mode |
| = std::ios_base::in | std::ios_base::out) |
| : basic_ios_t(), base_t(0), m_buf(mode) |
| { basic_ios_t::init(&m_buf); } |
| |
| //!Constructor. Throws if vector_type(const VectorParameter ¶m) |
| //!throws. |
| template<class VectorParameter> |
| basic_vectorstream(const VectorParameter ¶m, std::ios_base::openmode mode |
| = std::ios_base::in | std::ios_base::out) |
| : basic_ios_t(), base_t(0), m_buf(param, mode) |
| { basic_ios_t::init(&m_buf); } |
| |
| ~basic_vectorstream(){} |
| |
| public: |
| //Returns the address of the stored stream buffer. |
| basic_vectorbuf<CharVector, CharTraits>* rdbuf() const |
| { return const_cast<basic_vectorbuf<CharVector, CharTraits>*>(&m_buf); } |
| |
| //!Swaps the underlying vector with the passed vector. |
| //!This function resets the read/write position in the stream. |
| //!Does not throw. |
| void swap_vector(vector_type &vect) |
| { m_buf.swap_vector(vect); } |
| |
| //!Returns a const reference to the internal vector. |
| //!Does not throw. |
| const vector_type &vector() const |
| { return m_buf.vector(); } |
| |
| //!Calls reserve() method of the internal vector. |
| //!Resets the stream to the first position. |
| //!Throws if the internals vector's reserve throws. |
| void reserve(typename vector_type::size_type size) |
| { m_buf.reserve(size); } |
| |
| //!Calls clear() method of the internal vector. |
| //!Resets the stream to the first position. |
| void clear() |
| { m_buf.clear(); } |
| |
| /// @cond |
| private: |
| basic_vectorbuf<CharVector, CharTraits> m_buf; |
| /// @endcond |
| }; |
| |
| //Some typedefs to simplify usage |
| //! |
| //!typedef basic_vectorbuf<std::vector<char> > vectorbuf; |
| //!typedef basic_vectorstream<std::vector<char> > vectorstream; |
| //!typedef basic_ivectorstream<std::vector<char> > ivectorstream; |
| //!typedef basic_ovectorstream<std::vector<char> > ovectorstream; |
| //! |
| //!typedef basic_vectorbuf<std::vector<wchar_t> > wvectorbuf; |
| //!typedef basic_vectorstream<std::vector<wchar_t> > wvectorstream; |
| //!typedef basic_ivectorstream<std::vector<wchar_t> > wivectorstream; |
| //!typedef basic_ovectorstream<std::vector<wchar_t> > wovectorstream; |
| |
| }} //namespace boost { namespace interprocess { |
| |
| #include <boost/interprocess/detail/config_end.hpp> |
| |
| #endif /* BOOST_INTERPROCESS_VECTORSTREAM_HPP */ |