1 // (C) Copyright Jonathan Turkanis 2003-5.
2 // Distributed under the Boost Software License, Version 1.0. (See accompanying
3 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
4 
5 // See http://www.boost.org/libs/iostreams for documentation.
6 
7 #ifndef BOOST_IOSTREAMS_DETAIL_BUFFERS_HPP_INCLUDED
8 #define BOOST_IOSTREAMS_DETAIL_BUFFERS_HPP_INCLUDED
9 
10 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
11 # pragma once
12 #endif
13 
14 #include <algorithm>                           // swap.
15 #include <memory>                              // allocator.
16 #include <boost/config.hpp>                    // member templates.
17 #include <boost/iostreams/char_traits.hpp>
18 #include <boost/iostreams/detail/ios.hpp>      // streamsize.
19 #include <boost/iostreams/read.hpp>
20 #include <boost/iostreams/traits.hpp>          // int_type_of.
21 #include <boost/iostreams/checked_operations.hpp>
22 #include <boost/mpl/if.hpp>
23 #include <boost/type_traits/is_same.hpp>
24 
25 namespace boost { namespace iostreams { namespace detail {
26 
27 //----------------Buffers-----------------------------------------------------//
28 
29 //
30 // Template name: buffer
31 // Description: Character buffer.
32 // Template paramters:
33 //     Ch - The character type.
34 //     Alloc - The Allocator type.
35 //
36 template< typename Ch,
37           typename Alloc = std::allocator<Ch> >
38 class basic_buffer {
39 private:
40 #ifndef BOOST_NO_STD_ALLOCATOR
41     typedef typename Alloc::template rebind<Ch>::other allocator_type;
42 #else
43     typedef std::allocator<Ch> allocator_type;
44 #endif
45 public:
46     basic_buffer();
47     basic_buffer(int buffer_size);
48     ~basic_buffer();
49     void resize(int buffer_size);
begin() const50     Ch* begin() const { return buf_; }
end() const51     Ch* end() const { return buf_ + size_; }
data() const52     Ch* data() const { return buf_; }
size() const53     std::streamsize size() const { return size_; }
54     void swap(basic_buffer& rhs);
55 private:
56     // Disallow copying and assignment.
57     basic_buffer(const basic_buffer&);
58     basic_buffer& operator=(const basic_buffer&);
59     Ch*              buf_;
60     std::streamsize  size_;
61 };
62 
63 template<typename Ch, typename Alloc>
swap(basic_buffer<Ch,Alloc> & lhs,basic_buffer<Ch,Alloc> & rhs)64 void swap(basic_buffer<Ch, Alloc>& lhs, basic_buffer<Ch, Alloc>& rhs)
65 { lhs.swap(rhs); }
66 
67 //
68 // Template name: buffer
69 // Description: Character buffer with two pointers accessible via ptr() and
70 //      eptr().
71 // Template paramters:
72 //     Ch - A character type.
73 //
74 template< typename Ch,
75           typename Alloc = std::allocator<Ch> >
76 class buffer : public basic_buffer<Ch, Alloc> {
77 private:
78     typedef basic_buffer<Ch, Alloc> base;
79 public:
80     typedef iostreams::char_traits<Ch> traits_type;
81     using base::resize;
82     using base::data;
83     using base::size;
84     typedef Ch* const const_pointer;
85     buffer(int buffer_size);
ptr()86     Ch* & ptr() { return ptr_; }
ptr() const87     const_pointer& ptr() const { return ptr_; }
eptr()88     Ch* & eptr() { return eptr_; }
eptr() const89     const_pointer& eptr() const { return eptr_; }
90     void set(std::streamsize ptr, std::streamsize end);
91     void swap(buffer& rhs);
92 
93     // Returns an int_type as a status code.
94     template<typename Source>
fill(Source & src)95     typename int_type_of<Source>::type fill(Source& src)
96     {
97         using namespace std;
98         streamsize keep;
99         if ((keep = static_cast<streamsize>(eptr_ - ptr_)) > 0)
100             traits_type::move(this->data(), ptr_, keep);
101         set(0, keep);
102         streamsize result =
103             iostreams::read(src, this->data() + keep, this->size() - keep);
104         if (result != -1)
105             this->set(0, keep + result);
106         //return result == this->size() - keep ?
107         //    traits_type::good() :
108         //    keep == -1 ?
109         //        traits_type::eof() :
110         //        traits_type::would_block();
111         return result == -1 ?
112             traits_type::eof() :
113                 result == 0 ?
114                     traits_type::would_block() :
115                     traits_type::good();
116 
117     }
118 
119     // Returns true if one or more characters were written.
120     template<typename Sink>
flush(Sink & dest)121     bool flush(Sink& dest)
122     {
123         using namespace std;
124         streamsize amt = static_cast<std::streamsize>(eptr_ - ptr_);
125         streamsize result = iostreams::write_if(dest, ptr_, amt);
126         if (result < amt) {
127             traits_type::move( this->data(),
128                                ptr_ + result,
129                                amt - result );
130         }
131         this->set(0, amt - result);
132         return result != 0;
133     }
134 private:
135     Ch *ptr_, *eptr_;
136 };
137 
138 template<typename Ch, typename Alloc>
swap(buffer<Ch,Alloc> & lhs,buffer<Ch,Alloc> & rhs)139 void swap(buffer<Ch, Alloc>& lhs, buffer<Ch, Alloc>& rhs)
140 { lhs.swap(rhs); }
141 
142 //--------------Implementation of basic_buffer--------------------------------//
143 
144 template<typename Ch, typename Alloc>
basic_buffer()145 basic_buffer<Ch, Alloc>::basic_buffer() : buf_(0), size_(0) { }
146 
147 template<typename Ch, typename Alloc>
basic_buffer(int buffer_size)148 basic_buffer<Ch, Alloc>::basic_buffer(int buffer_size)
149     : buf_(static_cast<Ch*>(allocator_type().allocate(buffer_size, 0))),
150       size_(buffer_size) // Cast for SunPro 5.3.
151     { }
152 
153 template<typename Ch, typename Alloc>
~basic_buffer()154 inline basic_buffer<Ch, Alloc>::~basic_buffer()
155 { if (buf_) allocator_type().deallocate(buf_, size_); }
156 
157 template<typename Ch, typename Alloc>
resize(int buffer_size)158 inline void basic_buffer<Ch, Alloc>::resize(int buffer_size)
159 {
160     if (size_ != buffer_size) {
161         basic_buffer<Ch, Alloc> temp(buffer_size);
162         std::swap(size_, temp.size_);
163         std::swap(buf_, temp.buf_);
164     }
165 }
166 
167 template<typename Ch, typename Alloc>
swap(basic_buffer & rhs)168 void basic_buffer<Ch, Alloc>::swap(basic_buffer& rhs)
169 {
170     std::swap(buf_, rhs.buf_);
171     std::swap(size_, rhs.size_);
172 }
173 
174 //--------------Implementation of buffer--------------------------------------//
175 
176 template<typename Ch, typename Alloc>
buffer(int buffer_size)177 buffer<Ch, Alloc>::buffer(int buffer_size)
178     : basic_buffer<Ch, Alloc>(buffer_size) { }
179 
180 template<typename Ch, typename Alloc>
set(std::streamsize ptr,std::streamsize end)181 inline void buffer<Ch, Alloc>::set(std::streamsize ptr, std::streamsize end)
182 {
183     ptr_ = data() + ptr;
184     eptr_ = data() + end;
185 }
186 
187 template<typename Ch, typename Alloc>
swap(buffer & rhs)188 inline void buffer<Ch, Alloc>::swap(buffer& rhs)
189 {
190     base::swap(rhs);
191     std::swap(ptr_, rhs.ptr_);
192     std::swap(eptr_, rhs.eptr_);
193 }
194 
195 //----------------------------------------------------------------------------//
196 
197 } } } // End namespaces detail, iostreams, boost.
198 
199 #endif // #ifndef BOOST_IOSTREAMS_DETAIL_BUFFERS_HPP_INCLUDED
200