////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Ion Gaztanaga 2005-2012. 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-2012. // 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 #include #include #include #include // char traits #include // ptrdiff_t #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wreorder" #endif 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 basic_vectorbuf : public std::basic_streambuf { 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; #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) private: typedef std::basic_streambuf base_t; basic_vectorbuf(const basic_vectorbuf&); basic_vectorbuf & operator =(const basic_vectorbuf&); #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED 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 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(); } 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(std::size_t(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 = (int)(base_t::pptr() - base_t::pbase()); const_cast(this)->base_t::setp(old_ptr, old_ptr + high_pos); const_cast(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(); } #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) 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() BOOST_OVERRIDE { 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()) BOOST_OVERRIDE { 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() = CharTraits::to_char_type(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()) BOOST_OVERRIDE { 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(&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) BOOST_OVERRIDE { //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) || (off != 0 && this->gptr() == 0) )) || (out && (!(m_mode & std::ios_base::out) || (off != 0 && 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(mp_high_water - base_t::pbase()); } else{ limit = static_cast(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(this->gptr() - this->eback()) : static_cast(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(static_cast(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) BOOST_OVERRIDE { 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; #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED }; //!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 basic_ivectorstream : public std::basic_istream #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) , private basic_vectorbuf #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED { public: typedef CharVector vector_type; typedef typename std::basic_ios ::char_type char_type; typedef typename std::basic_ios::int_type int_type; typedef typename std::basic_ios::pos_type pos_type; typedef typename std::basic_ios::off_type off_type; typedef typename std::basic_ios::traits_type traits_type; #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) private: typedef basic_vectorbuf vectorbuf_t; typedef std::basic_ios basic_ios_t; typedef std::basic_istream base_t; vectorbuf_t & get_buf() { return *this; } const vectorbuf_t & get_buf() const{ return *this; } #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED public: //!Constructor. Throws if vector_type default //!constructor throws. basic_ivectorstream(std::ios_base::openmode mode = std::ios_base::in) : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base //(via basic_ios::init() call in base_t's constructor) without the risk of a //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. , vectorbuf_t(mode | std::ios_base::in) { this->base_t::rdbuf(&get_buf()); } //!Constructor. Throws if vector_type(const VectorParameter ¶m) //!throws. template basic_ivectorstream(const VectorParameter ¶m, std::ios_base::openmode mode = std::ios_base::in) : vectorbuf_t(param, mode | std::ios_base::in) //basic_ios_t() is constructed uninitialized as virtual base //and initialized inside base_t calling basic_ios::init() , base_t(&get_buf()) {} public: //!Returns the address of the stored //!stream buffer. basic_vectorbuf* rdbuf() const { return const_cast*>(&get_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) { get_buf().swap_vector(vect); } //!Returns a const reference to the internal vector. //!Does not throw. const vector_type &vector() const { return get_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) { get_buf().reserve(size); } //!Calls clear() method of the internal vector. //!Resets the stream to the first position. void clear() { get_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 basic_ovectorstream : public std::basic_ostream #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) , private basic_vectorbuf #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED { public: typedef CharVector vector_type; typedef typename std::basic_ios ::char_type char_type; typedef typename std::basic_ios::int_type int_type; typedef typename std::basic_ios::pos_type pos_type; typedef typename std::basic_ios::off_type off_type; typedef typename std::basic_ios::traits_type traits_type; #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) private: typedef basic_vectorbuf vectorbuf_t; typedef std::basic_ios basic_ios_t; typedef std::basic_ostream base_t; vectorbuf_t & get_buf() { return *this; } const vectorbuf_t & get_buf()const { return *this; } #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED public: //!Constructor. Throws if vector_type default //!constructor throws. basic_ovectorstream(std::ios_base::openmode mode = std::ios_base::out) : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base //(via basic_ios::init() call in base_t's constructor) without the risk of a //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. , vectorbuf_t(mode | std::ios_base::out) { this->base_t::rdbuf(&get_buf()); } //!Constructor. Throws if vector_type(const VectorParameter ¶m) //!throws. template basic_ovectorstream(const VectorParameter ¶m, std::ios_base::openmode mode = std::ios_base::out) : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base //(via basic_ios::init() call in base_t's constructor) without the risk of a //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. , vectorbuf_t(param, mode | std::ios_base::out) { this->base_t::rdbuf(&get_buf()); } public: //!Returns the address of the stored //!stream buffer. basic_vectorbuf* rdbuf() const { return const_cast*>(&get_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) { get_buf().swap_vector(vect); } //!Returns a const reference to the internal vector. //!Does not throw. const vector_type &vector() const { return get_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) { get_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 basic_vectorstream : public std::basic_iostream #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) , private basic_vectorbuf #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED { public: typedef CharVector vector_type; typedef typename std::basic_ios ::char_type char_type; typedef typename std::basic_ios::int_type int_type; typedef typename std::basic_ios::pos_type pos_type; typedef typename std::basic_ios::off_type off_type; typedef typename std::basic_ios::traits_type traits_type; #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) private: typedef basic_vectorbuf vectorbuf_t; typedef std::basic_ios basic_ios_t; typedef std::basic_iostream base_t; vectorbuf_t & get_buf() { return *this; } const vectorbuf_t & get_buf() const{ return *this; } #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED public: //!Constructor. Throws if vector_type default //!constructor throws. basic_vectorstream(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base //(via basic_ios::init() call in base_t's constructor) without the risk of a //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. , vectorbuf_t(mode) { this->base_t::rdbuf(&get_buf()); } //!Constructor. Throws if vector_type(const VectorParameter ¶m) //!throws. template basic_vectorstream(const VectorParameter ¶m, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base //(via basic_ios::init() call in base_t's constructor) without the risk of a //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. , vectorbuf_t(param, mode) { this->base_t::rdbuf(&get_buf()); } public: //Returns the address of the stored stream buffer. basic_vectorbuf* rdbuf() const { return const_cast*>(&get_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) { get_buf().swap_vector(vect); } //!Returns a const reference to the internal vector. //!Does not throw. const vector_type &vector() const { return get_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) { get_buf().reserve(size); } //!Calls clear() method of the internal vector. //!Resets the stream to the first position. void clear() { get_buf().clear(); } }; //Some typedefs to simplify usage //! //!typedef basic_vectorbuf > vectorbuf; //!typedef basic_vectorstream > vectorstream; //!typedef basic_ivectorstream > ivectorstream; //!typedef basic_ovectorstream > ovectorstream; //! //!typedef basic_vectorbuf > wvectorbuf; //!typedef basic_vectorstream > wvectorstream; //!typedef basic_ivectorstream > wivectorstream; //!typedef basic_ovectorstream > wovectorstream; }} //namespace boost { namespace interprocess { #ifdef __GNUC__ #pragma GCC diagnostic pop #endif #endif /* BOOST_INTERPROCESS_VECTORSTREAM_HPP */