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