1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/interprocess for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10 //
11 // This file comes from SGI's sstream file. Modified by Ion Gaztanaga 2005-2012.
12 // Changed internal SGI string to a buffer. Added efficient
13 // internal buffer get/set/swap functions, so that we can obtain/establish the
14 // internal buffer without any reallocation or copy. Kill those temporaries!
15 ///////////////////////////////////////////////////////////////////////////////
16 /*
17  * Copyright (c) 1998
18  * Silicon Graphics Computer Systems, Inc.
19  *
20  * Permission to use, copy, modify, distribute and sell this software
21  * and its documentation for any purpose is hereby granted without fee,
22  * provided that the above copyright notice appear in all copies and
23  * that both that copyright notice and this permission notice appear
24  * in supporting documentation.  Silicon Graphics makes no
25  * representations about the suitability of this software for any
26  * purpose.  It is provided "as is" without express or implied warranty.
27  */
28 
29 //!\file
30 //!This file defines basic_bufferbuf, basic_ibufferstream,
31 //!basic_obufferstream, and basic_bufferstream classes. These classes
32 //!represent streamsbufs and streams whose sources or destinations
33 //!are fixed size character buffers.
34 
35 #ifndef BOOST_INTERPROCESS_BUFFERSTREAM_HPP
36 #define BOOST_INTERPROCESS_BUFFERSTREAM_HPP
37 
38 #ifndef BOOST_CONFIG_HPP
39 #  include <boost/config.hpp>
40 #endif
41 #
42 #if defined(BOOST_HAS_PRAGMA_ONCE)
43 #  pragma once
44 #endif
45 
46 #include <boost/interprocess/detail/config_begin.hpp>
47 #include <boost/interprocess/detail/workaround.hpp>
48 
49 #include <iosfwd>
50 #include <ios>
51 #include <istream>
52 #include <ostream>
53 #include <string>    // char traits
54 #include <cstddef>   // ptrdiff_t
55 #include <boost/assert.hpp>
56 #include <boost/interprocess/interprocess_fwd.hpp>
57 
58 namespace boost {  namespace interprocess {
59 
60 //!A streambuf class that controls the transmission of elements to and from
61 //!a basic_xbufferstream. The elements are transmitted from a to a fixed
62 //!size buffer
63 template <class CharT, class CharTraits>
64 class basic_bufferbuf
65    : public std::basic_streambuf<CharT, CharTraits>
66 {
67    public:
68    typedef CharT                                         char_type;
69    typedef typename CharTraits::int_type                 int_type;
70    typedef typename CharTraits::pos_type                 pos_type;
71    typedef typename CharTraits::off_type                 off_type;
72    typedef CharTraits                                    traits_type;
73    typedef std::basic_streambuf<char_type, traits_type>  base_t;
74 
75    public:
76    //!Constructor.
77    //!Does not throw.
basic_bufferbuf(std::ios_base::openmode mode=std::ios_base::in|std::ios_base::out)78    explicit basic_bufferbuf(std::ios_base::openmode mode
79                             = std::ios_base::in | std::ios_base::out)
80       :  base_t(), m_mode(mode), m_buffer(0), m_length(0)
81       {}
82 
83    //!Constructor. Assigns formatting buffer.
84    //!Does not throw.
basic_bufferbuf(CharT * buf,std::size_t length,std::ios_base::openmode mode=std::ios_base::in|std::ios_base::out)85    explicit basic_bufferbuf(CharT *buf, std::size_t length,
86                             std::ios_base::openmode mode
87                               = std::ios_base::in | std::ios_base::out)
88       :  base_t(), m_mode(mode), m_buffer(buf), m_length(length)
89       {  this->set_pointers();   }
90 
~basic_bufferbuf()91    virtual ~basic_bufferbuf(){}
92 
93    public:
94    //!Returns the pointer and size of the internal buffer.
95    //!Does not throw.
buffer() const96    std::pair<CharT *, std::size_t> buffer() const
97       { return std::pair<CharT *, std::size_t>(m_buffer, m_length); }
98 
99    //!Sets the underlying buffer to a new value
100    //!Does not throw.
buffer(CharT * buf,std::size_t length)101    void buffer(CharT *buf, std::size_t length)
102       {  m_buffer = buf;   m_length = length;   this->set_pointers();   }
103 
104    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
105    private:
set_pointers()106    void set_pointers()
107    {
108       // The initial read position is the beginning of the buffer.
109       if(m_mode & std::ios_base::in)
110          this->setg(m_buffer, m_buffer, m_buffer + m_length);
111 
112       // The initial write position is the beginning of the buffer.
113       if(m_mode & std::ios_base::out)
114          this->setp(m_buffer, m_buffer + m_length);
115    }
116 
117    protected:
underflow()118    virtual int_type underflow()
119    {
120       // Precondition: gptr() >= egptr(). Returns a character, if available.
121       return this->gptr() != this->egptr() ?
122          CharTraits::to_int_type(*this->gptr()) : CharTraits::eof();
123    }
124 
pbackfail(int_type c=CharTraits::eof ())125    virtual int_type pbackfail(int_type c = CharTraits::eof())
126    {
127       if(this->gptr() != this->eback()) {
128          if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
129             if(CharTraits::eq(CharTraits::to_char_type(c), this->gptr()[-1])) {
130                this->gbump(-1);
131                return c;
132             }
133             else if(m_mode & std::ios_base::out) {
134                this->gbump(-1);
135                *this->gptr() = c;
136                return c;
137             }
138             else
139                return CharTraits::eof();
140          }
141          else {
142             this->gbump(-1);
143             return CharTraits::not_eof(c);
144          }
145       }
146       else
147          return CharTraits::eof();
148    }
149 
overflow(int_type c=CharTraits::eof ())150    virtual int_type overflow(int_type c = CharTraits::eof())
151    {
152       if(m_mode & std::ios_base::out) {
153          if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
154 //            if(!(m_mode & std::ios_base::in)) {
155 //               if(this->pptr() != this->epptr()) {
156 //                  *this->pptr() = CharTraits::to_char_type(c);
157 //                  this->pbump(1);
158 //                  return c;
159 //               }
160 //               else
161 //                  return CharTraits::eof();
162 //            }
163 //            else {
164                if(this->pptr() == this->epptr()) {
165                   //We can't append to a static buffer
166                   return CharTraits::eof();
167                }
168                else {
169                   *this->pptr() = CharTraits::to_char_type(c);
170                   this->pbump(1);
171                   return c;
172                }
173 //            }
174          }
175          else  // c is EOF, so we don't have to do anything
176             return CharTraits::not_eof(c);
177       }
178       else     // Overflow always fails if it's read-only.
179          return CharTraits::eof();
180    }
181 
seekoff(off_type off,std::ios_base::seekdir dir,std::ios_base::openmode mode=std::ios_base::in|std::ios_base::out)182    virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir,
183                               std::ios_base::openmode mode
184                                  = std::ios_base::in | std::ios_base::out)
185    {
186       bool in  = false;
187       bool out = false;
188 
189       const std::ios_base::openmode inout =
190          std::ios_base::in | std::ios_base::out;
191 
192       if((mode & inout) == inout) {
193          if(dir == std::ios_base::beg || dir == std::ios_base::end)
194             in = out = true;
195       }
196       else if(mode & std::ios_base::in)
197          in = true;
198       else if(mode & std::ios_base::out)
199          out = true;
200 
201       if(!in && !out)
202          return pos_type(off_type(-1));
203       else if((in  && (!(m_mode & std::ios_base::in) || (off != 0 && this->gptr() == 0) )) ||
204                (out && (!(m_mode & std::ios_base::out) || (off != 0 && this->pptr() == 0))))
205          return pos_type(off_type(-1));
206 
207       std::streamoff newoff;
208       switch(dir) {
209          case std::ios_base::beg:
210             newoff = 0;
211          break;
212          case std::ios_base::end:
213             newoff = static_cast<std::streamoff>(m_length);
214          break;
215          case std::ios_base::cur:
216             newoff = in ? static_cast<std::streamoff>(this->gptr() - this->eback())
217                         : static_cast<std::streamoff>(this->pptr() - this->pbase());
218          break;
219          default:
220             return pos_type(off_type(-1));
221       }
222 
223       off += newoff;
224 
225       if(in) {
226          std::ptrdiff_t n = this->egptr() - this->eback();
227 
228          if(off < 0 || off > n)
229             return pos_type(off_type(-1));
230          else
231             this->setg(this->eback(), this->eback() + off, this->eback() + n);
232       }
233 
234       if(out) {
235          std::ptrdiff_t n = this->epptr() - this->pbase();
236 
237          if(off < 0 || off > n)
238             return pos_type(off_type(-1));
239          else {
240             this->setp(this->pbase(), this->pbase() + n);
241             this->pbump(off);
242          }
243       }
244 
245       return pos_type(off);
246    }
247 
seekpos(pos_type pos,std::ios_base::openmode mode=std::ios_base::in|std::ios_base::out)248    virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode
249                                  = std::ios_base::in | std::ios_base::out)
250    {  return seekoff(pos - pos_type(off_type(0)), std::ios_base::beg, mode);  }
251 
252    private:
253    std::ios_base::openmode m_mode;
254    CharT *                 m_buffer;
255    std::size_t             m_length;
256    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
257 };
258 
259 //!A basic_istream class that uses a fixed size character buffer
260 //!as its formatting buffer.
261 template <class CharT, class CharTraits>
262 class basic_ibufferstream :
263    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
264    private basic_bufferbuf<CharT, CharTraits>,
265    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
266    public std::basic_istream<CharT, CharTraits>
267 {
268    public:                         // Typedefs
269    typedef typename std::basic_ios
270       <CharT, CharTraits>::char_type          char_type;
271    typedef typename std::basic_ios<char_type, CharTraits>::int_type     int_type;
272    typedef typename std::basic_ios<char_type, CharTraits>::pos_type     pos_type;
273    typedef typename std::basic_ios<char_type, CharTraits>::off_type     off_type;
274    typedef typename std::basic_ios<char_type, CharTraits>::traits_type  traits_type;
275 
276    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
277    private:
278    typedef basic_bufferbuf<CharT, CharTraits>         bufferbuf_t;
279    typedef std::basic_ios<char_type, CharTraits>      basic_ios_t;
280    typedef std::basic_istream<char_type, CharTraits>  base_t;
get_buf()281    bufferbuf_t &       get_buf()      {  return *this;  }
get_buf() const282    const bufferbuf_t & get_buf() const{  return *this;  }
283    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
284 
285    public:
286    //!Constructor.
287    //!Does not throw.
basic_ibufferstream(std::ios_base::openmode mode=std::ios_base::in)288    basic_ibufferstream(std::ios_base::openmode mode = std::ios_base::in)
289       :  //basic_ios_t() is called first (lefting it uninitialized) as it's a
290          //virtual base of basic_istream. The class will be initialized when
291          //basic_istream is constructed calling basic_ios_t::init().
292          //As bufferbuf_t's constructor does not throw there is no risk of
293          //calling the basic_ios_t's destructor without calling basic_ios_t::init()
294         bufferbuf_t(mode | std::ios_base::in)
295       , base_t(&get_buf())
296       {}
297 
298    //!Constructor. Assigns formatting buffer.
299    //!Does not throw.
basic_ibufferstream(const CharT * buf,std::size_t length,std::ios_base::openmode mode=std::ios_base::in)300    basic_ibufferstream(const CharT *buf, std::size_t length,
301                        std::ios_base::openmode mode = std::ios_base::in)
302       :  //basic_ios_t() is called first (lefting it uninitialized) as it's a
303          //virtual base of basic_istream. The class will be initialized when
304          //basic_istream is constructed calling basic_ios_t::init().
305          //As bufferbuf_t's constructor does not throw there is no risk of
306          //calling the basic_ios_t's destructor without calling basic_ios_t::init()
307         bufferbuf_t(const_cast<CharT*>(buf), length, mode | std::ios_base::in)
308       , base_t(&get_buf())
309       {}
310 
~basic_ibufferstream()311    ~basic_ibufferstream(){};
312 
313    public:
314    //!Returns the address of the stored
315    //!stream buffer.
rdbuf() const316    basic_bufferbuf<CharT, CharTraits>* rdbuf() const
317       { return const_cast<basic_bufferbuf<CharT, CharTraits>*>(&get_buf()); }
318 
319    //!Returns the pointer and size of the internal buffer.
320    //!Does not throw.
buffer() const321    std::pair<const CharT *, std::size_t> buffer() const
322       { return get_buf().buffer(); }
323 
324    //!Sets the underlying buffer to a new value. Resets
325    //!stream position. Does not throw.
buffer(const CharT * buf,std::size_t length)326    void buffer(const CharT *buf, std::size_t length)
327       {  get_buf().buffer(const_cast<CharT*>(buf), length);  }
328 };
329 
330 //!A basic_ostream class that uses a fixed size character buffer
331 //!as its formatting buffer.
332 template <class CharT, class CharTraits>
333 class basic_obufferstream :
334    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
335    private basic_bufferbuf<CharT, CharTraits>,
336    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
337    public std::basic_ostream<CharT, CharTraits>
338 {
339    public:
340    typedef typename std::basic_ios
341       <CharT, CharTraits>::char_type          char_type;
342    typedef typename std::basic_ios<char_type, CharTraits>::int_type     int_type;
343    typedef typename std::basic_ios<char_type, CharTraits>::pos_type     pos_type;
344    typedef typename std::basic_ios<char_type, CharTraits>::off_type     off_type;
345    typedef typename std::basic_ios<char_type, CharTraits>::traits_type  traits_type;
346 
347    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
348    private:
349    typedef basic_bufferbuf<CharT, CharTraits>         bufferbuf_t;
350    typedef std::basic_ios<char_type, CharTraits>      basic_ios_t;
351    typedef std::basic_ostream<char_type, CharTraits>  base_t;
get_buf()352    bufferbuf_t &       get_buf()      {  return *this;  }
get_buf() const353    const bufferbuf_t & get_buf() const{  return *this;  }
354    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
355 
356    public:
357    //!Constructor.
358    //!Does not throw.
basic_obufferstream(std::ios_base::openmode mode=std::ios_base::out)359    basic_obufferstream(std::ios_base::openmode mode = std::ios_base::out)
360       :  //basic_ios_t() is called first (lefting it uninitialized) as it's a
361          //virtual base of basic_istream. The class will be initialized when
362          //basic_istream is constructed calling basic_ios_t::init().
363          //As bufferbuf_t's constructor does not throw there is no risk of
364          //calling the basic_ios_t's destructor without calling basic_ios_t::init()
365          bufferbuf_t(mode | std::ios_base::out)
366       ,  base_t(&get_buf())
367       {}
368 
369    //!Constructor. Assigns formatting buffer.
370    //!Does not throw.
basic_obufferstream(CharT * buf,std::size_t length,std::ios_base::openmode mode=std::ios_base::out)371    basic_obufferstream(CharT *buf, std::size_t length,
372                        std::ios_base::openmode mode = std::ios_base::out)
373       :  //basic_ios_t() is called first (lefting it uninitialized) as it's a
374          //virtual base of basic_istream. The class will be initialized when
375          //basic_istream is constructed calling basic_ios_t::init().
376          //As bufferbuf_t's constructor does not throw there is no risk of
377          //calling the basic_ios_t's destructor without calling basic_ios_t::init()
378          bufferbuf_t(buf, length, mode | std::ios_base::out)
379       ,  base_t(&get_buf())
380       {}
381 
~basic_obufferstream()382    ~basic_obufferstream(){}
383 
384    public:
385    //!Returns the address of the stored
386    //!stream buffer.
rdbuf() const387    basic_bufferbuf<CharT, CharTraits>* rdbuf() const
388       { return const_cast<basic_bufferbuf<CharT, CharTraits>*>(&get_buf()); }
389 
390    //!Returns the pointer and size of the internal buffer.
391    //!Does not throw.
buffer() const392    std::pair<CharT *, std::size_t> buffer() const
393       { return get_buf().buffer(); }
394 
395    //!Sets the underlying buffer to a new value. Resets
396    //!stream position. Does not throw.
buffer(CharT * buf,std::size_t length)397    void buffer(CharT *buf, std::size_t length)
398       {  get_buf().buffer(buf, length);  }
399 };
400 
401 
402 //!A basic_iostream class that uses a fixed size character buffer
403 //!as its formatting buffer.
404 template <class CharT, class CharTraits>
405 class basic_bufferstream :
406    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
407    private basic_bufferbuf<CharT, CharTraits>,
408    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
409    public std::basic_iostream<CharT, CharTraits>
410 {
411    public:                         // Typedefs
412    typedef typename std::basic_ios
413       <CharT, CharTraits>::char_type          char_type;
414    typedef typename std::basic_ios<char_type, CharTraits>::int_type     int_type;
415    typedef typename std::basic_ios<char_type, CharTraits>::pos_type     pos_type;
416    typedef typename std::basic_ios<char_type, CharTraits>::off_type     off_type;
417    typedef typename std::basic_ios<char_type, CharTraits>::traits_type  traits_type;
418 
419    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
420    private:
421    typedef basic_bufferbuf<CharT, CharTraits>         bufferbuf_t;
422    typedef std::basic_ios<char_type, CharTraits>      basic_ios_t;
423    typedef std::basic_iostream<char_type, CharTraits> base_t;
get_buf()424    bufferbuf_t &       get_buf()      {  return *this;  }
get_buf() const425    const bufferbuf_t & get_buf() const{  return *this;  }
426    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
427 
428    public:
429    //!Constructor.
430    //!Does not throw.
basic_bufferstream(std::ios_base::openmode mode=std::ios_base::in|std::ios_base::out)431    basic_bufferstream(std::ios_base::openmode mode
432                       = std::ios_base::in | std::ios_base::out)
433       :  //basic_ios_t() is called first (lefting it uninitialized) as it's a
434          //virtual base of basic_istream. The class will be initialized when
435          //basic_istream is constructed calling basic_ios_t::init().
436          //As bufferbuf_t's constructor does not throw there is no risk of
437          //calling the basic_ios_t's destructor without calling basic_ios_t::init()
438          bufferbuf_t(mode)
439       ,  base_t(&get_buf())
440       {}
441 
442    //!Constructor. Assigns formatting buffer.
443    //!Does not throw.
basic_bufferstream(CharT * buf,std::size_t length,std::ios_base::openmode mode=std::ios_base::in|std::ios_base::out)444    basic_bufferstream(CharT *buf, std::size_t length,
445                       std::ios_base::openmode mode
446                         = std::ios_base::in | std::ios_base::out)
447       :  //basic_ios_t() is called first (lefting it uninitialized) as it's a
448          //virtual base of basic_istream. The class will be initialized when
449          //basic_istream is constructed calling basic_ios_t::init().
450          //As bufferbuf_t's constructor does not throw there is no risk of
451          //calling the basic_ios_t's destructor without calling basic_ios_t::init()
452          bufferbuf_t(buf, length, mode)
453       ,  base_t(&get_buf())
454       {}
455 
~basic_bufferstream()456    ~basic_bufferstream(){}
457 
458    public:
459    //!Returns the address of the stored
460    //!stream buffer.
rdbuf() const461    basic_bufferbuf<CharT, CharTraits>* rdbuf() const
462       { return const_cast<basic_bufferbuf<CharT, CharTraits>*>(&get_buf()); }
463 
464    //!Returns the pointer and size of the internal buffer.
465    //!Does not throw.
buffer() const466    std::pair<CharT *, std::size_t> buffer() const
467       { return get_buf().buffer(); }
468 
469    //!Sets the underlying buffer to a new value. Resets
470    //!stream position. Does not throw.
buffer(CharT * buf,std::size_t length)471    void buffer(CharT *buf, std::size_t length)
472       {  get_buf().buffer(buf, length);  }
473 };
474 
475 //Some typedefs to simplify usage
476 typedef basic_bufferbuf<char>        bufferbuf;
477 typedef basic_bufferstream<char>     bufferstream;
478 typedef basic_ibufferstream<char>    ibufferstream;
479 typedef basic_obufferstream<char>    obufferstream;
480 
481 typedef basic_bufferbuf<wchar_t>     wbufferbuf;
482 typedef basic_bufferstream<wchar_t>  wbufferstream;
483 typedef basic_ibufferstream<wchar_t> wibufferstream;
484 typedef basic_obufferstream<wchar_t> wobufferstream;
485 
486 
487 }} //namespace boost {  namespace interprocess {
488 
489 #include <boost/interprocess/detail/config_end.hpp>
490 
491 #endif /* BOOST_INTERPROCESS_BUFFERSTREAM_HPP */
492